📄 fs.c
字号:
#include "common.h"#include <auth.h>#include <fcall.h>#include <libsec.h>#include <ctype.h>#include "dat.h"enum{ OPERM = 0x3, // mask of all permission types in open mode};typedef struct Fid Fid;struct Fid{ Qid qid; short busy; short open; int fid; Fid *next; Mailbox *mb; Message *m; Message *mtop; // top level message //finger pointers to speed up reads of large directories long foff; // offset/DIRLEN of finger Message *fptr; // pointer to message at off int fvers; // mailbox version when finger was saved};ulong path; // incremented for each new fileFid *fids;int mfd[2];char user[Elemlen];int messagesize = 4*1024*IOHDRSZ;uchar mdata[8*1024*IOHDRSZ];uchar mbuf[8*1024*IOHDRSZ];Fcall thdr;Fcall rhdr;int fflg;char *mntpt;int biffing;int plumbing = 1;QLock mbllock;Mailbox *mbl;Fid *newfid(int);void error(char*);void io(void);void *erealloc(void*, ulong);void *emalloc(ulong);void usage(void);void reader(void);int readheader(Message*, char*, int, int);int cistrncmp(char*, char*, int);int tokenconvert(String*, char*, int);String* stringconvert(String*, char*, int);void post(char*, char*, int);char *rflush(Fid*), *rauth(Fid*), *rattach(Fid*), *rwalk(Fid*), *ropen(Fid*), *rcreate(Fid*), *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*), *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*), *rversion(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[] = "upas/fs: 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";char Ebadctl[] = "unknown control message";char *dirtab[] ={[Qdir] ".",[Qbody] "body",[Qbcc] "bcc",[Qcc] "cc",[Qdate] "date",[Qdigest] "digest",[Qdisposition] "disposition",[Qfilename] "filename",[Qfrom] "from",[Qheader] "header",[Qinfo] "info",[Qinreplyto] "inreplyto",[Qlines] "lines",[Qmimeheader] "mimeheader",[Qmessageid] "messageid",[Qraw] "raw",[Qrawunix] "rawunix",[Qrawbody] "rawbody",[Qrawheader] "rawheader",[Qreplyto] "replyto",[Qsender] "sender",[Qsubject] "subject",[Qto] "to",[Qtype] "type",[Qunixdate] "unixdate",[Qunixheader] "unixheader",[Qctl] "ctl",[Qmboxctl] "ctl",};enum{ Hsize= 1277,};Hash *htab[Hsize];int debug;int fflag;int logging;voidusage(void){ fprint(2, "usage: upas/fs [-bdlnps] [-f mboxfile] [-m mountpoint]\n"); exits("usage");}voidnotifyf(void *a, char *s){ USED(a); if(strncmp(s, "interrupt", 9) == 0) noted(NCONT); noted(NDFLT);}voidmain(int argc, char *argv[]){ int p[2], std, nodflt; char maildir[128]; char mbox[128]; char *mboxfile, *err; char srvfile[64]; int srvpost; rfork(RFNOTEG); mntpt = nil; fflag = 0; mboxfile = nil; std = 0; nodflt = 0; srvpost = 0; ARGBEGIN{ case 'b': biffing = 1; break; case 'f': fflag = 1; mboxfile = EARGF(usage()); break; case 'm': mntpt = EARGF(usage()); break; case 'd': debug = 1; break; case 'p': plumbing = 0; break; case 's': srvpost = 1; break; case 'l': logging = 1; break; case 'n': nodflt = 1; break; default: usage(); }ARGEND if(argc) usage(); if(pipe(p) < 0) error("pipe failed"); mfd[0] = p[0]; mfd[1] = p[0]; notify(notifyf); strcpy(user, getuser()); if(mntpt == nil){ snprint(maildir, sizeof(maildir), "/mail/fs"); mntpt = maildir; } if(mboxfile == nil && !nodflt){ snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user); mboxfile = mbox; std = 1; } if(debug) fmtinstall('F', fcallfmt); if(mboxfile != nil){ err = newmbox(mboxfile, "mbox", std); if(err != nil) sysfatal("opening mailbox: %s", err); } switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){ case -1: error("fork"); case 0: henter(PATH(0, Qtop), dirtab[Qctl], (Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil); close(p[1]); io(); postnote(PNGROUP, getpid(), "die yankee pig dog"); break; default: close(p[0]); /* don't deadlock if child fails */ if(srvpost){ sprint(srvfile, "/srv/upasfs.%s", user); post(srvfile, "upasfs", p[1]); } else { if(mount(p[1], -1, mntpt, MREPL, "") < 0) error("mount failed"); } } exits(0);}static intfileinfo(Message *m, int t, char **pp){ char *p; int len; p = ""; len = 0; switch(t){ case Qbody: p = m->body; len = m->bend - m->body; break; case Qbcc: if(m->bcc822){ p = s_to_c(m->bcc822); len = strlen(p); } break; case Qcc: if(m->cc822){ p = s_to_c(m->cc822); len = strlen(p); } break; case Qdisposition: switch(m->disposition){ case Dinline: p = "inline"; break; case Dfile: p = "file"; break; } len = strlen(p); break; case Qdate: if(m->date822){ p = s_to_c(m->date822); len = strlen(p); } else if(m->unixdate != nil){ p = s_to_c(m->unixdate); len = strlen(p); } break; case Qfilename: if(m->filename){ p = s_to_c(m->filename); len = strlen(p); } break; case Qinreplyto: if(m->inreplyto822){ p = s_to_c(m->inreplyto822); len = strlen(p); } break; case Qmessageid: if(m->messageid822){ p = s_to_c(m->messageid822); len = strlen(p); } break; case Qfrom: if(m->from822){ p = s_to_c(m->from822); len = strlen(p); } else if(m->unixfrom != nil){ p = s_to_c(m->unixfrom); len = strlen(p); } break; case Qheader: p = m->header; len = headerlen(m); break; case Qlines: p = m->lines; if(*p == 0) countlines(m); len = strlen(m->lines); break; case Qraw: p = m->start; if(strncmp(m->start, "From ", 5) == 0){ p = strchr(p, '\n'); if(p == nil) p = m->start; else p++; } len = m->end - p; break; case Qrawunix: p = m->start; len = m->end - p; break; case Qrawbody: p = m->rbody; len = m->rbend - p; break; case Qrawheader: p = m->header; len = m->hend - p; break; case Qmimeheader: p = m->mheader; len = m->mhend - p; break; case Qreplyto: p = nil; if(m->replyto822 != nil){ p = s_to_c(m->replyto822); len = strlen(p); } else if(m->from822 != nil){ p = s_to_c(m->from822); len = strlen(p); } else if(m->sender822 != nil){ p = s_to_c(m->sender822); len = strlen(p); } else if(m->unixfrom != nil){ p = s_to_c(m->unixfrom); len = strlen(p); } break; case Qsender: if(m->sender822){ p = s_to_c(m->sender822); len = strlen(p); } break; case Qsubject: p = nil; if(m->subject822){ p = s_to_c(m->subject822); len = strlen(p); } break; case Qto: if(m->to822){ p = s_to_c(m->to822); len = strlen(p); } break; case Qtype: if(m->type){ p = s_to_c(m->type); len = strlen(p); } break; case Qunixdate: if(m->unixdate){ p = s_to_c(m->unixdate); len = strlen(p); } break; case Qunixheader: if(m->unixheader){ p = s_to_c(m->unixheader); len = s_len(m->unixheader); } break; case Qdigest: if(m->sdigest){ p = s_to_c(m->sdigest); len = strlen(p); } break; } *pp = p; return len;}int infofields[] = { Qfrom, Qto, Qcc, Qreplyto, Qunixdate, Qsubject, Qtype, Qdisposition, Qfilename, Qdigest, Qbcc, Qinreplyto, Qdate, Qsender, Qmessageid, Qlines, -1,};static intreadinfo(Message *m, char *buf, long off, int count){ char *p; int len, i, n; String *s; s = s_new(); len = 0; for(i = 0; len < count && infofields[i] >= 0; i++){ n = fileinfo(m, infofields[i], &p); s = stringconvert(s, p, n); s_append(s, "\n"); p = s_to_c(s); n = strlen(p); if(off > 0){ if(off >= n){ off -= n; continue; } p += off; n -= off; off = 0; } if(n > count - len) n = count - len; if(buf) memmove(buf+len, p, n); len += n; } s_free(s); return len;}static voidmkstat(Dir *d, Mailbox *mb, Message *m, int t){ char *p; d->uid = user; d->gid = user; d->muid = user; d->mode = 0444; d->qid.vers = 0; d->qid.type = QTFILE; d->type = 0; d->dev = 0; if(mb != nil && mb->d != nil){ d->atime = mb->d->atime; d->mtime = mb->d->mtime; } else { d->atime = time(0); d->mtime = d->atime; } switch(t){ case Qtop: d->name = "."; d->mode = DMDIR|0555; d->atime = d->mtime = time(0); d->length = 0; d->qid.path = PATH(0, Qtop); d->qid.type = QTDIR; break; case Qmbox: d->name = mb->name; d->mode = DMDIR|0555; d->length = 0; d->qid.path = PATH(mb->id, Qmbox); d->qid.type = QTDIR; d->qid.vers = mb->vers; break; case Qdir: d->name = m->name; d->mode = DMDIR|0555; d->length = 0; d->qid.path = PATH(m->id, Qdir); d->qid.type = QTDIR; break; case Qctl: d->name = dirtab[t]; d->mode = 0666; d->atime = d->mtime = time(0); d->length = 0; d->qid.path = PATH(0, Qctl); break; case Qmboxctl: d->name = dirtab[t]; d->mode = 0222; d->atime = d->mtime = time(0); d->length = 0; d->qid.path = PATH(mb->id, Qmboxctl); break; case Qinfo: d->name = dirtab[t]; d->length = readinfo(m, nil, 0, 1<<30); d->qid.path = PATH(m->id, t); break; default: d->name = dirtab[t]; d->length = fileinfo(m, t, &p); d->qid.path = PATH(m->id, t); break; }}char*rversion(Fid*){ Fid *f; if(thdr.msize < 256) return "max messagesize too small"; if(thdr.msize < messagesize) messagesize = thdr.msize; rhdr.msize = messagesize; if(strncmp(thdr.version, "9P2000", 6) != 0) return "unknown 9P version"; else rhdr.version = "9P2000"; for(f = fids; f; f = f->next) if(f->busy) rclunk(f); return nil;}char*rauth(Fid*){ return Enoauth;}char*rflush(Fid *f){ USED(f); return 0;}char*rattach(Fid *f){ f->busy = 1; f->m = nil; f->mb = nil; f->qid.path = PATH(0, Qtop); f->qid.type = QTDIR; f->qid.vers = 0; rhdr.qid = f->qid; if(strcmp(thdr.uname, user) != 0) return Eperm; return 0;}static Fid*doclone(Fid *f, int nfid){ Fid *nf; nf = newfid(nfid); if(nf->busy) return nil; nf->busy = 1; nf->open = 0; nf->m = f->m; nf->mtop = f->mtop; nf->mb = f->mb; if(f->mb != nil) mboxincref(f->mb); if(f->mtop != nil){ qlock(f->mb); msgincref(f->mtop); qunlock(f->mb); } nf->qid = f->qid; return nf;}char*dowalk(Fid *f, char *name){ int t; Mailbox *omb, *mb; char *rv, *p; Hash *h; t = FILE(f->qid.path); rv = Enotexist; omb = f->mb; if(omb) qlock(omb); else qlock(&mbllock); // this must catch everything except . and ..retry: h = hlook(f->qid.path, name); if(h != nil){ f->mb = h->mb; f->m = h->m; switch(t){ case Qtop: if(f->mb != nil) mboxincref(f->mb); break; case Qmbox: if(f->m){ msgincref(f->m); f->mtop = f->m; } break; } f->qid = h->qid; rv = nil; } else if((p = strchr(name, '.')) != nil && *name != '.'){ *p = 0; goto retry; } if(omb) qunlock(omb); else qunlock(&mbllock); if(rv == nil) return rv; if(strcmp(name, ".") == 0) return nil; if(f->qid.type != QTDIR) return Enotdir; if(strcmp(name, "..") == 0){ switch(t){ case Qtop: f->qid.path = PATH(0, Qtop); f->qid.type = QTDIR; f->qid.vers = 0; break; case Qmbox: f->qid.path = PATH(0, Qtop); f->qid.type = QTDIR; f->qid.vers = 0; qlock(&mbllock); mb = f->mb; f->mb = nil; mboxdecref(mb); qunlock(&mbllock); break; case Qdir: qlock(f->mb); if(f->m->whole == f->mb->root){ f->qid.path = PATH(f->mb->id, Qmbox); f->qid.type = QTDIR; f->qid.vers = f->mb->d->qid.vers; msgdecref(f->mb, f->mtop); f->m = f->mtop = nil; } else { f->m = f->m->whole; f->qid.path = PATH(f->m->id, Qdir); f->qid.type = QTDIR; } qunlock(f->mb); break; } rv = nil; } return rv;}char*rwalk(Fid *f){ Fid *nf; char *rv; int i; if(f->open) return Eisopen; rhdr.nwqid = 0; nf = nil; /* clone if requested */ if(thdr.newfid != thdr.fid){ nf = doclone(f, thdr.newfid); if(nf == nil) return "new fid in use"; f = nf; } /* if it's just a clone, return */ if(thdr.nwname == 0 && nf != nil) return nil; /* walk each element */ rv = nil; for(i = 0; i < thdr.nwname; i++){ rv = dowalk(f, thdr.wname[i]); if(rv != nil){ if(nf != nil) rclunk(nf); break; } rhdr.wqid[i] = f->qid; } rhdr.nwqid = i; /* we only error out if no walk */ if(i > 0) rv = nil; return rv;}char *ropen(Fid *f){ int file; if(f->open) return Eisopen; file = FILE(f->qid.path); if(thdr.mode != OREAD) if(file != Qctl && file != Qmboxctl) return Eperm; // make sure we've decoded if(file == Qbody){ if(f->m->decoded == 0) decode(f->m); if(f->m->converted == 0) convert(f->m); } rhdr.iounit = 0; rhdr.qid = f->qid; f->open = 1; return 0;}char *rcreate(Fid*){ return Eperm;}intreadtopdir(Fid*, uchar *buf, long off, int cnt, int blen){ Dir d; int m, n; long pos; Mailbox *mb; n = 0; pos = 0; mkstat(&d, nil, nil, Qctl); m = convD2M(&d, &buf[n], blen); if(off <= pos){ if(m <= BIT16SZ || m > cnt) return 0; n += m; cnt -= m; } pos += m; for(mb = mbl; mb != nil; mb = mb->next){ mkstat(&d, mb, nil, Qmbox); m = convD2M(&d, &buf[n], blen-n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; n += m; cnt -= m; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -