Req *r;
qlock(&s->rlock);
- if((n = read9pmsg(s->infd, s->rbuf, s->msize)) <= 0){
+ n = read9pmsg(s->infd, s->rbuf, s->msize);
+ if(n <= 0){
qunlock(&s->rlock);
return nil;
}
}
static void
-sversion(Srv*, Req *r)
+sversion(Srv *srv, Req *r)
{
+ if(srv->rref.ref != 1){
+ respond(r, Ebotch);
+ return;
+ }
if(strncmp(r->ifcall.version, "9P", 2) != 0){
r->ofcall.version = "unknown";
+ r->ofcall.msize = 256;
respond(r, nil);
return;
}
-
r->ofcall.version = "9P2000";
- r->ofcall.msize = r->ifcall.msize;
+ if(r->ifcall.msize < 256){
+ respond(r, "version: message size too small");
+ return;
+ }
+ if(r->ifcall.msize < 1024*1024)
+ r->ofcall.msize = r->ifcall.msize;
+ else
+ r->ofcall.msize = 1024*1024;
respond(r, nil);
}
+
static void
rversion(Req *r, char *error)
{
- assert(error == nil);
- changemsize(r->srv, r->ofcall.msize);
+ if(error == nil)
+ changemsize(r->srv, r->ofcall.msize);
}
static void
}
}
+static int
+dirwritable(Fid *fid)
+{
+ File *f;
+
+ f = fid->file;
+ if(f){
+ rlock(f);
+ if(f->parent && !hasperm(f->parent, fid->uid, AWRITE)){
+ runlock(f);
+ return 0;
+ }
+ runlock(f);
+ }
+ return 1;
+}
+
static void
sopen(Srv *srv, Req *r)
{
respond(r, Eperm);
return;
}
- /* BUG RACE */
- if((r->ifcall.mode&ORCLOSE)
- && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
+ if((r->ifcall.mode&ORCLOSE) && !dirwritable(r->fid)){
respond(r, Eperm);
return;
}
return;
}
if((r->fid->qid.type&QTDIR) && r->fid->file){
- r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count);
+ r->ofcall.count = readdirfile(r->fid->rdir, r->rbuf, r->ifcall.count, r->ifcall.offset);
respond(r, nil);
return;
}
rread(Req *r, char *error)
{
if(error==nil && (r->fid->qid.type&QTDIR))
- r->fid->diroffset += r->ofcall.count;
+ r->fid->diroffset = r->ifcall.offset + r->ofcall.count;
}
static void
if(srv->write)
srv->write(r);
else
- respond(r, "no srv->write");
+ respond(r, Enowrite);
}
static void
rwrite(Req *r, char *error)
respond(r, Eunknownfid);
return;
}
- /* BUG RACE */
- if(r->fid->file && !hasperm(r->fid->file->parent, r->fid->uid, AWRITE)){
+ if(!dirwritable(r->fid)){
respond(r, Eperm);
return;
}
respond(r, Ebaddir);
return;
}
- if((ushort)~r->d.type){
- respond(r, "wstat -- attempt to change type");
- return;
- }
- if((uint)~r->d.dev){
- respond(r, "wstat -- attempt to change dev");
- return;
- }
- if((uchar)~r->d.qid.type || (ulong)~r->d.qid.vers || (uvlong)~r->d.qid.path){
- respond(r, "wstat -- attempt to change qid");
+ if(r->d.qid.path != ~0 && r->d.qid.path != r->fid->qid.path){
+ respond(r, "wstat -- attempt to change qid.path");
return;
}
- if(r->d.muid && r->d.muid[0]){
- respond(r, "wstat -- attempt to change muid");
+ if(r->d.qid.vers != ~0 && r->d.qid.vers != r->fid->qid.vers){
+ respond(r, "wstat -- attempt to change qid.vers");
return;
}
- if((ulong)~r->d.mode && ((r->d.mode&DMDIR)>>24) != (r->fid->qid.type&QTDIR)){
- respond(r, "wstat -- attempt to change DMDIR bit");
- return;
+ if(r->d.mode != ~0){
+ if(r->d.mode & ~(DMDIR|DMAPPEND|DMEXCL|DMTMP|0777)){
+ respond(r, "wstat -- unknown bits in mode");
+ return;
+ }
+ if(r->d.qid.type != (uchar)~0 && r->d.qid.type != ((r->d.mode>>24)&0xFF)){
+ respond(r, "wstat -- qid.type/mode mismatch");
+ return;
+ }
+ if(((r->d.mode>>24) ^ r->fid->qid.type) & ~(QTAPPEND|QTEXCL|QTTMP)){
+ respond(r, "wstat -- attempt to change qid.type");
+ return;
+ }
+ } else {
+ if(r->d.qid.type != (uchar)~0 && r->d.qid.type != r->fid->qid.type){
+ respond(r, "wstat -- attempt to change qid.type");
+ return;
+ }
}
srv->wstat(r);
}
{
}
-void
-srv(Srv *srv)
+static void srvclose(Srv *);
+
+static void
+srvwork(void *v)
{
+ Srv *srv = v;
Req *r;
- fmtinstall('D', dirfmt);
- fmtinstall('F', fcallfmt);
-
- if(srv->fpool == nil)
- srv->fpool = allocfidpool(srv->destroyfid);
- if(srv->rpool == nil)
- srv->rpool = allocreqpool(srv->destroyreq);
- if(srv->msize == 0)
- srv->msize = 8192+IOHDRSZ;
-
- changemsize(srv, srv->msize);
-
- srv->fpool->srv = srv;
- srv->rpool->srv = srv;
-
while(r = getreq(srv)){
+ incref(&srv->rref);
if(r->error){
respond(r, r->error);
continue;
}
+ qlock(&srv->slock);
switch(r->ifcall.type){
default:
respond(r, "unknown message");
case Tstat: sstat(srv, r); break;
case Twstat: swstat(srv, r); break;
}
+ if(srv->sref.ref > 8 && srv->spid != getpid()){
+ decref(&srv->sref);
+ qunlock(&srv->slock);
+ return;
+ }
+ qunlock(&srv->slock);
}
+ if(srv->end && srv->sref.ref == 1)
+ srv->end(srv);
+ if(decref(&srv->sref) == 0)
+ srvclose(srv);
+}
+
+static void
+srvclose(Srv *srv)
+{
+ if(srv->rref.ref || srv->sref.ref)
+ return;
+
+ if(chatty9p)
+ fprint(2, "srvclose\n");
+
free(srv->rbuf);
srv->rbuf = nil;
free(srv->wbuf);
freereqpool(srv->rpool);
srv->rpool = nil;
- if(srv->end)
- srv->end(srv);
+ if(srv->free)
+ srv->free(srv);
+}
+
+void
+srvacquire(Srv *srv)
+{
+ incref(&srv->sref);
+ qlock(&srv->slock);
+}
+
+void
+srvrelease(Srv *srv)
+{
+ if(decref(&srv->sref) == 0){
+ incref(&srv->sref);
+ _forker(srvwork, srv, 0);
+ }
+ qunlock(&srv->slock);
+}
+
+void
+srv(Srv *srv)
+{
+ fmtinstall('D', dirfmt);
+ fmtinstall('F', fcallfmt);
+
+ srv->spid = getpid();
+ srv->sref.ref = 0;
+ srv->rref.ref = 0;
+
+ if(srv->fpool == nil)
+ srv->fpool = allocfidpool(srv->destroyfid);
+ if(srv->rpool == nil)
+ srv->rpool = allocreqpool(srv->destroyreq);
+ if(srv->msize == 0)
+ srv->msize = 8192+IOHDRSZ;
+
+ changemsize(srv, srv->msize);
+
+ srv->fpool->srv = srv;
+ srv->rpool->srv = srv;
+
+ if(srv->start)
+ srv->start(srv);
+
+ incref(&srv->sref);
+ srvwork(srv);
}
void
r->error = error;
switch(r->ifcall.type){
- default:
- assert(0);
/*
* Flush is special. If the handler says so, we return
* without further processing. Respond will be called
qlock(&srv->wlock);
n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
if(n <= 0){
- fprint(2, "n = %d %F\n", n, &r->ofcall);
+ fprint(2, "msize = %d n = %d %F\n", srv->msize, n, &r->ofcall);
abort();
}
assert(n > 2);
closereq(removereq(r->pool, r->ifcall.tag));
m = write(srv->outfd, srv->wbuf, n);
if(m != n)
- sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
+ fprint(2, "lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
qunlock(&srv->wlock);
qlock(&r->lk); /* no one will add flushes now */
closereq(r);
else
free(r);
+
+ if(decref(&srv->rref) == 0)
+ srvclose(srv);
}
void
return 0;
}
+int
+sharefd(char *name, char *desc, int pfd)
+{
+ int fd;
+ char buf[80];
+
+ snprint(buf, sizeof buf, "#σc/%s", name);
+ if((fd = create(buf, OREAD, 0700|DMDIR)) >= 0)
+ close(fd);
+ snprint(buf, sizeof buf, "#σc/%s/%s", name, desc);
+ if(chatty9p)
+ fprint(2, "sharefd %s\n", buf);
+ fd = create(buf, OWRITE, 0600);
+ if(fd < 0){
+ if(chatty9p)
+ fprint(2, "create fails: %r\n");
+ return -1;
+ }
+ if(fprint(fd, "%d\n", pfd) < 0){
+ if(chatty9p)
+ fprint(2, "write fails: %r\n");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ if(chatty9p)
+ fprint(2, "sharefd successful\n");
+ return 0;
+}