📄 srv.c
字号:
#include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <thread.h>#include <9p.h>void (*_forker)(void(*)(void*), void*, int);static char Ebadattach[] = "unknown specifier in attach";static char Ebadoffset[] = "bad offset";static char Ebadcount[] = "bad count";static char Ebotch[] = "9P protocol botch";static char Ecreatenondir[] = "create in non-directory";static char Edupfid[] = "duplicate fid";static char Eduptag[] = "duplicate tag";static char Eisdir[] = "is a directory";static char Enocreate[] = "create prohibited";static char Enomem[] = "out of memory";static char Enoremove[] = "remove prohibited";static char Enostat[] = "stat prohibited";static char Enotfound[] = "file not found";static char Enowrite[] = "write prohibited";static char Enowstat[] = "wstat prohibited";static char Eperm[] = "permission denied";static char Eunknownfid[] = "unknown fid";static char Ebaddir[] = "bad directory in wstat";static char Ewalknodir[] = "walk in non-directory";static voidsetfcallerror(Fcall *f, char *err){ f->ename = err; f->type = Rerror;}static voidchangemsize(Srv *srv, int msize){ if(srv->rbuf && srv->wbuf && srv->msize == msize) return; qlock(&srv->rlock); qlock(&srv->wlock); srv->msize = msize; free(srv->rbuf); free(srv->wbuf); srv->rbuf = emalloc9p(msize); srv->wbuf = emalloc9p(msize); qunlock(&srv->rlock); qunlock(&srv->wlock);}static Req*getreq(Srv *s){ long n; uchar *buf; Fcall f; Req *r; qlock(&s->rlock); if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){ qunlock(&s->rlock); return nil; } buf = emalloc9p(n); memmove(buf, s->rbuf, n); qunlock(&s->rlock); if(convM2S(buf, n, &f) != n){ free(buf); return nil; } if((r=allocreq(s->rpool, f.tag)) == nil){ /* duplicate tag: cons up a fake Req */ r = emalloc9p(sizeof *r); incref(&r->ref); r->tag = f.tag; r->ifcall = f; r->error = Eduptag; r->buf = buf; r->responded = 0; r->type = 0; r->srv = s; r->pool = nil;if(chatty9p) fprint(2, "<-%d- %F: dup tag\n", s->infd, &f); return r; } r->srv = s; r->responded = 0; r->buf = buf; r->ifcall = f; memset(&r->ofcall, 0, sizeof r->ofcall); r->type = r->ifcall.type;if(chatty9p) if(r->error) fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error); else fprint(2, "<-%d- %F\n", s->infd, &r->ifcall); return r;}static voidfilewalk(Req *r){ int i; File *f; f = r->fid->file; assert(f != nil); incref(f); for(i=0; i<r->ifcall.nwname; i++) if(f = walkfile(f, r->ifcall.wname[i])) r->ofcall.wqid[i] = f->qid; else break; r->ofcall.nwqid = i; if(f){ r->newfid->file = f; r->newfid->qid = r->newfid->file->qid; } respond(r, nil);}voidwalkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg){ int i; char *e; if(r->fid == r->newfid && r->ifcall.nwname > 1){ respond(r, "lib9p: unused documented feature not implemented"); return; } if(r->fid != r->newfid){ r->newfid->qid = r->fid->qid; if(clone && (e = clone(r->fid, r->newfid, arg))){ respond(r, e); return; } } e = nil; for(i=0; i<r->ifcall.nwname; i++){ if(e = walk1(r->newfid, r->ifcall.wname[i], arg)) break; r->ofcall.wqid[i] = r->newfid->qid; } r->ofcall.nwqid = i; if(e && i==0) respond(r, e); else respond(r, nil);}static voidsversion(Srv*, Req *r){ if(strncmp(r->ifcall.version, "9P", 2) != 0){ r->ofcall.version = "unknown"; respond(r, nil); return; } r->ofcall.version = "9P2000"; r->ofcall.msize = r->ifcall.msize; respond(r, nil);}static voidrversion(Req *r, char *error){ assert(error == nil); changemsize(r->srv, r->ofcall.msize);}static voidsauth(Srv *srv, Req *r){ char e[ERRMAX]; if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){ respond(r, Edupfid); return; } if(srv->auth) srv->auth(r); else{ snprint(e, sizeof e, "%s: authentication not required", argv0); respond(r, e); }}static voidrauth(Req *r, char *error){ if(error && r->afid) closefid(removefid(r->srv->fpool, r->afid->fid));}static voidsattach(Srv *srv, Req *r){ if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){ respond(r, Edupfid); return; } r->afid = nil; if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){ respond(r, Eunknownfid); return; } r->fid->uid = estrdup9p(r->ifcall.uname); if(srv->tree){ r->fid->file = srv->tree->root; incref(r->fid->file); r->ofcall.qid = r->fid->file->qid; r->fid->qid = r->ofcall.qid; } if(srv->attach) srv->attach(r); else respond(r, nil); return;}static voidrattach(Req *r, char *error){ if(error && r->fid) closefid(removefid(r->srv->fpool, r->fid->fid));}static voidsflush(Srv *srv, Req *r){ r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag); if(r->oldreq == nil || r->oldreq == r) respond(r, nil); else if(srv->flush) srv->flush(r); else respond(r, nil);}static intrflush(Req *r, char *error){ Req *or; assert(error == nil); or = r->oldreq; if(or){ qlock(&or->lk); if(or->responded == 0){ or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0])); or->flush[or->nflush++] = r; qunlock(&or->lk); return -1; /* delay response until or is responded */ } qunlock(&or->lk); closereq(or); } r->oldreq = nil; return 0;}static char*oldwalk1(Fid *fid, char *name, void *arg){ char *e; Qid qid; Srv *srv; srv = arg; e = srv->walk1(fid, name, &qid); if(e) return e; fid->qid = qid; return nil;}static char*oldclone(Fid *fid, Fid *newfid, void *arg){ Srv *srv; srv = arg; if(srv->clone == nil) return nil; return srv->clone(fid, newfid);}static voidswalk(Srv *srv, Req *r){ if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ respond(r, Eunknownfid); return; } if(r->fid->omode != -1){ respond(r, "cannot clone open fid"); return; } if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){ respond(r, Ewalknodir); return; } if(r->ifcall.fid != r->ifcall.newfid){ if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){ respond(r, Edupfid); return; } r->newfid->uid = estrdup9p(r->fid->uid); }else{ incref(&r->fid->ref); r->newfid = r->fid; } if(r->fid->file){ filewalk(r); }else if(srv->walk1) walkandclone(r, oldwalk1, oldclone, srv); else if(srv->walk) srv->walk(r); else sysfatal("no walk function, no file trees");}static voidrwalk(Req *r, char *error){ if(error || r->ofcall.nwqid < r->ifcall.nwname){ if(r->ifcall.fid != r->ifcall.newfid && r->newfid) closefid(removefid(r->srv->fpool, r->newfid->fid)); if (r->ofcall.nwqid==0){ if(error==nil && r->ifcall.nwname!=0) r->error = Enotfound; }else r->error = nil; // No error on partial walks }else{ if(r->ofcall.nwqid == 0){ /* Just a clone */ r->newfid->qid = r->fid->qid; }else{ /* if file trees are in use, filewalk took care of the rest */ r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1]; } }}static voidsopen(Srv *srv, Req *r){ int p; if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){ respond(r, Eunknownfid); return; } if(r->fid->omode != -1){ respond(r, Ebotch); return; } if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){ respond(r, Eisdir); return; } r->ofcall.qid = r->fid->qid; switch(r->ifcall.mode&3){ default: assert(0); case OREAD: p = AREAD; break; case OWRITE: p = AWRITE; break; case ORDWR: p = AREAD|AWRITE; break; case OEXEC: p = AEXEC; break; } if(r->ifcall.mode&OTRUNC) p |= AWRITE; if((r->fid->qid.type&QTDIR) && p!=AREAD){ respond(r, Eperm); return; } if(r->fid->file){ if(!hasperm(r->fid->file, r->fid->uid, p)){ respond(r, Eperm); return; } /* BUG RACE */ if((r->ifcall.mode&ORCLOSE) && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){ respond(r, Eperm); return; } r->ofcall.qid = r->fid->file->qid; if((r->ofcall.qid.type&QTDIR) && (r->fid->rdir = opendirfile(r->fid->file)) == nil){ respond(r, "opendirfile failed"); return; } } if(srv->open) srv->open(r); else respond(r, nil);}static voidropen(Req *r, char *error){ char errbuf[ERRMAX]; if(error) return; if(chatty9p){ snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode); write(2, errbuf, strlen(errbuf)); } r->fid->omode = r->ifcall.mode;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -