📄 9p2.c
字号:
#include "all.h"#define MSIZE (MAXDAT+128)static voidseterror(Fcall *ou, int err){ if(0 <= err && err < MAXERR) ou->ename = errstring[err]; else ou->ename = "unknown error";}static intfsversion(Chan* chan, Fcall* f, Fcall* r){ if(f->msize < MSIZE) r->msize = f->msize; else r->msize = MSIZE; /* * Should check the '.' stuff here. * What happens if Tversion has already been seen? */ if(strcmp(f->version, VERSION9P) == 0){ r->version = VERSION9P; chan->msize = r->msize; }else r->version = "unknown"; fileinit(chan); return 0;}char *keyspec = "proto=p9any role=server";static intfsauth(Chan *chan, Fcall *f, Fcall *r){ int err, fd; char *aname; File *file; int afd; AuthRpc *rpc; err = 0; if(chan == cons.srvchan) return Eauthmsg; file = filep(chan, f->afid, 1); if(file == nil) return Efidinuse; /* forget any previous authentication */ file->cuid = 0; if(access("/mnt/factotum", 0) < 0) if((fd = open("/srv/factotum", ORDWR)) >= 0) mount(fd, -1, "/mnt", MBEFORE, ""); afd = open("/mnt/factotum/rpc", ORDWR); if(afd < 0){ err = Esystem; goto out; } rpc = auth_allocrpc(afd); if(rpc == nil){ close(afd); err = Esystem; goto out; } file->rpc = rpc; if(auth_rpc(rpc, "start", keyspec, strlen(keyspec)) != ARok){ err = Esystem; goto out; } aname = f->aname; if(!aname[0]) aname = "main"; file->fs = fsstr(aname); if(file->fs == nil){ err = Ebadspc; goto out; } file->uid = strtouid(f->uname); if(file->uid < 0){ err = Ebadu; goto out; } file->qid.path = 0; file->qid.vers = 0; file->qid.type = QTAUTH; r->qid = file->qid;out: if(file != nil){ qunlock(file); if(err != 0) freefp(file); } return err;}intauthread(File *file, uchar *data, int count){ AuthInfo *ai; AuthRpc *rpc; int rv; rpc = file->rpc; if(rpc == nil) return -1; rv = auth_rpc(rpc, "read", nil, 0); switch(rv){ case ARdone: ai = auth_getinfo(rpc); if(ai == nil) return -1; if(chat) print("authread identifies user as %s\n", ai->cuid); file->cuid = strtouid(ai->cuid); auth_freeAI(ai); if(file->cuid == 0) return -1; if(chat) print("%s is a known user\n", ai->cuid); return 0; case ARok: if(count < rpc->narg) return -1; memmove(data, rpc->arg, rpc->narg); return rpc->narg; case ARphase: return -1; default: return -1; }}intauthwrite(File *file, uchar *data, int count){ int ret; ret = auth_rpc(file->rpc, "write", data, count); if(ret != ARok) return -1; return count;}voidmkqid9p1(Qid9p1* qid9p1, Qid* qid){ if(qid->path & 0xFFFFFFFF00000000LL) panic("mkqid9p1: path %lluX\n", qid->path); qid9p1->path = qid->path & 0xFFFFFFFF; if(qid->type & QTDIR) qid9p1->path |= QPDIR; qid9p1->version = qid->vers;}voidauthfree(File *fp){ if(fp->rpc != nil){ close(fp->rpc->afd); free(fp->rpc); fp->rpc = nil; }}voidmkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode){ qid->path = (ulong)(qid9p1->path & ~QPDIR); qid->vers = qid9p1->version; qid->type = 0; if(mode & DDIR) qid->type |= QTDIR; if(mode & DAPND) qid->type |= QTAPPEND; if(mode & DLOCK) qid->type |= QTEXCL;}static intcheckattach(Chan *chan, File *afile, File *file, Filsys *fs){ uchar buf[1]; if(chan == cons.srvchan || chan == cons.chan) return 0; /* if no afile, this had better be none */ if(afile == nil){ if(file->uid == 0){ if(!allownone && !chan->authed) return Eauth; return 0; } return Eauth; } /* otherwise, we'ld better have a usable cuid */ if(!(afile->qid.type&QTAUTH)) return Eauth; if(afile->uid != file->uid || afile->fs != fs) return Eauth; if(afile->cuid <= 0){ if(authread(afile, buf, 0) != 0) return Eauth; if(afile->cuid <= 0) return Eauth; } file->uid = afile->cuid; /* once someone has authenticated on the channel, others can become none */ chan->authed = 1; return 0;} static intfsattach(Chan* chan, Fcall* f, Fcall* r){ char *aname; Iobuf *p; Dentry *d; File *file; File *afile; Filsys *fs; long raddr; int error, u; aname = f->aname; if(!aname[0]) /* default */ aname = "main"; p = nil; afile = filep(chan, f->afid, 0); file = filep(chan, f->fid, 1); if(file == nil){ error = Efidinuse; goto out; } u = -1; if(chan != cons.chan){ if(strcmp(f->uname, "adm") == 0){ error = Eauth; goto out; } u = strtouid(f->uname); if(u < 0){ error = Ebadu; goto out; } } file->uid = u; fs = fsstr(aname); if(fs == nil){ error = Ebadspc; goto out; } if(error = checkattach(chan, afile, file, fs)) goto out; raddr = getraddr(fs->dev); p = getbuf(fs->dev, raddr, Bread); d = getdir(p, 0); if(d == nil || checktag(p, Tdir, QPROOT) || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(iaccess(file, d, DEXEC)){ error = Eaccess; goto out; } if(file->uid == 0 && isro(fs->dev)) { /* * 'none' not allowed on dump */ error = Eaccess; goto out; } accessdir(p, d, FREAD); mkqid(&file->qid, d, 1); file->fs = fs; file->addr = raddr; file->slot = 0; file->open = 0; freewp(file->wpath); file->wpath = 0; r->qid = file->qid;// if(cons.flags & attachflag)// print("9p2: attach %s %T to \"%s\" C%d\n",// chan->whoname, chan->whotime, fs->name, chan->chan);out:// if((cons.flags & attachflag) && error)// print("9p2: attach %s %T SUCK EGGS --- %s\n",// f->uname, time(), errstr[error]); if(p != nil) putbuf(p); if(afile != nil) qunlock(afile); if(file != nil){ qunlock(file); if(error) freefp(file); } return error;}static intfsflush(Chan* chan, Fcall*, Fcall*){ runlock(&chan->reflock); wlock(&chan->reflock); wunlock(&chan->reflock); rlock(&chan->reflock); return 0;}static voidclone(File* nfile, File* file){ Wpath *wpath; nfile->qid = file->qid; lock(&wpathlock); nfile->wpath = file->wpath; for(wpath = nfile->wpath; wpath != nil; wpath = wpath->up) wpath->refs++; unlock(&wpathlock); nfile->fs = file->fs; nfile->addr = file->addr; nfile->slot = file->slot; nfile->uid = file->uid; nfile->cuid = 0; nfile->open = file->open & ~FREMOV;}static intwalkname(File* file, char* wname, Qid* wqid){ Wpath *w; Iobuf *p, *p1; Dentry *d, *d1; int error, slot; long addr, qpath; p = p1 = nil; /* * File must not have been opened for I/O by an open * or create message and must represent a directory. */ if(file->open != 0){ error = Emode; goto out; } p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Edir1; goto out; } if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if(!(d->mode & DDIR)){ error = Edir1; goto out; } if(error = mkqidcmp(&file->qid, d)) goto out; /* * For walked elements the implied user must * have permission to search the directory. */ if(file->cp != cons.chan && iaccess(file, d, DEXEC)){ error = Eaccess; goto out; } accessdir(p, d, FREAD); if(strcmp(wname, ".") == 0){setdot: if(wqid != nil) *wqid = file->qid; goto out; } if(strcmp(wname, "..") == 0){ if(file->wpath == 0) goto setdot; putbuf(p); p = nil; addr = file->wpath->addr; slot = file->wpath->slot; p1 = getbuf(file->fs->dev, addr, Bread); if(p1 == nil || checktag(p1, Tdir, QPNONE)){ error = Edir1; goto out; } if((d1 = getdir(p1, slot)) == nil || !(d1->mode & DALLOC)){ error = Ephase; goto out; } lock(&wpathlock); file->wpath->refs--; file->wpath = file->wpath->up; unlock(&wpathlock); goto found; } for(addr = 0; ; addr++){ if(p == nil){ p = getbuf(file->fs->dev, file->addr, Bread); if(p == nil || checktag(p, Tdir, QPNONE)){ error = Ealloc; goto out; } d = getdir(p, file->slot); if(d == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } } qpath = d->qid.path; p1 = dnodebuf1(p, d, addr, 0); p = nil; if(p1 == nil || checktag(p1, Tdir, qpath)){ error = Eentry; goto out; } for(slot = 0; slot < DIRPERBUF; slot++){ d1 = getdir(p1, slot); if(!(d1->mode & DALLOC)) continue; if(strncmp(wname, d1->name, NAMELEN) != 0) continue; /* * update walk path */ if((w = newwp()) == nil){ error = Ewalk; goto out; } w->addr = file->addr; w->slot = file->slot; w->up = file->wpath; file->wpath = w; slot += DIRPERBUF*addr; goto found; } putbuf(p1); p1 = nil; }found: file->addr = p1->addr; mkqid(&file->qid, d1, 1); putbuf(p1); p1 = nil; file->slot = slot; if(wqid != nil) *wqid = file->qid;out: if(p1 != nil) putbuf(p1); if(p != nil) putbuf(p); return error;}static intfswalk(Chan* chan, Fcall* f, Fcall* r){ int error, nwname; File *file, *nfile, tfile; /* * The file identified by f->fid must be valid in the * current session and must not have been opened for I/O * by an open or create message. */ if((file = filep(chan, f->fid, 0)) == nil) return Efid; if(file->open != 0){ qunlock(file); return Emode; } /* * If newfid is not the same as fid, allocate a new file; * a side effect is checking newfid is not already in use (error); * if there are no names to walk this will be equivalent to a * simple 'clone' operation. * Otherwise, fid and newfid are the same and if there are names * to walk make a copy of 'file' to be used during the walk as * 'file' must only be updated on success. * Finally, it's a no-op if newfid is the same as fid and f->nwname * is 0. */ r->nwqid = 0; if(f->newfid != f->fid){ if((nfile = filep(chan, f->newfid, 1)) == nil){ qunlock(file); return Efidinuse; } } else if(f->nwname != 0){ nfile = &tfile; memset(nfile, 0, sizeof(File)); nfile->cp = chan; nfile->fid = ~0; } else{ qunlock(file); return 0; } clone(nfile, file); /* * Should check name is not too long. */ error = 0; for(nwname = 0; nwname < f->nwname; nwname++){ error = walkname(nfile, f->wname[nwname], &r->wqid[r->nwqid]); if(error != 0 || ++r->nwqid >= MAXDAT/sizeof(Qid)) break; } if(f->nwname == 0){ /* * Newfid must be different to fid (see above) * so this is a simple 'clone' operation - there's * nothing to do except unlock unless there's * an error. */ if(error){ freewp(nfile->wpath); qunlock(nfile); freefp(nfile); } else qunlock(nfile); } else if(r->nwqid < f->nwname){ /* * Didn't walk all elements, 'clunk' nfile * and leave 'file' alone. * Clear error if some of the elements were * walked OK. */ freewp(nfile->wpath); if(nfile != &tfile){ qunlock(nfile); freefp(nfile); } if(r->nwqid != 0) error = 0; } else{ /* * Walked all elements. If newfid is the same * as fid must update 'file' from the temporary * copy used during the walk. * Otherwise just unlock (when using tfile there's * no need to unlock as it's a local). */ if(nfile == &tfile){ file->qid = nfile->qid; freewp(file->wpath); file->wpath = nfile->wpath; file->addr = nfile->addr; file->slot = nfile->slot; } else qunlock(nfile); } qunlock(file); return error;}static intfsopen(Chan* chan, Fcall* f, Fcall* r){ Iobuf *p; Dentry *d; File *file; Tlock *t; Qid qid; int error, ro, fmod, wok; wok = 0; p = nil; if(chan == cons.chan || writeallow) wok = 1; if((file = filep(chan, f->fid, 0)) == nil){ error = Efid; goto out; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -