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>
34 #include <afs/vlserver.h>
35 #include <afs/vldbint.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
;
51 ret
= malloc(sizeof(struct afscp_venusfid
));
57 ret
->fid
.Volume
= volume
;
58 ret
->fid
.Vnode
= vnode
;
59 ret
->fid
.Unique
= unique
;
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
));
77 ret
->fid
.Volume
= in
->fid
.Volume
;
78 ret
->fid
.Vnode
= in
->fid
.Vnode
;
79 ret
->fid
.Unique
= in
->fid
.Unique
;
84 afscp_FreeFid(struct afscp_venusfid
*avfp
)
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
)
96 if (sa
->me
.fid
.Vnode
> sb
->me
.fid
.Vnode
)
98 if (sa
->me
.fid
.Unique
< sb
->me
.fid
.Unique
)
100 if (sa
->me
.fid
.Unique
> sb
->me
.fid
.Unique
)
106 _StatCleanup(struct afscp_statent
*stored
)
108 pthread_cond_destroy(&(stored
->cv
));
109 pthread_mutex_unlock(&(stored
->mtx
));
110 pthread_mutex_destroy(&(stored
->mtx
));
115 afscp_WaitForCallback(const struct afscp_venusfid
*fid
, int seconds
)
118 struct afscp_volume
*v
;
119 struct afscp_statent
*stored
, key
;
122 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
126 memmove(&key
.me
, fid
, sizeof(*fid
));
128 cached
= tfind(&key
, &v
->statcache
, statcompare
);
129 if (cached
!= NULL
) {
133 stored
= *(struct afscp_statent
**)cached
;
136 gettimeofday(&tv
, NULL
);
137 ts
.tv_sec
= tv
.tv_sec
+ seconds
;
141 pthread_mutex_lock(&(stored
->mtx
));
144 code
= pthread_cond_timedwait(&(stored
->cv
), &(stored
->mtx
), &ts
);
146 pthread_cond_wait(&(stored
->cv
), &(stored
->mtx
));
147 if ((stored
->nwaiters
== 1) && stored
->cleanup
) {
148 pthread_mutex_unlock(&(stored
->mtx
));
149 _StatCleanup(stored
);
152 pthread_mutex_unlock(&(stored
->mtx
));
155 if ((code
== EINTR
) || (code
== ETIMEDOUT
)) {
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
;
175 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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
,
190 if (stored
->nwaiters
)
191 pthread_cond_broadcast(&(stored
->cv
));
192 pthread_mutex_unlock(&(stored
->mtx
));
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
++) {
202 code
= RXAFS_FetchStatus(server
->conns
[j
], &tf
, s
, &cb
, &vs
);
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",
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
)));
223 afscp_Stat(const struct afscp_venusfid
*fid
, struct stat
*s
)
226 struct AFSFetchStatus status
;
230 if (s
== NULL
|| fid
== NULL
) {
231 fprintf(stderr
, "NULL args given to afscp_Stat, cannot continue\n");
235 code
= afscp_GetStatus(fid
, &status
);
240 if (status
.FileType
== File
)
241 s
->st_mode
= S_IFREG
;
242 else if (status
.FileType
== Directory
)
243 s
->st_mode
= S_IFDIR
;
245 else if (status
.FileType
== SymbolicLink
)
246 s
->st_mode
= S_IFLNK
;
247 /* a behavior needs to be defined on Windows */
250 afscp_errno
= EINVAL
;
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
;
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
;
272 if (expiretime
== NULL
|| fid
== NULL
) {
273 fprintf(stderr
, "NULL args given to afscp_CheckCallback, cannot continue\n");
279 code
= afscp_GetStatus(fid
, &status
);
283 code
= afscp_FindCallBack(fid
, server
, &cb
);
289 *expiretime
= cb
->cb
.ExpirationTime
+ cb
->as_of
- now
;
296 _StatInvalidate(const struct afscp_venusfid
*fid
)
298 struct afscp_volume
*v
;
299 struct afscp_statent
*stored
, key
;
302 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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
));
317 pthread_mutex_unlock(&(stored
->mtx
));
319 pthread_mutex_unlock(&(stored
->mtx
));
320 _StatCleanup(stored
);
327 _StatStuff(const struct afscp_venusfid
*fid
, const struct AFSFetchStatus
*s
)
329 struct afscp_volume
*v
;
330 struct afscp_statent key
, *stored
;
333 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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;
347 memmove(&stored
->me
, fid
, sizeof(*fid
));
348 memmove(&stored
->status
, s
, sizeof(*s
));
349 *(struct afscp_statent
**)cached
= stored
;
351 tdelete(&key
, &v
->statcache
, statcompare
);
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
;
367 v
= afscp_VolumeById(fid
->cell
, fid
->fid
.Volume
);
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
);
379 _StatStuff(fid
, &fst
); /* calls _StatStuff */