📄 fsys.c
字号:
#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 "dat.h"#include "fns.h"char Eperm[] = "permission denied";char Eexist[] = "file does not exist";char Enotdir[] = "not a directory";char Ebadfcall[] = "bad fcall type";char Eoffset[] = "illegal offset";int messagesize = 8192+IOHDRSZ; /* good start */enum{ DEBUG = 0};Dirtab dirtab[]={ { ".", QTDIR, Qdir, 0500|DMDIR }, { "cons", QTFILE, Qcons, 0600 }, { "cursor", QTFILE, Qcursor, 0600 }, { "consctl", QTFILE, Qconsctl, 0200 }, { "winid", QTFILE, Qwinid, 0400 }, { "winname", QTFILE, Qwinname, 0400 }, { "kbdin", QTFILE, Qkbdin, 0200 }, { "label", QTFILE, Qlabel, 0600 }, { "mouse", QTFILE, Qmouse, 0600 }, { "screen", QTFILE, Qscreen, 0400 }, { "snarf", QTFILE, Qsnarf, 0600 }, { "text", QTFILE, Qtext, 0400 }, { "wdir", QTFILE, Qwdir, 0600 }, { "wctl", QTFILE, Qwctl, 0600 }, { "window", QTFILE, Qwindow, 0400 }, { "wsys", QTDIR, Qwsys, 0500|DMDIR }, { nil, }};static uint getclock(void);static void filsysproc(void*);static Fid* newfid(Filsys*, int);static int dostat(Filsys*, int, Dirtab*, uchar*, int, uint);int clockfd;int firstmessage = 1;char srvpipe[64];char srvwctl[64];static Xfid* filsysflush(Filsys*, Xfid*, Fid*);static Xfid* filsysversion(Filsys*, Xfid*, Fid*);static Xfid* filsysauth(Filsys*, Xfid*, Fid*);static Xfid* filsysnop(Filsys*, Xfid*, Fid*);static Xfid* filsysattach(Filsys*, Xfid*, Fid*);static Xfid* filsyswalk(Filsys*, Xfid*, Fid*);static Xfid* filsysopen(Filsys*, Xfid*, Fid*);static Xfid* filsyscreate(Filsys*, Xfid*, Fid*);static Xfid* filsysread(Filsys*, Xfid*, Fid*);static Xfid* filsyswrite(Filsys*, Xfid*, Fid*);static Xfid* filsysclunk(Filsys*, Xfid*, Fid*);static Xfid* filsysremove(Filsys*, Xfid*, Fid*);static Xfid* filsysstat(Filsys*, Xfid*, Fid*);static Xfid* filsyswstat(Filsys*, Xfid*, Fid*);Xfid* (*fcall[Tmax])(Filsys*, Xfid*, Fid*) ={ [Tflush] = filsysflush, [Tversion] = filsysversion, [Tauth] = filsysauth, [Tattach] = filsysattach, [Twalk] = filsyswalk, [Topen] = filsysopen, [Tcreate] = filsyscreate, [Tread] = filsysread, [Twrite] = filsyswrite, [Tclunk] = filsysclunk, [Tremove]= filsysremove, [Tstat] = filsysstat, [Twstat] = filsyswstat,};voidpost(char *name, char *envname, int srvfd){ int fd; char buf[32]; fd = create(name, OWRITE|ORCLOSE|OCEXEC, 0600); if(fd < 0) error(name); sprint(buf, "%d",srvfd); if(write(fd, buf, strlen(buf)) != strlen(buf)) error("srv write"); putenv(envname, name);}/* * Build pipe with OCEXEC set on second fd. * Can't put it on both because we want to post one in /srv. */intcexecpipe(int *p0, int *p1){ /* pipe the hard way to get close on exec */ if(bind("#|", "/mnt/temp", MREPL) < 0) return -1; *p0 = open("/mnt/temp/data", ORDWR); *p1 = open("/mnt/temp/data1", ORDWR|OCEXEC); unmount(nil, "/mnt/temp"); if(*p0<0 || *p1<0) return -1; return 0;}Filsys*filsysinit(Channel *cxfidalloc){ int n, fd, pid, p0; Filsys *fs; Channel *c; char buf[128]; fs = emalloc(sizeof(Filsys)); if(cexecpipe(&fs->cfd, &fs->sfd) < 0) goto Rescue; fmtinstall('F', fcallfmt); clockfd = open("/dev/time", OREAD|OCEXEC); fd = open("/dev/user", OREAD); strcpy(buf, "Jean-Paul_Belmondo"); if(fd >= 0){ n = read(fd, buf, sizeof buf-1); if(n > 0) buf[n] = 0; close(fd); } fs->user = estrdup(buf); fs->cxfidalloc = cxfidalloc; pid = getpid(); /* * Create and post wctl pipe */ if(cexecpipe(&p0, &wctlfd) < 0) goto Rescue; sprint(srvwctl, "/srv/riowctl.%s.%d", fs->user, pid); post(srvwctl, "wctl", p0); close(p0); /* * Start server processes */ c = chancreate(sizeof(char*), 0); if(c == nil) error("wctl channel"); proccreate(wctlproc, c, 4096); threadcreate(wctlthread, c, 4096); proccreate(filsysproc, fs, 10000); /* * Post srv pipe */ sprint(srvpipe, "/srv/rio.%s.%d", fs->user, pid); post(srvpipe, "wsys", fs->cfd); return fs;Rescue: free(fs); return nil;}staticvoidfilsysproc(void *arg){ int n; Xfid *x; Fid *f; Fcall t; uchar *buf; Filsys *fs; threadsetname("FILSYSPROC"); fs = arg; fs->pid = getpid(); x = nil; for(;;){ buf = emalloc(messagesize+UTFmax); /* UTFmax for appending partial rune in xfidwrite */ n = read9pmsg(fs->sfd, buf, messagesize); if(n <= 0){ yield(); /* if threadexitsall'ing, will not return */ fprint(2, "rio: %d: read9pmsg: %d %r\n", getpid(), n); errorshouldabort = 0; error("eof or i/o error on server channel"); } if(x == nil){ send(fs->cxfidalloc, nil); recv(fs->cxfidalloc, &x); x->fs = fs; } x->buf = buf; if(convM2S(buf, n, x) != n) error("convert error in convM2S"); if(DEBUG) fprint(2, "rio:<-%F\n", &x->Fcall); if(fcall[x->type] == nil) x = filsysrespond(fs, x, &t, Ebadfcall); else{ if(x->type==Tversion || x->type==Tauth) f = nil; else f = newfid(fs, x->fid); x->f = f; x = (*fcall[x->type])(fs, x, f); } firstmessage = 0; }}/* * Called only from a different FD group */intfilsysmount(Filsys *fs, int id){ char buf[32]; close(fs->sfd); /* close server end so mount won't hang if exiting */ sprint(buf, "%d", id); if(mount(fs->cfd, -1, "/mnt/wsys", MREPL, buf) < 0){ fprint(2, "mount failed: %r\n"); return -1; } if(bind("/mnt/wsys", "/dev", MBEFORE) < 0){ fprint(2, "bind failed: %r\n"); return -1; } return 0;}Xfid*filsysrespond(Filsys *fs, 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 = malloc(messagesize); n = convS2M(t, x->buf, messagesize); if(n <= 0) error("convert error in convS2M"); if(write(fs->sfd, x->buf, n) != n) error("write error in respond"); if(DEBUG) fprint(2, "rio:->%F\n", t); free(x->buf); x->buf = nil; return x;}voidfilsyscancel(Xfid *x){ if(x->buf){ free(x->buf); x->buf = nil; }}staticXfid*filsysversion(Filsys *fs, Xfid *x, Fid*){ Fcall t; if(!firstmessage) return filsysrespond(x->fs, x, &t, "version request not first message"); if(x->msize < 256) return filsysrespond(x->fs, x, &t, "version: message size too small"); messagesize = x->msize; t.msize = messagesize; if(strncmp(x->version, "9P2000", 6) != 0) return filsysrespond(x->fs, x, &t, "unrecognized 9P version"); t.version = "9P2000"; return filsysrespond(fs, x, &t, nil);}staticXfid*filsysauth(Filsys *fs, Xfid *x, Fid*){ Fcall t; return filsysrespond(fs, x, &t, "rio: authentication not required");}staticXfid*filsysflush(Filsys*, Xfid *x, Fid*){ sendp(x->c, xfidflush); return nil;}staticXfid*filsysattach(Filsys *, Xfid *x, Fid *f){ Fcall t; if(strcmp(x->uname, x->fs->user) != 0) return filsysrespond(x->fs, 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; sendp(x->c, xfidattach); return nil;}staticintnumeric(char *s){ for(; *s!='\0'; s++) if(*s<'0' || '9'<*s) return 0; return 1;}staticXfid*filsyswalk(Filsys *fs, Xfid *x, Fid *f){ Fcall t; Fid *nf; int i, id; uchar type; ulong path; Dirtab *d, *dir; Window *w; char *err; Qid qid; if(f->open) return filsysrespond(fs, x, &t, "walk of open file"); nf = nil; if(x->fid != x->newfid){ /* BUG: check exists */ nf = newfid(fs, x->newfid); if(nf->busy) return filsysrespond(fs, x, &t, "clone to busy fid"); nf->busy = TRUE; nf->open = FALSE; nf->dir = f->dir; nf->qid = f->qid; nf->w = f->w; incref(f->w); nf->nrpart = 0; /* not open, so must be zero */ f = nf; /* walk f */ } t.nwqid = 0; err = nil; /* update f->qid, f->dir only if walk completes */ qid = f->qid; dir = f->dir; if(x->nwname > 0){ for(i=0; i<x->nwname; i++){ if((qid.type & QTDIR) == 0){ err = Enotdir; break; } if(strcmp(x->wname[i], "..") == 0){ type = QTDIR; path = Qdir; dir = dirtab; if(FILE(qid) == Qwsysdir) path = Qwsys; id = 0; Accept: if(i == MAXWELEM){ err = "name too long"; break; } qid.type = type; qid.vers = 0; qid.path = QID(id, path); t.wqid[t.nwqid++] = qid; continue; } if(qid.path == Qwsys){ /* is it a numeric name? */ if(!numeric(x->wname[i])) break; /* yes: it's a directory */ id = atoi(x->wname[i]); qlock(&all); w = wlookid(id); if(w == nil){ qunlock(&all); break; } path = Qwsysdir; type = QTDIR; qunlock(&all); incref(w); sendp(winclosechan, f->w); f->w = w; dir = dirtab; goto Accept; } if(snarffd>=0 && strcmp(x->wname[i], "snarf")==0) break; /* don't serve /dev/snarf if it's provided in the environment */ id = WIN(f->qid); d = dirtab; 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){ if(nf->w) sendp(winclosechan, nf->w); nf->open = FALSE; nf->busy = FALSE; } }else if(t.nwqid == x->nwname){ f->dir = dir; f->qid = qid; } return filsysrespond(fs, x, &t, err);}staticXfid*filsysopen(Filsys *fs, 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 filsysrespond(fs, x, &t, Eperm);}staticXfid*filsyscreate(Filsys *fs, Xfid *x, Fid*){ Fcall t; return filsysrespond(fs, x, &t, Eperm);}staticintidcmp(void *a, void *b){ return *(int*)a - *(int*)b;}staticXfid*filsysread(Filsys *fs, Xfid *x, Fid *f){ Fcall t; uchar *b; int i, n, o, e, len, j, k, *ids; Dirtab *d, dt; uint clock; char buf[16]; if((f->qid.type & QTDIR) == 0){ sendp(x->c, xfidread); return nil; } o = x->offset; e = x->offset+x->count; clock = getclock(); b = malloc(messagesize-IOHDRSZ); /* avoid memset of emalloc */ if(b == nil) return filsysrespond(fs, x, &t, "out of memory"); n = 0; switch(FILE(f->qid)){ case Qdir: case Qwsysdir: d = dirtab; d++; /* first entry is '.' */ for(i=0; d->name!=nil && i<e; i+=len){ len = dostat(fs, WIN(x->f->qid), d, b+n, x->count-n, clock); if(len <= BIT16SZ) break; if(i >= o) n += len; d++; } break; case Qwsys: qlock(&all); ids = emalloc(nwindow*sizeof(int)); for(j=0; j<nwindow; j++) ids[j] = window[j]->id; qunlock(&all); qsort(ids, nwindow, sizeof ids[0], idcmp); dt.name = buf; for(i=0, j=0; j<nwindow && 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(fs, k, &dt, b+n, x->count-n, clock); if(len == 0) break; if(i >= o) n += len; j++; } free(ids); break; } t.data = (char*)b; t.count = n; filsysrespond(fs, x, &t, nil); free(b); return x;}staticXfid*filsyswrite(Filsys*, Xfid *x, Fid*){ sendp(x->c, xfidwrite); return nil;}staticXfid*filsysclunk(Filsys *fs, Xfid *x, Fid *f){ Fcall t; if(f->open){ f->busy = FALSE; f->open = FALSE; sendp(x->c, xfidclose); return nil; } if(f->w) sendp(winclosechan, f->w); f->busy = FALSE; f->open = FALSE; return filsysrespond(fs, x, &t, nil);}staticXfid*filsysremove(Filsys *fs, Xfid *x, Fid*){ Fcall t; return filsysrespond(fs, x, &t, Eperm);}staticXfid*filsysstat(Filsys *fs, Xfid *x, Fid *f){ Fcall t; t.stat = emalloc(messagesize-IOHDRSZ); t.nstat = dostat(fs, WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock()); x = filsysrespond(fs, x, &t, nil); free(t.stat); return x;}staticXfid*filsyswstat(Filsys *fs, Xfid *x, Fid*){ Fcall t; return filsysrespond(fs, x, &t, Eperm);}staticFid*newfid(Filsys *fs, int fid){ Fid *f, *ff, **fh; ff = nil; fh = &fs->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;}staticuintgetclock(void){ char buf[32]; seek(clockfd, 0, 0); read(clockfd, buf, sizeof buf); return atoi(buf);}staticintdostat(Filsys *fs, int id, Dirtab *dir, uchar *buf, int nbuf, uint clock){ Dir d; d.qid.path = QID(id, dir->qid); if(dir->qid == Qsnarf) d.qid.vers = snarfversion; else 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 = fs->user; d.gid = fs->user; d.muid = fs->user; d.atime = clock; d.mtime = clock; return convD2M(&d, buf, nbuf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -