7 static int nfsnull(int, Rpccall*, Rpccall*);
8 static int nfsgetattr(int, Rpccall*, Rpccall*);
9 static int nfssetattr(int, Rpccall*, Rpccall*);
10 static int nfsroot(int, Rpccall*, Rpccall*);
11 static int nfslookup(int, Rpccall*, Rpccall*);
12 static int nfsreadlink(int, Rpccall*, Rpccall*);
13 static int nfsread(int, Rpccall*, Rpccall*);
14 static int nfswritecache(int, Rpccall*, Rpccall*);
15 static int nfswrite(int, Rpccall*, Rpccall*);
16 static int nfscreate(int, Rpccall*, Rpccall*);
17 static int nfsremove(int, Rpccall*, Rpccall*);
18 static int nfsrename(int, Rpccall*, Rpccall*);
19 static int nfslink(int, Rpccall*, Rpccall*);
20 static int nfssymlink(int, Rpccall*, Rpccall*);
21 static int nfsmkdir(int, Rpccall*, Rpccall*);
22 static int nfsrmdir(int, Rpccall*, Rpccall*);
23 static int nfsreaddir(int, Rpccall*, Rpccall*);
24 static int nfsstatfs(int, Rpccall*, Rpccall*);
27 0, nfsnull, /* void */
28 1, nfsgetattr, /* Fhandle */
29 2, nfssetattr, /* Fhandle, Sattr */
30 3, nfsroot, /* void */
31 4, nfslookup, /* Fhandle, String */
32 5, nfsreadlink, /* Fhandle */
33 6, nfsread, /* Fhandle, long, long, long */
34 7, nfswritecache,/* void */
35 8, nfswrite, /* Fhandle, long, long, long, String */
36 9, nfscreate, /* Fhandle, String, Sattr */
37 10, nfsremove, /* Fhandle, String */
38 11, nfsrename, /* Fhandle, String, Fhandle, String */
39 12, nfslink, /* Fhandle, Fhandle, String */
40 13, nfssymlink, /* Fhandle, String, String, Sattr */
41 14, nfsmkdir, /* Fhandle, String, Sattr */
42 15, nfsrmdir, /* Fhandle, String */
43 16, nfsreaddir, /* Fhandle, long, long */
44 17, nfsstatfs, /* Fhandle */
48 void nfsinit(int, char**);
49 extern void mntinit(int, char**);
50 extern Procmap mntproc[];
53 100005, 1, mntinit, mntproc,
54 100003, 2, nfsinit, nfsproc,
63 main(int argc, char *argv[])
65 server(argc, argv, myport, progmap);
73 if(conftime+5*60 < nfstime){
75 readunixidmaps(config);
80 nfsinit(int argc, char **argv)
83 * mntinit will have already parsed our options.
86 clog("nfs file server init\n");
92 nfsnull(int n, Rpccall *cmd, Rpccall *reply)
102 nfsgetattr(int n, Rpccall *cmd, Rpccall *reply)
106 uchar *dataptr = reply->results;
110 return garbage(reply, "bad count");
111 xf = rpc2xfid(cmd, &dir);
113 return error(reply, NFSERR_STALE);
114 chat("%s...", xf->xp->name);
116 dataptr += dir2fattr(cmd->up, &dir, dataptr);
118 return dataptr - (uchar *)reply->results;
122 nfssetattr(int n, Rpccall *cmd, Rpccall *reply)
128 uchar *argptr = cmd->args;
129 uchar *dataptr = reply->results;
133 return garbage(reply, "count too small");
134 xf = rpc2xfid(cmd, &dir);
136 argptr += convM2sattr(argptr, &sattr);
137 if(argptr != &((uchar *)cmd->args)[n])
138 return garbage(reply, "bad count");
139 chat("mode=0%lo,u=%ld,g=%ld,size=%ld,atime=%ld,mtime=%ld...",
140 sattr.mode, sattr.uid, sattr.gid, sattr.size,
141 sattr.atime, sattr.mtime);
143 return error(reply, NFSERR_STALE);
144 if(sattr.uid != NOATTR || sattr.gid != NOATTR)
145 return error(reply, NFSERR_PERM);
147 if(xf->xp->s != xf->xp->parent->s){
148 if(xfauthremove(xf, cmd->user) < 0)
149 return error(reply, NFSERR_PERM);
150 }else if(dir.length && xfopen(xf, Trunc|Oread|Owrite) < 0)
151 return error(reply, NFSERR_PERM);
152 }else if(sattr.size != NOATTR)
153 return error(reply, NFSERR_PERM);
156 if(sattr.mode != NOATTR)
157 ++r, nd.mode = (dir.mode & ~0777) | (sattr.mode & 0777);
158 if(sattr.atime != NOATTR)
159 ++r, nd.atime = sattr.atime;
160 if(sattr.mtime != NOATTR)
161 ++r, nd.mtime = sattr.mtime;
162 chat("sattr.mode=%luo dir.mode=%luo nd.mode=%luo...", sattr.mode, dir.mode, nd.mode);
164 r = xfwstat(xf, &nd);
166 return error(reply, NFSERR_PERM);
168 if(xfstat(xf, &dir) < 0)
169 return error(reply, NFSERR_STALE);
171 dataptr += dir2fattr(cmd->up, &dir, dataptr);
173 return dataptr - (uchar *)reply->results;
177 nfsroot(int n, Rpccall *cmd, Rpccall *reply)
181 showauth(&cmd->cred);
187 nfslookup(int n, Rpccall *cmd, Rpccall *reply)
193 uchar *argptr = cmd->args;
194 uchar *dataptr = reply->results;
198 return garbage(reply, "count too small");
199 xf = rpc2xfid(cmd, 0);
201 argptr += string2S(argptr, &elem);
202 if(argptr != &((uchar *)cmd->args)[n])
203 return garbage(reply, "bad count");
205 return error(reply, NFSERR_STALE);
207 if(!(xp->qid.type & QTDIR))
208 return error(reply, NFSERR_NOTDIR);
209 chat("%s -> \"%.*s\"...", xp->name, utfnlen(elem.s, elem.n), elem.s);
210 if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
211 newxf = xfauth(xp, &elem);
213 newxf = xfwalkcr(Twalk, xf, &elem, 0);
215 return error(reply, NFSERR_NOENT);
216 if(xfstat(newxf, &dir) < 0)
217 return error(reply, NFSERR_IO);
219 dataptr += xp2fhandle(newxf->xp, dataptr);
220 dataptr += dir2fattr(cmd->up, &dir, dataptr);
222 return dataptr - (uchar *)reply->results;
226 nfsreadlink(int n, Rpccall *cmd, Rpccall *reply)
230 showauth(&cmd->cred);
231 return error(reply, NFSERR_NOENT);
235 nfsread(int n, Rpccall *cmd, Rpccall *reply)
241 uchar *argptr = cmd->args;
242 uchar *dataptr = reply->results;
243 uchar *readptr = dataptr + 4 + 17*4 + 4;
247 return garbage(reply, "bad count");
248 xf = rpc2xfid(cmd, 0);
253 return error(reply, NFSERR_STALE);
254 chat("%s %d %d...", xf->xp->name, offset, count);
255 if(xf->xp->s != xf->xp->parent->s){
256 count = xfauthread(xf, offset, readptr, count);
258 if(xfopen(xf, Oread) < 0)
259 return error(reply, NFSERR_PERM);
263 setfid(s, xf->opfid);
264 xf->opfid->tstale = nfstime + 60;
265 s->f.offset = offset;
267 if(xmesg(s, Tread) < 0)
268 return error(reply, NFSERR_IO);
270 memmove(readptr, s->f.data, count);
272 if(xfstat(xf, &dir) < 0)
273 return error(reply, NFSERR_IO);
275 dataptr += dir2fattr(cmd->up, &dir, dataptr);
277 dataptr += ROUNDUP(count);
278 chat("%d OK\n", count);
279 return dataptr - (uchar *)reply->results;
283 nfswritecache(int n, Rpccall *cmd, Rpccall *reply)
286 chat("writecache...");
287 showauth(&cmd->cred);
293 nfswrite(int n, Rpccall *cmd, Rpccall *reply)
299 uchar *argptr = cmd->args;
300 uchar *dataptr = reply->results;
304 return garbage(reply, "count too small");
305 xf = rpc2xfid(cmd, 0);
306 argptr += FHSIZE + 4;
311 return error(reply, NFSERR_STALE);
312 chat("%s %d %d...", xf->xp->name, offset, count);
313 if(xf->xp->s != xf->xp->parent->s){
314 if(xfauthwrite(xf, offset, argptr, count) < 0)
315 return error(reply, NFSERR_IO);
317 if(xfopen(xf, Owrite) < 0)
318 return error(reply, NFSERR_PERM);
320 setfid(s, xf->opfid);
321 xf->opfid->tstale = nfstime + 60;
322 s->f.offset = offset;
324 s->f.data = (char *)argptr;
325 if(xmesg(s, Twrite) < 0)
326 return error(reply, NFSERR_IO);
328 if(xfstat(xf, &dir) < 0)
329 return error(reply, NFSERR_IO);
331 dataptr += dir2fattr(cmd->up, &dir, dataptr);
333 return dataptr - (uchar *)reply->results;
337 creat(int n, Rpccall *cmd, Rpccall *reply, int chdir)
342 Dir dir; Sattr sattr;
343 uchar *argptr = cmd->args;
344 uchar *dataptr = reply->results;
348 return garbage(reply, "count too small");
349 xf = rpc2xfid(cmd, 0);
351 argptr += string2S(argptr, &elem);
352 argptr += convM2sattr(argptr, &sattr);
353 if(argptr != &((uchar *)cmd->args)[n])
354 return garbage(reply, "bad count");
356 return error(reply, NFSERR_STALE);
358 if(!(xp->qid.type & QTDIR))
359 return error(reply, NFSERR_NOTDIR);
360 chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
362 if(xp->parent == xp && elem.s[0] == '#'){
363 newxf = xfauth(xp, &elem);
365 return error(reply, NFSERR_PERM);
366 if(xfauthremove(newxf, cmd->user) < 0)
367 return error(reply, NFSERR_PERM);
370 newxf = xfwalkcr(Twalk, xf, &elem, 0);
372 newxf = xfwalkcr(Tcreate, xf, &elem, chdir|(sattr.mode&0777));
376 newxf = xfwalkcr(Twalk, xf, &elem, 0);
379 return error(reply, NFSERR_PERM);
380 if(!trunced && chdir)
381 return error(reply, NFSERR_EXIST);
382 if(!trunced && xfopen(newxf, Trunc|Oread|Owrite) < 0)
383 return error(reply, NFSERR_PERM);
384 if(xfstat(newxf, &dir) < 0)
385 return error(reply, NFSERR_IO);
388 dataptr += xp2fhandle(newxf->xp, dataptr);
389 dataptr += dir2fattr(cmd->up, &dir, dataptr);
391 return dataptr - (uchar *)reply->results;
395 nfscreate(int n, Rpccall *cmd, Rpccall *reply)
398 return creat(n, cmd, reply, 0);
402 remov(int n, Rpccall *cmd, Rpccall *reply)
409 uchar *argptr = cmd->args;
410 uchar *dataptr = reply->results;
413 return garbage(reply, "count too small");
414 xf = rpc2xfid(cmd, 0);
416 argptr += string2S(argptr, &elem);
417 if(argptr != &((uchar *)cmd->args)[n])
418 return garbage(reply, "bad count");
420 return error(reply, NFSERR_STALE);
422 if(!(xp->qid.type & QTDIR))
423 return error(reply, NFSERR_NOTDIR);
424 chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s);
425 if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#')
426 return error(reply, NFSERR_PERM);
427 newxf = xfwalkcr(Twalk, xf, &elem, 0);
429 return error(reply, NFSERR_NOENT);
432 setfid(s, newxf->urfid);
433 s->f.newfid = nfid - s->fids;
435 if(xmesg(s, Twalk) < 0){
437 return error(reply, NFSERR_IO);
439 s->f.fid = nfid - s->fids;
440 if(xmesg(s, Tremove) < 0){
442 return error(reply, NFSERR_PERM);
448 return dataptr - (uchar *)reply->results;
452 nfsremove(int n, Rpccall *cmd, Rpccall *reply)
455 return remov(n, cmd, reply);
459 nfsrename(int n, Rpccall *cmd, Rpccall *reply)
463 uchar *fromdir, *todir;
464 String fromelem, toelem;
466 uchar *argptr = cmd->args;
467 uchar *dataptr = reply->results;
471 return garbage(reply, "count too small");
472 xf = rpc2xfid(cmd, 0);
475 argptr += string2S(argptr, &fromelem);
478 argptr += string2S(argptr, &toelem);
479 if(argptr != &((uchar *)cmd->args)[n])
480 return garbage(reply, "bad count");
482 return error(reply, NFSERR_STALE);
484 if(!(xp->qid.type & QTDIR))
485 return error(reply, NFSERR_NOTDIR);
486 if(memcmp(fromdir, todir, FHSIZE) != 0)
487 return error(reply, NFSERR_NXIO);
488 newxf = xfwalkcr(Twalk, xf, &fromelem, 0);
490 return error(reply, NFSERR_NOENT);
491 if(xfstat(newxf, &dir) < 0)
492 return error(reply, NFSERR_IO);
494 if(xp->parent == xp && toelem.s[0] == '#')
495 return error(reply, NFSERR_PERM);
498 if(xfwstat(newxf, &dir) < 0)
499 return error(reply, NFSERR_PERM);
502 return dataptr - (uchar *)reply->results;
506 nfslink(int n, Rpccall *cmd, Rpccall *reply)
510 showauth(&cmd->cred);
511 return error(reply, NFSERR_NOENT);
515 nfssymlink(int n, Rpccall *cmd, Rpccall *reply)
519 showauth(&cmd->cred);
520 return error(reply, NFSERR_NOENT);
524 nfsmkdir(int n, Rpccall *cmd, Rpccall *reply)
527 return creat(n, cmd, reply, DMDIR);
531 nfsrmdir(int n, Rpccall *cmd, Rpccall *reply)
534 return remov(n, cmd, reply);
538 nfsreaddir(int n, Rpccall *cmd, Rpccall *reply)
544 int k, offset, count, sfcount, entries, dsize;
545 uchar *argptr = cmd->args;
546 uchar *dataptr = reply->results;
550 return garbage(reply, "bad count");
551 xf = rpc2xfid(cmd, 0);
556 return error(reply, NFSERR_STALE);
557 chat("%s (%ld) %d %d...", xf->xp->name, xf->offset, offset, count);
559 if((xf->mode & Open) && xf->offset > offset)
561 if(xfopen(xf, Oread) < 0)
562 return error(reply, NFSERR_PERM);
563 while(xf->offset < offset){ /* if we reopened, xf->offset will be zero */
564 sfcount = offset - xf->offset;
565 if(sfcount > messagesize-IOHDRSZ)
566 sfcount = messagesize-IOHDRSZ;
567 setfid(s, xf->opfid);
568 s->f.offset = xf->offset;
569 s->f.count = sfcount;
570 if(xmesg(s, Tread) < 0){
572 return error(reply, NFSERR_IO);
574 if(s->f.count <= BIT16SZ)
576 xf->offset += s->f.count;
578 if(count > messagesize-IOHDRSZ)
579 count = messagesize-IOHDRSZ;
582 while(count > 16){ /* at least 16 bytes required; we don't know size of name */
583 chat("top of loop\n");
584 setfid(s, xf->opfid);
585 s->f.offset = xf->offset;
586 s->f.count = count; /* as good a guess as any */
587 if(xmesg(s, Tread) < 0){
589 return error(reply, NFSERR_IO);
591 sfcount = s->f.count;
592 if(sfcount <= BIT16SZ)
594 xf->offset += sfcount;
595 chat("count %d data 0x%p\n", s->f.count, s->f.data);
597 /* now have a buffer of Plan 9 directories; unpack into NFS thingies */
599 dsize = convM2D((uchar*)rdata, sfcount, &dir, (char*)s->statbuf);
600 if(dsize <= BIT16SZ){
601 count = 0; /* force break from outer loop */
605 k = strlen(dir.name);
606 if(count < 16+ROUNDUP(k)){
607 count = 0; /* force break from outer loop */
615 count -= 16+ROUNDUP(k);
627 chat("%d OK\n", entries);
628 return dataptr - (uchar *)reply->results;
632 nfsstatfs(int n, Rpccall *cmd, Rpccall *reply)
634 uchar *dataptr = reply->results;
637 Maxlong = (long)((1ULL<<31) - 1),
638 Maxfreeblks = Maxlong / Xfersize,
642 showauth(&cmd->cred);
644 return garbage(reply, "bad count");
646 PLONG(4096); /* tsize (fs block size) */
647 PLONG(Xfersize); /* bsize (optimal transfer size) */
648 PLONG(Maxfreeblks); /* blocks in fs */
649 PLONG(Maxfreeblks); /* bfree to root*/
650 PLONG(Maxfreeblks); /* bavail (free to mortals) */
653 readunixidmaps(config);*/
654 return dataptr - (uchar *)reply->results;