8 // static char Ebadattach[] = "unknown specifier in attach";
9 static char Ebadoffset[] = "bad offset";
10 // static char Ebadcount[] = "bad count";
11 static char Ebotch[] = "9P protocol botch";
12 static char Ecreatenondir[] = "create in non-directory";
13 static char Edupfid[] = "duplicate fid";
14 static char Eduptag[] = "duplicate tag";
15 static char Eisdir[] = "is a directory";
16 static char Enocreate[] = "create prohibited";
17 // static char Enomem[] = "out of memory";
18 static char Enoremove[] = "remove prohibited";
19 static char Enostat[] = "stat prohibited";
20 static char Enotfound[] = "file not found";
21 // static char Enowrite[] = "write prohibited";
22 static char Enowstat[] = "wstat prohibited";
23 static char Eperm[] = "permission denied";
24 static char Eunknownfid[] = "unknown fid";
25 static char Ebaddir[] = "bad directory in wstat";
26 static char Ewalknodir[] = "walk in non-directory";
29 setfcallerror(Fcall *f, char *err)
36 changemsize(Srv *srv, int msize)
38 if(srv->rbuf && srv->wbuf && srv->msize == msize)
45 srv->rbuf = emalloc9p(msize);
46 srv->wbuf = emalloc9p(msize);
60 if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){
66 memmove(buf, s->rbuf, n);
69 if(convM2S(buf, n, &f) != n){
74 if((r=allocreq(s->rpool, f.tag)) == nil){ /* duplicate tag: cons up a fake Req */
75 r = emalloc9p(sizeof *r);
86 fprint(2, "<-%d- %F: dup tag\n", s->infd, &f);
94 memset(&r->ofcall, 0, sizeof r->ofcall);
95 r->type = r->ifcall.type;
99 fprint(2, "<-%d- %F: %s\n", s->infd, &r->ifcall, r->error);
101 fprint(2, "<-%d- %F\n", s->infd, &r->ifcall);
116 for(i=0; i<r->ifcall.nwname; i++)
117 if(f = walkfile(f, r->ifcall.wname[i]))
118 r->ofcall.wqid[i] = f->dir.qid;
125 r->newfid->qid = r->newfid->file->dir.qid;
131 walkandclone(Req *r, char *(*walk1)(Fid*, char*, void*), char *(*clone)(Fid*, Fid*, void*), void *arg)
136 if(r->fid == r->newfid && r->ifcall.nwname > 1){
137 respond(r, "lib9p: unused documented feature not implemented");
141 if(r->fid != r->newfid){
142 r->newfid->qid = r->fid->qid;
143 if(clone && (e = clone(r->fid, r->newfid, arg))){
150 for(i=0; i<r->ifcall.nwname; i++){
151 if(e = walk1(r->newfid, r->ifcall.wname[i], arg))
153 r->ofcall.wqid[i] = r->newfid->qid;
164 sversion(Srv *srv, Req *r)
168 if(strncmp(r->ifcall.version, "9P", 2) != 0){
169 r->ofcall.version = "unknown";
174 r->ofcall.version = "9P2000";
175 r->ofcall.msize = r->ifcall.msize;
179 rversion(Req *r, char *error)
181 assert(error == nil);
182 changemsize(r->srv, r->ofcall.msize);
186 sauth(Srv *srv, Req *r)
190 if((r->afid = allocfid(srv->fpool, r->ifcall.afid)) == nil){
197 snprint(e, sizeof e, "%s: authentication not required", argv0);
202 rauth(Req *r, char *error)
205 closefid(removefid(r->srv->fpool, r->afid->fid));
209 sattach(Srv *srv, Req *r)
211 if((r->fid = allocfid(srv->fpool, r->ifcall.fid)) == nil){
216 if(r->ifcall.afid != NOFID && (r->afid = lookupfid(srv->fpool, r->ifcall.afid)) == nil){
217 respond(r, Eunknownfid);
220 r->fid->uid = estrdup9p(r->ifcall.uname);
222 r->fid->file = srv->tree->root;
223 /* BUG? incref(r->fid->file) ??? */
224 r->ofcall.qid = r->fid->file->dir.qid;
225 r->fid->qid = r->ofcall.qid;
234 rattach(Req *r, char *error)
237 closefid(removefid(r->srv->fpool, r->fid->fid));
241 sflush(Srv *srv, Req *r)
243 r->oldreq = lookupreq(srv->rpool, r->ifcall.oldtag);
244 if(r->oldreq == nil || r->oldreq == r)
252 rflush(Req *r, char *error)
256 assert(error == nil);
260 if(or->responded == 0){
261 or->flush = erealloc9p(or->flush, (or->nflush+1)*sizeof(or->flush[0]));
262 or->flush[or->nflush++] = r;
264 return -1; /* delay response until or is responded */
274 oldwalk1(Fid *fid, char *name, void *arg)
281 e = srv->walk1(fid, name, &qid);
289 oldclone(Fid *fid, Fid *newfid, void *arg)
294 if(srv->clone == nil)
296 return srv->clone(fid, newfid);
300 swalk(Srv *srv, Req *r)
302 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
303 respond(r, Eunknownfid);
306 if(r->fid->omode != -1){
307 respond(r, "cannot clone open fid");
310 if(r->ifcall.nwname && !(r->fid->qid.type&QTDIR)){
311 respond(r, Ewalknodir);
314 if(r->ifcall.fid != r->ifcall.newfid){
315 if((r->newfid = allocfid(srv->fpool, r->ifcall.newfid)) == nil){
319 r->newfid->uid = estrdup9p(r->fid->uid);
321 incref(&r->fid->ref);
327 walkandclone(r, oldwalk1, oldclone, srv);
331 sysfatal("no walk function, no file trees");
334 rwalk(Req *r, char *error)
336 if(error || r->ofcall.nwqid < r->ifcall.nwname){
337 if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
338 closefid(removefid(r->srv->fpool, r->newfid->fid));
339 if (r->ofcall.nwqid==0){
340 if(error==nil && r->ifcall.nwname!=0)
341 r->error = Enotfound;
343 r->error = nil; // No error on partial walks
345 if(r->ofcall.nwqid == 0){
347 r->newfid->qid = r->fid->qid;
349 /* if file trees are in use, filewalk took care of the rest */
350 r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
356 sopen(Srv *srv, Req *r)
360 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
361 respond(r, Eunknownfid);
364 if(r->fid->omode != -1){
368 if((r->fid->qid.type&QTDIR) && (r->ifcall.mode&~ORCLOSE) != OREAD){
372 r->ofcall.qid = r->fid->qid;
373 switch(r->ifcall.mode&3){
389 if(r->ifcall.mode&OTRUNC)
391 if((r->fid->qid.type&QTDIR) && p!=AREAD){
396 if(!hasperm(r->fid->file, r->fid->uid, p)){
401 if((r->ifcall.mode&ORCLOSE)
402 && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
406 r->ofcall.qid = r->fid->file->dir.qid;
407 if((r->ofcall.qid.type&QTDIR)
408 && (r->fid->rdir = opendirfile(r->fid->file)) == nil){
409 respond(r, "opendirfile failed");
419 ropen(Req *r, char *error)
425 snprint(errbuf, sizeof errbuf, "fid mode is 0x%ux\n", r->ifcall.mode);
426 write(2, errbuf, strlen(errbuf));
428 r->fid->omode = r->ifcall.mode;
429 r->fid->qid = r->ofcall.qid;
430 if(r->ofcall.qid.type&QTDIR)
431 r->fid->diroffset = 0;
435 screate(Srv *srv, Req *r)
437 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil)
438 respond(r, Eunknownfid);
439 else if(r->fid->omode != -1)
441 else if(!(r->fid->qid.type&QTDIR))
442 respond(r, Ecreatenondir);
443 else if(r->fid->file && !hasperm(r->fid->file, r->fid->uid, AWRITE))
448 respond(r, Enocreate);
451 rcreate(Req *r, char *error)
455 r->fid->omode = r->ifcall.mode;
456 r->fid->qid = r->ofcall.qid;
460 sread(Srv *srv, Req *r)
464 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
465 respond(r, Eunknownfid);
468 if(r->ifcall.count < 0){
472 if(r->ifcall.offset < 0
473 || ((r->fid->qid.type&QTDIR) && r->ifcall.offset != 0 && r->ifcall.offset != r->fid->diroffset)){
474 respond(r, Ebadoffset);
478 if(r->ifcall.count > srv->msize - IOHDRSZ)
479 r->ifcall.count = srv->msize - IOHDRSZ;
480 r->rbuf = emalloc9p(r->ifcall.count);
481 r->ofcall.data = r->rbuf;
482 o = r->fid->omode & 3;
483 if(o != OREAD && o != ORDWR && o != OEXEC){
487 if((r->fid->qid.type&QTDIR) && r->fid->file){
488 r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count);
495 respond(r, "no srv->read");
498 rread(Req *r, char *error)
500 if(error==nil && (r->fid->qid.type&QTDIR))
501 r->fid->diroffset += r->ofcall.count;
505 swrite(Srv *srv, Req *r)
510 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
511 respond(r, Eunknownfid);
514 if(r->ifcall.count < 0){
518 if(r->ifcall.offset < 0){
522 if(r->ifcall.count > srv->msize - IOHDRSZ)
523 r->ifcall.count = srv->msize - IOHDRSZ;
524 o = r->fid->omode & 3;
525 if(o != OWRITE && o != ORDWR){
526 snprint(e, sizeof e, "write on fid with open mode 0x%ux", r->fid->omode);
533 respond(r, "no srv->write");
536 rwrite(Req *r, char *error)
541 r->fid->file->dir.qid.vers++;
545 sclunk(Srv *srv, Req *r)
547 if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil)
548 respond(r, Eunknownfid);
553 rclunk(Req *r, char *msg)
560 sremove(Srv *srv, Req *r)
562 if((r->fid = removefid(srv->fpool, r->ifcall.fid)) == nil){
563 respond(r, Eunknownfid);
567 if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
574 respond(r, r->fid->file ? nil : Enoremove);
577 rremove(Req *r, char *error, char *errbuf)
582 if(removefile(r->fid->file) < 0){
583 snprint(errbuf, ERRMAX, "remove %s: %r",
584 r->fid->file->dir.name);
592 sstat(Srv *srv, Req *r)
594 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
595 respond(r, Eunknownfid);
599 r->d = r->fid->file->dir;
601 r->d.name = estrdup9p(r->d.name);
603 r->d.uid = estrdup9p(r->d.uid);
605 r->d.gid = estrdup9p(r->d.gid);
607 r->d.muid = estrdup9p(r->d.muid);
611 else if(r->fid->file)
617 rstat(Req *r, char *error)
625 if(convD2M(&r->d, tmp, BIT16SZ) != BIT16SZ){
626 r->error = "convD2M(_,_,BIT16SZ) did not return BIT16SZ";
629 n = GBIT16(tmp)+BIT16SZ;
630 statbuf = emalloc9p(n);
632 r->error = "out of memory";
635 r->ofcall.nstat = convD2M(&r->d, statbuf, n);
636 r->ofcall.stat = statbuf; /* freed in closereq */
637 if(r->ofcall.nstat <= BIT16SZ){
638 r->error = "convD2M fails";
645 swstat(Srv *srv, Req *r)
647 if((r->fid = lookupfid(srv->fpool, r->ifcall.fid)) == nil){
648 respond(r, Eunknownfid);
651 if(srv->wstat == nil){
652 respond(r, Enowstat);
655 if(convM2D(r->ifcall.stat, r->ifcall.nstat, &r->d, (char*)r->ifcall.stat) != r->ifcall.nstat){
659 if((ushort)~r->d.type){
660 respond(r, "wstat -- attempt to change type");
664 respond(r, "wstat -- attempt to change dev");
667 if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){
668 respond(r, "wstat -- attempt to change qid");
671 if(r->d.muid && r->d.muid[0]){
672 respond(r, "wstat -- attempt to change muid");
675 if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){
676 respond(r, "wstat -- attempt to change DMDIR bit");
682 rwstat(Req *r, char *msg)
693 fmtinstall('D', dirfmt);
694 fmtinstall('F', fcallfmt);
696 if(srv->fpool == nil)
697 srv->fpool = allocfidpool(srv->destroyfid);
698 if(srv->rpool == nil)
699 srv->rpool = allocreqpool(srv->destroyreq);
701 srv->msize = 8192+IOHDRSZ;
703 changemsize(srv, srv->msize);
705 srv->fpool->srv = srv;
706 srv->rpool->srv = srv;
708 while(r = getreq(srv)){
710 respond(r, r->error);
713 switch(r->ifcall.type){
715 respond(r, "unknown message");
717 case Tversion: sversion(srv, r); break;
718 case Tauth: sauth(srv, r); break;
719 case Tattach: sattach(srv, r); break;
720 case Tflush: sflush(srv, r); break;
721 case Twalk: swalk(srv, r); break;
722 case Topen: sopen(srv, r); break;
723 case Tcreate: screate(srv, r); break;
724 case Tread: sread(srv, r); break;
725 case Twrite: swrite(srv, r); break;
726 case Tclunk: sclunk(srv, r); break;
727 case Tremove: sremove(srv, r); break;
728 case Tstat: sstat(srv, r); break;
729 case Twstat: swstat(srv, r); break;
738 respond(Req *r, char *error)
747 assert(r->responded == 0);
750 switch(r->ifcall.type){
754 * Flush is special. If the handler says so, we return
755 * without further processing. Respond will be called
756 * again once it is safe.
759 if(rflush(r, error)<0)
762 case Tversion: rversion(r, error); break;
763 case Tauth: rauth(r, error); break;
764 case Tattach: rattach(r, error); break;
765 case Twalk: rwalk(r, error); break;
766 case Topen: ropen(r, error); break;
767 case Tcreate: rcreate(r, error); break;
768 case Tread: rread(r, error); break;
769 case Twrite: rwrite(r, error); break;
770 case Tclunk: rclunk(r, error); break;
771 case Tremove: rremove(r, error, errbuf); break;
772 case Tstat: rstat(r, error); break;
773 case Twstat: rwstat(r, error); break;
776 r->ofcall.tag = r->ifcall.tag;
777 r->ofcall.type = r->ifcall.type+1;
779 setfcallerror(&r->ofcall, r->error);
782 fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);
785 n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
787 fprint(2, "n = %d %F\n", n, &r->ofcall);
791 if(r->pool) /* not a fake */
792 closereq(removereq(r->pool, r->ifcall.tag));
793 m = write(srv->outfd, srv->wbuf, n);
795 sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
796 qunlock(&srv->wlock);
798 qlock(&r->lk); /* no one will add flushes now */
802 for(i=0; i<r->nflush; i++)
803 respond(r->flush[i], nil);
813 postfd(char *name, int pfd)
818 snprint(buf, sizeof buf, "/srv/%s", name);
820 fprint(2, "postfd %s\n", buf);
821 fd = create(buf, OWRITE|ORCLOSE|OCEXEC, 0600);
824 fprint(2, "create fails: %r\n");
827 if(fprint(fd, "%d", pfd) < 0){
829 fprint(2, "write fails: %r\n");
834 fprint(2, "postfd successful\n");