libafscp: code cleanup
[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 int
106 afscp_GetStatus(const struct afscp_venusfid *fid, struct AFSFetchStatus *s)
107 {
108     struct afscp_volume *v;
109     struct afscp_server *server;
110     struct AFSCallBack cb;
111     struct AFSVolSync vs;
112     struct AFSFid tf = fid->fid;
113     struct afscp_statent *stored, key;
114     void *cached;
115     int code, i, j;
116     time_t now;
117
118     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
119     if (v == NULL) {
120         return -1;
121     }
122     memset(&key, 0, sizeof(key));
123     memcpy(&key.me, fid, sizeof(*fid));
124
125     cached = tfind(&key, &v->statcache, statcompare);
126     if (cached != NULL) {
127         stored = *(struct afscp_statent **)cached;
128         memmove(s, &stored->status, sizeof(*s));
129         afs_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n",
130                      fid->cell->id, fid->fid.Volume, fid->fid.Vnode,
131                      fid->fid.Unique));
132         return 0;
133     }
134
135     code = ENOENT;
136     for (i = 0; i < v->nservers; i++) {
137         server = afscp_ServerByIndex(v->servers[i]);
138         if (server && server->naddrs > 0) {
139             for (j = 0; j < server->naddrs; j++) {
140                 time(&now);
141                 code = RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs);
142                 if (code == 0) {
143                     afscp_AddCallBack(server, &fid->fid, s, &cb, now);  /* calls _StatStuff */
144                     afs_dprintf(("Stat %d.%lu.%lu.%lu"
145                                  " ok: type %ld size %ld\n",
146                                  fid->cell->id,
147                                  afs_printable_uint32_lu(fid->fid.Volume),
148                                  afs_printable_uint32_lu(fid->fid.Vnode),
149                                  afs_printable_uint32_lu(fid->fid.Unique),
150                                  afs_printable_int32_ld(s->FileType),
151                                  afs_printable_int32_ld(s->Length)));
152                     return 0;
153                 }
154             }
155         }
156     }
157     afscp_errno = code;
158     return -1;
159 }
160
161 int
162 afscp_Stat(const struct afscp_venusfid *fid, struct stat *s)
163 {
164
165     struct AFSFetchStatus status;
166     int code;
167
168
169     if (s == NULL || fid == NULL) {
170         fprintf(stderr, "NULL args given to afscp_Stat, cannot continue\n");
171         return -1;
172     }
173
174     code = afscp_GetStatus(fid, &status);
175     if (code != 0) {
176         return code;
177     }
178
179     if (status.FileType == File)
180         s->st_mode = S_IFREG;
181     else if (status.FileType == Directory)
182         s->st_mode = S_IFDIR;
183     else if (status.FileType == SymbolicLink)
184         s->st_mode = S_IFLNK;
185     else {
186         afscp_errno = EINVAL;
187         return -1;
188     }
189     s->st_mode |= (status.UnixModeBits & (~S_IFMT));
190     s->st_nlink = status.LinkCount;
191     s->st_size = status.Length;
192     s->st_uid = status.Owner;
193     /*s->st_blksize=status.SegSize; */
194     s->st_atime = s->st_mtime = status.ClientModTime;
195     s->st_ctime = status.ServerModTime;
196     s->st_gid = status.Group;
197     return 0;
198 }
199
200 int
201 _StatInvalidate(const struct afscp_venusfid *fid)
202 {
203     struct afscp_volume *v;
204     struct afscp_statent key;
205     void **cached;
206
207     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
208     if (v == NULL) {
209         return -1;
210     }
211     memmove(&key.me, fid, sizeof(*fid));
212
213     cached = tfind(&key, &v->statcache, statcompare);
214     if (cached != NULL) {
215         free(*cached);
216         tdelete(&key, &v->statcache, statcompare);
217     }
218     return 0;
219 }
220
221 int
222 _StatStuff(const struct afscp_venusfid *fid, const struct AFSFetchStatus *s)
223 {
224     struct afscp_volume *v;
225     struct afscp_statent key, *stored;
226     void **cached;
227
228     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
229     if (v == NULL) {
230         return -1;
231     }
232     memmove(&key.me, fid, sizeof(*fid));
233
234     cached = tsearch(&key, &v->statcache, statcompare);
235     if (cached != NULL) {
236         stored = malloc(sizeof(struct afscp_statent));
237         if (stored != NULL) {
238             memmove(&stored->me, fid, sizeof(*fid));
239             memmove(&stored->status, s, sizeof(*s));
240             *(struct afscp_statent **)cached = stored;
241         } else {
242             tdelete(&key, &v->statcache, statcompare);
243         }
244     }
245     return 0;
246 }
247
248 int
249 afscp_StoreStatus(const struct afscp_venusfid *fid, struct AFSStoreStatus *s)
250 {
251     struct afscp_volume *v;
252     struct afscp_server *server;
253     struct AFSVolSync vs;
254     struct AFSFetchStatus fst;
255     struct AFSFid tf = fid->fid;
256     int code, i, j;
257
258     v = afscp_VolumeById(fid->cell, fid->fid.Volume);
259     if (v == NULL) {
260         return -1;
261     }
262
263     code = ENOENT;
264     for (i = 0; i < v->nservers; i++) {
265         server = afscp_ServerByIndex(v->servers[i]);
266         if (server && server->naddrs > 0) {
267             for (j = 0; j < server->naddrs; j++) {
268                 code = RXAFS_StoreStatus(server->conns[j], &tf, s, &fst, &vs);
269                 if (code == 0) {
270                     _StatStuff(fid, &fst);      /* calls _StatStuff */
271                     return 0;
272                 }
273             }
274         }
275     }
276     afscp_errno = code;
277     return -1;
278 }