123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905 |
- #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 */
- typedef
- struct 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 int
- mkmode9p1(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;
- }
- void
- mkqid9p1(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 int
- mktype9p2(int mode9p1)
- {
- int type;
- type = 0;
- if(mode9p1 & DLOCK)
- type |= QTEXCL;
- if(mode9p1 & DAPND)
- type |= QTAPPEND;
- if(mode9p1 & DDIR)
- type |= QTDIR;
- return type;
- }
- static ulong
- mkmode9p2(int mode9p1)
- {
- ulong mode;
- mode = mode9p1 & 0777;
- if(mode9p1 & DLOCK)
- mode |= DMEXCL;
- if(mode9p1 & DAPND)
- mode |= DMAPPEND;
- if(mode9p1 & DDIR)
- mode |= DMDIR;
- return mode;
- }
- void
- mkqid9p2(Qid* qid, Qid9p1* qid9p1, int mode9p1)
- {
- qid->path = (ulong)(qid9p1->path & ~QPDIR);
- qid->vers = qid9p1->version;
- qid->type = mktype9p2(mode9p1);
- }
- static int
- mkdir9p2(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 int
- checkname9p2(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 int
- version(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 int
- auth(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;
- }
- int
- authorize(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 int
- attach(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 int
- flush(Chan* chan, Fcall*, Fcall*)
- {
- runlock(&chan->reflock);
- wlock(&chan->reflock);
- wunlock(&chan->reflock);
- rlock(&chan->reflock);
- return 0;
- }
- static void
- clone(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 int
- walkname(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 int
- walk(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 int
- open(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;
- }
- if(file->open != 0){
- error = Emode;
- goto out;
- }
- /*
- * if remove on close, check access here
- */
- ro = file->fs->dev->type == Devro;
- if(f->mode & ORCLOSE){
- if(ro){
- error = Eronly;
- goto out;
- }
- /*
- * check on parent directory of file to be deleted
- */
- if(file->wpath == 0 || file->wpath->addr == file->addr){
- error = Ephase;
- goto out;
- }
- p = getbuf(file->fs->dev, file->wpath->addr, Bread);
- if(p == nil || checktag(p, Tdir, QPNONE)){
- error = Ephase;
- goto out;
- }
- d = getdir(p, file->wpath->slot);
- if(d == nil || !(d->mode & DALLOC)){
- error = Ephase;
- goto out;
- }
- if(iaccess(file, d, DWRITE)){
- error = Eaccess;
- goto out;
- }
- putbuf(p);
- }
- 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;
- }
- if(error = mkqidcmp(&file->qid, d))
- goto out;
- mkqid(&qid, d, 1);
- switch(f->mode & 7){
- case OREAD:
- if(iaccess(file, d, DREAD) && !wok)
- goto badaccess;
- fmod = FREAD;
- break;
- case OWRITE:
- if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
- goto badaccess;
- if(ro){
- error = Eronly;
- goto out;
- }
- fmod = FWRITE;
- break;
- case ORDWR:
- if((d->mode & DDIR)
- || (iaccess(file, d, DREAD) && !wok)
- || (iaccess(file, d, DWRITE) && !wok))
- goto badaccess;
- if(ro){
- error = Eronly;
- goto out;
- }
- fmod = FREAD+FWRITE;
- break;
- case OEXEC:
- if((d->mode & DDIR) || (iaccess(file, d, DEXEC) && !wok))
- goto badaccess;
- fmod = FREAD;
- break;
- default:
- error = Emode;
- goto out;
- }
- if(f->mode & OTRUNC){
- if((d->mode & DDIR) || (iaccess(file, d, DWRITE) && !wok))
- goto badaccess;
- if(ro){
- error = Eronly;
- goto out;
- }
- }
- t = 0;
- if(d->mode & DLOCK){
- if((t = tlocked(p, d)) == nil){
- error = Elocked;
- goto out;
- }
- }
- if(f->mode & ORCLOSE)
- fmod |= FREMOV;
- file->open = fmod;
- if((f->mode & OTRUNC) && !(d->mode & DAPND)){
- dtrunc(p, d, file->uid);
- qid.vers = d->qid.version;
- }
- r->qid = qid;
- file->tlock = t;
- if(t != nil)
- t->file = file;
- file->lastra = 1;
- goto out;
- badaccess:
- error = Eaccess;
- file->open = 0;
- out:
- if(p != nil)
- putbuf(p);
- if(file != nil)
- qunlock(file);
- r->iounit = chan->msize-IOHDRSZ;
- return error;
- }
- static int
- create(Chan* chan, Fcall* f, Fcall* r)
- {
- Iobuf *p, *p1;
- Dentry *d, *d1;
- File *file;
- int error, slot, slot1, fmod, wok;
- Off addr, addr1, path;
- Tlock *t;
- Wpath *w;
- wok = 0;
- p = nil;
- if(chan == cons.chan || writeallow)
- wok = 1;
- if((file = filep(chan, f->fid, 0)) == nil){
- error = Efid;
- goto out;
- }
- if(file->fs->dev->type == Devro){
- error = Eronly;
- goto out;
- }
- if(file->qid.type & QTAUTH){
- error = Emode;
- goto out;
- }
- 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;
- }
- if(error = mkqidcmp(&file->qid, d))
- goto out;
- if(!(d->mode & DDIR)){
- error = Edir2;
- goto out;
- }
- if(iaccess(file, d, DWRITE) && !wok) {
- error = Eaccess;
- goto out;
- }
- accessdir(p, d, FREAD, file->uid);
- /*
- * Check the name is valid (and will fit in an old
- * directory entry for the moment).
- */
- if(error = checkname9p2(f->name))
- goto out;
- addr1 = 0;
- slot1 = 0; /* set */
- for(addr = 0; ; addr++){
- if((p1 = dnodebuf(p, d, addr, 0, file->uid)) == nil){
- if(addr1 != 0)
- break;
- p1 = dnodebuf(p, d, addr, Tdir, file->uid);
- }
- if(p1 == nil){
- error = Efull;
- goto out;
- }
- if(checktag(p1, Tdir, d->qid.path)){
- putbuf(p1);
- goto phase;
- }
- for(slot = 0; slot < DIRPERBUF; slot++){
- d1 = getdir(p1, slot);
- if(!(d1->mode & DALLOC)){
- if(addr1 == 0){
- addr1 = p1->addr;
- slot1 = slot + addr*DIRPERBUF;
- }
- continue;
- }
- if(strncmp(f->name, d1->name, sizeof(d1->name)) == 0){
- putbuf(p1);
- error = Eexist;
- goto out;
- }
- }
- putbuf(p1);
- }
- switch(f->mode & 7){
- case OEXEC:
- case OREAD: /* seems only useful to make directories */
- fmod = FREAD;
- break;
- case OWRITE:
- fmod = FWRITE;
- break;
- case ORDWR:
- fmod = FREAD+FWRITE;
- break;
- default:
- error = Emode;
- goto out;
- }
- if(f->perm & PDIR)
- if((f->mode & OTRUNC) || (f->perm & PAPND) || (fmod & FWRITE))
- goto badaccess;
- /*
- * do it
- */
- path = qidpathgen(file->fs->dev);
- if((p1 = getbuf(file->fs->dev, addr1, Bread|Bimm|Bmod)) == nil)
- goto phase;
- d1 = getdir(p1, slot1);
- if(d1 == nil || checktag(p1, Tdir, d->qid.path)) {
- putbuf(p1);
- goto phase;
- }
- if(d1->mode & DALLOC){
- putbuf(p1);
- goto phase;
- }
- strncpy(d1->name, f->name, sizeof(d1->name));
- if(chan == cons.chan){
- d1->uid = cons.uid;
- d1->gid = cons.gid;
- }
- else{
- d1->uid = file->uid;
- d1->gid = d->gid;
- f->perm &= d->mode | ~0666;
- if(f->perm & PDIR)
- f->perm &= d->mode | ~0777;
- }
- d1->qid.path = path;
- d1->qid.version = 0;
- d1->mode = DALLOC | (f->perm & 0777);
- if(f->perm & PDIR) {
- d1->mode |= DDIR;
- d1->qid.path |= QPDIR;
- }
- if(f->perm & PAPND)
- d1->mode |= DAPND;
- t = nil;
- if(f->perm & PLOCK){
- d1->mode |= DLOCK;
- t = tlocked(p1, d1);
- /* if nil, out of tlock structures */
- }
- accessdir(p1, d1, FWRITE, file->uid);
- mkqid(&r->qid, d1, 0);
- putbuf(p1);
- accessdir(p, d, FWRITE, file->uid);
- /*
- * do a walk to new directory entry
- */
- if((w = newwp()) == nil){
- error = Ewalk;
- goto out;
- }
- w->addr = file->addr;
- w->slot = file->slot;
- w->up = file->wpath;
- file->wpath = w;
- file->qid = r->qid;
- file->tlock = t;
- if(t != nil)
- t->file = file;
- file->lastra = 1;
- if(f->mode & ORCLOSE)
- fmod |= FREMOV;
- file->open = fmod;
- file->addr = addr1;
- file->slot = slot1;
- goto out;
- badaccess:
- error = Eaccess;
- goto out;
- phase:
- error = Ephase;
- out:
- if(p != nil)
- putbuf(p);
- if(file != nil)
- qunlock(file);
- r->iounit = chan->msize-IOHDRSZ;
- return error;
- }
- static int
- read(Chan* chan, Fcall* f, Fcall* r, uchar* data)
- {
- Iobuf *p, *p1;
- File *file;
- Dentry *d, *d1;
- Tlock *t;
- Off addr, offset, start;
- Timet tim;
- int error, iounit, nread, count, n, o, slot;
- Msgbuf *dmb;
- Dir dir;
- p = nil;
- error = 0;
- count = f->count;
- offset = f->offset;
- nread = 0;
- if((file = filep(chan, f->fid, 0)) == nil){
- error = Efid;
- goto out;
- }
- if(!(file->open & FREAD)){
- error = Eopen;
- goto out;
- }
- iounit = chan->msize-IOHDRSZ;
- if(count < 0 || count > iounit){
- error = Ecount;
- goto out;
- }
- if(offset < 0){
- error = Eoffset;
- goto out;
- }
- if(file->qid.type & QTAUTH){
- nread = authread(file, (uchar*)data, count);
- if(nread < 0)
- error = Eauth2;
- goto out;
- }
- 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;
- }
- if(error = mkqidcmp(&file->qid, d))
- goto out;
- if(t = file->tlock){
- tim = toytime();
- if(t->time < tim || t->file != file){
- error = Ebroken;
- goto out;
- }
- /* renew the lock */
- t->time = tim + TLOCK;
- }
- accessdir(p, d, FREAD, file->uid);
- if(d->mode & DDIR)
- goto dread;
- if(offset+count > d->size)
- count = d->size - offset;
- while(count > 0){
- 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;
- }
- }
- addr = offset / BUFSIZE;
- file->lastra = dbufread(p, d, addr, file->lastra, file->uid);
- o = offset % BUFSIZE;
- n = BUFSIZE - o;
- if(n > count)
- n = count;
- p1 = dnodebuf1(p, d, addr, 0, file->uid);
- p = nil;
- if(p1 != nil){
- if(checktag(p1, Tfile, QPNONE)){
- error = Ephase;
- putbuf(p1);
- goto out;
- }
- memmove(data+nread, p1->iobuf+o, n);
- putbuf(p1);
- }
- else
- memset(data+nread, 0, n);
- count -= n;
- nread += n;
- offset += n;
- }
- goto out;
- dread:
- /*
- * Pick up where we left off last time if nothing has changed,
- * otherwise must scan from the beginning.
- */
- if(offset == file->doffset /*&& file->qid.vers == file->dvers*/){
- addr = file->dslot/DIRPERBUF;
- slot = file->dslot%DIRPERBUF;
- start = offset;
- }
- else{
- addr = 0;
- slot = 0;
- start = 0;
- }
- dmb = mballoc(iounit, chan, Mbreply1);
- for (;;) {
- if(p == nil){
- /*
- * This is just a check to ensure the entry hasn't
- * gone away during the read of each directory block.
- */
- p = getbuf(file->fs->dev, file->addr, Bread);
- if(p == nil || checktag(p, Tdir, QPNONE)){
- error = Ealloc;
- goto out1;
- }
- d = getdir(p, file->slot);
- if(d == nil || !(d->mode & DALLOC)){
- error = Ealloc;
- goto out1;
- }
- }
- p1 = dnodebuf1(p, d, addr, 0, file->uid);
- p = nil;
- if(p1 == nil)
- goto out1;
- if(checktag(p1, Tdir, QPNONE)){
- error = Ephase;
- putbuf(p1);
- goto out1;
- }
- for(; slot < DIRPERBUF; slot++){
- d1 = getdir(p1, slot);
- if(!(d1->mode & DALLOC))
- continue;
- mkdir9p2(&dir, d1, dmb->data);
- n = convD2M(&dir, data+nread, iounit - nread);
- if(n <= BIT16SZ){
- putbuf(p1);
- goto out1;
- }
- start += n;
- if(start < offset)
- continue;
- if(count < n){
- putbuf(p1);
- goto out1;
- }
- count -= n;
- nread += n;
- offset += n;
- }
- putbuf(p1);
- slot = 0;
- addr++;
- }
- out1:
- mbfree(dmb);
- if(error == 0){
- file->doffset = offset;
- file->dvers = file->qid.vers;
- file->dslot = slot+DIRPERBUF*addr;
- }
- out:
- /*
- * Do we need this any more?
- count = f->count - nread;
- if(count > 0)
- memset(data+nread, 0, count);
- */
- if(p != nil)
- putbuf(p);
- if(file != nil)
- qunlock(file);
- r->count = nread;
- r->data = (char*)data;
- return error;
- }
- static int
- write(Chan* chan, Fcall* f, Fcall* r)
- {
- Iobuf *p, *p1;
- Dentry *d;
- File *file;
- Tlock *t;
- Off offset, addr, qpath;
- Timet tim;
- int count, error, nwrite, o, n;
- error = 0;
- offset = f->offset;
- count = f->count;
- nwrite = 0;
- p = nil;
- if((file = filep(chan, f->fid, 0)) == nil){
- error = Efid;
- goto out;
- }
- if(!(file->open & FWRITE)){
- error = Eopen;
- goto out;
- }
- if(count < 0 || count > chan->msize-IOHDRSZ){
- error = Ecount;
- goto out;
- }
- if(offset < 0) {
- error = Eoffset;
- goto out;
- }
- if(file->qid.type & QTAUTH){
- nwrite = authwrite(file, (uchar*)f->data, count);
- if(nwrite < 0)
- error = Eauth2;
- goto out;
- }
- else if(file->fs->dev->type == Devro){
- error = Eronly;
- goto out;
- }
- if ((p = getbuf(file->fs->dev, file->addr, Bread|Bmod)) == nil ||
- (d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)) {
- error = Ealloc;
- goto out;
- }
- if(error = mkqidcmp(&file->qid, d))
- goto out;
- if(t = file->tlock) {
- tim = toytime();
- if(t->time < tim || t->file != file){
- error = Ebroken;
- goto out;
- }
- /* renew the lock */
- t->time = tim + TLOCK;
- }
- accessdir(p, d, FWRITE, file->uid);
- if(d->mode & DAPND)
- offset = d->size;
- if(offset+count > d->size)
- d->size = offset+count;
- while(count > 0){
- if(p == nil){
- p = getbuf(file->fs->dev, file->addr, Bread|Bmod);
- if(p == nil){
- error = Ealloc;
- goto out;
- }
- d = getdir(p, file->slot);
- if(d == nil || !(d->mode & DALLOC)){
- error = Ealloc;
- goto out;
- }
- }
- addr = offset / BUFSIZE;
- o = offset % BUFSIZE;
- n = BUFSIZE - o;
- if(n > count)
- n = count;
- qpath = d->qid.path;
- p1 = dnodebuf1(p, d, addr, Tfile, file->uid);
- p = nil;
- if(p1 == nil) {
- error = Efull;
- goto out;
- }
- if(checktag(p1, Tfile, qpath)){
- putbuf(p1);
- error = Ephase;
- goto out;
- }
- memmove(p1->iobuf+o, f->data+nwrite, n);
- p1->flags |= Bmod;
- putbuf(p1);
- count -= n;
- nwrite += n;
- offset += n;
- }
- out:
- if(p != nil)
- putbuf(p);
- if(file != nil)
- qunlock(file);
- r->count = nwrite;
- return error;
- }
- static int
- _clunk(File* file, int remove, int wok)
- {
- Tlock *t;
- int error;
- error = 0;
- if(t = file->tlock){
- if(t->file == file)
- t->time = 0; /* free the lock */
- file->tlock = 0;
- }
- if(remove && (file->qid.type & QTAUTH) == 0)
- error = doremove(file, wok);
- file->open = 0;
- freewp(file->wpath);
- authfree(file->auth);
- freefp(file);
- qunlock(file);
- return error;
- }
- static int
- clunk(Chan* chan, Fcall* f, Fcall*)
- {
- File *file;
- if((file = filep(chan, f->fid, 0)) == nil)
- return Efid;
- _clunk(file, file->open & FREMOV, 0);
- return 0;
- }
- static int
- remove(Chan* chan, Fcall* f, Fcall*)
- {
- File *file;
- if((file = filep(chan, f->fid, 0)) == nil)
- return Efid;
- return _clunk(file, 1, chan == cons.chan);
- }
- static int
- stat(Chan* chan, Fcall* f, Fcall* r, uchar* data)
- {
- Dir dir;
- Iobuf *p;
- Dentry *d, dentry;
- File *file;
- int error, len;
- error = 0;
- p = nil;
- if((file = filep(chan, f->fid, 0)) == nil)
- return Efid;
- if(file->qid.type & QTAUTH){
- memset(&dentry, 0, sizeof dentry);
- d = &dentry;
- mkqid9p1(&d->qid, &file->qid);
- strcpy(d->name, "#¿");
- d->uid = authuid(file->auth);
- d->gid = d->uid;
- d->muid = d->uid;
- d->atime = time();
- d->mtime = d->atime;
- d->size = 0;
- } else {
- 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(error = mkqidcmp(&file->qid, d))
- goto out;
- if(d->qid.path == QPROOT) /* stat of root gives time */
- d->atime = time();
- }
- len = mkdir9p2(&dir, d, data);
- data += len;
- if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)
- error = Eedge;
- r->stat = data;
- out:
- if(p != nil)
- putbuf(p);
- if(file != nil)
- qunlock(file);
- return error;
- }
- static int
- wstat(Chan* chan, Fcall* f, Fcall*, char* strs)
- {
- Iobuf *p, *p1;
- Dentry *d, *d1;
- File *file;
- int error, err, gid, gl, muid, op, slot, tsync, uid;
- long addr;
- Dir dir;
- if(convM2D(f->stat, f->nstat, &dir, strs) == 0)
- return Econvert;
- /*
- * Get the file.
- * If user 'none' (uid == 0), can't do anything;
- * if filesystem is read-only, can't change anything.
- */
- if((file = filep(chan, f->fid, 0)) == nil)
- return Efid;
- p = p1 = nil;
- if(file->uid == 0){
- error = Eaccess;
- goto out;
- }
- if(file->fs->dev->type == Devro){
- error = Eronly;
- goto out;
- }
- if(file->qid.type & QTAUTH){
- error = Emode;
- goto out;
- }
- /*
- * Get the current entry and check it is still valid.
- */
- 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;
- }
- if(error = mkqidcmp(&file->qid, d))
- goto out;
- /*
- * Run through each of the (sub-)fields in the provided Dir
- * checking for validity and whether it's a default:
- * .type, .dev and .atime are completely ignored and not checked;
- * .qid.path, .qid.vers and .muid are checked for validity but
- * any attempt to change them is an error.
- * .qid.type/.mode, .mtime, .name, .length, .uid and .gid can
- * possibly be changed.
- *
- * 'Op' flags there are changed fields, i.e. it's not a no-op.
- * 'Tsync' flags all fields are defaulted.
- *
- * Wstatallow and writeallow are set to allow changes during the
- * fileserver bootstrap phase.
- */
- tsync = 1;
- if(dir.qid.path != ~0){
- if(dir.qid.path != file->qid.path){
- error = Ewstatp;
- goto out;
- }
- tsync = 0;
- }
- if(dir.qid.vers != ~0){
- if(dir.qid.vers != file->qid.vers){
- error = Ewstatv;
- goto out;
- }
- tsync = 0;
- }
- if(dir.muid != nil && *dir.muid != '\0'){
- muid = strtouid(dir.muid);
- if(muid != d->muid && !wstatallow){
- error = Ewstatm;
- goto out;
- }
- tsync = 0;
- }
- /*
- * .qid.type and .mode have some bits in common. Only .mode
- * is currently needed for comparisons with the old mode but
- * if there are changes to the bits also encoded in .qid.type
- * then file->qid must be updated appropriately later.
- */
- if(dir.qid.type == (uchar)~0){
- if(dir.mode == ~0)
- dir.qid.type = mktype9p2(d->mode);
- else
- dir.qid.type = dir.mode>>24;
- }
- else
- tsync = 0;
- if(dir.mode == ~0)
- dir.mode = mkmode9p2(d->mode);
- else
- tsync = 0;
- /*
- * Check dir.qid.type and dir.mode agree, check for any unknown
- * type/mode bits, check for an attempt to change the directory bit.
- */
- if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
- error = Ewstatq;
- goto out;
- }
- if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){
- error = Ewstatb;
- goto out;
- }
- op = dir.mode^mkmode9p2(d->mode);
- if(op & DMDIR){
- error = Ewstatd;
- goto out;
- }
- if(dir.mtime != ~0){
- if(dir.mtime != d->mtime)
- op = 1;
- tsync = 0;
- }
- else
- dir.mtime = d->mtime;
- if(dir.length == ~(Off)0)
- dir.length = d->size;
- else {
- if (dir.length < 0) {
- error = Ewstatl;
- goto out;
- } else if(dir.length != d->size)
- op = 1;
- tsync = 0;
- }
- /*
- * Check for permission to change .mode, .mtime or .length,
- * must be owner or leader of either group, for which test gid
- * is needed; permission checks on gid will be done later.
- * 'Gl' counts whether neither, one or both groups are led.
- */
- if(dir.gid != nil && *dir.gid != '\0'){
- gid = strtouid(dir.gid);
- tsync = 0;
- }
- else
- gid = d->gid;
- gl = leadgroup(file->uid, gid) != 0;
- gl += leadgroup(file->uid, d->gid) != 0;
- if(op && !wstatallow && d->uid != file->uid && !gl){
- error = Ewstato;
- goto out;
- }
- /*
- * Rename.
- * Check .name is valid and different to the current.
- */
- if(dir.name != nil && *dir.name != '\0'){
- if(error = checkname9p2(dir.name))
- goto out;
- if(strncmp(dir.name, d->name, NAMELEN))
- op = 1;
- else
- dir.name = d->name;
- tsync = 0;
- }
- else
- dir.name = d->name;
- /*
- * If the name is really to be changed check it's unique
- * and there is write permission in the parent.
- */
- if(dir.name != d->name){
- /*
- * First get parent.
- * Must drop current entry to prevent
- * deadlock when searching that new name
- * already exists below.
- */
- putbuf(p);
- p = nil;
- if(file->wpath == nil){
- error = Ephase;
- goto out;
- }
- p1 = getbuf(file->fs->dev, file->wpath->addr, Bread);
- if(p1 == nil || checktag(p1, Tdir, QPNONE)){
- error = Ephase;
- goto out;
- }
- d1 = getdir(p1, file->wpath->slot);
- if(d1 == nil || !(d1->mode & DALLOC)){
- error = Ephase;
- goto out;
- }
- /*
- * Check entries in parent for new name.
- */
- for(addr = 0; ; addr++){
- if((p = dnodebuf(p1, d1, addr, 0, file->uid)) == nil)
- break;
- if(checktag(p, Tdir, d1->qid.path)){
- putbuf(p);
- continue;
- }
- for(slot = 0; slot < DIRPERBUF; slot++){
- d = getdir(p, slot);
- if(!(d->mode & DALLOC) ||
- strncmp(dir.name, d->name, sizeof d->name))
- continue;
- error = Eexist;
- goto out;
- }
- putbuf(p);
- }
- /*
- * Reacquire entry and check it's still OK.
- */
- p = getbuf(file->fs->dev, file->addr, Bread);
- if(p == nil || checktag(p, Tdir, QPNONE)){
- error = Ephase;
- goto out;
- }
- d = getdir(p, file->slot);
- if(d == nil || !(d->mode & DALLOC)){
- error = Ephase;
- goto out;
- }
- /*
- * Check write permission in the parent.
- */
- if(!wstatallow && !writeallow && iaccess(file, d1, DWRITE)){
- error = Eaccess;
- goto out;
- }
- }
- /*
- * Check for permission to change owner - must be god.
- */
- if(dir.uid != nil && *dir.uid != '\0'){
- uid = strtouid(dir.uid);
- if(uid != d->uid){
- if(!wstatallow){
- error = Ewstatu;
- goto out;
- }
- op = 1;
- }
- tsync = 0;
- }
- else
- uid = d->uid;
- /*
- * Check for permission to change group, must be
- * either owner and in new group or leader of both groups.
- */
- if(gid != d->gid){
- if(!(wstatallow || writeallow)
- && !(d->uid == file->uid && ingroup(file->uid, gid))
- && !(gl == 2)){
- error = Ewstatg;
- goto out;
- }
- op = 1;
- }
- /*
- * Checks all done, update if necessary.
- */
- if(op){
- d->mode = mkmode9p1(dir.mode);
- file->qid.type = mktype9p2(d->mode);
- d->mtime = dir.mtime;
- if (dir.length < d->size) {
- err = dtrunclen(p, d, dir.length, uid);
- if (error == 0)
- error = err;
- }
- d->size = dir.length;
- if(dir.name != d->name)
- strncpy(d->name, dir.name, sizeof(d->name));
- d->uid = uid;
- d->gid = gid;
- }
- if(!tsync)
- accessdir(p, d, FREAD, file->uid);
- out:
- if(p != nil)
- putbuf(p);
- if(p1 != nil)
- putbuf(p1);
- qunlock(file);
- return error;
- }
- int
- serve9p2(Msgbuf* mb)
- {
- Chan *chan;
- Fcall f, r;
- Msgbuf *data, *rmb;
- char ename[64];
- int error, n, type;
- static int once;
- if(once == 0){
- fmtinstall('F', fcallfmt);
- once = 1;
- }
- /*
- * 0 return means i don't understand this message,
- * 1 return means i dealt with it, including error
- * replies.
- */
- if(convM2S(mb->data, mb->count, &f) != mb->count)
- {
- print("didn't like %d byte message\n", mb->count);
- return 0;
- }
- type = f.type;
- if(type < Tversion || type >= Tmax || (type & 1) || type == Terror)
- return 0;
- chan = mb->chan;
- if(CHAT(chan))
- print("9p2: f %F\n", &f);
- r.type = type+1;
- r.tag = f.tag;
- error = 0;
- data = nil;
- switch(type){
- default:
- r.type = Rerror;
- snprint(ename, sizeof(ename), "unknown message: %F", &f);
- r.ename = ename;
- break;
- case Tversion:
- error = version(chan, &f, &r);
- break;
- case Tauth:
- error = auth(chan, &f, &r);
- break;
- case Tattach:
- error = attach(chan, &f, &r);
- break;
- case Tflush:
- error = flush(chan, &f, &r);
- break;
- case Twalk:
- error = walk(chan, &f, &r);
- break;
- case Topen:
- error = open(chan, &f, &r);
- break;
- case Tcreate:
- error = create(chan, &f, &r);
- break;
- case Tread:
- data = mballoc(chan->msize, chan, Mbreply1);
- error = read(chan, &f, &r, data->data);
- break;
- case Twrite:
- error = write(chan, &f, &r);
- break;
- case Tclunk:
- error = clunk(chan, &f, &r);
- break;
- case Tremove:
- error = remove(chan, &f, &r);
- break;
- case Tstat:
- data = mballoc(chan->msize, chan, Mbreply1);
- error = stat(chan, &f, &r, data->data);
- break;
- case Twstat:
- data = mballoc(chan->msize, chan, Mbreply1);
- error = wstat(chan, &f, &r, (char*)data->data);
- break;
- }
- if(error != 0){
- r.type = Rerror;
- if(error >= MAXERR){
- snprint(ename, sizeof(ename), "error %d", error);
- r.ename = ename;
- }
- else
- r.ename = errstr9p[error];
- }
- if(CHAT(chan))
- print("9p2: r %F\n", &r);
- rmb = mballoc(chan->msize, chan, Mbreply2);
- n = convS2M(&r, rmb->data, chan->msize);
- if(data != nil)
- mbfree(data);
- if(n == 0){
- type = r.type;
- r.type = Rerror;
- /*
- * If a Tversion has not been seen on the chan then
- * chan->msize will be 0. In that case craft a special
- * Rerror message. It's fortunate that the mballoc above
- * for rmb will have returned a Msgbuf of MAXMSG size
- * when given a request with count of 0...
- */
- if(chan->msize == 0){
- r.ename = "Tversion not seen";
- n = convS2M(&r, rmb->data, MAXMSG);
- }
- else{
- snprint(ename, sizeof(ename), "9p2: convS2M: type %d", type);
- r.ename = ename;
- n = convS2M(&r, rmb->data, chan->msize);
- }
- print("%s\n", r.ename);
- if(n == 0){
- /*
- * What to do here, the failure notification failed?
- */
- mbfree(rmb);
- return 1;
- }
- }
- rmb->count = n;
- rmb->param = mb->param;
- send(chan->reply, rmb);
- return 1;
- }
|