Merge 1.8.0~pre4 packaging into master
[pkg-k5-afs_openafs.git] / src / libafscp / afscp_fid.c
blob7c3ca65368bb9865f4e557c958d7b9b9fd9fc5ed
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 #include <roken.h>
32 #include <search.h>
34 #include <afs/vlserver.h>
35 #include <afs/vldbint.h>
36 #include "afscp.h"
37 #include "afscp_internal.h"
40 * Allocate and populate an afscp_venusfid struct from component parts
42 struct afscp_venusfid *
43 afscp_MakeFid(struct afscp_cell *cell, afs_uint32 volume,
44 afs_uint32 vnode, afs_uint32 unique)
46 struct afscp_venusfid *ret;
48 if (cell == NULL) {
49 return NULL;
51 ret = malloc(sizeof(struct afscp_venusfid));
52 if (ret == NULL) {
53 afscp_errno = errno;
54 return NULL;
56 ret->cell = cell;
57 ret->fid.Volume = volume;
58 ret->fid.Vnode = vnode;
59 ret->fid.Unique = unique;
60 return ret;
64 * Duplicate an existing afscp_venusfid struct
66 struct afscp_venusfid *
67 afscp_DupFid(const struct afscp_venusfid *in)
69 struct afscp_venusfid *ret;
71 ret = malloc(sizeof(struct afscp_venusfid));
72 if (ret == NULL) {
73 afscp_errno = errno;
74 return NULL;
76 ret->cell = in->cell;
77 ret->fid.Volume = in->fid.Volume;
78 ret->fid.Vnode = in->fid.Vnode;
79 ret->fid.Unique = in->fid.Unique;
80 return ret;
83 void
84 afscp_FreeFid(struct afscp_venusfid *avfp)
86 if (avfp != NULL)
87 free(avfp);
90 static int
91 statcompare(const void *a, const void *b)
93 const struct afscp_statent *sa = a, *sb = b;
94 if (sa->me.fid.Vnode < sb->me.fid.Vnode)
95 return -1;
96 if (sa->me.fid.Vnode > sb->me.fid.Vnode)
97 return 1;
98 if (sa->me.fid.Unique < sb->me.fid.Unique)
99 return -1;
100 if (sa->me.fid.Unique > sb->me.fid.Unique)
101 return 1;
102 return 0;
105 static void
106 _StatCleanup(struct afscp_statent *stored)
108 pthread_cond_destroy(&(stored->cv));
109 pthread_mutex_unlock(&(stored->mtx));
110 pthread_mutex_destroy(&(stored->mtx));
111 free(stored);
115 afscp_WaitForCallback(const struct afscp_venusfid *fid, int seconds)
117 void **cached;
118 struct afscp_volume *v;
119 struct afscp_statent *stored, key;
120 int code = 0;
122 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
123 if (v == NULL) {
124 return -1;
126 memmove(&key.me, fid, sizeof(*fid));
128 cached = tfind(&key, &v->statcache, statcompare);
129 if (cached != NULL) {
130 struct timeval tv;
131 struct timespec ts;
133 stored = *(struct afscp_statent **)cached;
135 if (seconds) {
136 gettimeofday(&tv, NULL);
137 ts.tv_sec = tv.tv_sec + seconds;
138 ts.tv_nsec = 0;
141 pthread_mutex_lock(&(stored->mtx));
142 stored->nwaiters++;
143 if (seconds)
144 code = pthread_cond_timedwait(&(stored->cv), &(stored->mtx), &ts);
145 else
146 pthread_cond_wait(&(stored->cv), &(stored->mtx));
147 if ((stored->nwaiters == 1) && stored->cleanup) {
148 pthread_mutex_unlock(&(stored->mtx));
149 _StatCleanup(stored);
150 } else {
151 stored->nwaiters--;
152 pthread_mutex_unlock(&(stored->mtx));
155 if ((code == EINTR) || (code == ETIMEDOUT)) {
156 afscp_errno = code;
157 code = -1;
159 return code;
163 afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
165 struct afscp_volume *v;
166 struct afscp_server *server;
167 struct AFSCallBack cb;
168 struct AFSVolSync vs;
169 struct AFSFid tf = fid->fid;
170 struct afscp_statent *stored, key;
171 void *cached;
172 int code, i, j;
173 time_t now;
175 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
176 if (v == NULL) {
177 return -1;
179 memset(&key, 0, sizeof(key));
180 memcpy(&key.me, fid, sizeof(*fid));
182 cached = tfind(&key, &v->statcache, statcompare);
183 if (cached != NULL) {
184 stored = *(struct afscp_statent **)cached;
185 pthread_mutex_lock(&(stored->mtx));
186 memmove(s, &stored->status, sizeof(*s));
187 afs_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n",
188 fid->cell->id, fid->fid.Volume, fid->fid.Vnode,
189 fid->fid.Unique));
190 if (stored->nwaiters)
191 pthread_cond_broadcast(&(stored->cv));
192 pthread_mutex_unlock(&(stored->mtx));
193 return 0;
196 code = ENOENT;
197 for (i = 0; i < v->nservers; i++) {
198 server = afscp_ServerByIndex(v->servers[i]);
199 if (server && server->naddrs > 0) {
200 for (j = 0; j < server->naddrs; j++) {
201 time(&now);
202 code = RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs);
203 if (code == 0) {
204 afscp_AddCallBack(server, &fid->fid, s, &cb, now); /* calls _StatStuff */
205 afs_dprintf(("Stat %d.%lu.%lu.%lu"
206 " ok: type %ld size %ld\n",
207 fid->cell->id,
208 afs_printable_uint32_lu(fid->fid.Volume),
209 afs_printable_uint32_lu(fid->fid.Vnode),
210 afs_printable_uint32_lu(fid->fid.Unique),
211 afs_printable_int32_ld(s->FileType),
212 afs_printable_int32_ld(s->Length)));
213 return 0;
218 afscp_errno = code;
219 return -1;
223 afscp_Stat(const struct afscp_venusfid *fid, struct stat *s)
226 struct AFSFetchStatus status;
227 int code;
230 if (s == NULL || fid == NULL) {
231 fprintf(stderr, "NULL args given to afscp_Stat, cannot continue\n");
232 return -1;
235 code = afscp_GetStatus(fid, &status);
236 if (code != 0) {
237 return code;
240 if (status.FileType == File)
241 s->st_mode = S_IFREG;
242 else if (status.FileType == Directory)
243 s->st_mode = S_IFDIR;
244 #ifndef AFS_NT40_ENV
245 else if (status.FileType == SymbolicLink)
246 s->st_mode = S_IFLNK;
247 /* a behavior needs to be defined on Windows */
248 #endif
249 else {
250 afscp_errno = EINVAL;
251 return -1;
253 s->st_mode |= (status.UnixModeBits & (~S_IFMT));
254 s->st_nlink = status.LinkCount;
255 s->st_size = status.Length;
256 s->st_uid = status.Owner;
257 /*s->st_blksize=status.SegSize; */
258 s->st_atime = s->st_mtime = status.ClientModTime;
259 s->st_ctime = status.ServerModTime;
260 s->st_gid = status.Group;
261 return 0;
265 afscp_CheckCallBack(const struct afscp_venusfid *fid, const struct afscp_server *server, afs_uint32 *expiretime)
267 struct AFSFetchStatus status;
268 struct afscp_callback *cb = NULL;
269 int code;
270 time_t now;
272 if (expiretime == NULL || fid == NULL) {
273 fprintf(stderr, "NULL args given to afscp_CheckCallback, cannot continue\n");
274 return -1;
277 *expiretime = 0;
279 code = afscp_GetStatus(fid, &status);
280 if (code != 0)
281 return code;
283 code = afscp_FindCallBack(fid, server, &cb);
284 if (code != 0)
285 return code;
287 if (cb) {
288 time(&now);
289 *expiretime = cb->cb.ExpirationTime + cb->as_of - now;
292 return 0;
296 _StatInvalidate(const struct afscp_venusfid *fid)
298 struct afscp_volume *v;
299 struct afscp_statent *stored, key;
300 void **cached;
302 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
303 if (v == NULL) {
304 return -1;
306 memmove(&key.me, fid, sizeof(*fid));
308 cached = tfind(&key, &v->statcache, statcompare);
309 if (cached != NULL) {
310 stored = *(struct afscp_statent **)cached;
311 pthread_mutex_lock(&(stored->mtx));
312 tdelete(&key, &v->statcache, statcompare);
313 if (stored->nwaiters) {
314 /* avoid blocking callback thread */
315 pthread_cond_broadcast(&(stored->cv));
316 stored->cleanup = 1;
317 pthread_mutex_unlock(&(stored->mtx));
318 } else {
319 pthread_mutex_unlock(&(stored->mtx));
320 _StatCleanup(stored);
323 return 0;
327 _StatStuff(const struct afscp_venusfid *fid, const struct AFSFetchStatus *s)
329 struct afscp_volume *v;
330 struct afscp_statent key, *stored;
331 void **cached;
333 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
334 if (v == NULL) {
335 return -1;
337 memmove(&key.me, fid, sizeof(*fid));
339 cached = tsearch(&key, &v->statcache, statcompare);
340 if (cached != NULL) {
341 stored = malloc(sizeof(struct afscp_statent));
342 if (stored != NULL) {
343 pthread_mutex_init(&(stored->mtx), NULL);
344 pthread_cond_init(&(stored->cv), NULL);
345 stored->nwaiters = 0;
346 stored->cleanup = 0;
347 memmove(&stored->me, fid, sizeof(*fid));
348 memmove(&stored->status, s, sizeof(*s));
349 *(struct afscp_statent **)cached = stored;
350 } else {
351 tdelete(&key, &v->statcache, statcompare);
354 return 0;
358 afscp_StoreStatus(const struct afscp_venusfid *fid, struct AFSStoreStatus *s)
360 struct afscp_volume *v;
361 struct afscp_server *server;
362 struct AFSVolSync vs;
363 struct AFSFetchStatus fst;
364 struct AFSFid tf = fid->fid;
365 int code, i, j;
367 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
368 if (v == NULL) {
369 return -1;
372 code = ENOENT;
373 for (i = 0; i < v->nservers; i++) {
374 server = afscp_ServerByIndex(v->servers[i]);
375 if (server && server->naddrs > 0) {
376 for (j = 0; j < server->naddrs; j++) {
377 code = RXAFS_StoreStatus(server->conns[j], &tf, s, &fst, &vs);
378 if (code == 0) {
379 _StatStuff(fid, &fst); /* calls _StatStuff */
380 return 0;
385 afscp_errno = code;
386 return -1;