23 static Fid *fids[Nhash];
27 static Xfid* fsysflush(Xfid*, Fid*);
28 static Xfid* fsysauth(Xfid*, Fid*);
29 static Xfid* fsysversion(Xfid*, Fid*);
30 static Xfid* fsysattach(Xfid*, Fid*);
31 static Xfid* fsyswalk(Xfid*, Fid*);
32 static Xfid* fsysopen(Xfid*, Fid*);
33 static Xfid* fsyscreate(Xfid*, Fid*);
34 static Xfid* fsysread(Xfid*, Fid*);
35 static Xfid* fsyswrite(Xfid*, Fid*);
36 static Xfid* fsysclunk(Xfid*, Fid*);
37 static Xfid* fsysremove(Xfid*, Fid*);
38 static Xfid* fsysstat(Xfid*, Fid*);
39 static Xfid* fsyswstat(Xfid*, Fid*);
41 Xfid* (*fcall[Tmax])(Xfid*, Fid*) =
44 [Tversion] = fsysversion,
46 [Tattach] = fsysattach,
49 [Tcreate] = fsyscreate,
53 [Tremove]= fsysremove,
58 char Eperm[] = "permission denied";
59 char Eexist[] = "file does not exist";
60 char Enotdir[] = "not a directory";
64 { ".", QTDIR, Qdir, 0500|DMDIR },
65 { "acme", QTDIR, Qacme, 0500|DMDIR },
66 { "cons", QTFILE, Qcons, 0600 },
67 { "consctl", QTFILE, Qconsctl, 0000 },
68 { "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */
69 { "editout", QTFILE, Qeditout, 0200 },
70 { "index", QTFILE, Qindex, 0400 },
71 { "label", QTFILE, Qlabel, 0600 },
72 { "new", QTDIR, Qnew, 0500|DMDIR },
78 { ".", QTDIR, Qdir, 0500|DMDIR },
79 { "addr", QTFILE, QWaddr, 0600 },
80 { "body", QTAPPEND, QWbody, 0600|DMAPPEND },
81 { "ctl", QTFILE, QWctl, 0600 },
82 { "data", QTFILE, QWdata, 0600 },
83 { "editout", QTFILE, QWeditout, 0200 },
84 { "errors", QTFILE, QWerrors, 0200 },
85 { "event", QTFILE, QWevent, 0600 },
86 { "rdsel", QTFILE, QWrdsel, 0400 },
87 { "wrsel", QTFILE, QWwrsel, 0200 },
88 { "tag", QTAPPEND, QWtag, 0600|DMAPPEND },
89 { "xdata", QTFILE, QWxdata, 0600 },
93 typedef struct Mnt Mnt;
103 Xfid* respond(Xfid*, Fcall*, char*);
104 int dostat(int, Dirtab*, uchar*, int, uint);
107 char *user = "Wile E. Coyote";
109 static int closing = 0;
110 int messagesize = Maxblock+IOHDRSZ; /* good start */
112 void fsysproc(void *);
122 error("can't create pipe");
125 fmtinstall('F', fcallfmt);
126 clockfd = open("/dev/time", OREAD|OCEXEC);
127 fd = open("/dev/user", OREAD);
129 n = read(fd, buf, sizeof buf-1);
136 proccreate(fsysproc, nil, STACK);
150 buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
151 n = read9pmsg(sfd, buf, messagesize);
155 error("i/o error on server channel");
158 sendp(cxfidalloc, nil);
159 x = recvp(cxfidalloc);
162 if(convM2S(buf, n, x) != n)
163 error("convert error in convM2S");
165 fprint(2, "%F\n", &x->Fcall);
166 if(fcall[x->type] == nil)
167 x = respond(x, &t, "bad fcall type");
182 x = respond(x, &t, "fid not in use");
188 x = (*fcall[x->type])(x, f);
194 fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
201 m = emalloc(sizeof *m);
204 m->ref = 1; /* one for Command, one will be incremented in attach */
223 fsysdelid(Mntdir *idm)
237 for(m=mnt.md; m; m=m->next){
240 prev->next = m->next;
243 for(i=0; i<m->nincl; i++)
254 sprint(buf, "fsysdelid: can't find id %d\n", idm->id);
255 sendp(cerr, estrdup(buf));
259 * Called only in exec.c:/^run(), from a different FD group
262 fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
267 /* close server side so don't hang if acme is half-exited */
269 m = fsysaddid(dir, ndir, incl, nincl);
270 sprint(buf, "%d", m->id);
271 if(mount(cfd, -1, "/mnt/acme", MREPL, buf) < 0){
276 bind("/mnt/acme", "/mnt/wsys", MREPL);
277 if(bind("/mnt/acme", "/dev", MBEFORE) < 0){
293 respond(Xfid *x, Fcall *t, char *err)
305 x->buf = emalloc(messagesize);
306 n = convS2M(t, x->buf, messagesize);
308 error("convert error in convS2M");
309 if(write(sfd, x->buf, n) != n)
310 error("write error in respond");
314 fprint(2, "r: %F\n", t);
320 fsysversion(Xfid *x, Fid*)
325 return respond(x, &t, "version: message size too small");
326 messagesize = x->msize;
327 t.msize = messagesize;
328 if(strncmp(x->version, "9P2000", 6) != 0)
329 return respond(x, &t, "unrecognized 9P version");
330 t.version = "9P2000";
331 return respond(x, &t, nil);
336 fsysauth(Xfid *x, Fid*)
340 return respond(x, &t, "acme: authentication not required");
345 fsysflush(Xfid *x, Fid*)
347 sendp(x->c, xfidflush);
353 fsysattach(Xfid *x, Fid *f)
359 if(strcmp(x->uname, user) != 0)
360 return respond(x, &t, Eperm);
373 for(m=mnt.md; m; m=m->next)
380 sendp(cerr, estrdup("unknown id in attach"));
382 return respond(x, &t, nil);
387 fsyswalk(Xfid *x, Fid *f)
402 return respond(x, &t, "walk of open file");
403 if(x->fid != x->newfid){
404 nf = newfid(x->newfid);
406 return respond(x, &t, "newfid already in use");
409 nf->mntdir = f->mntdir;
415 nf->nrpart = 0; /* not open, so must be zero */
428 for(i=0; i<x->nwname; i++){
429 if((q.type & QTDIR) == 0){
434 if(strcmp(x->wname[i], "..") == 0){
444 err = "name too long";
449 q.path = QID(id, path);
450 t.wqid[t.nwqid++] = q;
454 /* is it a numeric name? */
455 for(j=0; (c=x->wname[i][j]); j++)
458 /* yes: it's a directory */
459 if(w) /* name has form 27/23; get out before losing w */
461 id = atoi(x->wname[i]);
463 w = lookid(id, FALSE);
468 incref(w); /* we'll drop reference at end if there's an error */
476 // if(FILE(f->qid) == Qacme) /* empty directory */
478 if(strcmp(x->wname[i], "new") == 0){
480 error("w set in walk to new");
481 sendp(cnewwindow, nil); /* signal newwindowthread */
482 w = recvp(cnewwindow); /* receive new window */
485 path = QID(w->id, Qdir);
497 if(strcmp(x->wname[i], d->name) == 0){
504 break; /* file not found */
507 if(i==0 && err == nil)
511 if(err!=nil || t.nwqid<x->nwname){
514 fsysdelid(nf->mntdir);
516 }else if(t.nwqid == x->nwname){
519 w = nil; /* don't drop the reference */
529 return respond(x, &t, err);
534 fsysopen(Xfid *x, Fid *f)
539 /* can't truncate anything, so just disregard */
540 x->mode &= ~(OTRUNC|OCEXEC);
541 /* can't execute or remove anything */
542 if(x->mode==OEXEC || (x->mode&ORCLOSE))
557 if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
560 sendp(x->c, xfidopen);
564 return respond(x, &t, Eperm);
569 fsyscreate(Xfid *x, Fid*)
573 return respond(x, &t, Eperm);
578 idcmp(void *a, void *b)
580 return *(int*)a - *(int*)b;
585 fsysread(Xfid *x, Fid *f)
589 int i, id, n, o, e, j, k, *ids, nids;
595 if(f->qid.type & QTDIR){
596 if(FILE(f->qid) == Qacme){ /* empty dir */
603 e = x->offset+x->count;
605 b = emalloc(messagesize);
612 d++; /* first entry is '.' */
613 for(i=0; d->name!=nil && i<e; i+=len){
614 len = dostat(WIN(x->f->qid), d, b+n, x->count-n, clock);
625 for(j=0; j<row.ncol; j++){
627 for(k=0; k<c->nw; k++){
628 ids = realloc(ids, (nids+1)*sizeof(int));
629 ids[nids++] = c->w[k]->id;
633 qsort(ids, nids, sizeof ids[0], idcmp);
636 for(; j<nids && i<e; i+=len){
638 sprint(dt.name, "%d", k);
639 dt.qid = QID(k, Qdir);
641 dt.perm = DMDIR|0700;
642 len = dostat(k, &dt, b+n, x->count-n, clock);
657 sendp(x->c, xfidread);
663 fsyswrite(Xfid *x, Fid*)
665 sendp(x->c, xfidwrite);
671 fsysclunk(Xfid *x, Fid *f)
673 fsysdelid(f->mntdir);
674 sendp(x->c, xfidclose);
680 fsysremove(Xfid *x, Fid*)
684 return respond(x, &t, Eperm);
689 fsysstat(Xfid *x, Fid *f)
693 t.stat = emalloc(messagesize-IOHDRSZ);
694 t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
695 x = respond(x, &t, nil);
702 fsyswstat(Xfid *x, Fid*)
706 return respond(x, &t, Eperm);
715 fh = &fids[fid&(Nhash-1)];
716 for(f=*fh; f; f=f->next)
719 else if(ff==nil && f->busy==FALSE)
725 f = emalloc(sizeof *f);
738 pread(clockfd, buf, sizeof buf, 0);
743 dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
747 d.qid.path = QID(id, dir->qid);
749 d.qid.type = dir->type;
751 d.length = 0; /* would be nice to do better */
758 return convD2M(&d, buf, nbuf);