123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975 |
- #include <u.h>
- #include <libc.h>
- #include <bio.h>
- #include <regexp.h>
- #include <thread.h>
- #include <auth.h>
- #include <fcall.h>
- #include <plumb.h>
- #include "plumber.h"
- enum
- {
- Stack = 8*1024
- };
- typedef struct Dirtab Dirtab;
- typedef struct Fid Fid;
- typedef struct Holdq Holdq;
- typedef struct Readreq Readreq;
- typedef struct Sendreq Sendreq;
- struct Dirtab
- {
- char *name;
- uchar type;
- uint qid;
- uint perm;
- int nopen; /* #fids open on this port */
- Fid *fopen;
- Holdq *holdq;
- Readreq *readq;
- Sendreq *sendq;
- };
- struct Fid
- {
- int fid;
- int busy;
- int open;
- int mode;
- Qid qid;
- Dirtab *dir;
- long offset; /* zeroed at beginning of each message, read or write */
- char *writebuf; /* partial message written so far; offset tells how much */
- Fid *next;
- Fid *nextopen;
- };
- struct Readreq
- {
- Fid *fid;
- Fcall *fcall;
- uchar *buf;
- Readreq *next;
- };
- struct Sendreq
- {
- int nfid; /* number of fids that should receive this message */
- int nleft; /* number left that haven't received it */
- Fid **fid; /* fid[nfid] */
- Plumbmsg *msg;
- char *pack; /* plumbpack()ed message */
- int npack; /* length of pack */
- Sendreq *next;
- };
- struct Holdq
- {
- Plumbmsg *msg;
- Holdq *next;
- };
- struct /* needed because incref() doesn't return value */
- {
- Lock;
- int ref;
- } rulesref;
- enum
- {
- DEBUG = 0,
- NDIR = 50,
- Nhash = 16,
- Qdir = 0,
- Qrules = 1,
- Qsend = 2,
- Qport = 3,
- NQID = Qport
- };
- static Dirtab dir[NDIR] =
- {
- { ".", QTDIR, Qdir, 0500|DMDIR },
- { "rules", QTFILE, Qrules, 0600 },
- { "send", QTFILE, Qsend, 0200 },
- };
- static int ndir = NQID;
- static int srvfd;
- static int srvclosefd; /* rock for end of pipe to close */
- static int clockfd;
- static int clock;
- static Fid *fids[Nhash];
- static QLock readlock;
- static QLock queue;
- static char srvfile[128];
- static int messagesize = 8192+IOHDRSZ; /* good start */
- static void fsysproc(void*);
- static void fsysrespond(Fcall*, uchar*, char*);
- static Fid* newfid(int);
- static Fcall* fsysflush(Fcall*, uchar*, Fid*);
- static Fcall* fsysversion(Fcall*, uchar*, Fid*);
- static Fcall* fsysauth(Fcall*, uchar*, Fid*);
- static Fcall* fsysattach(Fcall*, uchar*, Fid*);
- static Fcall* fsyswalk(Fcall*, uchar*, Fid*);
- static Fcall* fsysopen(Fcall*, uchar*, Fid*);
- static Fcall* fsyscreate(Fcall*, uchar*, Fid*);
- static Fcall* fsysread(Fcall*, uchar*, Fid*);
- static Fcall* fsyswrite(Fcall*, uchar*, Fid*);
- static Fcall* fsysclunk(Fcall*, uchar*, Fid*);
- static Fcall* fsysremove(Fcall*, uchar*, Fid*);
- static Fcall* fsysstat(Fcall*, uchar*, Fid*);
- static Fcall* fsyswstat(Fcall*, uchar*, Fid*);
- Fcall* (*fcall[Tmax])(Fcall*, uchar*, Fid*) =
- {
- [Tflush] = fsysflush,
- [Tversion] = fsysversion,
- [Tauth] = fsysauth,
- [Tattach] = fsysattach,
- [Twalk] = fsyswalk,
- [Topen] = fsysopen,
- [Tcreate] = fsyscreate,
- [Tread] = fsysread,
- [Twrite] = fsyswrite,
- [Tclunk] = fsysclunk,
- [Tremove]= fsysremove,
- [Tstat] = fsysstat,
- [Twstat] = fsyswstat,
- };
- char Ebadfcall[] = "bad fcall type";
- char Eperm[] = "permission denied";
- char Enomem[] = "malloc failed for buffer";
- char Enotdir[] = "not a directory";
- char Enoexist[] = "plumb file does not exist";
- char Eisdir[] = "file is a directory";
- char Ebadmsg[] = "bad plumb message format";
- char Enosuchport[] ="no such plumb port";
- char Enoport[] = "couldn't find destination for message";
- char Einuse[] = "file already open";
- /*
- * Add new port. A no-op if port already exists or is the null string
- */
- void
- addport(char *port)
- {
- int i;
- if(port == nil)
- return;
- for(i=NQID; i<ndir; i++)
- if(strcmp(port, dir[i].name) == 0)
- return;
- if(i == NDIR){
- fprint(2, "plumb: too many ports; max %d\n", NDIR);
- return;
- }
- ndir++;
- dir[i].name = estrdup(port);
- dir[i].qid = i;
- dir[i].perm = 0400;
- nports++;
- ports = erealloc(ports, nports*sizeof(char*));
- ports[nports-1] = dir[i].name;
- }
- static ulong
- getclock(void)
- {
- char buf[32];
- seek(clockfd, 0, 0);
- read(clockfd, buf, sizeof buf);
- return atoi(buf);
- }
- void
- startfsys(void)
- {
- int p[2], fd;
- fmtinstall('F', fcallfmt);
- clockfd = open("/dev/time", OREAD|OCEXEC);
- clock = getclock();
- if(pipe(p) < 0)
- error("can't create pipe: %r");
- /* 0 will be server end, 1 will be client end */
- srvfd = p[0];
- srvclosefd = p[1];
- sprint(srvfile, "/srv/plumb.%s.%d", user, getpid());
- if(putenv("plumbsrv", srvfile) < 0)
- error("can't write $plumbsrv: %r");
- fd = create(srvfile, OWRITE|OCEXEC|ORCLOSE, 0600);
- if(fd < 0)
- error("can't create /srv file: %r");
- if(fprint(fd, "%d", p[1]) <= 0)
- error("can't write /srv/file: %r");
- /* leave fd open; ORCLOSE will take care of it */
- procrfork(fsysproc, nil, Stack, RFFDG);
- close(p[0]);
- if(mount(p[1], -1, "/mnt/plumb", MREPL, "") < 0)
- error("can't mount /mnt/plumb: %r");
- close(p[1]);
- }
- static void
- fsysproc(void*)
- {
- int n;
- Fcall *t;
- Fid *f;
- uchar *buf;
- close(srvclosefd);
- srvclosefd = -1;
- t = nil;
- for(;;){
- buf = malloc(messagesize); /* avoid memset of emalloc */
- if(buf == nil)
- error("malloc failed: %r");
- qlock(&readlock);
- n = read9pmsg(srvfd, buf, messagesize);
- if(n <= 0){
- if(n < 0)
- error("i/o error on server channel");
- threadexitsall("unmounted");
- }
- if(readlock.head == nil) /* no other processes waiting to read; start one */
- proccreate(fsysproc, nil, Stack);
- qunlock(&readlock);
- if(t == nil)
- t = emalloc(sizeof(Fcall));
- if(convM2S(buf, n, t) != n)
- error("convert error in convM2S");
- if(DEBUG)
- fprint(2, "<= %F\n", t);
- if(fcall[t->type] == nil)
- fsysrespond(t, buf, Ebadfcall);
- else{
- if(t->type==Tversion || t->type==Tauth)
- f = nil;
- else
- f = newfid(t->fid);
- t = (*fcall[t->type])(t, buf, f);
- }
- }
- }
- static void
- fsysrespond(Fcall *t, uchar *buf, char *err)
- {
- int n;
- if(err){
- t->type = Rerror;
- t->ename = err;
- }else
- t->type++;
- if(buf == nil)
- buf = emalloc(messagesize);
- n = convS2M(t, buf, messagesize);
- if(n < 0)
- error("convert error in convS2M");
- if(write(srvfd, buf, n) != n)
- error("write error in respond");
- if(DEBUG)
- fprint(2, "=> %F\n", t);
- free(buf);
- }
- static
- Fid*
- newfid(int fid)
- {
- Fid *f, *ff, **fh;
- qlock(&queue);
- ff = nil;
- fh = &fids[fid&(Nhash-1)];
- for(f=*fh; f; f=f->next)
- if(f->fid == fid)
- goto Return;
- else if(ff==nil && !f->busy)
- ff = f;
- if(ff){
- ff->fid = fid;
- f = ff;
- goto Return;
- }
- f = emalloc(sizeof *f);
- f->fid = fid;
- f->next = *fh;
- *fh = f;
- Return:
- qunlock(&queue);
- return f;
- }
- static uint
- dostat(Dirtab *dir, uchar *buf, uint nbuf, uint clock)
- {
- Dir d;
- d.qid.type = dir->type;
- d.qid.path = dir->qid;
- d.qid.vers = 0;
- d.mode = dir->perm;
- d.length = 0; /* would be nice to do better */
- d.name = dir->name;
- d.uid = user;
- d.gid = user;
- d.muid = user;
- d.atime = clock;
- d.mtime = clock;
- return convD2M(&d, buf, nbuf);
- }
- static void
- queuesend(Dirtab *d, Plumbmsg *m)
- {
- Sendreq *s, *t;
- Fid *f;
- int i;
- s = emalloc(sizeof(Sendreq));
- s->nfid = d->nopen;
- s->nleft = s->nfid;
- s->fid = emalloc(s->nfid*sizeof(Fid*));
- i = 0;
- /* build array of fids open on this channel */
- for(f=d->fopen; f!=nil; f=f->nextopen)
- s->fid[i++] = f;
- s->msg = m;
- s->next = nil;
- /* link to end of queue; drainqueue() searches in sender order so this implements a FIFO */
- for(t=d->sendq; t!=nil; t=t->next)
- if(t->next == nil)
- break;
- if(t == nil)
- d->sendq = s;
- else
- t->next = s;
- }
- static void
- queueread(Dirtab *d, Fcall *t, uchar *buf, Fid *f)
- {
- Readreq *r;
- r = emalloc(sizeof(Readreq));
- r->fcall = t;
- r->buf = buf;
- r->fid = f;
- r->next = d->readq;
- d->readq = r;
- }
- static void
- drainqueue(Dirtab *d)
- {
- Readreq *r, *nextr, *prevr;
- Sendreq *s, *nexts, *prevs;
- int i, n;
- prevs = nil;
- for(s=d->sendq; s!=nil; s=nexts){
- nexts = s->next;
- for(i=0; i<s->nfid; i++){
- prevr = nil;
- for(r=d->readq; r!=nil; r=nextr){
- nextr = r->next;
- if(r->fid == s->fid[i]){
- /* pack the message if necessary */
- if(s->pack == nil)
- s->pack = plumbpack(s->msg, &s->npack);
- /* exchange the stuff... */
- r->fcall->data = s->pack+r->fid->offset;
- n = s->npack - r->fid->offset;
- if(n > messagesize-IOHDRSZ)
- n = messagesize-IOHDRSZ;
- if(n > r->fcall->count)
- n = r->fcall->count;
- r->fcall->count = n;
- fsysrespond(r->fcall, r->buf, nil);
- r->fid->offset += n;
- if(r->fid->offset >= s->npack){
- /* message transferred; delete this fid from send queue */
- r->fid->offset = 0;
- s->fid[i] = nil;
- s->nleft--;
- }
- /* delete read request from queue */
- if(prevr)
- prevr->next = r->next;
- else
- d->readq = r->next;
- free(r->fcall);
- free(r);
- break;
- }else
- prevr = r;
- }
- }
- /* if no fids left, delete this send from queue */
- if(s->nleft == 0){
- free(s->fid);
- plumbfree(s->msg);
- free(s->pack);
- if(prevs)
- prevs->next = s->next;
- else
- d->sendq = s->next;
- free(s);
- }else
- prevs = s;
- }
- }
- /* can't flush a send because they are always answered synchronously */
- static void
- flushqueue(Dirtab *d, int oldtag)
- {
- Readreq *r, *prevr;
- prevr = nil;
- for(r=d->readq; r!=nil; r=r->next){
- if(oldtag == r->fcall->tag){
- /* delete read request from queue */
- if(prevr)
- prevr->next = r->next;
- else
- d->readq = r->next;
- free(r->fcall);
- free(r->buf);
- free(r);
- return;
- }
- prevr = r;
- }
- }
- /* remove messages awaiting delivery to now-closing fid */
- static void
- removesenders(Dirtab *d, Fid *fid)
- {
- Sendreq *s, *nexts, *prevs;
- int i;
- prevs = nil;
- for(s=d->sendq; s!=nil; s=nexts){
- nexts = s->next;
- for(i=0; i<s->nfid; i++)
- if(fid == s->fid[i]){
- /* delete this fid from send queue */
- s->fid[i] = nil;
- s->nleft--;
- break;
- }
- /* if no fids left, delete this send from queue */
- if(s->nleft == 0){
- free(s->fid);
- plumbfree(s->msg);
- free(s->pack);
- if(prevs)
- prevs->next = s->next;
- else
- d->sendq = s->next;
- free(s);
- }else
- prevs = s;
- }
- }
- static void
- hold(Plumbmsg *m, Dirtab *d)
- {
- Holdq *h, *q;
- h = emalloc(sizeof(Holdq));
- h->msg = m;
- /* add to end of queue */
- if(d->holdq == nil)
- d->holdq = h;
- else{
- for(q=d->holdq; q->next!=nil; q=q->next)
- ;
- q->next = h;
- }
- }
- static void
- queueheld(Dirtab *d)
- {
- Holdq *h;
- while(d->holdq != nil){
- h = d->holdq;
- d->holdq = h->next;
- queuesend(d, h->msg);
- /* no need to drain queue because we know no-one is reading yet */
- free(h);
- }
- }
- static void
- dispose(Fcall *t, uchar *buf, Plumbmsg *m, Ruleset *rs, Exec *e)
- {
- int i;
- char *err;
- qlock(&queue);
- err = nil;
- if(m->dst==nil || m->dst[0]=='\0'){
- err = Enoport;
- if(rs != nil)
- err = startup(rs, e);
- plumbfree(m);
- }else
- for(i=NQID; i<ndir; i++)
- if(strcmp(m->dst, dir[i].name) == 0){
- if(dir[i].nopen == 0){
- err = startup(rs, e);
- if(e!=nil && e->holdforclient)
- hold(m, &dir[i]);
- else
- plumbfree(m);
- }else{
- queuesend(&dir[i], m);
- drainqueue(&dir[i]);
- }
- break;
- }
- freeexec(e);
- qunlock(&queue);
- fsysrespond(t, buf, err);
- free(t);
- }
- static Fcall*
- fsysversion(Fcall *t, uchar *buf, Fid*)
- {
- if(t->msize < 256){
- fsysrespond(t, buf, "version: message size too small");
- return t;
- }
- if(t->msize < messagesize)
- messagesize = t->msize;
- t->msize = messagesize;
- if(strncmp(t->version, "9P2000", 6) != 0){
- fsysrespond(t, buf, "unrecognized 9P version");
- return t;
- }
- t->version = "9P2000";
- fsysrespond(t, buf, nil);
- return t;
- }
- static Fcall*
- fsysauth(Fcall *t, uchar *buf, Fid*)
- {
- fsysrespond(t, buf, "plumber: authentication not required");
- return t;
- }
- static Fcall*
- fsysattach(Fcall *t, uchar *buf, Fid *f)
- {
- Fcall out;
- if(strcmp(t->uname, user) != 0){
- fsysrespond(&out, buf, Eperm);
- return t;
- }
- f->busy = 1;
- f->open = 0;
- f->qid.type = QTDIR;
- f->qid.path = Qdir;
- f->qid.vers = 0;
- f->dir = dir;
- memset(&out, 0, sizeof(Fcall));
- out.type = t->type;
- out.tag = t->tag;
- out.fid = f->fid;
- out.qid = f->qid;
- fsysrespond(&out, buf, nil);
- return t;
- }
- static Fcall*
- fsysflush(Fcall *t, uchar *buf, Fid*)
- {
- int i;
- qlock(&queue);
- for(i=NQID; i<ndir; i++)
- flushqueue(&dir[i], t->oldtag);
- qunlock(&queue);
- fsysrespond(t, buf, nil);
- return t;
- }
- static Fcall*
- fsyswalk(Fcall *t, uchar *buf, Fid *f)
- {
- Fcall out;
- Fid *nf;
- ulong path;
- Dirtab *d, *dir;
- Qid q;
- int i;
- uchar type;
- char *err;
- if(f->open){
- fsysrespond(t, buf, "clone of an open fid");
- return t;
- }
- nf = nil;
- if(t->fid != t->newfid){
- nf = newfid(t->newfid);
- if(nf->busy){
- fsysrespond(t, buf, "clone to a busy fid");
- return t;
- }
- nf->busy = 1;
- nf->open = 0;
- nf->dir = f->dir;
- nf->qid = f->qid;
- f = nf; /* walk f */
- }
- out.nwqid = 0;
- err = nil;
- dir = f->dir;
- q = f->qid;
- if(t->nwname > 0){
- for(i=0; i<t->nwname; i++){
- if((q.type & QTDIR) == 0){
- err = Enotdir;
- break;
- }
- if(strcmp(t->wname[i], "..") == 0){
- type = QTDIR;
- path = Qdir;
- Accept:
- q.type = type;
- q.vers = 0;
- q.path = path;
- out.wqid[out.nwqid++] = q;
- continue;
- }
- d = dir;
- d++; /* skip '.' */
- for(; d->name; d++)
- if(strcmp(t->wname[i], d->name) == 0){
- type = d->type;
- path = d->qid;
- dir = d;
- goto Accept;
- }
- err = Enoexist;
- break;
- }
- }
- out.type = t->type;
- out.tag = t->tag;
- if(err!=nil || out.nwqid<t->nwname){
- if(nf)
- nf->busy = 0;
- }else if(out.nwqid == t->nwname){
- f->qid = q;
- f->dir = dir;
- }
- fsysrespond(&out, buf, err);
- return t;
- }
- static Fcall*
- fsysopen(Fcall *t, uchar *buf, Fid *f)
- {
- int m, clearrules, mode;
- clearrules = 0;
- if(t->mode & OTRUNC){
- if(f->qid.path != Qrules)
- goto Deny;
- clearrules = 1;
- }
- /* can't truncate anything, so just disregard */
- mode = t->mode & ~(OTRUNC|OCEXEC);
- /* can't execute or remove anything */
- if(mode==OEXEC || (mode&ORCLOSE))
- goto Deny;
- switch(mode){
- default:
- goto Deny;
- case OREAD:
- m = 0400;
- break;
- case OWRITE:
- m = 0200;
- break;
- case ORDWR:
- m = 0600;
- break;
- }
- if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
- goto Deny;
- if(f->qid.path==Qrules && (mode==OWRITE || mode==ORDWR)){
- lock(&rulesref);
- if(rulesref.ref++ != 0){
- rulesref.ref--;
- unlock(&rulesref);
- fsysrespond(t, buf, Einuse);
- return t;
- }
- unlock(&rulesref);
- }
- if(clearrules){
- writerules(nil, 0);
- rules[0] = nil;
- }
- t->qid = f->qid;
- t->iounit = 0;
- qlock(&queue);
- f->mode = mode;
- f->open = 1;
- f->dir->nopen++;
- f->nextopen = f->dir->fopen;
- f->dir->fopen = f;
- queueheld(f->dir);
- qunlock(&queue);
- fsysrespond(t, buf, nil);
- return t;
- Deny:
- fsysrespond(t, buf, Eperm);
- return t;
- }
- static Fcall*
- fsyscreate(Fcall *t, uchar *buf, Fid*)
- {
- fsysrespond(t, buf, Eperm);
- return t;
- }
- static Fcall*
- fsysreadrules(Fcall *t, uchar *buf)
- {
- char *p;
- int n;
- p = printrules();
- n = strlen(p);
- t->data = p;
- if(t->offset >= n)
- t->count = 0;
- else{
- t->data = p+t->offset;
- if(t->offset+t->count > n)
- t->count = n-t->offset;
- }
- fsysrespond(t, buf, nil);
- free(p);
- return t;
- }
- static Fcall*
- fsysread(Fcall *t, uchar *buf, Fid *f)
- {
- uchar *b;
- int i, n, o, e;
- uint len;
- Dirtab *d;
- uint clock;
- if(f->qid.path != Qdir){
- if(f->qid.path == Qrules)
- return fsysreadrules(t, buf);
- /* read from port */
- if(f->qid.path < NQID){
- fsysrespond(t, buf, "internal error: unknown read port");
- return t;
- }
- qlock(&queue);
- queueread(f->dir, t, buf, f);
- drainqueue(f->dir);
- qunlock(&queue);
- return nil;
- }
- o = t->offset;
- e = t->offset+t->count;
- clock = getclock();
- b = malloc(messagesize-IOHDRSZ);
- if(b == nil){
- fsysrespond(t, buf, Enomem);
- return t;
- }
- n = 0;
- d = dir;
- d++; /* first entry is '.' */
- for(i=0; d->name!=nil && i<e; i+=len){
- len = dostat(d, b+n, messagesize-IOHDRSZ-n, clock);
- if(len <= BIT16SZ)
- break;
- if(i >= o)
- n += len;
- d++;
- }
- t->data = (char*)b;
- t->count = n;
- fsysrespond(t, buf, nil);
- free(b);
- return t;
- }
- static Fcall*
- fsyswrite(Fcall *t, uchar *buf, Fid *f)
- {
- Plumbmsg *m;
- int i, n;
- long count;
- char *data;
- Exec *e;
- switch((int)f->qid.path){
- case Qdir:
- fsysrespond(t, buf, Eisdir);
- return t;
- case Qrules:
- clock = getclock();
- fsysrespond(t, buf, writerules(t->data, t->count));
- return t;
- case Qsend:
- if(f->offset == 0){
- data = t->data;
- count = t->count;
- }else{
- /* partial message already assembled */
- f->writebuf = erealloc(f->writebuf, f->offset + t->count);
- memmove(f->writebuf+f->offset, t->data, t->count);
- data = f->writebuf;
- count = f->offset+t->count;
- }
- m = plumbunpackpartial(data, count, &n);
- if(m == nil){
- if(n == 0){
- f->offset = 0;
- free(f->writebuf);
- f->writebuf = nil;
- fsysrespond(t, buf, Ebadmsg);
- return t;
- }
- /* can read more... */
- if(f->offset == 0){
- f->writebuf = emalloc(t->count);
- memmove(f->writebuf, t->data, t->count);
- }
- /* else buffer has already been grown */
- f->offset += t->count;
- fsysrespond(t, buf, nil);
- return t;
- }
- /* release partial buffer */
- f->offset = 0;
- free(f->writebuf);
- f->writebuf = nil;
- for(i=0; rules[i]; i++)
- if((e=matchruleset(m, rules[i])) != nil){
- dispose(t, buf, m, rules[i], e);
- return nil;
- }
- if(m->dst != nil){
- dispose(t, buf, m, nil, nil);
- return nil;
- }
- fsysrespond(t, buf, "no matching plumb rule");
- return t;
- }
- fsysrespond(t, buf, "internal error: write to unknown file");
- return t;
- }
- static Fcall*
- fsysstat(Fcall *t, uchar *buf, Fid *f)
- {
- t->stat = emalloc(messagesize-IOHDRSZ);
- t->nstat = dostat(f->dir, t->stat, messagesize-IOHDRSZ, clock);
- fsysrespond(t, buf, nil);
- free(t->stat);
- t->stat = nil;
- return t;
- }
- static Fcall*
- fsyswstat(Fcall *t, uchar *buf, Fid*)
- {
- fsysrespond(t, buf, Eperm);
- return t;
- }
- static Fcall*
- fsysremove(Fcall *t, uchar *buf, Fid*)
- {
- fsysrespond(t, buf, Eperm);
- return t;
- }
- static Fcall*
- fsysclunk(Fcall *t, uchar *buf, Fid *f)
- {
- Fid *prev, *p;
- Dirtab *d;
- qlock(&queue);
- if(f->open){
- d = f->dir;
- d->nopen--;
- if(d->qid==Qrules && (f->mode==OWRITE || f->mode==ORDWR)){
- /*
- * just to be sure last rule is parsed; error messages will be lost, though,
- * unless last write ended with a blank line
- */
- writerules(nil, 0);
- lock(&rulesref);
- rulesref.ref--;
- unlock(&rulesref);
- }
- prev = nil;
- for(p=d->fopen; p; p=p->nextopen){
- if(p == f){
- if(prev)
- prev->nextopen = f->nextopen;
- else
- d->fopen = f->nextopen;
- removesenders(d, f);
- break;
- }
- prev = p;
- }
- }
- f->busy = 0;
- f->open = 0;
- f->offset = 0;
- if(f->writebuf != nil){
- free(f->writebuf);
- f->writebuf = nil;
- }
- qunlock(&queue);
- fsysrespond(t, buf, nil);
- return t;
- }
|