/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h" /* * Cf. /lib/rfc/rfc1094 */ static int nfsnull(int, Rpccall*, Rpccall*);static int nfsgetattr(int, Rpccall*, Rpccall*);static int nfssetattr(int, Rpccall*, Rpccall*);static int nfsroot(int, Rpccall*, Rpccall*);static int nfslookup(int, Rpccall*, Rpccall*);static int nfsreadlink(int, Rpccall*, Rpccall*);static int nfsread(int, Rpccall*, Rpccall*);static int nfswritecache(int, Rpccall*, Rpccall*);static int nfswrite(int, Rpccall*, Rpccall*);static int nfscreate(int, Rpccall*, Rpccall*);static int nfsremove(int, Rpccall*, Rpccall*);static int nfsrename(int, Rpccall*, Rpccall*);static int nfslink(int, Rpccall*, Rpccall*);static int nfssymlink(int, Rpccall*, Rpccall*);static int nfsmkdir(int, Rpccall*, Rpccall*);static int nfsrmdir(int, Rpccall*, Rpccall*);static int nfsreaddir(int, Rpccall*, Rpccall*);static int nfsstatfs(int, Rpccall*, Rpccall*); Procmap nfsproc[] = { 0, nfsnull, /* void */ 1, nfsgetattr, /* Fhandle */ 2, nfssetattr, /* Fhandle, Sattr */ 3, nfsroot, /* void */ 4, nfslookup, /* Fhandle, String */ 5, nfsreadlink, /* Fhandle */ 6, nfsread, /* Fhandle, long, long, long */ 7, nfswritecache,/* void */ 8, nfswrite, /* Fhandle, long, long, long, String */ 9, nfscreate, /* Fhandle, String, Sattr */ 10, nfsremove, /* Fhandle, String */ 11, nfsrename, /* Fhandle, String, Fhandle, String */ 12, nfslink, /* Fhandle, Fhandle, String */ 13, nfssymlink, /* Fhandle, String, String, Sattr */ 14, nfsmkdir, /* Fhandle, String, Sattr */ 15, nfsrmdir, /* Fhandle, String */ 16, nfsreaddir, /* Fhandle, long, long */ 17, nfsstatfs, /* Fhandle */ 0, 0}; void nfsinit(int, char**);extern void mntinit(int, char**);extern Procmap mntproc[]; Progmap progmap[] = { 100005, 1, mntinit, mntproc, 100003, 2, nfsinit, nfsproc, 0, 0, 0,}; int myport = 2049;long nfstime;int conftime; voidmain(int argc, char *argv[]){ server(argc, argv, myport, progmap);} static voiddoalarm(void){ nfstime = time(0); mnttimer(nfstime); if(conftime+5*60 < nfstime){ conftime = nfstime; readunixidmaps(config); }} voidnfsinit(int argc, char **argv){ /* * mntinit will have already parsed our options. */ USED(argc, argv); clog("nfs file server init\n"); rpcalarm = doalarm; nfstime = time(0);} static intnfsnull(int n, Rpccall *cmd, Rpccall *reply){ USED(n, reply); chat("nfsnull..."); showauth(&cmd->cred); chat("OK\n"); return 0;} static intnfsgetattr(int n, Rpccall *cmd, Rpccall *reply){ Xfid *xf; Dir dir; uchar *dataptr = reply->results; chat("getattr..."); if(n != FHSIZE) return garbage(reply, "bad count"); xf = rpc2xfid(cmd, &dir); if(xf == 0) return error(reply, NFSERR_STALE); chat("%s...", xf->xp->name); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results;} static intnfssetattr(int n, Rpccall *cmd, Rpccall *reply){ Xfid *xf; Dir dir, nd; Sattr sattr; int r; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("setattr..."); if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, &dir); argptr += FHSIZE; argptr += convM2sattr(argptr, &sattr); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); chat("mode=0%lo,u=%ld,g=%ld,size=%ld,atime=%ld,mtime=%ld...", sattr.mode, sattr.uid, sattr.gid, sattr.size, sattr.atime, sattr.mtime); if(xf == 0) return error(reply, NFSERR_STALE); if(sattr.uid != NOATTR || sattr.gid != NOATTR) return error(reply, NFSERR_PERM); if(sattr.size == 0){ if(xf->xp->s != xf->xp->parent->s){ if(xfauthremove(xf, cmd->user) < 0) return error(reply, NFSERR_PERM); }else if(dir.length && xfopen(xf, Trunc|Oread|Owrite) < 0) return error(reply, NFSERR_PERM); }else if(sattr.size != NOATTR) return error(reply, NFSERR_PERM); r = 0; nulldir(&nd); if(sattr.mode != NOATTR) ++r, nd.mode = (dir.mode & ~0777) | (sattr.mode & 0777); if(sattr.atime != NOATTR) ++r, nd.atime = sattr.atime; if(sattr.mtime != NOATTR) ++r, nd.mtime = sattr.mtime; chat("sattr.mode=%luo dir.mode=%luo nd.mode=%luo...", sattr.mode, dir.mode, nd.mode); if(r){ r = xfwstat(xf, &nd); if(r < 0) return error(reply, NFSERR_PERM); } if(xfstat(xf, &dir) < 0) return error(reply, NFSERR_STALE); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results;} static intnfsroot(int n, Rpccall *cmd, Rpccall *reply){ USED(n, reply); chat("nfsroot..."); showauth(&cmd->cred); chat("OK\n"); return 0;} static intnfslookup(int n, Rpccall *cmd, Rpccall *reply){ Xfile *xp; Xfid *xf, *newxf; String elem; Dir dir; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("lookup..."); if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; argptr += string2S(argptr, &elem); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); chat("%s -> \"%.*s\"...", xp->name, utfnlen(elem.s, elem.n), elem.s); if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#') newxf = xfauth(xp, &elem); else newxf = xfwalkcr(Twalk, xf, &elem, 0); if(newxf == 0) return error(reply, NFSERR_NOENT); if(xfstat(newxf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += xp2fhandle(newxf->xp, dataptr); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results;} static intnfsreadlink(int n, Rpccall *cmd, Rpccall *reply){ USED(n, reply); chat("readlink..."); showauth(&cmd->cred); return error(reply, NFSERR_NOENT);} static intnfsread(int n, Rpccall *cmd, Rpccall *reply){ Session *s; Xfid *xf; Dir dir; int offset, count; uchar *argptr = cmd->args; uchar *dataptr = reply->results; uchar *readptr = dataptr + 4 + 17*4 + 4; chat("read..."); if(n != FHSIZE+12) return garbage(reply, "bad count"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; offset = GLONG(); count = GLONG(); if(xf == 0) return error(reply, NFSERR_STALE); chat("%s %d %d...", xf->xp->name, offset, count); if(xf->xp->s != xf->xp->parent->s){ count = xfauthread(xf, offset, readptr, count); }else{ if(xfopen(xf, Oread) < 0) return error(reply, NFSERR_PERM); if(count > 8192) count = 8192; s = xf->xp->s; setfid(s, xf->opfid); xf->opfid->tstale = nfstime + 60; s->f.offset = offset; s->f.count = count; if(xmesg(s, Tread) < 0) return error(reply, NFSERR_IO); count = s->f.count; memmove(readptr, s->f.data, count); } if(xfstat(xf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); PLONG(count); dataptr += ROUNDUP(count); chat("%d OK\n", count); return dataptr - (uchar *)reply->results;} static intnfswritecache(int n, Rpccall *cmd, Rpccall *reply){ USED(n, reply); chat("writecache..."); showauth(&cmd->cred); chat("OK\n"); return 0;} static intnfswrite(int n, Rpccall *cmd, Rpccall *reply){ Session *s; Xfid *xf; Dir dir; int offset, count; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("write..."); if(n < FHSIZE+16) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE + 4; offset = GLONG(); argptr += 4; count = GLONG(); if(xf == 0) return error(reply, NFSERR_STALE); chat("%s %d %d...", xf->xp->name, offset, count); if(xf->xp->s != xf->xp->parent->s){ if(xfauthwrite(xf, offset, argptr, count) < 0) return error(reply, NFSERR_IO); }else{ if(xfopen(xf, Owrite) < 0) return error(reply, NFSERR_PERM); s = xf->xp->s; setfid(s, xf->opfid); xf->opfid->tstale = nfstime + 60; s->f.offset = offset; s->f.count = count; s->f.data = (char *)argptr; if(xmesg(s, Twrite) < 0) return error(reply, NFSERR_IO); } if(xfstat(xf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results;} static intcreat(int n, Rpccall *cmd, Rpccall *reply, int chdir){ Xfid *xf, *newxf; Xfile *xp; String elem; Dir dir; Sattr sattr; uchar *argptr = cmd->args; uchar *dataptr = reply->results; int trunced; if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; argptr += string2S(argptr, &elem); argptr += convM2sattr(argptr, &sattr); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s); trunced = 0; if(xp->parent == xp && elem.s[0] == '#'){ newxf = xfauth(xp, &elem); if(newxf == 0) return error(reply, NFSERR_PERM); if(xfauthremove(newxf, cmd->user) < 0) return error(reply, NFSERR_PERM); trunced = 1; }else newxf = xfwalkcr(Twalk, xf, &elem, 0); if(newxf == 0){ newxf = xfwalkcr(Tcreate, xf, &elem, chdir|(sattr.mode&0777)); if(newxf) trunced = 1; else newxf = xfwalkcr(Twalk, xf, &elem, 0); } if(newxf == 0) return error(reply, NFSERR_PERM); if(!trunced && chdir) return error(reply, NFSERR_EXIST); if(!trunced && xfopen(newxf, Trunc|Oread|Owrite) < 0) return error(reply, NFSERR_PERM); if(xfstat(newxf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += xp2fhandle(newxf->xp, dataptr); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results;} static intnfscreate(int n, Rpccall *cmd, Rpccall *reply){ chat("create..."); return creat(n, cmd, reply, 0);} static intremov(int n, Rpccall *cmd, Rpccall *reply){ Session *s; Xfile *xp; Xfid *xf, *newxf; String elem; Fid *nfid; uchar *argptr = cmd->args; uchar *dataptr = reply->results; if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; argptr += string2S(argptr, &elem); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s); if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#') return error(reply, NFSERR_PERM); newxf = xfwalkcr(Twalk, xf, &elem, 0); if(newxf == 0) return error(reply, NFSERR_NOENT); s = xp->s; nfid = newfid(s); setfid(s, newxf->urfid); s->f.newfid = nfid - s->fids; s->f.nwname = 0; if(xmesg(s, Twalk) < 0){ putfid(s, nfid); return error(reply, NFSERR_IO); } s->f.fid = nfid - s->fids; if(xmesg(s, Tremove) < 0){ putfid(s, nfid); return error(reply, NFSERR_PERM); } putfid(s, nfid); xpclear(newxf->xp); PLONG(NFS_OK); chat("OK\n"); return dataptr - (uchar *)reply->results;} static intnfsremove(int n, Rpccall *cmd, Rpccall *reply){ chat("remove..."); return remov(n, cmd, reply);} static intnfsrename(int n, Rpccall *cmd, Rpccall *reply){ Xfid *xf, *newxf; Xfile *xp; uchar *fromdir, *todir; String fromelem, toelem; Dir dir; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("rename..."); if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); fromdir = argptr; argptr += FHSIZE; argptr += string2S(argptr, &fromelem); todir = argptr; argptr += FHSIZE; argptr += string2S(argptr, &toelem); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); if(memcmp(fromdir, todir, FHSIZE) != 0) return error(reply, NFSERR_NXIO); newxf = xfwalkcr(Twalk, xf, &fromelem, 0); if(newxf == 0) return error(reply, NFSERR_NOENT); if(xfstat(newxf, &dir) < 0)Lines 1–500 of 664. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "all.h" /* * Cf. /lib/rfc/rfc1094 */ static int nfsnull(int, Rpccall*, Rpccall*); static int nfsgetattr(int, Rpccall*, Rpccall*); static int nfssetattr(int, Rpccall*, Rpccall*); static int nfsroot(int, Rpccall*, Rpccall*); static int nfslookup(int, Rpccall*, Rpccall*); static int nfsreadlink(int, Rpccall*, Rpccall*); static int nfsread(int, Rpccall*, Rpccall*); static int nfswritecache(int, Rpccall*, Rpccall*); static int nfswrite(int, Rpccall*, Rpccall*); static int nfscreate(int, Rpccall*, Rpccall*); static int nfsremove(int, Rpccall*, Rpccall*); static int nfsrename(int, Rpccall*, Rpccall*); static int nfslink(int, Rpccall*, Rpccall*); static int nfssymlink(int, Rpccall*, Rpccall*); static int nfsmkdir(int, Rpccall*, Rpccall*); static int nfsrmdir(int, Rpccall*, Rpccall*); static int nfsreaddir(int, Rpccall*, Rpccall*); static int nfsstatfs(int, Rpccall*, Rpccall*); Procmap nfsproc[] = { 0, nfsnull, /* void */ 1, nfsgetattr, /* Fhandle */ 2, nfssetattr, /* Fhandle, Sattr */ 3, nfsroot, /* void */ 4, nfslookup, /* Fhandle, String */ 5, nfsreadlink, /* Fhandle */ 6, nfsread, /* Fhandle, long, long, long */ 7, nfswritecache,/* void */ 8, nfswrite, /* Fhandle, long, long, long, String */ 9, nfscreate, /* Fhandle, String, Sattr */ 10, nfsremove, /* Fhandle, String */ 11, nfsrename, /* Fhandle, String, Fhandle, String */ 12, nfslink, /* Fhandle, Fhandle, String */ 13, nfssymlink, /* Fhandle, String, String, Sattr */ 14, nfsmkdir, /* Fhandle, String, Sattr */ 15, nfsrmdir, /* Fhandle, String */ 16, nfsreaddir, /* Fhandle, long, long */ 17, nfsstatfs, /* Fhandle */ 0, 0 }; void nfsinit(int, char**); extern void mntinit(int, char**); extern Procmap mntproc[]; Progmap progmap[] = { 100005, 1, mntinit, mntproc, 100003, 2, nfsinit, nfsproc, 0, 0, 0, }; int myport = 2049; long nfstime; int conftime; void main(int argc, char *argv[]) { server(argc, argv, myport, progmap); } static void doalarm(void) { nfstime = time(0); mnttimer(nfstime); if(conftime+5*60 < nfstime){ conftime = nfstime; readunixidmaps(config); } } void nfsinit(int argc, char **argv) { /* * mntinit will have already parsed our options. */ USED(argc, argv); clog("nfs file server init\n"); rpcalarm = doalarm; nfstime = time(0); } static int nfsnull(int n, Rpccall *cmd, Rpccall *reply) { USED(n, reply); chat("nfsnull..."); showauth(&cmd->cred); chat("OK\n"); return 0; } static int nfsgetattr(int n, Rpccall *cmd, Rpccall *reply) { Xfid *xf; Dir dir; uchar *dataptr = reply->results; chat("getattr..."); if(n != FHSIZE) return garbage(reply, "bad count"); xf = rpc2xfid(cmd, &dir); if(xf == 0) return error(reply, NFSERR_STALE); chat("%s...", xf->xp->name); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results; } static int nfssetattr(int n, Rpccall *cmd, Rpccall *reply) { Xfid *xf; Dir dir, nd; Sattr sattr; int r; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("setattr..."); if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, &dir); argptr += FHSIZE; argptr += convM2sattr(argptr, &sattr); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); chat("mode=0%lo,u=%ld,g=%ld,size=%ld,atime=%ld,mtime=%ld...", sattr.mode, sattr.uid, sattr.gid, sattr.size, sattr.atime, sattr.mtime); if(xf == 0) return error(reply, NFSERR_STALE); if(sattr.uid != NOATTR || sattr.gid != NOATTR) return error(reply, NFSERR_PERM); if(sattr.size == 0){ if(xf->xp->s != xf->xp->parent->s){ if(xfauthremove(xf, cmd->user) < 0) return error(reply, NFSERR_PERM); }else if(dir.length && xfopen(xf, Trunc|Oread|Owrite) < 0) return error(reply, NFSERR_PERM); }else if(sattr.size != NOATTR) return error(reply, NFSERR_PERM); r = 0; nulldir(&nd); if(sattr.mode != NOATTR) ++r, nd.mode = (dir.mode & ~0777) | (sattr.mode & 0777); if(sattr.atime != NOATTR) ++r, nd.atime = sattr.atime; if(sattr.mtime != NOATTR) ++r, nd.mtime = sattr.mtime; chat("sattr.mode=%luo dir.mode=%luo nd.mode=%luo...", sattr.mode, dir.mode, nd.mode); if(r){ r = xfwstat(xf, &nd); if(r < 0) return error(reply, NFSERR_PERM); } if(xfstat(xf, &dir) < 0) return error(reply, NFSERR_STALE); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results; } static int nfsroot(int n, Rpccall *cmd, Rpccall *reply) { USED(n, reply); chat("nfsroot..."); showauth(&cmd->cred); chat("OK\n"); return 0; } static int nfslookup(int n, Rpccall *cmd, Rpccall *reply) { Xfile *xp; Xfid *xf, *newxf; String elem; Dir dir; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("lookup..."); if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; argptr += string2S(argptr, &elem); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); chat("%s -> \"%.*s\"...", xp->name, utfnlen(elem.s, elem.n), elem.s); if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#') newxf = xfauth(xp, &elem); else newxf = xfwalkcr(Twalk, xf, &elem, 0); if(newxf == 0) return error(reply, NFSERR_NOENT); if(xfstat(newxf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += xp2fhandle(newxf->xp, dataptr); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results; } static int nfsreadlink(int n, Rpccall *cmd, Rpccall *reply) { USED(n, reply); chat("readlink..."); showauth(&cmd->cred); return error(reply, NFSERR_NOENT); } static int nfsread(int n, Rpccall *cmd, Rpccall *reply) { Session *s; Xfid *xf; Dir dir; int offset, count; uchar *argptr = cmd->args; uchar *dataptr = reply->results; uchar *readptr = dataptr + 4 + 17*4 + 4; chat("read..."); if(n != FHSIZE+12) return garbage(reply, "bad count"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; offset = GLONG(); count = GLONG(); if(xf == 0) return error(reply, NFSERR_STALE); chat("%s %d %d...", xf->xp->name, offset, count); if(xf->xp->s != xf->xp->parent->s){ count = xfauthread(xf, offset, readptr, count); }else{ if(xfopen(xf, Oread) < 0) return error(reply, NFSERR_PERM); if(count > 8192) count = 8192; s = xf->xp->s; setfid(s, xf->opfid); xf->opfid->tstale = nfstime + 60; s->f.offset = offset; s->f.count = count; if(xmesg(s, Tread) < 0) return error(reply, NFSERR_IO); count = s->f.count; memmove(readptr, s->f.data, count); } if(xfstat(xf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); PLONG(count); dataptr += ROUNDUP(count); chat("%d OK\n", count); return dataptr - (uchar *)reply->results; } static int nfswritecache(int n, Rpccall *cmd, Rpccall *reply) { USED(n, reply); chat("writecache..."); showauth(&cmd->cred); chat("OK\n"); return 0; } static int nfswrite(int n, Rpccall *cmd, Rpccall *reply) { Session *s; Xfid *xf; Dir dir; int offset, count; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("write..."); if(n < FHSIZE+16) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE + 4; offset = GLONG(); argptr += 4; count = GLONG(); if(xf == 0) return error(reply, NFSERR_STALE); chat("%s %d %d...", xf->xp->name, offset, count); if(xf->xp->s != xf->xp->parent->s){ if(xfauthwrite(xf, offset, argptr, count) < 0) return error(reply, NFSERR_IO); }else{ if(xfopen(xf, Owrite) < 0) return error(reply, NFSERR_PERM); s = xf->xp->s; setfid(s, xf->opfid); xf->opfid->tstale = nfstime + 60; s->f.offset = offset; s->f.count = count; s->f.data = (char *)argptr; if(xmesg(s, Twrite) < 0) return error(reply, NFSERR_IO); } if(xfstat(xf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results; } static int creat(int n, Rpccall *cmd, Rpccall *reply, int chdir) { Xfid *xf, *newxf; Xfile *xp; String elem; Dir dir; Sattr sattr; uchar *argptr = cmd->args; uchar *dataptr = reply->results; int trunced; if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; argptr += string2S(argptr, &elem); argptr += convM2sattr(argptr, &sattr); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s); trunced = 0; if(xp->parent == xp && elem.s[0] == '#'){ newxf = xfauth(xp, &elem); if(newxf == 0) return error(reply, NFSERR_PERM); if(xfauthremove(newxf, cmd->user) < 0) return error(reply, NFSERR_PERM); trunced = 1; }else newxf = xfwalkcr(Twalk, xf, &elem, 0); if(newxf == 0){ newxf = xfwalkcr(Tcreate, xf, &elem, chdir|(sattr.mode&0777)); if(newxf) trunced = 1; else newxf = xfwalkcr(Twalk, xf, &elem, 0); } if(newxf == 0) return error(reply, NFSERR_PERM); if(!trunced && chdir) return error(reply, NFSERR_EXIST); if(!trunced && xfopen(newxf, Trunc|Oread|Owrite) < 0) return error(reply, NFSERR_PERM); if(xfstat(newxf, &dir) < 0) return error(reply, NFSERR_IO); PLONG(NFS_OK); dataptr += xp2fhandle(newxf->xp, dataptr); dataptr += dir2fattr(cmd->up, &dir, dataptr); chat("OK\n"); return dataptr - (uchar *)reply->results; } static int nfscreate(int n, Rpccall *cmd, Rpccall *reply) { chat("create..."); return creat(n, cmd, reply, 0); } static int remov(int n, Rpccall *cmd, Rpccall *reply) { Session *s; Xfile *xp; Xfid *xf, *newxf; String elem; Fid *nfid; uchar *argptr = cmd->args; uchar *dataptr = reply->results; if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); argptr += FHSIZE; argptr += string2S(argptr, &elem); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); chat("%s/%.*s...", xp->name, utfnlen(elem.s, elem.n), elem.s); if(xp->s->noauth == 0 && xp->parent == xp && elem.s[0] == '#') return error(reply, NFSERR_PERM); newxf = xfwalkcr(Twalk, xf, &elem, 0); if(newxf == 0) return error(reply, NFSERR_NOENT); s = xp->s; nfid = newfid(s); setfid(s, newxf->urfid); s->f.newfid = nfid - s->fids; s->f.nwname = 0; if(xmesg(s, Twalk) < 0){ putfid(s, nfid); return error(reply, NFSERR_IO); } s->f.fid = nfid - s->fids; if(xmesg(s, Tremove) < 0){ putfid(s, nfid); return error(reply, NFSERR_PERM); } putfid(s, nfid); xpclear(newxf->xp); PLONG(NFS_OK); chat("OK\n"); return dataptr - (uchar *)reply->results; } static int nfsremove(int n, Rpccall *cmd, Rpccall *reply) { chat("remove..."); return remov(n, cmd, reply); } static int nfsrename(int n, Rpccall *cmd, Rpccall *reply) { Xfid *xf, *newxf; Xfile *xp; uchar *fromdir, *todir; String fromelem, toelem; Dir dir; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("rename..."); if(n <= FHSIZE) return garbage(reply, "count too small"); xf = rpc2xfid(cmd, 0); fromdir = argptr; argptr += FHSIZE; argptr += string2S(argptr, &fromelem); todir = argptr; argptr += FHSIZE; argptr += string2S(argptr, &toelem); if(argptr != &((uchar *)cmd->args)[n]) return garbage(reply, "bad count"); if(xf == 0) return error(reply, NFSERR_STALE); xp = xf->xp; if(!(xp->qid.type & QTDIR)) return error(reply, NFSERR_NOTDIR); if(memcmp(fromdir, todir, FHSIZE) != 0) return error(reply, NFSERR_NXIO); newxf = xfwalkcr(Twalk, xf, &fromelem, 0); if(newxf == 0) return error(reply, NFSERR_NOENT); if(xfstat(newxf, &dir) < 0)