Pull in patch that properly includes stdint.h
[pkg-k5-afs_openafs.git] / src / libafscp / afscp_fid.c
blob2aad962672a5ac3cf229dac4146982e1fdac17b0
1 /* AUTORIGHTS
2 Copyright (C) 2003 - 2010 Chaskiel Grundman
3 All rights reserved
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <afsconfig.h>
28 #include <afs/param.h>
30 #ifdef HAVE_SEARCH_H
31 #include <search.h>
32 #else
33 #include "afscp_search.h"
34 #endif
36 #include <afs/vlserver.h>
37 #include <afs/vldbint.h>
38 #include "afscp.h"
39 #include "afscp_internal.h"
42 * Allocate and populate an afscp_venusfid struct from component parts
44 struct afscp_venusfid *
45 afscp_MakeFid(struct afscp_cell *cell, afs_uint32 volume,
46 afs_uint32 vnode, afs_uint32 unique)
48 struct afscp_venusfid *ret;
50 if (cell == NULL) {
51 return NULL;
53 ret = malloc(sizeof(struct afscp_venusfid));
54 if (ret == NULL) {
55 afscp_errno = errno;
56 return NULL;
58 ret->cell = cell;
59 ret->fid.Volume = volume;
60 ret->fid.Vnode = vnode;
61 ret->fid.Unique = unique;
62 return ret;
66 * Duplicate an existing afscp_venusfid struct
68 struct afscp_venusfid *
69 afscp_DupFid(const struct afscp_venusfid *in)
71 struct afscp_venusfid *ret;
73 ret = malloc(sizeof(struct afscp_venusfid));
74 if (ret == NULL) {
75 afscp_errno = errno;
76 return NULL;
78 ret->cell = in->cell;
79 ret->fid.Volume = in->fid.Volume;
80 ret->fid.Vnode = in->fid.Vnode;
81 ret->fid.Unique = in->fid.Unique;
82 return ret;
85 void
86 afscp_FreeFid(struct afscp_venusfid *avfp)
88 if (avfp != NULL)
89 free(avfp);
92 static int
93 statcompare(const void *a, const void *b)
95 const struct afscp_statent *sa = a, *sb = b;
96 if (sa->me.fid.Vnode < sb->me.fid.Vnode)
97 return -1;
98 if (sa->me.fid.Vnode > sb->me.fid.Vnode)
99 return 1;
100 if (sa->me.fid.Unique < sb->me.fid.Unique)
101 return -1;
102 if (sa->me.fid.Unique > sb->me.fid.Unique)
103 return 1;
104 return 0;
107 static void
108 _StatCleanup(struct afscp_statent *stored)
110 pthread_cond_destroy(&(stored->cv));
111 pthread_mutex_unlock(&(stored->mtx));
112 pthread_mutex_destroy(&(stored->mtx));
113 free(stored);
117 afscp_WaitForCallback(const struct afscp_venusfid *fid, int seconds)
119 void **cached;
120 struct afscp_volume *v;
121 struct afscp_statent *stored, key;
122 int code = 0;
124 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
125 if (v == NULL) {
126 return -1;
128 memmove(&key.me, fid, sizeof(*fid));
130 cached = tfind(&key, &v->statcache, statcompare);
131 if (cached != NULL) {
132 struct timeval tv;
133 struct timespec ts;
135 stored = *(struct afscp_statent **)cached;
137 if (seconds) {
138 gettimeofday(&tv, NULL);
139 ts.tv_sec = tv.tv_sec + seconds;
140 ts.tv_nsec = 0;
143 pthread_mutex_lock(&(stored->mtx));
144 stored->nwaiters++;
145 if (seconds)
146 code = pthread_cond_timedwait(&(stored->cv), &(stored->mtx), &ts);
147 else
148 pthread_cond_wait(&(stored->cv), &(stored->mtx));
149 if ((stored->nwaiters == 1) && stored->cleanup) {
150 pthread_mutex_unlock(&(stored->mtx));
151 _StatCleanup(stored);
152 } else {
153 stored->nwaiters--;
154 pthread_mutex_unlock(&(stored->mtx));
157 if ((code == EINTR) || (code == ETIMEDOUT)) {
158 afscp_errno = code;
159 code = -1;
161 return code;
165 afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
167 struct afscp_volume *v;
168 struct afscp_server *server;
169 struct AFSCallBack cb;
170 struct AFSVolSync vs;
171 struct AFSFid tf = fid->fid;
172 struct afscp_statent *stored, key;
173 void *cached;
174 int code, i, j;
175 time_t now;
177 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
178 if (v == NULL) {
179 return -1;
181 memset(&key, 0, sizeof(key));
182 memcpy(&key.me, fid, sizeof(*fid));
184 cached = tfind(&key, &v->statcache, statcompare);
185 if (cached != NULL) {
186 stored = *(struct afscp_statent **)cached;
187 pthread_mutex_lock(&(stored->mtx));
188 memmove(s, &stored->status, sizeof(*s));
189 afs_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n",
190 fid->cell->id, fid->fid.Volume, fid->fid.Vnode,
191 fid->fid.Unique));
192 if (stored->nwaiters)
193 pthread_cond_broadcast(&(stored->cv));
194 pthread_mutex_unlock(&(stored->mtx));
195 return 0;
198 code = ENOENT;
199 for (i = 0; i < v->nservers; i++) {
200 server = afscp_ServerByIndex(v->servers[i]);
201 if (server && server->naddrs > 0) {
202 for (j = 0; j < server->naddrs; j++) {
203 time(&now);
204 code = RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs);
205 if (code == 0) {
206 afscp_AddCallBack(server, &fid->fid, s, &cb, now); /* calls _StatStuff */
207 afs_dprintf(("Stat %d.%lu.%lu.%lu"
208 " ok: type %ld size %ld\n",
209 fid->cell->id,
210 afs_printable_uint32_lu(fid->fid.Volume),
211 afs_printable_uint32_lu(fid->fid.Vnode),
212 afs_printable_uint32_lu(fid->fid.Unique),
213 afs_printable_int32_ld(s->FileType),
214 afs_printable_int32_ld(s->Length)));
215 return 0;
220 afscp_errno = code;
221 return -1;
225 afscp_Stat(const struct afscp_venusfid *fid, struct stat *s)
228 struct AFSFetchStatus status;
229 int code;
232 if (s == NULL || fid == NULL) {
233 fprintf(stderr, "NULL args given to afscp_Stat, cannot continue\n");
234 return -1;
237 code = afscp_GetStatus(fid, &status);
238 if (code != 0) {
239 return code;
242 if (status.FileType == File)
243 s->st_mode = S_IFREG;
244 else if (status.FileType == Directory)
245 s->st_mode = S_IFDIR;
246 #ifndef AFS_NT40_ENV
247 else if (status.FileType == SymbolicLink)
248 s->st_mode = S_IFLNK;
249 /* a behavior needs to be defined on Windows */
250 #endif
251 else {
252 afscp_errno = EINVAL;
253 return -1;
255 s->st_mode |= (status.UnixModeBits & (~S_IFMT));
256 s->st_nlink = status.LinkCount;
257 s->st_size = status.Length;
258 s->st_uid = status.Owner;
259 /*s->st_blksize=status.SegSize; */
260 s->st_atime = s->st_mtime = status.ClientModTime;
261 s->st_ctime = status.ServerModTime;
262 s->st_gid = status.Group;
263 return 0;
267 afscp_CheckCallBack(const struct afscp_venusfid *fid, const struct afscp_server *server, afs_uint32 *expiretime)
269 struct AFSFetchStatus status;
270 struct afscp_callback *cb = NULL;
271 int code;
272 time_t now;
274 if (expiretime == NULL || fid == NULL) {
275 fprintf(stderr, "NULL args given to afscp_CheckCallback, cannot continue\n");
276 return -1;
279 *expiretime = 0;
281 code = afscp_GetStatus(fid, &status);
282 if (code != 0)
283 return code;
285 code = afscp_FindCallBack(fid, server, &cb);
286 if (code != 0)
287 return code;
289 if (cb) {
290 time(&now);
291 *expiretime = cb->cb.ExpirationTime + cb->as_of - now;
294 return 0;
298 _StatInvalidate(const struct afscp_venusfid *fid)
300 struct afscp_volume *v;
301 struct afscp_statent *stored, key;
302 void **cached;
304 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
305 if (v == NULL) {
306 return -1;
308 memmove(&key.me, fid, sizeof(*fid));
310 cached = tfind(&key, &v->statcache, statcompare);
311 if (cached != NULL) {
312 stored = *(struct afscp_statent **)cached;
313 pthread_mutex_lock(&(stored->mtx));
314 tdelete(&key, &v->statcache, statcompare);
315 if (stored->nwaiters) {
316 /* avoid blocking callback thread */
317 pthread_cond_broadcast(&(stored->cv));
318 stored->cleanup = 1;
319 pthread_mutex_unlock(&(stored->mtx));
320 } else {
321 pthread_mutex_unlock(&(stored->mtx));
322 _StatCleanup(stored);
325 return 0;
329 _StatStuff(const struct afscp_venusfid *fid, const struct AFSFetchStatus *s)
331 struct afscp_volume *v;
332 struct afscp_statent key, *stored;
333 void **cached;
335 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
336 if (v == NULL) {
337 return -1;
339 memmove(&key.me, fid, sizeof(*fid));
341 cached = tsearch(&key, &v->statcache, statcompare);
342 if (cached != NULL) {
343 stored = malloc(sizeof(struct afscp_statent));
344 if (stored != NULL) {
345 pthread_mutex_init(&(stored->mtx), NULL);
346 pthread_cond_init(&(stored->cv), NULL);
347 stored->nwaiters = 0;
348 stored->cleanup = 0;
349 memmove(&stored->me, fid, sizeof(*fid));
350 memmove(&stored->status, s, sizeof(*s));
351 *(struct afscp_statent **)cached = stored;
352 } else {
353 tdelete(&key, &v->statcache, statcompare);
356 return 0;
360 afscp_StoreStatus(const struct afscp_venusfid *fid, struct AFSStoreStatus *s)
362 struct afscp_volume *v;
363 struct afscp_server *server;
364 struct AFSVolSync vs;
365 struct AFSFetchStatus fst;
366 struct AFSFid tf = fid->fid;
367 int code, i, j;
369 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
370 if (v == NULL) {
371 return -1;
374 code = ENOENT;
375 for (i = 0; i < v->nservers; i++) {
376 server = afscp_ServerByIndex(v->servers[i]);
377 if (server && server->naddrs > 0) {
378 for (j = 0; j < server->naddrs; j++) {
379 code = RXAFS_StoreStatus(server->conns[j], &tf, s, &fst, &vs);
380 if (code == 0) {
381 _StatStuff(fid, &fst); /* calls _StatStuff */
382 return 0;
387 afscp_errno = code;
388 return -1;