Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / libafscp / afscp_fid.c
1 /* AUTORIGHTS
2 Copyright (C) 2003 - 2010 Chaskiel Grundman
3 All rights reserved
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
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.
15
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.
26 */
27 #include <afsconfig.h>
28 #include <afs/param.h>
29
30 #include <roken.h>
31
32 #include <search.h>
33
34 #include <afs/vlserver.h>
35 #include <afs/vldbint.h>
36 #include "afscp.h"
37 #include "afscp_internal.h"
38
39 /*
40 * Allocate and populate an afscp_venusfid struct from component parts
41 */
42 struct afscp_venusfid *
43 afscp_MakeFid(struct afscp_cell *cell, afs_uint32 volume,
44 afs_uint32 vnode, afs_uint32 unique)
45 {
46 struct afscp_venusfid *ret;
47
48 if (cell == NULL) {
49 return NULL;
50 }
51 ret = malloc(sizeof(struct afscp_venusfid));
52 if (ret == NULL) {
53 afscp_errno = errno;
54 return NULL;
55 }
56 ret->cell = cell;
57 ret->fid.Volume = volume;
58 ret->fid.Vnode = vnode;
59 ret->fid.Unique = unique;
60 return ret;
61 }
62
63 /*
64 * Duplicate an existing afscp_venusfid struct
65 */
66 struct afscp_venusfid *
67 afscp_DupFid(const struct afscp_venusfid *in)
68 {
69 struct afscp_venusfid *ret;
70
71 ret = malloc(sizeof(struct afscp_venusfid));
72 if (ret == NULL) {
73 afscp_errno = errno;
74 return NULL;
75 }
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;
81 }
82
83 void
84 afscp_FreeFid(struct afscp_venusfid *avfp)
85 {
86 if (avfp != NULL)
87 free(avfp);
88 }
89
90 static int
91 statcompare(const void *a, const void *b)
92 {
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;
103 }
104
105 static void
106 _StatCleanup(struct afscp_statent *stored)
107 {
108 pthread_cond_destroy(&(stored->cv));
109 pthread_mutex_unlock(&(stored->mtx));
110 pthread_mutex_destroy(&(stored->mtx));
111 free(stored);
112 }
113
114 int
115 afscp_WaitForCallback(const struct afscp_venusfid *fid, int seconds)
116 {
117 void **cached;
118 struct afscp_volume *v;
119 struct afscp_statent *stored, key;
120 int code = 0;
121
122 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
123 if (v == NULL) {
124 return -1;
125 }
126 memmove(&key.me, fid, sizeof(*fid));
127
128 cached = tfind(&key, &v->statcache, statcompare);
129 if (cached != NULL) {
130 struct timeval tv;
131 struct timespec ts;
132
133 stored = *(struct afscp_statent **)cached;
134
135 if (seconds) {
136 gettimeofday(&tv, NULL);
137 ts.tv_sec = tv.tv_sec + seconds;
138 ts.tv_nsec = 0;
139 }
140
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));
153 }
154 }
155 if ((code == EINTR) || (code == ETIMEDOUT)) {
156 afscp_errno = code;
157 code = -1;
158 }
159 return code;
160 }
161
162 int
163 afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
164 {
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;
174
175 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
176 if (v == NULL) {
177 return -1;
178 }
179 memset(&key, 0, sizeof(key));
180 memcpy(&key.me, fid, sizeof(*fid));
181
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;
194 }
195
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;
214 }
215 }
216 }
217 }
218 afscp_errno = code;
219 return -1;
220 }
221
222 int
223 afscp_Stat(const struct afscp_venusfid *fid, struct stat *s)
224 {
225
226 struct AFSFetchStatus status;
227 int code;
228
229
230 if (s == NULL || fid == NULL) {
231 fprintf(stderr, "NULL args given to afscp_Stat, cannot continue\n");
232 return -1;
233 }
234
235 code = afscp_GetStatus(fid, &status);
236 if (code != 0) {
237 return code;
238 }
239
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;
252 }
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;
262 }
263
264 int
265 afscp_CheckCallBack(const struct afscp_venusfid *fid, const struct afscp_server *server, afs_uint32 *expiretime)
266 {
267 struct AFSFetchStatus status;
268 struct afscp_callback *cb = NULL;
269 int code;
270 time_t now;
271
272 if (expiretime == NULL || fid == NULL) {
273 fprintf(stderr, "NULL args given to afscp_CheckCallback, cannot continue\n");
274 return -1;
275 }
276
277 *expiretime = 0;
278
279 code = afscp_GetStatus(fid, &status);
280 if (code != 0)
281 return code;
282
283 code = afscp_FindCallBack(fid, server, &cb);
284 if (code != 0)
285 return code;
286
287 if (cb) {
288 time(&now);
289 *expiretime = cb->cb.ExpirationTime + cb->as_of - now;
290 }
291
292 return 0;
293 }
294
295 int
296 _StatInvalidate(const struct afscp_venusfid *fid)
297 {
298 struct afscp_volume *v;
299 struct afscp_statent *stored, key;
300 void **cached;
301
302 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
303 if (v == NULL) {
304 return -1;
305 }
306 memmove(&key.me, fid, sizeof(*fid));
307
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);
321 }
322 }
323 return 0;
324 }
325
326 int
327 _StatStuff(const struct afscp_venusfid *fid, const struct AFSFetchStatus *s)
328 {
329 struct afscp_volume *v;
330 struct afscp_statent key, *stored;
331 void **cached;
332
333 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
334 if (v == NULL) {
335 return -1;
336 }
337 memmove(&key.me, fid, sizeof(*fid));
338
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);
352 }
353 }
354 return 0;
355 }
356
357 int
358 afscp_StoreStatus(const struct afscp_venusfid *fid, struct AFSStoreStatus *s)
359 {
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;
366
367 v = afscp_VolumeById(fid->cell, fid->fid.Volume);
368 if (v == NULL) {
369 return -1;
370 }
371
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;
381 }
382 }
383 }
384 }
385 afscp_errno = code;
386 return -1;
387 }