diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/acme/fsys.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/acme/fsys.c')
-rwxr-xr-x | sys/src/cmd/acme/fsys.c | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/sys/src/cmd/acme/fsys.c b/sys/src/cmd/acme/fsys.c new file mode 100755 index 000000000..7235bbe22 --- /dev/null +++ b/sys/src/cmd/acme/fsys.c @@ -0,0 +1,759 @@ +#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*, uchar*, 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 *) +{ + int n; + Xfid *x; + Fid *f; + Fcall t; + uchar *buf; + + 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) < 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*) +{ + Fcall t; + + if(x->msize < 256) + return respond(x, &t, "version: message size too small"); + 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*) +{ + Fcall t; + + return respond(x, &t, "acme: authentication not required"); +} + +static +Xfid* +fsysflush(Xfid *x, Fid*) +{ + 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; + uchar type; + ulong 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*) +{ + Fcall t; + + return respond(x, &t, Eperm); +} + +static +int +idcmp(void *a, void *b) +{ + return *(int*)a - *(int*)b; +} + +static +Xfid* +fsysread(Xfid *x, Fid *f) +{ + Fcall t; + uchar *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 = realloc(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*) +{ + 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*) +{ + 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*) +{ + 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, uchar *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); +} |