📄 fs.c
字号:
pos += m; } return n;}intreadmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen){ Dir d; int n, m; long pos; Message *msg; n = 0; if(f->mb->ctl){ mkstat(&d, f->mb, nil, Qmboxctl); m = convD2M(&d, &buf[n], blen); if(off == 0){ if(m <= BIT16SZ || m > cnt){ f->fptr = nil; return 0; } n += m; cnt -= m; } else off -= m; } // to avoid n**2 reads of the directory, use a saved finger pointer if(f->mb->vers == f->fvers && off >= f->foff && f->fptr != nil){ msg = f->fptr; pos = f->foff; } else { msg = f->mb->root->part; pos = 0; } for(; cnt > 0 && msg != nil; msg = msg->next){ // act like deleted files aren't there if(msg->deleted) continue; mkstat(&d, f->mb, msg, Qdir); m = convD2M(&d, &buf[n], blen-n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; n += m; cnt -= m; } pos += m; } // save a finger pointer for next read of the mbox directory f->foff = pos; f->fptr = msg; f->fvers = f->mb->vers; return n;}intreadmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen){ Dir d; int i, n, m; long pos; Message *msg; n = 0; pos = 0; for(i = 0; i < Qmax; i++){ mkstat(&d, f->mb, f->m, i); m = convD2M(&d, &buf[n], blen-n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) return n; n += m; cnt -= m; } pos += m; } for(msg = f->m->part; msg != nil; msg = msg->next){ mkstat(&d, f->mb, msg, Qdir); m = convD2M(&d, &buf[n], blen-n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; n += m; cnt -= m; } pos += m; } return n;}char*rread(Fid *f){ long off; int t, i, n, cnt; char *p; rhdr.count = 0; off = thdr.offset; cnt = thdr.count; if(cnt > messagesize - IOHDRSZ) cnt = messagesize - IOHDRSZ; rhdr.data = (char*)mbuf; t = FILE(f->qid.path); if(f->qid.type & QTDIR){ if(t == Qtop) { qlock(&mbllock); n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ); qunlock(&mbllock); } else if(t == Qmbox) { qlock(f->mb); if(off == 0) syncmbox(f->mb, 1); n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ); qunlock(f->mb); } else if(t == Qmboxctl) { n = 0; } else { n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ); } rhdr.count = n; return nil; } if(FILE(f->qid.path) == Qheader){ rhdr.count = readheader(f->m, (char*)mbuf, off, cnt); return nil; } if(FILE(f->qid.path) == Qinfo){ rhdr.count = readinfo(f->m, (char*)mbuf, off, cnt); return nil; } i = fileinfo(f->m, FILE(f->qid.path), &p); if(off < i){ if((off + cnt) > i) cnt = i - off; memmove(mbuf, p + off, cnt); rhdr.count = cnt; } return nil;}char*rwrite(Fid *f){ char *err; char *token[1024]; int t, n; String *file; t = FILE(f->qid.path); rhdr.count = thdr.count; switch(t){ case Qctl: if(thdr.count == 0) return Ebadctl; if(thdr.data[thdr.count-1] == '\n') thdr.data[thdr.count-1] = 0; else thdr.data[thdr.count] = 0; n = tokenize(thdr.data, token, nelem(token)); if(n == 0) return Ebadctl; if(strcmp(token[0], "open") == 0){ file = s_new(); switch(n){ case 1: err = Ebadctl; break; case 2: mboxpath(token[1], getlog(), file, 0); err = newmbox(s_to_c(file), nil, 0); break; default: mboxpath(token[1], getlog(), file, 0); if(strchr(token[2], '/') != nil) err = "/ not allowed in mailbox name"; else err = newmbox(s_to_c(file), token[2], 0); break; } s_free(file); return err; } if(strcmp(token[0], "close") == 0){ if(n < 2) return nil; freembox(token[1]); return nil; } if(strcmp(token[0], "delete") == 0){ if(n < 3) return nil; delmessages(n-1, &token[1]); return nil; } return Ebadctl; case Qmboxctl: if(f->mb && f->mb->ctl){ if(thdr.count == 0) return Ebadctl; if(thdr.data[thdr.count-1] == '\n') thdr.data[thdr.count-1] = 0; else thdr.data[thdr.count] = 0; n = tokenize(thdr.data, token, nelem(token)); if(n == 0) return Ebadctl; return (*f->mb->ctl)(f->mb, n, token); } } return Eperm;}char *rclunk(Fid *f){ Mailbox *mb; f->busy = 0; f->open = 0; if(f->mtop != nil){ qlock(f->mb); msgdecref(f->mb, f->mtop); qunlock(f->mb); } f->m = f->mtop = nil; mb = f->mb; if(mb != nil){ f->mb = nil; assert(mb->refs > 0); qlock(&mbllock); mboxdecref(mb); qunlock(&mbllock); } f->fid = -1; return 0;}char *rremove(Fid *f){ if(f->m != nil){ if(f->m->deleted == 0) mailplumb(f->mb, f->m, 1); f->m->deleted = 1; } return rclunk(f);}char *rstat(Fid *f){ Dir d; if(FILE(f->qid.path) == Qmbox){ qlock(f->mb); syncmbox(f->mb, 1); qunlock(f->mb); } mkstat(&d, f->mb, f->m, FILE(f->qid.path)); rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ); rhdr.stat = mbuf; return 0;}char *rwstat(Fid*){ return Eperm;}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->fptr = nil; return ff; } f = emalloc(sizeof *f); f->fid = fid; f->fptr = nil; f->next = fids; fids = f; return f;}intfidmboxrefs(Mailbox *mb){ Fid *f; int refs = 0; for(f = fids; f; f = f->next){ if(f->mb == mb) refs++; } return refs;}voidio(void){ char *err; int n; /* start a process to watch the mailboxes*/ if(plumbing){ switch(rfork(RFPROC|RFMEM)){ case -1: /* oh well */ break; case 0: reader(); exits(nil); default: break; } } for(;;){ /* * 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 */ checkmboxrefs(); n = read9pmsg(mfd[0], mdata, messagesize); if(n == 0) continue; if(n < 0) return; if(convM2S(mdata, n, &thdr) == 0) continue; if(debug) fprint(2, "%s:<-%F\n", argv0, &thdr); rhdr.data = (char*)mdata + messagesize; if(!fcalls[thdr.type]) err = "bad fcall type"; else err = (*fcalls[thdr.type])(newfid(thdr.fid)); if(err){ rhdr.type = Rerror; rhdr.ename = err; }else{ rhdr.type = thdr.type + 1; rhdr.fid = thdr.fid; } rhdr.tag = thdr.tag; if(debug) fprint(2, "%s:->%F\n", argv0, &rhdr);/**/ n = convS2M(&rhdr, mdata, messagesize); if(write(mfd[1], mdata, n) != n) error("mount write"); }}voidreader(void){ ulong t; Dir *d; Mailbox *mb; sleep(15*1000); for(;;){ t = time(0); qlock(&mbllock); for(mb = mbl; mb != nil; mb = mb->next){ assert(mb->refs > 0); if(mb->waketime != 0 && t > mb->waketime){ qlock(mb); mb->waketime = 0; break; } d = dirstat(mb->path); if(d == nil) continue; qlock(mb); if(mb->d) if(d->qid.path != mb->d->qid.path || d->qid.vers != mb->d->qid.vers){ free(d); break; } qunlock(mb); free(d); } qunlock(&mbllock); if(mb != nil){ syncmbox(mb, 1); qunlock(mb); } else sleep(15*1000); }}intnewid(void){ int rv; static int id; static Lock idlock; lock(&idlock); rv = ++id; unlock(&idlock); return rv;}voiderror(char *s){ postnote(PNGROUP, getpid(), "die yankee pig dog"); fprint(2, "%s: %s: %r\n", argv0, s); exits(s);}typedef struct Ignorance Ignorance;struct Ignorance{ Ignorance *next; char *str; /* string */ int partial; /* true if not exact match */};Ignorance *ignorance;/* * read the file of headers to ignore */voidreadignore(void){ char *p; Ignorance *i; Biobuf *b; if(ignorance != nil) return; b = Bopen("/mail/lib/ignore", OREAD); if(b == 0) return; while(p = Brdline(b, '\n')){ p[Blinelen(b)-1] = 0; while(*p && (*p == ' ' || *p == '\t')) p++; if(*p == '#') continue; i = malloc(sizeof(Ignorance)); if(i == 0) break; i->partial = strlen(p); i->str = strdup(p); if(i->str == 0){ free(i); break; } i->next = ignorance; ignorance = i; } Bterm(b);}intignore(char *p){ Ignorance *i; readignore(); for(i = ignorance; i != nil; i = i->next) if(cistrncmp(i->str, p, i->partial) == 0) return 1; return 0;}inthdrlen(char *p, char *e){ char *ep; ep = p; do { ep = strchr(ep, '\n'); if(ep == nil){ ep = e; break; } ep++; if(ep >= e){ ep = e; break; } } while(*ep == ' ' || *ep == '\t'); return ep - p;}// rfc2047 non-ascii: =?charset?q?encoded-text?=intrfc2047convert(String *s, char *token, int len){ char charset[100], decoded[1024], *e, *x; int l; if(len == 0) return -1; e = token+len-2; token += 2; x = memchr(token, '?', e-token); if(x == nil || (l=x-token) >= sizeof charset) return -1; memmove(charset, token, l); charset[l] = 0; token = x+1; // bail if it doesn't fit if(e-token > sizeof(decoded)-1) return -1; // bail if we don't understand the encoding if(cistrncmp(token, "b?", 2) == 0){ token += 2; len = dec64((uchar*)decoded, sizeof(decoded), token, e-token); decoded[len] = 0; } else if(cistrncmp(token, "q?", 2) == 0){ token += 2; len = decquoted(decoded, token, e, 1); if(len > 0 && decoded[len-1] == '\n') len--; decoded[len] = 0; } else return -1; if(xtoutf(charset, &x, decoded, decoded+len) <= 0) s_append(s, decoded); else { s_append(s, x); free(x); } return 0;}char*rfc2047start(char *start, char *end){ int quests; if(*--end != '=') return nil; if(*--end != '?') return nil; quests = 0; for(end--; end >= start; end--){ switch(*end){ case '=': if(quests == 3 && *(end+1) == '?') return end; break; case '?': ++quests; break; case ' ': case '\t': case '\n': case '\r': /* can't have white space in a token */ return nil; } } return nil;}// convert a header lineString*stringconvert(String *s, char *uneaten, int len){ char *token, *p, *e; s = s_reset(s); p = uneaten; for(e = p+len; p < e; ){ while(*p++ == '=' && (token = rfc2047start(uneaten, p))){ s_nappend(s, uneaten, token-uneaten); if(rfc2047convert(s, token, p - token) < 0) s_nappend(s, token, p - token); uneaten = p; for(; p<e && isspace(*p);) p++; if(p+2 < e && p[0] == '=' && p[1] == '?') uneaten = p; // paste } } if(p > uneaten) s_nappend(s, uneaten, p-uneaten); return s;}intreadheader(Message *m, char *buf, int off, int cnt){ char *p, *e; int n, ns; char *to = buf; String *s; p = m->header; e = m->hend; s = nil; // copy in good headers while(cnt > 0 && p < e){ n = hdrlen(p, e); if(ignore(p)){ p += n; continue; } // rfc2047 processing s = stringconvert(s, p, n); ns = s_len(s); if(off > 0){ if(ns <= off){ off -= ns; p += n; continue; } ns -= off; } if(ns > cnt) ns = cnt; memmove(to, s_to_c(s)+off, ns); to += ns; p += n; cnt -= ns; off = 0; } s_free(s); return to - buf;}intheaderlen(Message *m){ char buf[1024]; int i, n; if(m->hlen >= 0) return m->hlen; for(n = 0; ; n += i){ i = readheader(m, buf, n, sizeof(buf)); if(i <= 0) break; } m->hlen = n; return n;}QLock hashlock;uinthash(ulong ppath, char *name){ uchar *p; uint h; h = 0; for(p = (uchar*)name; *p; p++) h = h*7 + *p; h += ppath; return h % Hsize;}Hash*hlook(ulong ppath, char *name){ int h; Hash *hp; qlock(&hashlock); h = hash(ppath, name); for(hp = htab[h]; hp != nil; hp = hp->next) if(ppath == hp->ppath && strcmp(name, hp->name) == 0){ qunlock(&hashlock); return hp; } qunlock(&hashlock); return nil;}voidhenter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb){ int h; Hash *hp, **l; qlock(&hashlock); h = hash(ppath, name); for(l = &htab[h]; *l != nil; l = &(*l)->next){ hp = *l; if(ppath == hp->ppath && strcmp(name, hp->name) == 0){ hp->m = m; hp->mb = mb; hp->qid = qid; qunlock(&hashlock); return; } } *l = hp = emalloc(sizeof(*hp)); hp->m = m; hp->mb = mb; hp->qid = qid; hp->name = name; hp->ppath = ppath; qunlock(&hashlock);}voidhfree(ulong ppath, char *name){ int h; Hash *hp, **l; qlock(&hashlock); h = hash(ppath, name); for(l = &htab[h]; *l != nil; l = &(*l)->next){ hp = *l; if(ppath == hp->ppath && strcmp(name, hp->name) == 0){ hp->mb = nil; *l = hp->next; free(hp); break; } } qunlock(&hashlock);}inthashmboxrefs(Mailbox *mb){ int h; Hash *hp; int refs = 0; qlock(&hashlock); for(h = 0; h < Hsize; h++){ for(hp = htab[h]; hp != nil; hp = hp->next) if(hp->mb == mb) refs++; } qunlock(&hashlock); return refs;}voidcheckmboxrefs(void){ int f, refs; Mailbox *mb; qlock(&mbllock); for(mb=mbl; mb; mb=mb->next){ qlock(mb); refs = (f=fidmboxrefs(mb))+1; if(refs != mb->refs){ fprint(2, "mbox %s %s ref mismatch actual %d (%d+1) expected %d\n", mb->name, mb->path, refs, f, mb->refs); abort(); } qunlock(mb); } qunlock(&mbllock);}voidpost(char *name, char *envname, int srvfd){ int fd; char buf[32]; fd = create(name, OWRITE, 0600); if(fd < 0) error("post failed"); sprint(buf, "%d",srvfd); if(write(fd, buf, strlen(buf)) != strlen(buf)) error("srv write"); close(fd); putenv(envname, name);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -