📄 fs.c
字号:
#include <u.h>#include <libc.h>#include <authsrv.h>#include <fcall.h>#include "tapefs.h"Fid *fids;Ram *ram;int mfd[2];char *user;uchar mdata[Maxbuf+IOHDRSZ];int messagesize = Maxbuf+IOHDRSZ;Fcall rhdr;Fcall thdr;ulong path;Idmap *uidmap;Idmap *gidmap;int replete;int blocksize; /* for 32v */int verbose;int newtap; /* tap with time in sec */int blocksize;Fid * newfid(int);int ramstat(Ram*, uchar*, int);void io(void);void usage(void);int perm(int);char *rflush(Fid*), *rversion(Fid*), *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);char *(*fcalls[])(Fid*) = { [Tflush] rflush, [Tversion] rversion, [Tauth] rauth, [Tattach] rattach, [Twalk] rwalk, [Topen] ropen, [Tcreate] rcreate, [Tread] rread, [Twrite] rwrite, [Tclunk] rclunk, [Tremove] rremove, [Tstat] rstat, [Twstat] rwstat,};char Eperm[] = "permission denied";char Enotdir[] = "not a directory";char Enoauth[] = "tapefs: authentication not required";char Enotexist[] = "file does not exist";char Einuse[] = "file in use";char Eexist[] = "file exists";char Enotowner[] = "not owner";char Eisopen[] = "file already open for I/O";char Excl[] = "exclusive use file already open";char Ename[] = "illegal name";voidnotifyf(void *a, char *s){ USED(a); if(strncmp(s, "interrupt", 9) == 0) noted(NCONT); noted(NDFLT);}voidmain(int argc, char *argv[]){ Ram *r; char *defmnt; int p[2]; char buf[TICKREQLEN]; fmtinstall('F', fcallfmt); defmnt = "/n/tapefs"; ARGBEGIN{ case 'm': defmnt = EARGF(usage()); break; case 'p': /* password file */ uidmap = getpass(EARGF(usage())); break; case 'g': /* group file */ gidmap = getpass(EARGF(usage())); break; case 'v': verbose++; break; case 'n': newtap++; break; case 'b': blocksize = atoi(EARGF(usage())); break; default: usage(); }ARGEND if(argc==0) error("no file to mount"); user = getuser(); if(user == nil) user = "dmr"; ram = r = (Ram *)emalloc(sizeof(Ram)); r->busy = 1; r->data = 0; r->ndata = 0; r->perm = DMDIR | 0775; r->qid.path = 0; r->qid.vers = 0; r->qid.type = QTDIR; r->parent = 0; r->child = 0; r->next = 0; r->user = user; r->group = user; r->atime = time(0); r->mtime = r->atime; r->replete = 0; r->name = estrdup("."); populate(argv[0]); r->replete |= replete; if(pipe(p) < 0) error("pipe failed"); mfd[0] = mfd[1] = p[0]; notify(notifyf); switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){ case -1: error("fork"); case 0: close(p[1]); notify(notifyf); io(); break; default: close(p[0]); /* don't deadlock if child fails */ if(mount(p[1], -1, defmnt, MREPL|MCREATE, "") < 0) { sprint(buf, "mount on `%s' failed", defmnt); error(buf); } } exits(0);}char*rversion(Fid *unused){ Fid *f; USED(unused); if(rhdr.msize < 256) return "version: message too small"; if(rhdr.msize > messagesize) rhdr.msize = messagesize; else messagesize = rhdr.msize; thdr.msize = messagesize; if(strncmp(rhdr.version, "9P2000", 6) != 0) return "unrecognized 9P version"; thdr.version = "9P2000"; for(f = fids; f; f = f->next) if(f->busy) rclunk(f); return 0;}char*rauth(Fid *unused){ USED(unused); return Enoauth;}char*rflush(Fid *f){ USED(f); return 0;}char*rattach(Fid *f){ /* no authentication! */ f->busy = 1; f->rclose = 0; f->ram = ram; thdr.qid = f->ram->qid; if(rhdr.uname[0]) f->user = strdup(rhdr.uname); else f->user = "none"; return 0;}char*rwalk(Fid *f){ Fid *nf; Ram *r; char *err; char *name; Ram *dir; int i; nf = nil; if(f->ram->busy == 0) return Enotexist; if(f->open) return Eisopen; if(rhdr.newfid != rhdr.fid){ nf = newfid(rhdr.newfid); nf->busy = 1; nf->open = 0; nf->rclose = 0; nf->ram = f->ram; nf->user = f->user; /* no ref count; the leakage is minor */ f = nf; } thdr.nwqid = 0; err = nil; r = f->ram; if(rhdr.nwname > 0){ for(i=0; i<rhdr.nwname; i++){ if((r->qid.type & QTDIR) == 0){ err = Enotdir; break; } if(r->busy == 0){ err = Enotexist; break; } r->atime = time(0); name = rhdr.wname[i]; dir = r; if(!perm(Pexec)){ err = Eperm; break; } if(strcmp(name, "..") == 0){ r = dir->parent; Accept: if(i == MAXWELEM){ err = "name too long"; break; } thdr.wqid[thdr.nwqid++] = r->qid; continue; } if(!dir->replete) popdir(dir); for(r=dir->child; r; r=r->next) if(r->busy && strcmp(name, r->name)==0) goto Accept; break; /* file not found */ } if(i==0 && err == nil) err = Enotexist; } if(err!=nil || thdr.nwqid<rhdr.nwname){ if(nf){ nf->busy = 0; nf->open = 0; nf->ram = 0; } }else if(thdr.nwqid == rhdr.nwname) f->ram = r; return err;}char *ropen(Fid *f){ Ram *r; int mode, trunc; if(f->open) return Eisopen; r = f->ram; if(r->busy == 0) return Enotexist; if(r->perm & DMEXCL) if(r->open) return Excl; mode = rhdr.mode; if(r->qid.type & QTDIR){ if(mode != OREAD) return Eperm; thdr.qid = r->qid; return 0; } if(mode & ORCLOSE) return Eperm; trunc = mode & OTRUNC; mode &= OPERM; if(mode==OWRITE || mode==ORDWR || trunc) if(!perm(Pwrite)) return Eperm; if(mode==OREAD || mode==ORDWR) if(!perm(Pread)) return Eperm; if(mode==OEXEC) if(!perm(Pexec)) return Eperm; if(trunc && (r->perm&DMAPPEND)==0){ r->ndata = 0; dotrunc(r); r->qid.vers++; } thdr.qid = r->qid; thdr.iounit = messagesize-IOHDRSZ; f->open = 1; r->open++; return 0;}char *rcreate(Fid *f){ USED(f); return Eperm;}char*rread(Fid *f){ int i, len; Ram *r; char *buf; uvlong off, end; int n, cnt; if(f->ram->busy == 0) return Enotexist; n = 0; thdr.count = 0; off = rhdr.offset; end = rhdr.offset + rhdr.count; cnt = rhdr.count; if(cnt > messagesize-IOHDRSZ) cnt = messagesize-IOHDRSZ; buf = thdr.data; if(f->ram->qid.type & QTDIR){ if(!f->ram->replete) popdir(f->ram); for(i=0,r=f->ram->child; r!=nil && i<end; r=r->next){ if(!r->busy) continue; len = ramstat(r, (uchar*)buf+n, cnt-n); if(len <= BIT16SZ) break; if(i >= off) n += len; i += len; } thdr.count = n; return 0; } r = f->ram; if(off >= r->ndata) return 0; r->atime = time(0); n = cnt; if(off+n > r->ndata) n = r->ndata - off; thdr.data = doread(r, off, n); thdr.count = n; return 0;}char*rwrite(Fid *f){ Ram *r; ulong off; int cnt; r = f->ram; if(dopermw(f->ram)==0) return Eperm; if(r->busy == 0) return Enotexist; off = rhdr.offset; if(r->perm & DMAPPEND) off = r->ndata; cnt = rhdr.count; if(r->qid.type & QTDIR) return "file is a directory"; if(off > 100*1024*1024) /* sanity check */ return "write too big"; dowrite(r, rhdr.data, off, cnt); r->qid.vers++; r->mtime = time(0); thdr.count = cnt; return 0;}char *rclunk(Fid *f){ if(f->open) f->ram->open--; f->busy = 0; f->open = 0; f->ram = 0; return 0;}char *rremove(Fid *f){ USED(f); return Eperm;}char *rstat(Fid *f){ if(f->ram->busy == 0) return Enotexist; thdr.nstat = ramstat(f->ram, thdr.stat, messagesize-IOHDRSZ); return 0;}char *rwstat(Fid *f){ if(f->ram->busy == 0) return Enotexist; return Eperm;}intramstat(Ram *r, uchar *buf, int nbuf){ Dir dir; dir.name = r->name; dir.qid = r->qid; dir.mode = r->perm; dir.length = r->ndata; dir.uid = r->user; dir.gid = r->group; dir.muid = r->user; dir.atime = r->atime; dir.mtime = r->mtime; return convD2M(&dir, buf, nbuf);}Fid *newfid(int fid){ Fid *f, *ff; ff = 0; for(f = fids; f; f = f->next) if(f->fid == fid) return f; else if(!ff && !f->busy) ff = f; if(ff){ ff->fid = fid; ff->open = 0; ff->busy = 1; } f = emalloc(sizeof *f); f->ram = 0; f->fid = fid; f->busy = 1; f->open = 0; f->next = fids; fids = f; return f;}voidio(void){ char *err; int n, nerr; char buf[ERRMAX]; errstr(buf, sizeof buf); for(nerr=0, buf[0]='\0'; nerr<100; nerr++){ /* * reading from a pipe or a network device * will give an error after a few eof reads * however, we cannot tell the difference * between a zero-length read and an interrupt * on the processes writing to us, * so we wait for the error */ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n==0) continue; if(n < 0){ if(buf[0]=='\0') errstr(buf, sizeof buf); continue; } nerr = 0; buf[0] = '\0'; if(convM2S(mdata, n, &rhdr) != n) error("convert error in convM2S"); if(verbose) fprint(2, "tapefs: <=%F\n", &rhdr);/**/ thdr.data = (char*)mdata + IOHDRSZ; thdr.stat = mdata + IOHDRSZ; if(!fcalls[rhdr.type]) err = "bad fcall type"; else err = (*fcalls[rhdr.type])(newfid(rhdr.fid)); if(err){ thdr.type = Rerror; thdr.ename = err; }else{ thdr.type = rhdr.type + 1; thdr.fid = rhdr.fid; } thdr.tag = rhdr.tag; n = convS2M(&thdr, mdata, messagesize); if(n <= 0) error("convert error in convS2M"); if(verbose) fprint(2, "tapefs: =>%F\n", &thdr);/**/ if(write(mfd[1], mdata, n) != n) error("mount write"); } if(buf[0]=='\0' || strstr(buf, "hungup")) exits(""); fprint(2, "%s: mount read: %s\n", argv0, buf); exits(buf);}intperm(int p){ if(p==Pwrite) return 0; return 1;}voiderror(char *s){ fprint(2, "%s: %s: ", argv0, s); perror(""); exits(s);}char*estrdup(char *s){ char *t; t = emalloc(strlen(s)+1); strcpy(t, s); return t;}void *emalloc(ulong n){ void *p; p = mallocz(n, 1); if(!p) error("out of memory"); return p;}void *erealloc(void *p, ulong n){ p = realloc(p, n); if(!p) error("out of memory"); return p;}voidusage(void){ fprint(2, "usage: %s [-s] [-m mountpoint]\n", argv0); exits("usage");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -