Req *r;
qlock(&s->rlock);
- while((n = read9pmsg(s->infd, s->rbuf, s->msize)) == 0)
- ;
- if(n < 0){
+ n = read9pmsg(s->infd, s->rbuf, s->msize);
+ if(n <= 0){
qunlock(&s->rlock);
return nil;
}
static void
sversion(Srv *srv, Req *r)
{
- if(srv->rref.ref != 2){
+ 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;
}
}
}
+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);
}
Srv *srv = v;
Req *r;
- incref(&srv->rref);
- incref(&srv->sref);
while(r = getreq(srv)){
incref(&srv->rref);
if(r->error){
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);
}
- decref(&srv->sref);
- srvclose(srv);
+
+ if(srv->end && srv->sref.ref == 1)
+ srv->end(srv);
+ if(decref(&srv->sref) == 0)
+ srvclose(srv);
}
static void
srvclose(Srv *srv)
{
- if(decref(&srv->rref))
+ if(srv->rref.ref || srv->sref.ref)
return;
if(chatty9p)
freereqpool(srv->rpool);
srv->rpool = nil;
- if(srv->end)
- srv->end(srv);
+ if(srv->free)
+ srv->free(srv);
}
void
void
srvrelease(Srv *srv)
{
- if(decref(&srv->sref) == 0)
+ if(decref(&srv->sref) == 0){
+ incref(&srv->sref);
_forker(srvwork, srv, 0);
+ }
qunlock(&srv->slock);
}
fmtinstall('D', dirfmt);
fmtinstall('F', fcallfmt);
+ srv->spid = getpid();
srv->sref.ref = 0;
srv->rref.ref = 0;
if(srv->start)
srv->start(srv);
+ incref(&srv->sref);
srvwork(srv);
}
else
free(r);
- srvclose(srv);
+ if(decref(&srv->rref) == 0)
+ srvclose(srv);
}
void