Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <thread.h>
5 #include <sunrpc.h>
6 #include <nfs3.h>
7 #include <diskfs.h>
8 #include <venti.h>
9 #include <libsec.h>
11 #undef stime
12 #define stime configstime /* sometimes in <time.h> */
13 typedef struct Entry Entry;
14 struct Entry
15 {
16 Entry *parent;
17 Entry *nextdir;
18 Entry *nexthash;
19 Entry *kids;
20 int isfsys;
21 Fsys *fsys;
22 uchar score[VtScoreSize]; /* of fsys */
23 char *name;
24 uchar sha1[VtScoreSize]; /* of path to this entry */
25 ulong time;
26 };
28 typedef struct Config Config;
29 struct Config
30 {
31 VtCache *vcache;
32 Entry *root;
33 Entry *hash[1024];
34 Qid qid;
35 };
37 Config *config;
38 static ulong mtime; /* mod time */
39 static ulong stime; /* sync time */
40 static char* configfile;
42 static int addpath(Config*, char*, uchar[VtScoreSize], ulong);
43 Fsys fsysconfig;
45 static void
46 freeconfig(Config *c)
47 {
48 Entry *next, *e;
49 int i;
51 for(i=0; i<nelem(c->hash); i++){
52 for(e=c->hash[i]; e; e=next){
53 next = e->nexthash;
54 free(e);
55 }
56 }
57 free(c);
58 }
60 static int
61 namehash(uchar *s)
62 {
63 return (s[0]<<2)|(s[1]>>6);
64 }
66 static Entry*
67 entrybyhandle(Nfs3Handle *h)
68 {
69 int hh;
70 Entry *e;
72 hh = namehash(h->h);
73 for(e=config->hash[hh]; e; e=e->nexthash)
74 if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
75 return e;
76 return nil;
77 }
79 static Config*
80 readconfigfile(char *name, VtCache *vcache)
81 {
82 char *p, *pref, *f[10];
83 int ok;
84 Config *c;
85 uchar score[VtScoreSize];
86 int h, nf, line;
87 Biobuf *b;
88 Dir *dir;
90 configfile = vtstrdup(name);
92 if((dir = dirstat(name)) == nil)
93 return nil;
95 if((b = Bopen(name, OREAD)) == nil){
96 free(dir);
97 return nil;
98 }
100 line = 0;
101 ok = 1;
102 c = emalloc(sizeof(Config));
103 c->vcache = vcache;
104 c->qid = dir->qid;
105 free(dir);
106 c->root = emalloc(sizeof(Entry));
107 c->root->name = "/";
108 c->root->parent = c->root;
109 sha1((uchar*)"/", 1, c->root->sha1, nil);
110 h = namehash(c->root->sha1);
111 c->hash[h] = c->root;
113 for(; (p = Brdstr(b, '\n', 1)) != nil; free(p)){
114 line++;
115 if(p[0] == '#')
116 continue;
117 nf = tokenize(p, f, nelem(f));
118 if(nf != 3){
119 fprint(2, "%s:%d: syntax error\n", name, line);
120 /* ok = 0; */
121 continue;
123 if(vtparsescore(f[1], &pref, score) < 0){
124 fprint(2, "%s:%d: bad score '%s'\n", name, line, f[1]);
125 /* ok = 0; */
126 continue;
128 if(f[0][0] != '/'){
129 fprint(2, "%s:%d: unrooted path '%s'\n", name, line, f[0]);
130 /* ok = 0; */
131 continue;
133 if(addpath(c, f[0], score, strtoul(f[2], 0, 0)) < 0){
134 fprint(2, "%s:%d: %s: %r\n", name, line, f[0]);
135 /* ok = 0; */
136 continue;
139 Bterm(b);
141 if(!ok){
142 freeconfig(c);
143 return nil;
146 return c;
149 static void
150 refreshconfig(void)
152 ulong now;
153 Config *c, *old;
154 Dir *d;
156 now = time(0);
157 if(now - stime < 60)
158 return;
159 if((d = dirstat(configfile)) == nil)
160 return;
161 if(d->mtime == mtime){
162 free(d);
163 stime = now;
164 return;
167 c = readconfigfile(configfile, config->vcache);
168 if(c == nil){
169 free(d);
170 return;
173 old = config;
174 config = c;
175 stime = now;
176 mtime = d->mtime;
177 free(d);
178 freeconfig(old);
181 static Entry*
182 entrylookup(Entry *e, char *p, int np)
184 for(e=e->kids; e; e=e->nextdir)
185 if(strlen(e->name) == np && memcmp(e->name, p, np) == 0)
186 return e;
187 return nil;
190 static Entry*
191 walkpath(Config *c, char *name)
193 Entry *e, *ee;
194 char *p, *nextp;
195 int h;
197 e = c->root;
198 p = name;
199 for(; *p; p=nextp){
200 assert(*p == '/');
201 p++;
202 nextp = strchr(p, '/');
203 if(nextp == nil)
204 nextp = p+strlen(p);
205 if(e->fsys){
206 werrstr("%.*s is already a mount point", utfnlen(name, nextp-name), name);
207 return nil;
209 if((ee = entrylookup(e, p, nextp-p)) == nil){
210 ee = emalloc(sizeof(Entry)+(nextp-p)+1);
211 ee->parent = e;
212 ee->nextdir = e->kids;
213 e->kids = ee;
214 ee->name = (char*)&ee[1];
215 memmove(ee->name, p, nextp-p);
216 ee->name[nextp-p] = 0;
217 sha1((uchar*)name, nextp-name, ee->sha1, nil);
218 h = namehash(ee->sha1);
219 ee->nexthash = c->hash[h];
220 c->hash[h] = ee;
222 e = ee;
224 if(e->kids){
225 werrstr("%s already has children; cannot be mount point", name);
226 return nil;
228 return e;
231 static int
232 addpath(Config *c, char *name, uchar score[VtScoreSize], ulong time)
234 Entry *e;
236 e = walkpath(c, name);
237 if(e == nil)
238 return -1;
239 e->isfsys = 1;
240 e->time = time;
241 memmove(e->score, score, VtScoreSize);
242 return 0;
245 static void
246 mkhandle(Nfs3Handle *h, Entry *e)
248 memmove(h->h, e->sha1, VtScoreSize);
249 h->len = VtScoreSize;
252 Nfs3Status
253 handleparse(Nfs3Handle *h, Fsys **pfsys, Nfs3Handle *nh, int isgetattr)
255 int hh;
256 Entry *e;
257 Disk *disk;
258 Fsys *fsys;
260 refreshconfig();
262 if(h->len < VtScoreSize)
263 return Nfs3ErrBadHandle;
265 hh = namehash(h->h);
266 for(e=config->hash[hh]; e; e=e->nexthash)
267 if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
268 break;
269 if(e == nil)
270 return Nfs3ErrBadHandle;
272 if(e->isfsys == 1 && e->fsys == nil && (h->len != VtScoreSize || !isgetattr)){
273 if((disk = diskopenventi(config->vcache, e->score)) == nil){
274 fprint(2, "cannot open disk %V: %r\n", e->score);
275 return Nfs3ErrIo;
277 if((fsys = fsysopen(disk)) == nil){
278 fprint(2, "cannot open fsys on %V: %r\n", e->score);
279 diskclose(disk);
280 return Nfs3ErrIo;
282 e->fsys = fsys;
285 if(e->fsys == nil || (isgetattr && h->len == VtScoreSize)){
286 if(h->len != VtScoreSize)
287 return Nfs3ErrBadHandle;
288 *pfsys = &fsysconfig;
289 *nh = *h;
290 return Nfs3Ok;
292 *pfsys = e->fsys;
293 if(h->len == VtScoreSize)
294 return fsysroot(*pfsys, nh);
295 nh->len = h->len - VtScoreSize;
296 memmove(nh->h, h->h+VtScoreSize, nh->len);
297 return Nfs3Ok;
300 void
301 handleunparse(Fsys *fsys, Nfs3Handle *h, Nfs3Handle *nh, int dotdot)
303 Entry *e;
304 int hh;
306 refreshconfig();
308 if(fsys == &fsysconfig)
309 return;
311 if(dotdot && nh->len == h->len - VtScoreSize
312 && memcmp(h->h+VtScoreSize, nh->h, nh->len) == 0){
313 /* walked .. but didn't go anywhere: must be at root */
314 hh = namehash(h->h);
315 for(e=config->hash[hh]; e; e=e->nexthash)
316 if(memcmp(e->sha1, h->h, VtScoreSize) == 0)
317 break;
318 if(e == nil)
319 return; /* cannot happen */
321 /* walk .. */
322 e = e->parent;
323 nh->len = VtScoreSize;
324 memmove(nh->h, e->sha1, VtScoreSize);
325 return;
328 /* otherwise just insert the same prefix */
329 memmove(nh->h+VtScoreSize, nh->h, VtScoreSize);
330 nh->len += VtScoreSize;
331 memmove(nh->h, h->h, VtScoreSize);
334 Nfs3Status
335 fsysconfigroot(Fsys *fsys, Nfs3Handle *h)
337 USED(fsys);
339 mkhandle(h, config->root);
340 return Nfs3Ok;
343 Nfs3Status
344 fsysconfiggetattr(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, Nfs3Attr *attr)
346 Entry *e;
348 USED(fsys);
349 USED(au);
351 if(h->len != VtScoreSize)
352 return Nfs3ErrBadHandle;
354 e = entrybyhandle(h);
355 if(e == nil)
356 return Nfs3ErrNoEnt;
358 memset(attr, 0, sizeof *attr);
359 attr->type = Nfs3FileDir;
360 attr->mode = 0555;
361 attr->nlink = 2;
362 attr->size = 1024;
363 attr->fileid = *(u64int*)h->h;
364 attr->atime.sec = e->time;
365 attr->mtime.sec = e->time;
366 attr->ctime.sec = e->time;
367 return Nfs3Ok;
370 Nfs3Status
371 fsysconfigaccess(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int want, u32int *got, Nfs3Attr *attr)
373 want &= Nfs3AccessRead|Nfs3AccessLookup|Nfs3AccessExecute;
374 *got = want;
375 return fsysconfiggetattr(fsys, au, h, attr);
378 Nfs3Status
379 fsysconfiglookup(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char *name, Nfs3Handle *nh)
381 Entry *e;
383 USED(fsys);
384 USED(au);
386 if(h->len != VtScoreSize)
387 return Nfs3ErrBadHandle;
389 e = entrybyhandle(h);
390 if(e == nil)
391 return Nfs3ErrNoEnt;
393 if(strcmp(name, "..") == 0)
394 e = e->parent;
395 else if(strcmp(name, ".") == 0){
396 /* nothing */
397 }else{
398 if((e = entrylookup(e, name, strlen(name))) == nil)
399 return Nfs3ErrNoEnt;
402 mkhandle(nh, e);
403 return Nfs3Ok;
406 Nfs3Status
407 fsysconfigreadlink(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, char **link)
409 USED(h);
410 USED(fsys);
411 USED(au);
413 *link = 0;
414 return Nfs3ErrNotSupp;
417 Nfs3Status
418 fsysconfigreadfile(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int offset, uchar **pdata, u32int *pcount, u1int *peof)
420 USED(fsys);
421 USED(h);
422 USED(count);
423 USED(offset);
424 USED(pdata);
425 USED(pcount);
426 USED(peof);
427 USED(au);
429 return Nfs3ErrNotSupp;
432 Nfs3Status
433 fsysconfigreaddir(Fsys *fsys, SunAuthUnix *au, Nfs3Handle *h, u32int count, u64int cookie, uchar **pdata, u32int *pcount, u1int *peof)
435 uchar *data, *p, *ep, *np;
436 u64int c;
437 Entry *e;
438 Nfs3Entry ne;
440 USED(fsys);
441 USED(au);
443 if(h->len != VtScoreSize)
444 return Nfs3ErrBadHandle;
446 e = entrybyhandle(h);
447 if(e == nil)
448 return Nfs3ErrNoEnt;
450 e = e->kids;
451 c = cookie;
452 for(; c && e; c--)
453 e = e->nextdir;
454 if(e == nil){
455 *pdata = 0;
456 *pcount = 0;
457 *peof = 1;
458 return Nfs3Ok;
461 data = emalloc(count);
462 p = data;
463 ep = data+count;
464 while(e && p < ep){
465 ne.name = e->name;
466 ne.namelen = strlen(e->name);
467 ne.cookie = ++cookie;
468 ne.fileid = *(u64int*)e->sha1;
469 if(nfs3entrypack(p, ep, &np, &ne) < 0)
470 break;
471 p = np;
472 e = e->nextdir;
474 *pdata = data;
475 *pcount = p - data;
476 *peof = 0;
477 return Nfs3Ok;
480 void
481 fsysconfigclose(Fsys *fsys)
483 USED(fsys);
486 int
487 readconfig(char *name, VtCache *vcache, Nfs3Handle *h)
489 Config *c;
490 Dir *d;
492 if((d = dirstat(name)) == nil)
493 return -1;
495 c = readconfigfile(name, vcache);
496 if(c == nil){
497 free(d);
498 return -1;
501 config = c;
502 mtime = d->mtime;
503 stime = time(0);
504 free(d);
506 mkhandle(h, c->root);
507 fsysconfig._lookup = fsysconfiglookup;
508 fsysconfig._access = fsysconfigaccess;
509 fsysconfig._getattr = fsysconfiggetattr;
510 fsysconfig._readdir = fsysconfigreaddir;
511 fsysconfig._readfile = fsysconfigreadfile;
512 fsysconfig._readlink = fsysconfigreadlink;
513 fsysconfig._root = fsysconfigroot;
514 fsysconfig._close = fsysconfigclose;
515 return 0;