libafscp: a library for "clientless" operations
[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 <afs/param.h>
28 #include <afs/afsint.h>
29 #include <afs/vlserver.h>
30 #include <afs/vldbint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <search.h>
35 #include <sys/stat.h>
36 #include <inttypes.h>
37 #include "afscp.h"
38 #include "afscp_internal.h"
39
40 struct afs_venusfid *makefid(struct afs_cell *cell, afs_uint32 volume,
41                              afs_uint32 vnode, afs_uint32 unique)
42 {
43      struct afs_venusfid *ret;
44
45      if (!cell)
46           return NULL;
47      ret=malloc(sizeof(struct afs_venusfid));
48      if (!ret) {
49           afs_errno=errno;
50           return NULL;
51      }
52      ret->cell=cell;
53      ret->fid.Volume=volume;
54      ret->fid.Vnode=vnode;
55      ret->fid.Unique=unique;
56      return ret;
57 }
58
59 struct afs_venusfid *dupfid(const struct afs_venusfid *in)
60 {
61      struct afs_venusfid *ret;
62
63      ret=malloc(sizeof(struct afs_venusfid));
64      if (!ret) {
65           afs_errno=errno;
66           return NULL;
67      }
68      ret->cell=in->cell;
69      ret->fid.Volume=in->fid.Volume;
70      ret->fid.Vnode=in->fid.Vnode;
71      ret->fid.Unique=in->fid.Unique;
72      return ret;
73 }
74
75
76 static int statcompare(const void *a, const void *b)
77 {
78      const struct afs_statent *sa=a,*sb=b;
79      if (sa->me.fid.Vnode < sb->me.fid.Vnode) return -1;
80      if (sa->me.fid.Vnode > sb->me.fid.Vnode) return 1;
81      if (sa->me.fid.Unique < sb->me.fid.Unique) return -1;
82      if (sa->me.fid.Unique > sb->me.fid.Unique) return 1;
83      return 0;
84 }
85
86
87 int afs_GetStatus(const struct afs_venusfid *fid, struct AFSFetchStatus *s)
88 {
89      struct afs_volume *v;
90      struct afs_server *server;
91      struct AFSCallBack cb;
92      struct AFSVolSync vs;
93      struct AFSFid tf = fid->fid;
94      struct afs_statent *stored,key;
95      void *cached;
96
97      int code,i,j;
98
99      v=afs_volumebyid(fid->cell, fid->fid.Volume);
100      if (!v)
101           return -1;
102      memset(&key, 0, sizeof(key));
103      memcpy(&key.me,fid,sizeof(*fid));
104
105      cached=tfind(&key, &v->statcache, statcompare);
106      if (cached) {
107           stored=*(struct afs_statent **)cached;
108           memmove(s, &stored->status,sizeof(*s));
109           afscp_dprintf(("Stat %u.%lu.%lu.%lu returning cached result\n",
110                  fid->cell->id, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique));
111           return 0;
112      }
113
114
115      code=ENOENT;
116      for (i=0;i<v->nservers;i++) {
117        server=afs_serverbyindex(v->servers[i]);
118        if (server && server->naddrs > 0) {
119          for (j=0;j < server->naddrs;j++) {
120            code=RXAFS_FetchStatus(server->conns[j], &tf, s, &cb, &vs);
121            if (!code) {
122              AddCallBack(server, &fid->fid, s, &cb); /* calls _StatStuff */
123              afscp_dprintf(("Stat %u.%" PRIu32 ".%" PRIu32 ".%" PRIu32 " ok: type %" PRId32 " size %" PRId32 "\n",
124                  fid->cell->id, fid->fid.Volume, fid->fid.Vnode, fid->fid.Unique, s->FileType, s->Length));
125              return 0;
126            }
127          }
128        }
129      }
130      afs_errno=code;
131      return -1;
132 }
133
134
135
136 int afs_stat(const struct afs_venusfid *fid, struct stat *s)
137 {
138
139      struct AFSFetchStatus status;
140      int code;
141
142      code=afs_GetStatus(fid, &status);
143      if (code)
144           return code;
145
146      if (status.FileType==File)
147           s->st_mode=S_IFREG;
148      else if (status.FileType==Directory)
149           s->st_mode=S_IFDIR;
150      else if (status.FileType==SymbolicLink)
151           s->st_mode=S_IFLNK;
152      else {
153           afs_errno=EINVAL;
154           return -1;
155      }
156      s->st_mode |= (status.UnixModeBits & (~S_IFMT));
157      s->st_nlink = status.LinkCount;
158      s->st_size =status.Length;
159      s->st_uid =status.Owner;
160      /*s->st_blksize=status.SegSize;*/
161      s->st_atime=s->st_mtime=status.ClientModTime;
162      s->st_ctime=status.ServerModTime;
163      s->st_gid = status.Group;
164      return 0;
165 }
166
167
168 int _StatInvalidate(const struct afs_venusfid *fid) {
169      struct afs_volume *v;
170      struct afs_statent key;
171      void **cached;
172
173      v=afs_volumebyid(fid->cell, fid->fid.Volume);
174      if (!v)
175           return -1;
176      memmove(&key.me,fid,sizeof(*fid));
177
178      cached=tfind(&key, &v->statcache, statcompare);
179      if (cached) {
180               free(*cached);
181               tdelete(&key, &v->statcache, statcompare);
182      }
183      return 0;
184 }
185
186 int _StatStuff(const struct afs_venusfid *fid, const struct AFSFetchStatus *s) {
187      struct afs_volume *v;
188      struct afs_statent key, *stored;
189      void **cached;
190
191      v=afs_volumebyid(fid->cell, fid->fid.Volume);
192      if (!v)
193           return -1;
194      memmove(&key.me,fid,sizeof(*fid));
195
196      cached=tsearch(&key, &v->statcache, statcompare);
197      if (cached) {
198           stored=malloc(sizeof(struct afs_statent));
199           if (stored) {
200                memmove(&stored->me, fid, sizeof(*fid));
201                memmove(&stored->status,s,sizeof(*s));
202                *(struct afs_statent **)cached=stored;
203           } else {
204                tdelete(&key, &v->statcache, statcompare);
205           }
206      }
207      return 0;
208 }
209
210 int afs_StoreStatus(const struct afs_venusfid *fid, struct AFSStoreStatus *s)
211 {
212      struct afs_volume *v;
213      struct afs_server *server;
214      struct AFSCallBack cb;
215      struct AFSVolSync vs;
216      struct AFSFetchStatus fst;
217      struct AFSFid tf = fid->fid;
218      int code,i,j;
219
220      v=afs_volumebyid(fid->cell, fid->fid.Volume);
221      if (!v)
222           return -1;
223
224
225      code=ENOENT;
226      for (i=0;i<v->nservers;i++) {
227        server=afs_serverbyindex(v->servers[i]);
228        if (server && server->naddrs > 0) {
229          for (j=0;j < server->naddrs;j++) {
230            code=RXAFS_StoreStatus(server->conns[j], &tf, s, &fst, &vs);
231            if (!code) {
232              _StatStuff(fid, &fst); /* calls _StatStuff */
233              return 0;
234            }
235          }
236        }
237      }
238      afs_errno=code;
239      return -1;
240 }