22 static Fid *fids[Nhash];
26 static Xfid* fsysflush(Xfid*, Fid*);
27 static Xfid* fsysauth(Xfid*, Fid*);
28 static Xfid* fsysversion(Xfid*, Fid*);
29 static Xfid* fsysattach(Xfid*, Fid*);
30 static Xfid* fsyswalk(Xfid*, Fid*);
31 static Xfid* fsysopen(Xfid*, Fid*);
32 static Xfid* fsyscreate(Xfid*, Fid*);
33 static Xfid* fsysread(Xfid*, Fid*);
34 static Xfid* fsyswrite(Xfid*, Fid*);
35 static Xfid* fsysclunk(Xfid*, Fid*);
36 static Xfid* fsysremove(Xfid*, Fid*);
37 static Xfid* fsysstat(Xfid*, Fid*);
38 static Xfid* fsyswstat(Xfid*, Fid*);
40 Xfid* (*fcall[Tmax])(Xfid*, Fid*);
45 fcall[Tflush] = fsysflush;
46 fcall[Tversion] = fsysversion;
47 fcall[Tauth] = fsysauth;
48 fcall[Tattach] = fsysattach;
49 fcall[Twalk] = fsyswalk;
50 fcall[Topen] = fsysopen;
51 fcall[Tcreate] = fsyscreate;
52 fcall[Tread] = fsysread;
53 fcall[Twrite] = fsyswrite;
54 fcall[Tclunk] = fsysclunk;
55 fcall[Tremove]= fsysremove;
56 fcall[Tstat] = fsysstat;
57 fcall[Twstat] = fsyswstat;
60 char Eperm[] = "permission denied";
61 char Eexist[] = "file does not exist";
62 char Enotdir[] = "not a directory";
66 { ".", QTDIR, Qdir, 0500|DMDIR },
67 { "acme", QTDIR, Qacme, 0500|DMDIR },
68 { "cons", QTFILE, Qcons, 0600 },
69 { "consctl", QTFILE, Qconsctl, 0000 },
70 { "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */
71 { "editout", QTFILE, Qeditout, 0200 },
72 { "index", QTFILE, Qindex, 0400 },
73 { "label", QTFILE, Qlabel, 0600 },
74 { "new", QTDIR, Qnew, 0500|DMDIR },
80 { ".", QTDIR, Qdir, 0500|DMDIR },
81 { "addr", QTFILE, QWaddr, 0600 },
82 { "body", QTAPPEND, QWbody, 0600|DMAPPEND },
83 { "ctl", QTFILE, QWctl, 0600 },
84 { "data", QTFILE, QWdata, 0600 },
85 { "editout", QTFILE, QWeditout, 0200 },
86 { "errors", QTFILE, QWerrors, 0200 },
87 { "event", QTFILE, QWevent, 0600 },
88 { "rdsel", QTFILE, QWrdsel, 0400 },
89 { "wrsel", QTFILE, QWwrsel, 0200 },
90 { "tag", QTAPPEND, QWtag, 0600|DMAPPEND },
91 { "xdata", QTFILE, QWxdata, 0600 },
95 typedef struct Mnt Mnt;
105 Xfid* respond(Xfid*, Fcall*, char*);
106 int dostat(int, Dirtab*, uchar*, int, uint);
109 char *user = "Wile E. Coyote";
110 static int closing = 0;
111 int messagesize = Maxblock+IOHDRSZ; /* good start */
113 void fsysproc(void *);
123 error("can't create pipe");
124 if(post9pservice(p[0], "acme") < 0)
125 error("can't post service");
127 fmtinstall('F', fcallfmt);
128 if((u = getuser()) != nil)
130 proccreate(fsysproc, nil, STACK);
145 buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
146 n = read9pmsg(sfd, buf, messagesize);
150 error("i/o error on server channel");
153 sendp(cxfidalloc, nil);
154 x = recvp(cxfidalloc);
157 if(convM2S(buf, n, &x->fcall) != n)
158 error("convert error in convM2S");
160 fprint(2, "%F\n", &x->fcall);
161 if(fcall[x->fcall.type] == nil)
162 x = respond(x, &t, "bad fcall type");
164 switch(x->fcall.type){
171 f = newfid(x->fcall.fid);
174 f = newfid(x->fcall.fid);
177 x = respond(x, &t, "fid not in use");
183 x = (*fcall[x->fcall.type])(x, f);
189 fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
196 m = emalloc(sizeof *m);
199 m->ref = 1; /* one for Command, one will be incremented in attach */
218 fsysdelid(Mntdir *idm)
232 for(m=mnt.md; m; m=m->next){
235 prev->next = m->next;
238 for(i=0; i<m->nincl; i++)
249 sprint(buf, "fsysdelid: can't find id %d\n", idm->id);
250 sendp(cerr, estrdup(buf));
254 * Called only in exec.c:/^run(), from a different FD group
257 fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
259 return fsysaddid(dir, ndir, incl, nincl);
270 respond(Xfid *x, Fcall *t, char *err)
278 t->type = x->fcall.type+1;
279 t->fid = x->fcall.fid;
280 t->tag = x->fcall.tag;
282 x->buf = emalloc(messagesize);
283 n = convS2M(t, x->buf, messagesize);
286 fprint(2, "convert error (n=%d, msgsize %d): have %F\n", n, messagesize, &x->fcall);
287 fprint(2, "\tresponse: %F\n", t);
288 error("convert error in convS2M");
290 if(write(sfd, x->buf, n) != n)
291 error("write error in respond");
295 fprint(2, "r: %F\n", t);
301 fsysversion(Xfid *x, Fid *f)
306 if(x->fcall.msize < 256)
307 return respond(x, &t, "version: message size too small");
308 messagesize = x->fcall.msize;
309 t.msize = messagesize;
310 if(strncmp(x->fcall.version, "9P2000", 6) != 0)
311 return respond(x, &t, "unrecognized 9P version");
312 t.version = "9P2000";
313 return respond(x, &t, nil);
318 fsysauth(Xfid *x, Fid *f)
323 return respond(x, &t, "acme: authentication not required");
328 fsysflush(Xfid *x, Fid *f)
331 sendp(x->c, (void*)xfidflush);
337 fsysattach(Xfid *x, Fid *f)
344 if(strcmp(x->fcall.uname, user) != 0)
345 return respond(x, &t, Eperm);
356 id = atoi(x->fcall.aname);
358 for(m=mnt.md; m; m=m->next)
364 if(m == nil && x->fcall.aname[0]){
365 snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
366 sendp(cerr, estrdup(buf));
369 return respond(x, &t, nil);
374 fsyswalk(Xfid *x, Fid *f)
389 return respond(x, &t, "walk of open file");
390 if(x->fcall.fid != x->fcall.newfid){
391 nf = newfid(x->fcall.newfid);
393 return respond(x, &t, "newfid already in use");
396 nf->mntdir = f->mntdir;
402 nf->nrpart = 0; /* not open, so must be zero */
414 if(x->fcall.nwname > 0){
415 for(i=0; i<x->fcall.nwname; i++){
416 if((q.type & QTDIR) == 0){
421 if(strcmp(x->fcall.wname[i], "..") == 0){
431 err = "name too long";
436 q.path = QID(id, path);
437 t.wqid[t.nwqid++] = q;
441 /* is it a numeric name? */
442 for(j=0; (c=x->fcall.wname[i][j]); j++)
445 /* yes: it's a directory */
446 if(w) /* name has form 27/23; get out before losing w */
448 id = atoi(x->fcall.wname[i]);
450 w = lookid(id, FALSE);
455 incref(&w->ref); /* we'll drop reference at end if there's an error */
463 // if(FILE(f->qid) == Qacme) /* empty directory */
465 if(strcmp(x->fcall.wname[i], "new") == 0){
467 error("w set in walk to new");
468 sendp(cnewwindow, nil); /* signal newwindowthread */
469 w = recvp(cnewwindow); /* receive new window */
472 path = QID(w->id, Qdir);
484 if(strcmp(x->fcall.wname[i], d->name) == 0){
491 break; /* file not found */
494 if(i==0 && err == nil)
498 if(err!=nil || t.nwqid<x->fcall.nwname){
501 fsysdelid(nf->mntdir);
503 }else if(t.nwqid == x->fcall.nwname){
506 w = nil; /* don't drop the reference */
516 return respond(x, &t, err);
521 fsysopen(Xfid *x, Fid *f)
526 /* can't truncate anything, so just disregard */
527 x->fcall.mode &= ~(OTRUNC|OCEXEC);
528 /* can't execute or remove anything */
529 if(x->fcall.mode==OEXEC || (x->fcall.mode&ORCLOSE))
531 switch(x->fcall.mode){
544 if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
547 sendp(x->c, (void*)xfidopen);
551 return respond(x, &t, Eperm);
556 fsyscreate(Xfid *x, Fid *f)
561 return respond(x, &t, Eperm);
566 idcmp(const void *a, const void *b)
568 return *(int*)a - *(int*)b;
573 fsysread(Xfid *x, Fid *f)
577 int i, id, n, o, e, j, k, *ids, nids;
583 if(f->qid.type & QTDIR){
584 if(FILE(f->qid) == Qacme){ /* empty dir */
591 e = x->fcall.offset+x->fcall.count;
593 b = emalloc(messagesize);
600 d++; /* first entry is '.' */
601 for(i=0; d->name!=nil && i<e; i+=len){
602 len = dostat(WIN(x->f->qid), d, b+n, x->fcall.count-n, clock);
613 for(j=0; j<row.ncol; j++){
615 for(k=0; k<c->nw; k++){
616 ids = realloc(ids, (nids+1)*sizeof(int));
617 ids[nids++] = c->w[k]->id;
621 qsort(ids, nids, sizeof ids[0], idcmp);
624 for(; j<nids && i<e; i+=len){
626 sprint(dt.name, "%d", k);
627 dt.qid = QID(k, Qdir);
629 dt.perm = DMDIR|0700;
630 len = dostat(k, &dt, b+n, x->fcall.count-n, clock);
645 sendp(x->c, (void*)xfidread);
651 fsyswrite(Xfid *x, Fid *f)
654 sendp(x->c, (void*)xfidwrite);
660 fsysclunk(Xfid *x, Fid *f)
662 fsysdelid(f->mntdir);
663 sendp(x->c, (void*)xfidclose);
669 fsysremove(Xfid *x, Fid *f)
674 return respond(x, &t, Eperm);
679 fsysstat(Xfid *x, Fid *f)
683 t.stat = emalloc(messagesize-IOHDRSZ);
684 t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
685 x = respond(x, &t, nil);
692 fsyswstat(Xfid *x, Fid *f)
697 return respond(x, &t, Eperm);
706 fh = &fids[fid&(Nhash-1)];
707 for(f=*fh; f; f=f->next)
710 else if(ff==nil && f->busy==FALSE)
716 f = emalloc(sizeof *f);
730 pread(clockfd, buf, sizeof buf, 0);
737 dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
741 d.qid.path = QID(id, dir->qid);
743 d.qid.type = dir->type;
745 d.length = 0; /* would be nice to do better */
752 return convD2M(&d, buf, nbuf);