summaryrefslogtreecommitdiff
path: root/sys/src/cmd/acme/fsys.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/acme/fsys.c759
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);
+}