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; }
int clunkfid(Session *s, Fid *f) { putfid(s, f); if(s == 0 || f == 0) return 0; s->f.fid = f - s->fids; return xmesg(s, Tclunk); }
static int dowrite(Session *s, Fid *f, void *buf, int n) { s->f.fid = f - s->fids; s->f.offset = 0; s->f.count = n; s->f.data = (char *)buf; if(xmesg(s, Twrite) < 0) return -1; return n; }
static int doread(Session *s, Fid *f, void *buf, int n) { s->f.fid = f - s->fids; s->f.offset = 0; s->f.count = n; if(xmesg(s, Tread) < 0) return -1; n = s->f.count; memmove(buf, s->f.data, n); return n; }
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; }
Fid * newfid(Session *s) { Fid *f, *fN; chat("newfid.."); if(s->list.prev == 0){ chat("init.."); s->list.prev = &s->list; s->list.next = &s->list; s->free = s->fids; if(0 && chatty) fN = &s->fids[25]; else fN = &s->fids[nelem(s->fids)]; for(f=s->fids; f<fN; f++){ f->owner = 0; f->prev = 0; f->next = f+1; } (f-1)->next = 0; } if(s->free){ f = s->free; s->free = f->next; LINK(&s->list, f); }else{ for(f=s->list.prev; f!=&s->list; f=f->prev) if(f->owner) break; if(f == &s->list){ clog("fid leak"); return 0; } setfid(s, f); if(xmesg(s, Tclunk) < 0){ clog("clunk failed, no fids?"); /*return 0;*/ } *(f->owner) = 0; f->owner = 0; } chat("%ld...", f - s->fids); f->tstale = nfstime + staletime; return f; }
int xfstat(Xfid *xf, Dir *dp) { Xfile *xp; Session *s; char buf[128]; xp = xf->xp; s = xp->s; if(s != xp->parent->s){ seprint(buf, buf+sizeof buf, "#%s", xf->uid); dp->name = strstore(buf); dp->uid = xf->uid; dp->gid = xf->uid; dp->muid = xf->uid; dp->qid.path = (uvlong)xf->uid; dp->qid.type = QTFILE; dp->qid.vers = 0; dp->mode = 0666; dp->atime = time(0); dp->mtime = dp->atime; dp->length = NETCHLEN; dp->type = 0; dp->type = 0; return 0; } setfid(s, xf->urfid); if(xmesg(s, Tstat) == 0){ convM2D(s->f.stat, s->f.nstat, dp, (char*)s->statbuf); if(xp->qid.path == dp->qid.path){ xp->name = strstore(dp->name); return 0; } /* not reached ? */ chat("xp->qid.path=0x%.16llux, dp->qid.path=0x%.16llux name=%s...", xp->qid.path, dp->qid.path, dp->name); } if(xp != xp->parent) xpclear(xp); else clog("can't stat root: %s", s->f.type == Rerror ? s->f.ename : "??"); return -1; }
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; }
Xfid * setuser(Xfile *xp, char *user) { Xfid *xf, *xpf; Session *s; xf = xfid(user, xp, 1); if(xf->urfid) return xf; if(xp->parent==xp || !(xpf = setuser(xp->parent, user))) /* assign = */ return xfid(user, xp, -1); s = xp->s; xf->urfid = newfid(s); xf->urfid->owner = &xf->urfid; setfid(s, xpf->urfid); s->f.newfid = xf->urfid - s->fids; s->f.nwname = 1; s->f.wname[0] = xp->name; if(xmesg(s, Twalk) || s->f.nwqid != 1) return xfid(user, xp, -1); return xf; }
int xfwstat(Xfid *xf, Dir *dp) { Xfile *xp; Session *s; xp = xf->xp; s = xp->s; /* * xf->urfid can be zero because some DOS NFS clients * try to do wstat on the #user authentication files on close. */ if(s == 0 || xf->urfid == 0) return -1; setfid(s, xf->urfid); s->f.stat = s->statbuf; convD2M(dp, s->f.stat, Maxstatdata); if(xmesg(s, Twstat)) return -1; xp->name = strstore(dp->name); return 0; }
/* returns 0 if auth succeeded (or unneeded), -1 otherwise */ int authhostowner(Session *s) { Fid *af, *f; int rv = -1; int afd; AuthInfo *ai; AuthRpc *rpc; /* get a fid to authenticate over */ f = nil; af = newfid(s); s->f.afid = af - s->fids; s->f.uname = getuser(); s->f.aname = s->spec; if(xmesg(s, Tauth)){ /* not needed */ rv = 0; goto out; } quotefmtinstall(); /* just in case */ afd = open("/mnt/factotum/rpc", ORDWR); if(afd < 0){ werrstr("opening /mnt/factotum/rpc: %r"); goto out; } rpc = auth_allocrpc(afd); if(rpc == nil) goto out; ai = authproto(s, af, rpc, auth_getkey, "proto=p9any role=client"); if(ai != nil){ rv = 0; auth_freeAI(ai); } auth_freerpc(rpc); close(afd); /* try attaching with the afid */ chat("attaching as hostowner..."); f = newfid(s); s->f.fid = f - s->fids; s->f.afid = af - s->fids;; s->f.uname = getuser(); s->f.aname = s->spec; if(xmesg(s, Tattach) == 0) rv = 0; out: if(af != nil){ putfid(s, af); s->f.fid = af - s->fids; xmesg(s, Tclunk); } if(f != nil){ putfid(s, f); s->f.fid = f - s->fids; xmesg(s, Tclunk); } return rv; }
void srvinit(int fd, char *file, char *addr) { char fdservice[16], *naddr; Session *s; Xfile *xp; Xfid *xf; Fid *f; s = calloc(1, sizeof(Session)); s->spec = ""; s->fd = -1; if(fd >= 0){ s->fd = fd; sprint(fdservice, "/fd/%d", s->fd); s->service = strstore(fdservice); chat("fd = %d\n", s->fd); }else if(file){ chat("file = \"%s\"\n", file); s->service = file; s->fd = open(file, ORDWR); if(s->fd < 0){ clog("can't open %s: %r\n", file); goto error; } }else if(addr){ chat("addr = \"%s\"\n", addr); naddr = netmkaddr(addr, 0, "9fs"); s->service = addr; s->fd = dial(naddr, 0, 0, 0); if(s->fd < 0){ clog("can't dial %s: %r\n", naddr); goto error; } } chat("version..."); s->tag = NOTAG-1; s->f.msize = Maxfdata+IOHDRSZ; s->f.version = "9P2000"; xmesg(s, Tversion); messagesize = IOHDRSZ+s->f.msize; chat("version spec %s size %d\n", s->f.version, s->f.msize); s->tag = 0; chat("authenticate..."); if(authhostowner(s) < 0){ clog("auth failed %r\n"); goto error; } chat("attach as none..."); f = newfid(s); s->f.fid = f - s->fids; s->f.afid = ~0x0UL; s->f.uname = "none"; s->f.aname = s->spec; if(xmesg(s, Tattach)){ clog("attach failed\n"); goto error; } xp = xfile(&s->f.qid, s, 1); s->root = xp; xp->parent = xp; xp->name = "/"; xf = xfid("none", xp, 1); xf->urfid = f; clog("service=%s uid=%s fid=%ld\n", s->service, xf->uid, xf->urfid - s->fids); if(tail) tail->next = s; else head = s; tail = s; return; error: if(s->fd >= 0) close(s->fd); free(s); }
static int nfsreaddir(int n, Rpccall *cmd, Rpccall *reply) { Session *s; Xfid *xf; Dir dir; char *rdata; int k, offset, count, sfcount, entries, dsize; uchar *argptr = cmd->args; uchar *dataptr = reply->results; chat("readdir..."); if(n != FHSIZE+8) 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 (%ld) %d %d...", xf->xp->name, xf->offset, offset, count); s = xf->xp->s; if((xf->mode & Open) && xf->offset > offset) xfclose(xf); if(xfopen(xf, Oread) < 0) return error(reply, NFSERR_PERM); while(xf->offset < offset){ /* if we reopened, xf->offset will be zero */ sfcount = offset - xf->offset; if(sfcount > messagesize-IOHDRSZ) sfcount = messagesize-IOHDRSZ; setfid(s, xf->opfid); s->f.offset = xf->offset; s->f.count = sfcount; if(xmesg(s, Tread) < 0){ xfclose(xf); return error(reply, NFSERR_IO); } if(s->f.count <= BIT16SZ) break; xf->offset += s->f.count; } if(count > messagesize-IOHDRSZ) count = messagesize-IOHDRSZ; PLONG(NFS_OK); entries = 0; while(count > 16){ /* at least 16 bytes required; we don't know size of name */ chat("top of loop\n"); setfid(s, xf->opfid); s->f.offset = xf->offset; s->f.count = count; /* as good a guess as any */ if(xmesg(s, Tread) < 0){ xfclose(xf); return error(reply, NFSERR_IO); } sfcount = s->f.count; if(sfcount <= BIT16SZ) break; xf->offset += sfcount; chat("count %d data 0x%p\n", s->f.count, s->f.data); rdata = s->f.data; /* now have a buffer of Plan 9 directories; unpack into NFS thingies */ while(sfcount >= 0){ dsize = convM2D((uchar*)rdata, sfcount, &dir, (char*)s->statbuf); if(dsize <= BIT16SZ){ count = 0; /* force break from outer loop */ break; } offset += dsize; k = strlen(dir.name); if(count < 16+ROUNDUP(k)){ count = 0; /* force break from outer loop */ break; } PLONG(TRUE); PLONG(dir.qid.path); PLONG(k); PPTR(dir.name, k); PLONG(offset); count -= 16+ROUNDUP(k); rdata += dsize; sfcount -= dsize; } } PLONG(FALSE); if(s->f.count <= 0){ xfclose(xf); chat("eof..."); PLONG(TRUE); }else PLONG(FALSE); chat("%d OK\n", entries); return dataptr - (uchar *)reply->results; }