12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865 |
- #include "all.h"
- #define MSIZE (MAXDAT+128)
- static void
- seterror(Fcall *ou, int err)
- {
- if(0 <= err && err < MAXERR)
- ou->ename = errstring[err];
- else
- ou->ename = "unknown error";
- }
- static int
- fsversion(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 int
- fsauth(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;
- }
- int
- authread(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;
- }
- }
- int
- authwrite(File *file, uchar *data, int count)
- {
- int ret;
- ret = auth_rpc(file->rpc, "write", data, count);
- if(ret != ARok)
- return -1;
- return count;
- }
- void
- mkqid9p1(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;
- }
- void
- authfree(File *fp)
- {
- if(fp->rpc != nil){
- close(fp->rpc->afd);
- free(fp->rpc);
- fp->rpc = nil;
- }
- }
- void
- mkqid9p2(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 int
- checkattach(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 int
- fsattach(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 int
- fsflush(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->cuid = 0;
- 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;
- 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 int
- fswalk(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
- fsopen(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 remove on close, check access here
- */
- ro = isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup));
- 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;
- }
- if((d = getdir(p, file->wpath->slot)) == 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;
- }
- if((d = getdir(p, file->slot)) == 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);
- 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
- dir9p2(Dir* dir, Dentry* dentry, void* strs)
- {
- char *op, *p;
- memset(dir, 0, sizeof(Dir));
- mkqid(&dir->qid, dentry, 1);
- dir->mode = (dir->qid.type<<24)|(dentry->mode & 0777);
- 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);
- p += strlen(p)+1;
- dir->gid = p;
- uidtostr(p, dentry->gid);
- p += strlen(p)+1;
- dir->muid = p;
- strcpy(p, "");
- p += strlen(p)+1;
- return p-op;
- }
- static int
- checkname9p2(char* name)
- {
- char *p;
- /*
- * Return length of string if valid, 0 if not.
- */
- if(name == nil)
- return 0;
- for(p = name; *p != 0; p++){
- if((*p & 0xFF) <= 040)
- return 0;
- }
- return p-name;
- }
- static int
- fscreate(Chan* chan, Fcall* f, Fcall* r)
- {
- Iobuf *p, *p1;
- Dentry *d, *d1;
- File *file;
- int error, slot, slot1, fmod, wok, l;
- long 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(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
- error = Eronly;
- goto out;
- }
- p = getbuf(file->fs->dev, file->addr, Bread);
- if(p == nil || checktag(p, Tdir, QPNONE)){
- error = Ealloc;
- goto out;
- }
- if((d = getdir(p, file->slot)) == 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);
- /*
- * Check the name is valid and will fit in an old
- * directory entry.
- */
- if((l = checkname9p2(f->name)) == 0){
- error = Ename;
- goto out;
- }
- if(l+1 > NAMELEN){
- error = Etoolong;
- goto out;
- }
- if(strcmp(f->name, ".") == 0 || strcmp(f->name, "..") == 0){
- error = Edot;
- goto out;
- }
- addr1 = 0;
- slot1 = 0; /* set */
- for(addr = 0; ; addr++){
- if((p1 = dnodebuf(p, d, addr, 0)) == nil){
- if(addr1 != 0)
- break;
- p1 = dnodebuf(p, d, addr, Tdir);
- }
- 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);
- mkqid(&r->qid, d1, 0);
- putbuf(p1);
- accessdir(p, d, FWRITE);
- /*
- * 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
- fsread(Chan* chan, Fcall* f, Fcall* r)
- {
- uchar *data;
- Iobuf *p, *p1;
- File *file;
- Dentry *d, *d1;
- Tlock *t;
- long addr, offset, start, tim;
- int error, iounit, nread, count, n, o, slot;
- Dir dir;
- char strdata[28*10];
- p = nil;
- data = (uchar*)r->data;
- count = f->count;
- offset = f->offset;
- nread = 0;
- if((file = filep(chan, f->fid, 0)) == nil){
- error = Efid;
- goto out;
- }
- if(file->qid.type & QTAUTH){
- nread = authread(file, data, count);
- if(nread < 0)
- error = Esystem;
- else
- error = 0;
- 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;
- }
- p = getbuf(file->fs->dev, file->addr, Bread);
- if(p == nil || checktag(p, Tdir, QPNONE)){
- error = Ealloc;
- goto out;
- }
- if((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 = time(0);
- if(t->time < tim || t->file != file){
- error = Ebroken;
- goto out;
- }
- /* renew the lock */
- t->time = tim + TLOCK;
- }
- accessdir(p, d, FREAD);
- 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;
- }
- if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
- error = Ealloc;
- goto out;
- }
- }
- addr = offset / BUFSIZE;
- o = offset % BUFSIZE;
- n = BUFSIZE - o;
- if(n > count)
- n = count;
- p1 = dnodebuf1(p, d, addr, 0);
- 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;
- }
- dread1:
- 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;
- }
- if((d = getdir(p, file->slot)) == nil || !(d->mode & DALLOC)){
- error = Ealloc;
- goto out1;
- }
- }
- p1 = dnodebuf1(p, d, addr, 0);
- 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;
- dir9p2(&dir, d1, strdata);
- if((n = convD2M(&dir, data+nread, iounit - nread)) <= 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++;
- goto dread1;
- out1:
- 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
- fswrite(Chan* chan, Fcall* f, Fcall* r)
- {
- Iobuf *p, *p1;
- Dentry *d;
- File *file;
- Tlock *t;
- long offset, addr, tim, qpath;
- int count, error, nwrite, o, n;
- offset = f->offset;
- count = f->count;
- nwrite = 0;
- p = nil;
- if((file = filep(chan, f->fid, 0)) == nil){
- error = Efid;
- goto out;
- }
- if(file->qid.type & QTAUTH){
- nwrite = authwrite(file, (uchar*)f->data, count);
- if(nwrite < 0)
- error = Esystem;
- else
- error = 0;
- goto out;
- }
- if(!(file->open & FWRITE)){
- error = Eopen;
- goto out;
- }
- if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
- error = Eronly;
- goto out;
- }
- if(count < 0 || count > chan->msize-IOHDRSZ){
- error = Ecount;
- goto out;
- }
- if(offset < 0) {
- error = Eoffset;
- goto out;
- }
- if((p = getbuf(file->fs->dev, file->addr, Bread|Bmod)) == nil){
- error = Ealloc;
- goto out;
- }
- if((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 = time(0);
- if(t->time < tim || t->file != file){
- error = Ebroken;
- goto out;
- }
- /* renew the lock */
- t->time = tim + TLOCK;
- }
- accessdir(p, d, FWRITE);
- 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((d = getdir(p, file->slot)) == 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);
- 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)
- error = doremove(file, wok);
- file->open = 0;
- freewp(file->wpath);
- freefp(file);
- qunlock(file);
- return error;
- }
- static int
- fsclunk(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
- fsremove(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
- fsstat(Chan* chan, Fcall* f, Fcall* r, uchar* data)
- {
- Dir dir;
- Iobuf *p;
- Dentry *d;
- File *file;
- int error, len;
- if((file = filep(chan, f->fid, 0)) == nil)
- return Efid;
- 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(error = mkqidcmp(&file->qid, d))
- goto out;
- if(d->qid.path == QPROOT) /* stat of root gives time */
- d->atime = time(0);
- len = dir9p2(&dir, d, data);
- data += len;
- if((r->nstat = convD2M(&dir, data, chan->msize - len)) == 0)
- error = Ersc;
- else
- r->stat = data;
- out:
- if(p != nil)
- putbuf(p);
- if(file != nil)
- qunlock(file);
- return error;
- }
- static int
- fswstat(Chan* chan, Fcall* f, Fcall*, char *strs)
- {
- Iobuf *p, *p1;
- Dentry *d, *d1, xd;
- File *file;
- int error, slot, uid, gid, l;
- long addr;
- Dir dir;
- ulong mode;
- p = p1 = nil;
- d1 = nil;
- if((file = filep(chan, f->fid, 0)) == nil){
- error = Efid;
- goto out;
- }
- /*
- * if user none,
- * can't do anything
- * unless allow.
- */
- if(file->uid == 0 && !wstatallow){
- error = Eaccess;
- goto out;
- }
- if(isro(file->fs->dev) || (writegroup && !ingroup(file->uid, writegroup))){
- error = Eronly;
- goto out;
- }
- /*
- * first get parent
- */
- if(file->wpath){
- p1 = getbuf(file->fs->dev, file->wpath->addr, Bread);
- if(p1 == nil){
- error = Ephase;
- goto out;
- }
- d1 = getdir(p1, file->wpath->slot);
- if(d1 == nil || checktag(p1, Tdir, QPNONE) || !(d1->mode & DALLOC)){
- error = Ephase;
- goto out;
- }
- }
- if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){
- error = Ealloc;
- goto out;
- }
- d = getdir(p, file->slot);
- if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)){
- error = Ealloc;
- goto out;
- }
- if(error = mkqidcmp(&file->qid, d))
- goto out;
- /*
- * Convert the message and fix up
- * fields not to be changed.
- */
- if(convM2D(f->stat, f->nstat, &dir, strs) == 0){
- print("9p2: convM2D returns 0\n");
- error = Econvert;
- goto out;
- }
- if(dir.uid == nil || strlen(dir.uid) == 0)
- uid = d->uid;
- else
- uid = strtouid(dir.uid);
- if(dir.gid == nil || strlen(dir.gid) == 0)
- gid = d->gid;
- else
- gid = strtouid(dir.gid);
- if(dir.name == nil || strlen(dir.name) == 0)
- dir.name = d->name;
- else{
- if((l = checkname9p2(dir.name)) == 0){
- error = Ename;
- goto out;
- }
- if(l > NAMELEN){
- error = Etoolong;
- goto out;
- }
- }
- /*
- * Before doing sanity checks, find out what the
- * new 'mode' should be:
- * if 'type' and 'mode' are both defaults, take the
- * new mode from the old directory entry;
- * else if 'type' is the default, use the new mode entry;
- * else if 'mode' is the default, create the new mode from
- * 'type' or'ed with the old directory mode;
- * else neither are defaults, use the new mode but check
- * it agrees with 'type'.
- */
- if(dir.qid.type == 0xFF && dir.mode == ~0){
- dir.mode = d->mode & 0777;
- if(d->mode & DLOCK)
- dir.mode |= DMEXCL;
- if(d->mode & DAPND)
- dir.mode |= DMAPPEND;
- if(d->mode & DDIR)
- dir.mode |= DMDIR;
- }
- else if(dir.qid.type == 0xFF){
- /* nothing to do */
- }
- else if(dir.mode == ~0)
- dir.mode = (dir.qid.type<<24)|(d->mode & 0777);
- else if(dir.qid.type != ((dir.mode>>24) & 0xFF)){
- error = Eqidmode;
- goto out;
- }
- /*
- * Check for unknown type/mode bits
- * and an attempt to change the directory bit.
- */
- if(dir.mode & ~(DMDIR|DMAPPEND|DMEXCL|0777)){
- error = Enotm;
- goto out;
- }
- if(d->mode & DDIR)
- mode = DMDIR;
- else
- mode = 0;
- if((dir.mode^mode) & DMDIR){
- error = Enotd;
- goto out;
- }
- if(dir.mtime == ~0)
- dir.mtime = d->mtime;
- if(dir.length == ~0)
- dir.length = d->size;
- /*
- * Currently, can't change length.
- */
- if(dir.length != d->size){
- error = Enotl;
- goto out;
- }
- /*
- * if chown,
- * must be god
- * wstatallow set to allow chown during boot
- */
- if(uid != d->uid && !wstatallow) {
- error = Enotu;
- goto out;
- }
- /*
- * if chgroup,
- * must be either
- * a) owner and in new group
- * b) leader of both groups
- * wstatallow and writeallow are set to allow chgrp during boot
- */
- while(gid != d->gid) {
- if(wstatallow || writeallow)
- break;
- if(d->uid == file->uid && ingroup(file->uid, gid))
- break;
- if(leadgroup(file->uid, gid))
- if(leadgroup(file->uid, d->gid))
- break;
- error = Enotg;
- goto out;
- }
- /*
- * if rename,
- * must have write permission in parent
- */
- while(strncmp(d->name, dir.name, sizeof(d->name)) != 0) {
- if(checkname(dir.name) || d1 == nil) {
- error = Ename;
- goto out;
- }
- if(strcmp(dir.name, ".") == 0 || strcmp(xd.name, "..") == 0) {
- error = Ename;
- goto out;
- }
- /*
- * drop entry to prevent lock, then
- * check that destination name is unique,
- */
- putbuf(p);
- for(addr = 0; ; addr++) {
- if((p = dnodebuf(p1, d1, addr, 0)) == 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))
- continue;
- if(strncmp(dir.name, d->name, sizeof(d->name)) == 0) {
- error = Eexist;
- goto out;
- }
- }
- putbuf(p);
- }
- /*
- * reacquire entry
- */
- if((p = getbuf(file->fs->dev, file->addr, Bread)) == nil){
- error = Ephase;
- goto out;
- }
- d = getdir(p, file->slot);
- if(d == nil || checktag(p, Tdir, QPNONE) || !(d->mode & DALLOC)) {
- error = Ephase;
- goto out;
- }
- if(wstatallow || writeallow) /* set to allow rename during boot */
- break;
- if(d1 == nil || iaccess(file, d1, DWRITE)) {
- error = Eaccess;
- goto out;
- }
- break;
- }
- /*
- * if mode/time, either
- * a) owner
- * b) leader of either group
- */
- mode = dir.mode & 0777;
- if(dir.mode & DMAPPEND)
- mode |= DAPND;
- if(dir.mode & DMEXCL)
- mode |= DLOCK;
- while(d->mtime != dir.mtime || ((d->mode^mode) & (DAPND|DLOCK|0777))) {
- if(wstatallow) /* set to allow chmod during boot */
- break;
- if(d->uid == file->uid)
- break;
- if(leadgroup(file->uid, gid))
- break;
- if(leadgroup(file->uid, d->gid))
- break;
- error = Enotu;
- goto out;
- }
- d->mtime = dir.mtime;
- d->uid = uid;
- d->gid = gid;
- d->mode = (mode & (DAPND|DLOCK|0777)) | (d->mode & (DALLOC|DDIR));
- strncpy(d->name, dir.name, sizeof(d->name));
- accessdir(p, d, FWSTAT);
- out:
- if(p != nil)
- putbuf(p);
- if(p1 != nil)
- putbuf(p1);
- if(file != nil)
- qunlock(file);
- return error;
- }
- static int
- recv(Chan *c, uchar *buf, int n)
- {
- int fd, m, len;
- fd = c->chan;
- /* read count */
- qlock(&c->rlock);
- m = readn(fd, buf, BIT32SZ);
- if(m != BIT32SZ){
- qunlock(&c->rlock);
- if(m < 0){
- print("readn(BIT32SZ) fails: %r\n");
- return -1;
- }
- print("readn(BIT32SZ) returns %d: %r\n", m);
- return 0;
- }
- len = GBIT32(buf);
- if(len <= BIT32SZ || len > n){
- print("recv bad length %d\n", len);
- werrstr("bad length in 9P2000 message header");
- qunlock(&c->rlock);
- return -1;
- }
- len -= BIT32SZ;
- m = readn(fd, buf+BIT32SZ, len);
- qunlock(&c->rlock);
- if(m < len){
- print("recv wanted %d got %d\n", len, m);
- return 0;
- }
- return BIT32SZ+m;
- }
- static void
- send(Chan *c, uchar *buf, int n)
- {
- int fd, m;
- fd = c->chan;
- qlock(&c->wlock);
- m = write(fd, buf, n);
- qunlock(&c->wlock);
- if(m == n)
- return;
- panic("write failed");
- }
- void
- serve9p2(Chan *chan, uchar *ib, int nib)
- {
- uchar inbuf[MSIZE+IOHDRSZ], outbuf[MSIZE+IOHDRSZ];
- Fcall f, r;
- char ename[64];
- int error, n, type;
- chan->msize = MSIZE;
- fmtinstall('F', fcallfmt);
- for(;;){
- if(nib){
- memmove(inbuf, ib, nib);
- n = nib;
- nib = 0;
- }else
- n = recv(chan, inbuf, sizeof inbuf);
- if(chat){
- print("read msg %d (fd %d)\n", n, chan->chan);
- if(n <= 0)
- print("\terr: %r\n");
- }
- if(n == 0 && (chan == cons.srvchan || chan == cons.chan))
- continue;
- if(n <= 0)
- break;
- if(convM2S(inbuf, n, &f) != n){
- print("9p2: cannot decode\n");
- continue;
- }
- type = f.type;
- if(type < Tversion || type >= Tmax || (type&1) || type == Terror){
- print("9p2: bad message type %d\n", type);
- continue;
- }
- if(CHAT(chan))
- print("9p2: f %F\n", &f);
- r.type = type+1;
- r.tag = f.tag;
- error = 0;
- rlock(&mainlock);
- rlock(&chan->reflock);
- switch(type){
- default:
- r.type = Rerror;
- snprint(ename, sizeof ename, "unknown message: %F", &f);
- r.ename = ename;
- break;
- case Tversion:
- error = fsversion(chan, &f, &r);
- break;
- case Tauth:
- error = fsauth(chan, &f, &r);
- break;
- case Tattach:
- error = fsattach(chan, &f, &r);
- break;
- case Tflush:
- error = fsflush(chan, &f, &r);
- break;
- case Twalk:
- error = fswalk(chan, &f, &r);
- break;
- case Topen:
- error = fsopen(chan, &f, &r);
- break;
- case Tcreate:
- error = fscreate(chan, &f, &r);
- break;
- case Tread:
- r.data = (char*)inbuf;
- error = fsread(chan, &f, &r);
- break;
- case Twrite:
- error = fswrite(chan, &f, &r);
- break;
- case Tclunk:
- error = fsclunk(chan, &f, &r);
- break;
- case Tremove:
- error = fsremove(chan, &f, &r);
- break;
- case Tstat:
- error = fsstat(chan, &f, &r, inbuf);
- break;
- case Twstat:
- error = fswstat(chan, &f, &r, (char*)outbuf);
- break;
- }
- runlock(&chan->reflock);
- runlock(&mainlock);
- if(error != 0){
- r.type = Rerror;
- if(error >= MAXERR){
- snprint(ename, sizeof(ename), "error %d", error);
- r.ename = ename;
- }
- else
- r.ename = errstring[error];
- }
- if(CHAT(chan))
- print("9p2: r %F\n", &r);
-
- n = convS2M(&r, outbuf, sizeof outbuf);
- if(n == 0){
- type = r.type;
- r.type = Rerror;
- snprint(ename, sizeof(ename), "9p2: convS2M: type %d", type);
- r.ename = ename;
- print(ename);
- n = convS2M(&r, outbuf, sizeof outbuf);
- if(n == 0){
- /*
- * What to do here, the failure notification failed?
- */
- panic("can't write anything at all");
- }
- }
- send(chan, outbuf, n);
- }
- fileinit(chan);
- close(chan->chan);
- if(chan == cons.srvchan || chan == cons.chan)
- print("console chan read error");
- }
|