123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <thread.h>
- #include <cursor.h>
- #include <mouse.h>
- #include <keyboard.h>
- #include <frame.h>
- #include <fcall.h>
- #include <plumb.h>
- #include "dat.h"
- #include "fns.h"
- static int cfd;
- static int sfd;
- enum
- {
- Nhash = 16,
- DEBUG = 0
- };
- static Fid *fids[Nhash];
- Fid *newfid(int);
- static Xfid* fsysflush(Xfid*, Fid*);
- static Xfid* fsysauth(Xfid*, Fid*);
- static Xfid* fsysversion(Xfid*, Fid*);
- static Xfid* fsysattach(Xfid*, Fid*);
- static Xfid* fsyswalk(Xfid*, Fid*);
- static Xfid* fsysopen(Xfid*, Fid*);
- static Xfid* fsyscreate(Xfid*, Fid*);
- static Xfid* fsysread(Xfid*, Fid*);
- static Xfid* fsyswrite(Xfid*, Fid*);
- static Xfid* fsysclunk(Xfid*, Fid*);
- static Xfid* fsysremove(Xfid*, Fid*);
- static Xfid* fsysstat(Xfid*, Fid*);
- static Xfid* fsyswstat(Xfid*, Fid*);
- Xfid* (*fcall[Tmax])(Xfid*, 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 Eperm[] = "permission denied";
- char Eexist[] = "file does not exist";
- char Enotdir[] = "not a directory";
- Dirtab dirtab[]=
- {
- { ".", QTDIR, Qdir, 0500|DMDIR },
- { "acme", QTDIR, Qacme, 0500|DMDIR },
- { "cons", QTFILE, Qcons, 0600 },
- { "consctl", QTFILE, Qconsctl, 0000 },
- { "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */
- { "editout", QTFILE, Qeditout, 0200 },
- { "index", QTFILE, Qindex, 0400 },
- { "label", QTFILE, Qlabel, 0600 },
- { "new", QTDIR, Qnew, 0500|DMDIR },
- { nil, }
- };
- Dirtab dirtabw[]=
- {
- { ".", QTDIR, Qdir, 0500|DMDIR },
- { "addr", QTFILE, QWaddr, 0600 },
- { "body", QTAPPEND, QWbody, 0600|DMAPPEND },
- { "ctl", QTFILE, QWctl, 0600 },
- { "data", QTFILE, QWdata, 0600 },
- { "editout", QTFILE, QWeditout, 0200 },
- { "errors", QTFILE, QWerrors, 0200 },
- { "event", QTFILE, QWevent, 0600 },
- { "rdsel", QTFILE, QWrdsel, 0400 },
- { "wrsel", QTFILE, QWwrsel, 0200 },
- { "tag", QTAPPEND, QWtag, 0600|DMAPPEND },
- { "xdata", QTFILE, QWxdata, 0600 },
- { nil, }
- };
- typedef struct Mnt Mnt;
- struct Mnt
- {
- QLock;
- int id;
- Mntdir *md;
- };
- Mnt mnt;
- Xfid* respond(Xfid*, Fcall*, char*);
- int dostat(int, Dirtab*, uint8_t*, int, uint);
- uint getclock(void);
- char *user = "Wile E. Coyote";
- int clockfd;
- static int closing = 0;
- int messagesize = Maxblock+IOHDRSZ; /* good start */
- void fsysproc(void *);
- void
- fsysinit(void)
- {
- int p[2];
- int n, fd;
- char buf[256];
- if(pipe(p) < 0)
- error("can't create pipe");
- cfd = p[0];
- sfd = p[1];
- fmtinstall('F', fcallfmt);
- clockfd = open("/dev/time", OREAD|OCEXEC);
- fd = open("/dev/user", OREAD);
- if(fd >= 0){
- n = read(fd, buf, sizeof buf-1);
- if(n > 0){
- buf[n] = 0;
- user = estrdup(buf);
- }
- close(fd);
- }
- proccreate(fsysproc, nil, STACK);
- }
- void
- fsysproc(void *v)
- {
- int n;
- Xfid *x;
- Fid *f;
- Fcall t;
- uint8_t *buf;
- threadsetname("fsysproc");
- x = nil;
- for(;;){
- buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
- n = read9pmsg(sfd, buf, messagesize);
- if(n <= 0){
- if(closing)
- break;
- error("i/o error on server channel");
- }
- if(x == nil){
- sendp(cxfidalloc, nil);
- x = recvp(cxfidalloc);
- }
- x->buf = buf;
- if(convM2S(buf, n, x) != n)
- error("convert error in convM2S");
- if(DEBUG)
- fprint(2, "%F\n", &x->Fcall);
- if(fcall[x->type] == nil)
- x = respond(x, &t, "bad fcall type");
- else{
- switch(x->type){
- case Tversion:
- case Tauth:
- case Tflush:
- f = nil;
- break;
- case Tattach:
- f = newfid(x->fid);
- break;
- default:
- f = newfid(x->fid);
- if(!f->busy){
- x->f = f;
- x = respond(x, &t, "fid not in use");
- continue;
- }
- break;
- }
- x->f = f;
- x = (*fcall[x->type])(x, f);
- }
- }
- }
- Mntdir*
- fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
- {
- Mntdir *m;
- int id;
- qlock(&mnt);
- id = ++mnt.id;
- m = emalloc(sizeof *m);
- m->id = id;
- m->dir = dir;
- m->ref = 1; /* one for Command, one will be incremented in attach */
- m->ndir = ndir;
- m->next = mnt.md;
- m->incl = incl;
- m->nincl = nincl;
- mnt.md = m;
- qunlock(&mnt);
- return m;
- }
- void
- fsysincid(Mntdir *m)
- {
- qlock(&mnt);
- m->ref++;
- qunlock(&mnt);
- }
- void
- fsysdelid(Mntdir *idm)
- {
- Mntdir *m, *prev;
- int i;
- char buf[64];
- if(idm == nil)
- return;
- qlock(&mnt);
- if(--idm->ref > 0){
- qunlock(&mnt);
- return;
- }
- prev = nil;
- for(m=mnt.md; m; m=m->next){
- if(m == idm){
- if(prev)
- prev->next = m->next;
- else
- mnt.md = m->next;
- for(i=0; i<m->nincl; i++)
- free(m->incl[i]);
- free(m->incl);
- free(m->dir);
- free(m);
- qunlock(&mnt);
- return;
- }
- prev = m;
- }
- qunlock(&mnt);
- sprint(buf, "fsysdelid: can't find id %d\n", idm->id);
- sendp(cerr, estrdup(buf));
- }
- /*
- * Called only in exec.c:/^run(), from a different FD group
- */
- Mntdir*
- fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
- {
- char buf[256];
- Mntdir *m;
- /* close server side so don't hang if acme is half-exited */
- close(sfd);
- m = fsysaddid(dir, ndir, incl, nincl);
- sprint(buf, "%d", m->id);
- if(mount(cfd, -1, "/mnt/acme", MREPL, buf, 'M') < 0){
- fsysdelid(m);
- return nil;
- }
- close(cfd);
- bind("/mnt/acme", "/mnt/wsys", MREPL);
- if(bind("/mnt/acme", "/dev", MBEFORE) < 0){
- fsysdelid(m);
- return nil;
- }
- return m;
- }
- void
- fsysclose(void)
- {
- closing = 1;
- close(cfd);
- close(sfd);
- }
- Xfid*
- respond(Xfid *x, Fcall *t, char *err)
- {
- int n;
- if(err){
- t->type = Rerror;
- t->ename = err;
- }else
- t->type = x->type+1;
- t->fid = x->fid;
- t->tag = x->tag;
- if(x->buf == nil)
- x->buf = emalloc(messagesize);
- n = convS2M(t, x->buf, messagesize);
- if(n <= 0)
- error("convert error in convS2M");
- if(write(sfd, x->buf, n) != n)
- error("write error in respond");
- free(x->buf);
- x->buf = nil;
- if(DEBUG)
- fprint(2, "r: %F\n", t);
- return x;
- }
- static
- Xfid*
- fsysversion(Xfid *x, Fid*f)
- {
- Fcall t;
- if(x->msize < 256)
- return respond(x, &t, "version: message size too small");
- if(x->msize < messagesize)
- messagesize = x->msize;
- t.msize = messagesize;
- if(strncmp(x->version, "9P2000", 6) != 0)
- return respond(x, &t, "unrecognized 9P version");
- t.version = "9P2000";
- return respond(x, &t, nil);
- }
- static
- Xfid*
- fsysauth(Xfid *x, Fid*f)
- {
- Fcall t;
- return respond(x, &t, "acme: authentication not required");
- }
- static
- Xfid*
- fsysflush(Xfid *x, Fid*f)
- {
- sendp(x->c, xfidflush);
- return nil;
- }
- static
- Xfid*
- fsysattach(Xfid *x, Fid *f)
- {
- Fcall t;
- int id;
- Mntdir *m;
- if(strcmp(x->uname, user) != 0)
- return respond(x, &t, Eperm);
- f->busy = TRUE;
- f->open = FALSE;
- f->qid.path = Qdir;
- f->qid.type = QTDIR;
- f->qid.vers = 0;
- f->dir = dirtab;
- f->nrpart = 0;
- f->w = nil;
- t.qid = f->qid;
- f->mntdir = nil;
- id = atoi(x->aname);
- qlock(&mnt);
- for(m=mnt.md; m; m=m->next)
- if(m->id == id){
- f->mntdir = m;
- m->ref++;
- break;
- }
- if(m == nil)
- sendp(cerr, estrdup("unknown id in attach"));
- qunlock(&mnt);
- return respond(x, &t, nil);
- }
- static
- Xfid*
- fsyswalk(Xfid *x, Fid *f)
- {
- Fcall t;
- int c, i, j, id;
- Qid q;
- uint8_t type;
- uint32_t path;
- Fid *nf;
- Dirtab *d, *dir;
- Window *w;
- char *err;
- nf = nil;
- w = nil;
- if(f->open)
- return respond(x, &t, "walk of open file");
- if(x->fid != x->newfid){
- nf = newfid(x->newfid);
- if(nf->busy)
- return respond(x, &t, "newfid already in use");
- nf->busy = TRUE;
- nf->open = FALSE;
- nf->mntdir = f->mntdir;
- if(f->mntdir)
- f->mntdir->ref++;
- nf->dir = f->dir;
- nf->qid = f->qid;
- nf->w = f->w;
- nf->nrpart = 0; /* not open, so must be zero */
- if(nf->w)
- incref(nf->w);
- f = nf; /* walk f */
- }
- t.nwqid = 0;
- err = nil;
- dir = nil;
- id = WIN(f->qid);
- q = f->qid;
- if(x->nwname > 0){
- for(i=0; i<x->nwname; i++){
- if((q.type & QTDIR) == 0){
- err = Enotdir;
- break;
- }
- if(strcmp(x->wname[i], "..") == 0){
- type = QTDIR;
- path = Qdir;
- id = 0;
- if(w){
- winclose(w);
- w = nil;
- }
- Accept:
- if(i == MAXWELEM){
- err = "name too long";
- break;
- }
- q.type = type;
- q.vers = 0;
- q.path = QID(id, path);
- t.wqid[t.nwqid++] = q;
- continue;
- }
- /* is it a numeric name? */
- for(j=0; (c=x->wname[i][j]); j++)
- if(c<'0' || '9'<c)
- goto Regular;
- /* yes: it's a directory */
- if(w) /* name has form 27/23; get out before losing w */
- break;
- id = atoi(x->wname[i]);
- qlock(&row);
- w = lookid(id, FALSE);
- if(w == nil){
- qunlock(&row);
- break;
- }
- incref(w); /* we'll drop reference at end if there's an error */
- path = Qdir;
- type = QTDIR;
- qunlock(&row);
- dir = dirtabw;
- goto Accept;
-
- Regular:
- // if(FILE(f->qid) == Qacme) /* empty directory */
- // break;
- if(strcmp(x->wname[i], "new") == 0){
- if(w)
- error("w set in walk to new");
- sendp(cnewwindow, nil); /* signal newwindowthread */
- w = recvp(cnewwindow); /* receive new window */
- incref(w);
- type = QTDIR;
- path = QID(w->id, Qdir);
- id = w->id;
- dir = dirtabw;
- goto Accept;
- }
- if(id == 0)
- d = dirtab;
- else
- d = dirtabw;
- d++; /* skip '.' */
- for(; d->name; d++)
- if(strcmp(x->wname[i], d->name) == 0){
- path = d->qid;
- type = d->type;
- dir = d;
- goto Accept;
- }
- break; /* file not found */
- }
- if(i==0 && err == nil)
- err = Eexist;
- }
- if(err!=nil || t.nwqid<x->nwname){
- if(nf){
- nf->busy = FALSE;
- fsysdelid(nf->mntdir);
- }
- }else if(t.nwqid == x->nwname){
- if(w){
- f->w = w;
- w = nil; /* don't drop the reference */
- }
- if(dir)
- f->dir = dir;
- f->qid = q;
- }
- if(w != nil)
- winclose(w);
- return respond(x, &t, err);
- }
- static
- Xfid*
- fsysopen(Xfid *x, Fid *f)
- {
- Fcall t;
- int m;
- /* can't truncate anything, so just disregard */
- x->mode &= ~(OTRUNC|OCEXEC);
- /* can't execute or remove anything */
- if(x->mode==OEXEC || (x->mode&ORCLOSE))
- goto Deny;
- switch(x->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;
- sendp(x->c, xfidopen);
- return nil;
- Deny:
- return respond(x, &t, Eperm);
- }
- static
- Xfid*
- fsyscreate(Xfid *x, Fid*f)
- {
- Fcall t;
- return respond(x, &t, Eperm);
- }
- static
- int
- idcmp(const void *a, const void *b)
- {
- return *(int*)a - *(int*)b;
- }
- static
- Xfid*
- fsysread(Xfid *x, Fid *f)
- {
- Fcall t;
- uint8_t *b;
- int i, id, n, o, e, j, k, *ids, nids;
- Dirtab *d, dt;
- Column *c;
- uint clock, len;
- char buf[16];
- if(f->qid.type & QTDIR){
- if(FILE(f->qid) == Qacme){ /* empty dir */
- t.data = nil;
- t.count = 0;
- respond(x, &t, nil);
- return x;
- }
- o = x->offset;
- e = x->offset+x->count;
- clock = getclock();
- b = emalloc(messagesize);
- id = WIN(f->qid);
- n = 0;
- if(id > 0)
- d = dirtabw;
- else
- d = dirtab;
- d++; /* first entry is '.' */
- for(i=0; d->name!=nil && i<e; i+=len){
- len = dostat(WIN(x->f->qid), d, b+n, x->count-n, clock);
- if(len <= BIT16SZ)
- break;
- if(i >= o)
- n += len;
- d++;
- }
- if(id == 0){
- qlock(&row);
- nids = 0;
- ids = nil;
- for(j=0; j<row.ncol; j++){
- c = row.col[j];
- for(k=0; k<c->nw; k++){
- ids = erealloc(ids, (nids+1)*sizeof(int));
- ids[nids++] = c->w[k]->id;
- }
- }
- qunlock(&row);
- qsort(ids, nids, sizeof ids[0], idcmp);
- j = 0;
- dt.name = buf;
- for(; j<nids && i<e; i+=len){
- k = ids[j];
- sprint(dt.name, "%d", k);
- dt.qid = QID(k, Qdir);
- dt.type = QTDIR;
- dt.perm = DMDIR|0700;
- len = dostat(k, &dt, b+n, x->count-n, clock);
- if(len == 0)
- break;
- if(i >= o)
- n += len;
- j++;
- }
- free(ids);
- }
- t.data = (char*)b;
- t.count = n;
- respond(x, &t, nil);
- free(b);
- return x;
- }
- sendp(x->c, xfidread);
- return nil;
- }
- static
- Xfid*
- fsyswrite(Xfid *x, Fid*f)
- {
- sendp(x->c, xfidwrite);
- return nil;
- }
- static
- Xfid*
- fsysclunk(Xfid *x, Fid *f)
- {
- fsysdelid(f->mntdir);
- sendp(x->c, xfidclose);
- return nil;
- }
- static
- Xfid*
- fsysremove(Xfid *x, Fid*f)
- {
- Fcall t;
- return respond(x, &t, Eperm);
- }
- static
- Xfid*
- fsysstat(Xfid *x, Fid *f)
- {
- Fcall t;
- t.stat = emalloc(messagesize-IOHDRSZ);
- t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
- x = respond(x, &t, nil);
- free(t.stat);
- return x;
- }
- static
- Xfid*
- fsyswstat(Xfid *x, Fid*f)
- {
- Fcall t;
- return respond(x, &t, Eperm);
- }
- Fid*
- newfid(int fid)
- {
- Fid *f, *ff, **fh;
- ff = nil;
- fh = &fids[fid&(Nhash-1)];
- for(f=*fh; f; f=f->next)
- if(f->fid == fid)
- return f;
- else if(ff==nil && f->busy==FALSE)
- ff = f;
- if(ff){
- ff->fid = fid;
- return ff;
- }
- f = emalloc(sizeof *f);
- f->fid = fid;
- f->next = *fh;
- *fh = f;
- return f;
- }
- uint
- getclock()
- {
- char buf[32];
- buf[0] = '\0';
- pread(clockfd, buf, sizeof buf, 0);
- return atoi(buf);
- }
- int
- dostat(int id, Dirtab *dir, uint8_t *buf, int nbuf, uint clock)
- {
- Dir d;
- d.qid.path = QID(id, dir->qid);
- d.qid.vers = 0;
- d.qid.type = dir->type;
- 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);
- }
|