2 Copyright (C) 2003 - 2010 Chaskiel Grundman
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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>
33 #include "afscp_search.h"
36 #include <afs/vlserver.h>
37 #include <afs/vldbint.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
;
53 ret
= malloc(sizeof(struct afscp_venusfid
));
59 ret
->fid
.Volume
= volume
;
60 ret
->fid
.Vnode
= vnode
;
61 ret
->fid
.Unique
= unique
;
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
));
79 ret
->fid
.Volume
= in
->fid
.Volume
;
80 ret
->fid
.Vnode
= in
->fid
.Vnode
;
81 ret
->fid
.Unique
= in
->fid
.Unique
;
86 afscp_FreeFid(struct afscp_venusfid
*avfp
)
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
)
98 if (sa
->me
.fid
.Vnode
> sb
->me
.fid
.Vnode
)
100 if (sa
->me
.fid
.Unique
< sb
->me
.fid
.Unique
)
102 if (sa
->me
.fid
.Unique
> sb
->me
.fid
.Unique
)
108 _StatCleanup(struct afscp_statent
*stored
)
110 pthread_cond_destroy(&(stored
->cv
));
111 pthread_mutex_unlock(&(stored
->mtx
));
112 pthread_mutex_destroy(&(stored
->mtx
));
117 afscp_WaitForCallback(const struct afscp_venusfid
*fid
, int seconds
)
120 struct afscp_volume
*v
;
121 struct afscp_statent
*stored
, key
;
124 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
128 memmove(&key
.me
, fid
, sizeof(*fid
));
130 cached
= tfind(&key
, &v
->statcache
, statcompare
);
131 if (cached
!= NULL
) {
135 stored
= *(struct afscp_statent
**)cached
;
138 gettimeofday(&tv
, NULL
);
139 ts
.tv_sec
= tv
.tv_sec
+ seconds
;
143 pthread_mutex_lock(&(stored
->mtx
));
146 code
= pthread_cond_timedwait(&(stored
->cv
), &(stored
->mtx
), &ts
);
148 pthread_cond_wait(&(stored
->cv
), &(stored
->mtx
));
149 if ((stored
->nwaiters
== 1) && stored
->cleanup
) {
150 pthread_mutex_unlock(&(stored
->mtx
));
151 _StatCleanup(stored
);
154 pthread_mutex_unlock(&(stored
->mtx
));
157 if ((code
== EINTR
) || (code
== ETIMEDOUT
)) {
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
;
177 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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
,
192 if (stored
->nwaiters
)
193 pthread_cond_broadcast(&(stored
->cv
));
194 pthread_mutex_unlock(&(stored
->mtx
));
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
++) {
204 code
= RXAFS_FetchStatus(server
->conns
[j
], &tf
, s
, &cb
, &vs
);
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",
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
)));
225 afscp_Stat(const struct afscp_venusfid
*fid
, struct stat
*s
)
228 struct AFSFetchStatus status
;
232 if (s
== NULL
|| fid
== NULL
) {
233 fprintf(stderr
, "NULL args given to afscp_Stat, cannot continue\n");
237 code
= afscp_GetStatus(fid
, &status
);
242 if (status
.FileType
== File
)
243 s
->st_mode
= S_IFREG
;
244 else if (status
.FileType
== Directory
)
245 s
->st_mode
= S_IFDIR
;
247 else if (status
.FileType
== SymbolicLink
)
248 s
->st_mode
= S_IFLNK
;
249 /* a behavior needs to be defined on Windows */
252 afscp_errno
= EINVAL
;
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
;
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
;
274 if (expiretime
== NULL
|| fid
== NULL
) {
275 fprintf(stderr
, "NULL args given to afscp_CheckCallback, cannot continue\n");
281 code
= afscp_GetStatus(fid
, &status
);
285 code
= afscp_FindCallBack(fid
, server
, &cb
);
291 *expiretime
= cb
->cb
.ExpirationTime
+ cb
->as_of
- now
;
298 _StatInvalidate(const struct afscp_venusfid
*fid
)
300 struct afscp_volume
*v
;
301 struct afscp_statent
*stored
, key
;
304 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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
));
319 pthread_mutex_unlock(&(stored
->mtx
));
321 pthread_mutex_unlock(&(stored
->mtx
));
322 _StatCleanup(stored
);
329 _StatStuff(const struct afscp_venusfid
*fid
, const struct AFSFetchStatus
*s
)
331 struct afscp_volume
*v
;
332 struct afscp_statent key
, *stored
;
335 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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;
349 memmove(&stored
->me
, fid
, sizeof(*fid
));
350 memmove(&stored
->status
, s
, sizeof(*s
));
351 *(struct afscp_statent
**)cached
= stored
;
353 tdelete(&key
, &v
->statcache
, statcompare
);
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
;
369 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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
);
381 _StatStuff(fid
, &fst
); /* calls _StatStuff */