📄 9p2.c
字号:
#include "all.h"/* * stuff from /sys/include/libc.h for 9P2000 */#define STATMAX 65535U /* max length of machine-independent stat structure */#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */#define ERRMAX 128 /* max length of error string *//* bits in Dir.mode */#define DMDIR 0x80000000 /* mode bit for directories */#define DMAPPEND 0x40000000 /* mode bit for append only files */#define DMEXCL 0x20000000 /* mode bit for exclusive use files */#define DMMOUNT 0x10000000 /* mode bit for mounted channel */#define DMREAD 0x4 /* mode bit for read permission */#define DMWRITE 0x2 /* mode bit for write permission */#define DMEXEC 0x1 /* mode bit for execute permission */typedefstruct Dir { /* system-modified data */ ushort type; /* server type */ uint dev; /* server subtype */ /* file data */ Qid qid; /* unique id from server */ ulong mode; /* permissions */ ulong atime; /* last read time */ ulong mtime; /* last write time */ vlong length; /* file length: see <u.h> */ char *name; /* last element of path */ char *uid; /* owner name */ char *gid; /* group name */ char *muid; /* last modifier name */} Dir;#define MSIZE (MAXDAT+MAXMSG)#include "fcall.h"static intmkmode9p1(ulong mode9p2){ int mode; /* * Assume this is for an allocated entry. */ mode = DALLOC|(mode9p2 & 0777); if(mode9p2 & DMEXCL) mode |= DLOCK; if(mode9p2 & DMAPPEND) mode |= DAPND; if(mode9p2 & DMDIR) mode |= DDIR; return mode;}voidmkqid9p1(Qid9p1* qid9p1, Qid* qid){ if(qid->path & 0xFFFFFFFF00000000LL) panic("mkqid9p1: path %lluX\n", (Wideoff)qid->path); qid9p1->path = qid->path & 0xFFFFFFFF; if(qid->type & QTDIR) qid9p1->path |= QPDIR; qid9p1->version = qid->vers;}static intmktype9p2(int mode9p1){ int type; type = 0; if(mode9p1 & DLOCK) type |= QTEXCL; if(mode9p1 & DAPND) type |= QTAPPEND; if(mode9p1 & DDIR) type |= QTDIR; return type;}static ulongmkmode9p2(int mode9p1){ ulong mode; mode = mode9p1 & 0777; if(mode9p1 & DLOCK) mode |= DMEXCL; if(mode9p1 & DAPND) mode |= DMAPPEND; if(mode9p1 & DDIR) mode |= DMDIR; return mode;}voidmkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode9p1){ qid->path = (ulong)(qid9p1->path & ~QPDIR); qid->vers = qid9p1->version; qid->type = mktype9p2(mode9p1);}static intmkdir9p2(Dir* dir, Dentry* dentry, void* strs){ char *op, *p; memset(dir, 0, sizeof(Dir)); mkqid(&dir->qid, dentry, 1); dir->mode = mkmode9p2(dentry->mode); dir->atime = dentry->atime; dir->mtime = dentry->mtime; dir->length = dentry->size; op = p = strs; dir->name = p; p += sprint(p, "%s", dentry->name)+1; dir->uid = p; uidtostr(p, dentry->uid, 1); p += strlen(p)+1; dir->gid = p; uidtostr(p, dentry->gid, 1); p += strlen(p)+1; dir->muid = p; uidtostr(p, dentry->muid, 1); p += strlen(p)+1; return p-op;}static intcheckname9p2(char* name){ char *p; /* * Return error or 0 if OK. */ if(name == nil || *name == 0) return Ename; for(p = name; *p != 0; p++){ if(p-name >= NAMELEN-1) return Etoolong; if((*p & 0xFF) <= 040) return Ename; } if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) return Edot; return 0;}static intversion(Chan* chan, Fcall* f, Fcall* r){ if(chan->protocol != nil) return Eversion; if(f->msize < MSIZE) r->msize = f->msize; else r->msize = MSIZE; /* * Should check the '.' stuff here. */ if(strcmp(f->version, VERSION9P) == 0){ r->version = VERSION9P; chan->protocol = serve9p2; chan->msize = r->msize; } else r->version = "unknown"; fileinit(chan); return 0;}struct{ Lock; ulong hi;} authpath;static intauth(Chan* chan, Fcall* f, Fcall* r){ char *aname; File *file; Filsys *fs; int error; if(cons.flags & authdisableflag) return Eauthdisabled; error = 0; aname = f->aname; if(strcmp(f->uname, "none") == 0) return Eauthnone; if(!aname[0]) /* default */ aname = "main"; file = filep(chan, f->afid, 1); if(file == nil){ error = Efidinuse; goto out; } fs = fsstr(aname); if(fs == nil){ error = Ebadspc; goto out; } lock(&authpath); file->qid.path = authpath.hi++; unlock(&authpath); file->qid.type = QTAUTH; file->qid.vers = 0; file->fs = fs; file->open = FREAD+FWRITE; freewp(file->wpath); file->wpath = 0; file->auth = authnew(f->uname, f->aname); if(file->auth == nil){ error = Eauthfile; goto out; } r->aqid = file->qid;out: if((cons.flags & attachflag) && error) print("9p2: auth %s %T SUCK EGGS --- %s\n", f->uname, time(), errstr9p[error]); if(file != nil){ qunlock(file); if(error) freefp(file); } return error;}intauthorize(Chan* chan, Fcall* f){ File* af; int uid = -1; int db; db = cons.flags & authdebugflag; if(strcmp(f->uname, "none") == 0){ uid = strtouid(f->uname); if(db) print("permission granted to none: uid %s = %d\n", f->uname, uid); return uid; } if(cons.flags & authdisableflag){ uid = strtouid(f->uname); if(db) print("permission granted by authdisable uid %s = %d\n", f->uname, uid); return uid; } af = filep(chan, f->afid, 0); if(af == nil){ if(db) print("authorize: af == nil\n"); return -1; } if(af->auth == nil){ if(db) print("authorize: af->auth == nil\n"); goto out; } if(strcmp(f->uname, authuname(af->auth)) != 0){ if(db) print("authorize: strcmp(f->uname, authuname(af->auth)) != 0\n"); goto out; } if(strcmp(f->aname, authaname(af->auth)) != 0){ if(db) print("authorize: strcmp(f->aname, authaname(af->auth)) != 0\n"); goto out; } uid = authuid(af->auth); if(db) print("authorize: uid is %d\n", uid);out: qunlock(af); return uid;}static intattach(Chan* chan, Fcall* f, Fcall* r){ char *aname; Iobuf *p; Dentry *d; File *file; Filsys *fs; Off raddr; int error, u; aname = f->aname; if(!aname[0]) /* default */ aname = "main"; p = nil; error = 0; file = filep(chan, f->fid, 1); if(file == nil){ error = Efidinuse; goto out; } u = -1; if(chan != cons.chan){ if(noattach && strcmp(f->uname, "none")) { error = Enoattach; goto out; } u = authorize(chan, f); if(u < 0){ error = Ebadu; goto out; } } file->uid = u; fs = fsstr(aname); if(fs == nil){ error = Ebadspc; goto out; } raddr = getraddr(fs->dev); p = getbuf(fs->dev, raddr, Bread); if(p == nil || checktag(p, Tdir, QPROOT)){ error = Ealloc; goto out; } d = getdir(p, 0); if(d == nil || !(d->mode & DALLOC)){ error = Ealloc; goto out; } if (iaccess(file, d, DEXEC) || file->uid == 0 && fs->dev->type == Devro) { /* * 'none' not allowed on dump */ error = Eaccess; goto out; } accessdir(p, d, FREAD, file->uid); 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; strncpy(chan->whoname, f->uname, sizeof(chan->whoname)); chan->whotime = time(); 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(), errstr9p[error]); if(p != nil) putbuf(p); if(file != nil){ qunlock(file); if(error) freefp(file); } return error;}static intflush(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->open = file->open & ~FREMOV;}static intwalkname(File* file, char* wname, Qid* wqid){ Wpath *w; Iobuf *p, *p1; Dentry *d, *d1; int error, slot; Off 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; } d = getdir(p, file->slot); if(d == 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, file->uid); 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; } d1 = getdir(p1, slot); if(d == 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, file->uid); 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) || 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 intwalk(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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -