diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-03-12 17:15:03 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2017-03-12 17:15:03 +0100 |
commit | 963cfc9a6f6e721f52aa949e6d1af0c3e8dc2ecc (patch) | |
tree | 749b74875dbc49bcf6ed0776648b8f0ef9417407 /sys/src/cmd/upas/fs/fs.c | |
parent | 8177d20fb2709ba9290dfd41308b8e5bee4e00f8 (diff) |
merging erik quanstros nupas
Diffstat (limited to 'sys/src/cmd/upas/fs/fs.c')
-rw-r--r-- | sys/src/cmd/upas/fs/fs.c | 1293 |
1 files changed, 785 insertions, 508 deletions
diff --git a/sys/src/cmd/upas/fs/fs.c b/sys/src/cmd/upas/fs/fs.c index fffb290aa..acfca8838 100644 --- a/sys/src/cmd/upas/fs/fs.c +++ b/sys/src/cmd/upas/fs/fs.c @@ -1,17 +1,10 @@ #include "common.h" -#include <auth.h> #include <fcall.h> #include <libsec.h> -#include <ctype.h> +#include <pool.h> #include "dat.h" -enum -{ - OPERM = 0x3, // mask of all permission types in open mode -}; - typedef struct Fid Fid; - struct Fid { Qid qid; @@ -21,31 +14,13 @@ struct Fid Fid *next; Mailbox *mb; Message *m; - Message *mtop; // top level message + 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 + 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 file -Fid *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); @@ -54,9 +29,6 @@ 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*), @@ -93,30 +65,36 @@ 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 Ebadargs[] = "invalid arguments"; +char Enotme[] = "path not served by this file server"; -char *dirtab[] = -{ +char *dirtab[] = { [Qdir] ".", -[Qbody] "body", [Qbcc] "bcc", +[Qbody] "body", [Qcc] "cc", [Qdate] "date", [Qdigest] "digest", [Qdisposition] "disposition", +[Qffrom] "ffrom", +[Qfileid] "fileid", [Qfilename] "filename", +[Qflags] "flags", [Qfrom] "from", [Qheader] "header", [Qinfo] "info", [Qinreplyto] "inreplyto", -[Qlines] "lines", -[Qmimeheader] "mimeheader", +[Qlines] "lines", [Qmessageid] "messageid", +[Qmimeheader] "mimeheader", [Qraw] "raw", -[Qrawunix] "rawunix", [Qrawbody] "rawbody", [Qrawheader] "rawheader", +[Qrawunix] "rawunix", +[Qreferences] "references", [Qreplyto] "replyto", [Qsender] "sender", +[Qsize] "size", [Qsubject] "subject", [Qto] "to", [Qtype] "type", @@ -128,61 +106,290 @@ char *dirtab[] = enum { - Hsize= 1277, + Hsize= 1999, }; -Hash *htab[Hsize]; +char *mntpt; +char user[Elemlen]; +int Dflag; +int Sflag; +int iflag; +int lflag; +int biffing; int debug; -int fflag; -int logging; +int plumbing = 1; +ulong cachetarg = Maxcache; +Mailbox *mbl; +QLock mbllock; + +static int messagesize = 8*1024 + IOHDRSZ; +static int mfd[2]; +static char hbuf[32*1024]; +static uchar mbuf[16*1024 + IOHDRSZ]; +static uchar mdata[16*1024 + IOHDRSZ]; +static ulong path; /* incremented for each new file */ +static Hash *htab[Hsize]; +static Fcall rhdr; +static Fcall thdr; +static Fid *fids; +static uintptr bos = 0xd0000000; /* pc kernel specific */ + +#define onstack(x) ((uintptr)(x) >= bos) +#define intext(x) ((char*)(x) <= end) +#define validgptr(x) assert(!onstack(x) && !intext(x)) +void +sanemsg(Message *m) +{ + if(bos == 0) + bos = absbos(); + assert(m->refs < 100); + validgptr(m->whole); + if(debug) + poolcheck(mainmem); + validgptr(m); + assert(m->next != m); + if(m->end < m->start) + abort(); + if(m->ballocd && (m->start <= m->body && m->end >= m->body)) + abort(); + if(m->end - m->start > Maxmsg) + abort(); + if(m->size > Maxmsg) + abort(); + if(m->fileid != 0 && m->fileid <= 1000000ull<<8) + abort(); +} + +void +sanembmsg(Mailbox *mb, Message *m) +{ + sanemsg(m); + if(Topmsg(mb, m)){ + if(m->start > end && m->size == 0) + abort(); + if(m->fileid <= 1000000ull<<8) + abort(); + } +} + +static void +sanefid(Fid *f) +{ + if(f->m == 0) + return; + if(f->mtop){ + sanemsg(f->mtop); + assert(f->mtop->refs > 0); + } + sanemsg(f->m); + if(f->m) + if(Topmsg(f->mb, f->m)) + assert(f->m->refs > 0); +} + +void +sanefids(void) +{ + Fid *f; + + for(f = fids; f; f = f->next) + if(f->busy) + sanefid(f); +} + +static int +Afmt(Fmt *f) +{ + char buf[SHA1dlen*2 + 1]; + uchar *u, i; + + u = va_arg(f->args, uchar*); + if(u == 0 && f->flags & FmtSharp) + return fmtstrcpy(f, "-"); + if(u == 0) + return fmtstrcpy(f, "<nildigest>"); + for(i = 0; i < SHA1dlen; i++) + sprint(buf + 2*i, "%2.2ux", u[i]); + return fmtstrcpy(f, buf); +} + +static int +Δfmt(Fmt *f) +{ + char buf[32]; + uvlong v; + + v = va_arg(f->args, uvlong); + if(f->flags & FmtSharp) + if((v>>8) == 0) + return fmtstrcpy(f, ""); + strcpy(buf, ctime(v>>8)); + buf[28] = 0; + return fmtstrcpy(f, buf); +} + +static int +Dfmt(Fmt *f) +{ + char buf[32]; + int seq; + uvlong v; + + v = va_arg(f->args, uvlong); + seq = v & 0xff; + if(seq > 99) + seq = 99; + snprint(buf, sizeof buf, "%llud.%.2d", v>>8, seq); + return fmtstrcpy(f, buf); +} + +Mpair +mpair(Mailbox *mb, Message *m) +{ + Mpair mp; + + mp.mb = mb; + mp.m = m; + return mp; +} + +static int +Pfmt(Fmt *f) +{ + char buf[128], *p, *e; + int i, dots; + Mailbox *mb; + Message *t[32], *m; + Mpair mp; + + mp = va_arg(f->args, Mpair); + mb = mp.mb; + m = mp.m; + if(m == nil || mb == nil) + return fmtstrcpy(f, "<P nil>"); + i = 0; + for(; !Topmsg(mb, m); m = m->whole){ + t[i++] = m; + if(i == nelem(t)-1) + break; + } + t[i++] = m; + dots = 0; + if(i == nelem(t)) + dots = 1; + e = buf + sizeof buf; + p = buf; + if(dots) + p = seprint(p, e, ".../"); + while(--i >= 1) + p = seprint(p, e, "%s/", t[i]->name); + if(i == 0) + seprint(p, e, "%s", t[0]->name); + return fmtstrcpy(f, buf); +} void usage(void) { - fprint(2, "usage: upas/fs [-bdlnps] [-f mboxfile] [-m mountpoint]\n"); + fprint(2, "usage: upas/fs [-DSbdlmnps] [-c cachetarg] [-f mboxfile] [-m mountpoint]\n"); exits("usage"); } void notifyf(void *, char *s) { - if(strstr(s, "alarm") || strstr(s, "interrupt")) + if(strncmp(s, "interrupt", 9) == 0) noted(NCONT); + if(strncmp(s, "die: yankee pig dog", 19) != 0) + /* don't want to call syslog from notify handler */ + fprint(2, "upas/fs: user: %s; note: %s\n", getuser(), s); noted(NDFLT); } void +setname(char **v) +{ + char buf[128], buf2[32], *p, *e; + int fd, i; + + e = buf + sizeof buf; + p = seprint(buf, e, "%s", v[0]); + for(i = 0; v[++i]; ) + p = seprint(p, e, " %s", v[i]); + snprint(buf2, sizeof buf2, "#p/%d/args", getpid()); + if((fd = open(buf2, OWRITE)) >= 0){ + write(fd, buf, p - buf); + close(fd); + } +} + +ulong +ntoi(char *s) +{ + ulong n; + + n = strtoul(s, &s, 0); + for(;;) + switch(*s++){ + default: + usage(); + case 'g': + n *= 1024; + case 'm': + n *= 1024; + case 'k': + n *= 1024; + break; + case 0: + return n; + } +} + +void main(int argc, char *argv[]) { - int p[2], std, nodflt; - char maildir[128]; - char mbox[128]; + char maildir[Pathlen], mbox[Pathlen], srvfile[64], **v; char *mboxfile, *err; - char srvfile[64]; - int srvpost; + int p[2], nodflt, srvpost; rfork(RFNOTEG); - mntpt = nil; - fflag = 0; mboxfile = nil; - std = 0; nodflt = 0; srvpost = 0; + v = argv; ARGBEGIN{ + case 'D': + Dflag = 1; + break; + case 'S': + Sflag = 1; + break; case 'b': biffing = 1; break; + case 'c': + cachetarg = ntoi(EARGF(usage())); + break; + case 'd': + debug = 1; + mainmem->flags |= POOL_PARANOIA; + break; case 'f': - fflag = 1; mboxfile = EARGF(usage()); break; + case 'i': + iflag++; + break; + case 'l': + lflag = 1; + break; case 'm': mntpt = EARGF(usage()); break; - case 'd': - debug = 1; + case 'n': + nodflt = 1; break; case 'p': plumbing = 0; @@ -190,18 +397,19 @@ main(int argc, char *argv[]) case 's': srvpost = 1; break; - case 'l': - logging = 1; - break; - case 'n': - nodflt = 1; - break; default: usage(); }ARGEND if(argc) usage(); + fmtinstall('A', Afmt); + fmtinstall('D', Dfmt); + fmtinstall(L'Δ', Δfmt); + fmtinstall('F', fcallfmt); + fmtinstall('H', encodefmt); /* forces tls stuff */ + fmtinstall('P', Pfmt); + quotefmtinstall(); if(pipe(p) < 0) error("pipe failed"); mfd[0] = p[0]; @@ -214,19 +422,13 @@ main(int argc, char *argv[]) mntpt = maildir; } if(mboxfile == nil && !nodflt){ - snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user); + 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) + if(mboxfile != nil) + if(err = newmbox(mboxfile, "mbox", 0, 0)) sysfatal("opening %s: %s", mboxfile, err); - } switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){ case -1: @@ -235,46 +437,67 @@ main(int argc, char *argv[]) henter(PATH(0, Qtop), dirtab[Qctl], (Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil); close(p[1]); + setname(v); io(); - postnote(PNGROUP, getpid(), "die yankee pig dog"); + syncallmboxes(); + syskillpg(getpid()); break; default: close(p[0]); /* don't deadlock if child fails */ if(srvpost){ - sprint(srvfile, "/srv/upasfs.%s", user); + snprint(srvfile, sizeof srvfile, "/srv/upasfs.%s", user); post(srvfile, "upasfs", p[1]); - } else { + }else if(mount(p[1], -1, mntpt, MREPL, "") < 0) error("mount failed"); - } } - exits(0); + exits(""); } -static int -fileinfo(Message *m, int t, char **pp) +char* +sputc(char *p, char *e, int c) { - char *p; - int len; + if(p < e - 1) + *p++ = c; + return p; +} + +char* +seappend(char *s, char *e, char *a, int n) +{ + int l; - p = ""; - len = 0; + l = e - s - 1; + if(l < n) + n = l; + memcpy(s, a, n); + s += n; + *s = 0; + return s; +} + +static int +fileinfo(Mailbox *mb, Message *m, int t, char **pp) +{ + char *s, *e, *p; + int len, i; + static char buf[64 + 512]; + + cacheidx(mb, m); + sanembmsg(mb, m); + p = nil; + len = -1; switch(t){ case Qbody: + cachebody(mb, m); p = m->body; - len = m->bend - m->body; + len = m->bend - p; break; case Qbcc: - if(m->bcc822){ - p = s_to_c(m->bcc822); - len = strlen(p); - } + p = m->bcc; break; case Qcc: - if(m->cc822){ - p = s_to_c(m->cc822); - len = strlen(p); - } + p = m->cc; break; case Qdisposition: switch(m->disposition){ @@ -285,142 +508,131 @@ fileinfo(Message *m, int t, char **pp) 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); + p = m->date822; + if(!p){ + p = buf; + len = snprint(buf, sizeof buf, "%#Δ", m->fileid); } break; case Qfilename: - if(m->filename){ - p = s_to_c(m->filename); - len = strlen(p); - } + p = m->filename; + break; + case Qflags: + p = flagbuf(buf, m->flags); break; case Qinreplyto: - if(m->inreplyto822){ - p = s_to_c(m->inreplyto822); - len = strlen(p); - } + p = m->inreplyto; break; case Qmessageid: - if(m->messageid822){ - p = s_to_c(m->messageid822); - len = strlen(p); - } + p = m->messageid; 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); - } + if(m->from) + p = m->from; + else + p = m->unixfrom; break; - case Qheader: - p = m->header; - len = headerlen(m); + case Qffrom: + if(m->ffrom) + p = m->ffrom; break; case Qlines: - p = m->lines; - if(*p == 0) - countlines(m); - len = strlen(m->lines); + len = snprint(buf, sizeof buf, "%lud", m->lines); + p = buf; break; case Qraw: + cachebody(mb, m); 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; + if(strncmp(m->start, "From ", 5) == 0) + if(e = strchr(p, '\n')) + p = e + 1; + len = m->rbend - p; break; case Qrawunix: + cachebody(mb, m); p = m->start; len = m->end - p; break; case Qrawbody: + cachebody(mb, m); p = m->rbody; len = m->rbend - p; break; case Qrawheader: + cacheheaders(mb, m); p = m->header; len = m->hend - p; break; case Qmimeheader: + cacheheaders(mb, m); 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); + case Qreferences: + cacheheaders(mb, m); + e = buf + sizeof buf; + s = buf; + for(i = 0; i < nelem(m->references); i++){ + if(m->references[i] == 0) + break; + s = seprint(s, e, "%s\n", m->references[i]); } + *s = 0; + p = buf; + len = s - buf; + break; + case Qreplyto: + if(m->replyto != nil) + p = m->replyto; + else if(m->from != nil) + p = m->from; + else if(m->sender != nil) + p = m->sender; + else if(m->unixfrom != nil) + p = m->unixfrom; break; case Qsender: - if(m->sender822){ - p = s_to_c(m->sender822); - len = strlen(p); - } + p = m->sender; break; case Qsubject: - p = nil; - if(m->subject822){ - p = s_to_c(m->subject822); - len = strlen(p); - } + p = m->subject; + break; + case Qsize: + len = snprint(buf, sizeof buf, "%lud", m->size); + p = buf; break; case Qto: - if(m->to822){ - p = s_to_c(m->to822); - len = strlen(p); - } + p = m->to; break; case Qtype: - if(m->type){ - p = s_to_c(m->type); - len = strlen(p); - } + p = rtab[m->type].s; + len = rtab[m->type].l; break; case Qunixdate: - if(m->unixdate){ - p = s_to_c(m->unixdate); - len = strlen(p); - } + p = buf; + len = snprint(buf, sizeof buf, "%#Δ", m->fileid); + break; + case Qfileid: + p = buf; + len = snprint(buf, sizeof buf, "%D", m->fileid); break; case Qunixheader: - if(m->unixheader){ - p = s_to_c(m->unixheader); - len = s_len(m->unixheader); - } + cacheheaders(mb, m); + p = m->unixheader; break; case Qdigest: - if(m->sdigest){ - p = s_to_c(m->sdigest); - len = strlen(p); - } + p = buf; + len = snprint(buf, sizeof buf, "%A", m->digest); break; } + if(p == nil) + p = ""; + if(len == -1) + len = strlen(p); *pp = p; + putcache(mb, m); return len; } @@ -441,47 +653,53 @@ int infofields[] = { Qsender, Qmessageid, Qlines, - -1, + Qsize, + Qflags, + Qfileid, + Qffrom, }; -static int -readinfo(Message *m, char *buf, long off, int count) +int +readinfo(Mailbox *mb, 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; + char *s, *p, *e; + int i, n; + long off0; + + if(m->infolen > 0 && off >= m->infolen) + return 0; + off0 = off; + s = buf; + e = s + count; + for(i = 0; s < e; i++){ + if(i == nelem(infofields)){ + m->infolen = s - buf + off0; + break; + } + n = fileinfo(mb, m, infofields[i], &p); + if(off > n){ + off -= n + 1; + continue; + } + if(off){ n -= off; + p += off; off = 0; } - if(n > count - len) - n = count - len; - if(buf) - memmove(buf+len, p, n); - len += n; + if(s + n > e) + n = e - s; + memcpy(s, p, n); + s += n; + if(s < e) + *s++ = '\n'; } - s_free(s); - return len; + return s - buf; } static void mkstat(Dir *d, Mailbox *mb, Message *m, int t) { - char *p; + char *p, *e; d->uid = user; d->gid = user; @@ -491,13 +709,13 @@ mkstat(Dir *d, Mailbox *mb, Message *m, int t) 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 { + if(m && m->fileid > 1000000ull) + d->atime = m->fileid >> 8; + else if(mb && mb->d) + d->atime = mb->d->mtime; + else d->atime = time(0); - d->mtime = d->atime; - } + d->mtime = d->atime; switch(t){ case Qtop: @@ -530,6 +748,12 @@ mkstat(Dir *d, Mailbox *mb, Message *m, int t) d->length = 0; d->qid.path = PATH(0, Qctl); break; + case Qheader: + d->name = dirtab[t]; + cacheheaders(mb, m); + d->length = readheader(m, hbuf, 0, sizeof hbuf); + putcache(mb, m); + break; case Qmboxctl: d->name = dirtab[t]; d->mode = 0222; @@ -539,12 +763,37 @@ mkstat(Dir *d, Mailbox *mb, Message *m, int t) break; case Qinfo: d->name = dirtab[t]; - d->length = readinfo(m, nil, 0, 1<<30); + d->length = readinfo(mb, m, hbuf, 0, sizeof hbuf); d->qid.path = PATH(m->id, t); break; + case Qraw: + cacheheaders(mb, m); + p = m->start; + if(strncmp(m->start, "From ", 5) == 0) + if(e = strchr(p, '\n')) + p = e + 1; + d->name = dirtab[t]; + d->length = m->size - (p - m->start); + putcache(mb, m); + break; + case Qrawbody: + d->name = dirtab[t]; + d->length = m->rawbsize; + break; + case Qrawunix: + d->name = dirtab[t]; + d->length = m->size; + if(mb->addfrom && Topmsg(mb, m)){ + cacheheaders(mb, m); + d->length += strlen(m->unixheader); + putcache(mb, m); + } + break; + case Qflags: + d->mode = 0666; default: d->name = dirtab[t]; - d->length = fileinfo(m, t, &p); + d->length = fileinfo(mb, m, t, &p); d->qid.path = PATH(m->id, t); break; } @@ -577,9 +826,8 @@ rauth(Fid*) } char* -rflush(Fid *f) +rflush(Fid*) { - USED(f); return 0; } @@ -608,30 +856,43 @@ doclone(Fid *f, int nfid) 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); + if(nf->mb = f->mb) + mboxincref(nf->mb); + if(nf->m = f->m) + msgincref(gettopmsg(nf->mb, nf->m)); + if(nf->mtop = f->mtop){ + qlock(nf->mb); + msgincref(nf->mtop); + qunlock(nf->mb); } nf->qid = f->qid; +sanefid(nf); +sanefid(f); return nf; } +/* slow? binary search? */ +static int +dindex(char *name) +{ + int i; + + for(i = 0; i < Qmax; i++) + if(dirtab[i] != nil) + if(strcmp(dirtab[i], name) == 0) + return i; + return -1; +} + char* dowalk(Fid *f, char *name) { - int t; - Mailbox *omb, *mb; char *rv, *p; + int t, t1; + Mailbox *omb, *mb; Hash *h; t = FILE(f->qid.path); - rv = Enotexist; omb = f->mb; @@ -640,12 +901,26 @@ dowalk(Fid *f, char *name) else qlock(&mbllock); - // this must catch everything except . and .. + /* this must catch everything except . and .. */ retry: - h = hlook(f->qid.path, name); +sanefid(f); + t1 = FILE(f->qid.path); + if((t1 == Qmbox || t1 == Qdir) && *name >= 'a' && *name <= 'z'){ + h = hlook(f->qid.path, "xxx"); /* sleezy speedup */ + t1 = dindex(name); + if(t1 == -1) + h = nil; + }else + h = hlook(f->qid.path, name); if(h != nil){ + if(f->m) + msgdecref(f->mb, gettopmsg(f->mb, f->m)); + if(f->mb && f->mb != h->mb) + mboxdecref(f->mb); f->mb = h->mb; f->m = h->m; + if(f->m) + msgincref(gettopmsg(f->mb, f->m)); switch(t){ case Qtop: if(f->mb != nil) @@ -659,8 +934,11 @@ retry: break; } f->qid = h->qid; + if(t1 < Qmax) + f->qid.path = PATH(f->m->id, t1); /* sleezy speedup */ +sanefid(f); rv = nil; - } else if((p = strchr(name, '.')) != nil && *name != '.'){ + }else if((p = strchr(name, '.')) != nil && *name != '.'){ *p = 0; goto retry; } @@ -697,13 +975,15 @@ retry: break; case Qdir: qlock(f->mb); - if(f->m->whole == f->mb->root){ + if(Topmsg(f->mb, f->m)){ 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); + msgdecref(f->mb, f->m); f->m = f->mtop = nil; } else { + /* refs don't change; still the same message */ f->m = f->m->whole; f->qid.path = PATH(f->m->id, Qdir); f->qid.type = QTDIR; @@ -723,6 +1003,7 @@ rwalk(Fid *f) char *rv; int i; +sanefid(f); if(f->open) return Eisopen; @@ -754,32 +1035,31 @@ rwalk(Fid *f) } rhdr.nwqid = i; - /* we only error out if no walk */ + /* we only error out if no walk */ if(i > 0) rv = nil; - +sanefid(f); return rv; } -char * +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) + if(file != Qctl && file != Qmboxctl && file != Qflags) return Eperm; - // make sure we've decoded + /* make sure we've decoded */ if(file == Qbody){ - if(f->m->decoded == 0) - decode(f->m); - if(f->m->converted == 0) - convert(f->m); + cachebody(f->mb, f->m); + decode(f->m); + convert(f->m); + putcache(f->mb, f->m); } rhdr.iounit = 0; @@ -788,7 +1068,7 @@ ropen(Fid *f) return 0; } -char * +char* rcreate(Fid*) { return Eperm; @@ -816,7 +1096,7 @@ readtopdir(Fid*, uchar *buf, long off, int cnt, int blen) for(mb = mbl; mb != nil; mb = mb->next){ mkstat(&d, mb, nil, Qmbox); - m = convD2M(&d, &buf[n], blen-n); + m = convD2M(&d, &buf[n], blen - n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; @@ -851,22 +1131,22 @@ readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen) off -= m; } - // to avoid n**2 reads of the directory, use a saved finger pointer + /* 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 + /* act like deleted files aren't there */ if(msg->deleted) continue; mkstat(&d, f->mb, msg, Qdir); - m = convD2M(&d, &buf[n], blen-n); + m = convD2M(&d, &buf[n], blen - n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; @@ -876,7 +1156,7 @@ readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen) pos += m; } - // save a finger pointer for next read of the mbox directory + /* save a finger pointer for next read of the mbox directory */ f->foff = pos; f->fptr = msg; f->fvers = f->mb->vers; @@ -896,7 +1176,7 @@ readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen) pos = 0; for(i = 0; i < Qmax; i++){ mkstat(&d, f->mb, f->m, i); - m = convD2M(&d, &buf[n], blen-n); + m = convD2M(&d, &buf[n], blen - n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) return n; @@ -907,7 +1187,7 @@ readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen) } for(msg = f->m->part; msg != nil; msg = msg->next){ mkstat(&d, f->mb, msg, Qdir); - m = convD2M(&d, &buf[n], blen-n); + m = convD2M(&d, &buf[n], blen - n); if(off <= pos){ if(m <= BIT16SZ || m > cnt) break; @@ -920,60 +1200,110 @@ readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen) return n; } +static int +mboxctlread(Mailbox *mb, char **p) +{ + static char buf[128]; + + *p = buf; + return snprint(*p, sizeof buf, "%s\n%ld\n", mb->path, mb->vers); +} + char* rread(Fid *f) { - long off; - int t, i, n, cnt; char *p; + int t, i, n, cnt; + long off; rhdr.count = 0; off = thdr.offset; cnt = thdr.count; - if(cnt > messagesize - IOHDRSZ) cnt = messagesize - IOHDRSZ; - rhdr.data = (char*)mbuf; +sanefid(f); t = FILE(f->qid.path); if(f->qid.type & QTDIR){ - if(t == Qtop) { + if(t == Qtop){ qlock(&mbllock); n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ); qunlock(&mbllock); - } else if(t == Qmbox) { + }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) { + }else if(t == Qmboxctl) n = 0; - } else { + else n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ); - } - rhdr.count = n; return nil; } - if(FILE(f->qid.path) == Qheader){ + switch(t){ + case Qctl: + rhdr.count = 0; + break; + case Qmboxctl: + i = mboxctlread(f->mb, &p); + goto output; + break; + case Qheader: + cacheheaders(f->mb, f->m); 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; + putcache(f->mb, f->m); + break; + case Qinfo: + if(cnt > sizeof mbuf) + cnt = sizeof mbuf; + rhdr.count = readinfo(f->mb, f->m, (char*)mbuf, off, cnt); + break; + case Qrawunix: + if(f->mb->addfrom && Topmsg(f->mb, f->m)){ + cacheheaders(f->mb, f->m); + p = f->m->unixheader; + if(off < strlen(p)){ + rhdr.count = strlen(p + off); + memmove(mbuf, p + off, rhdr.count); + break; + } + off -= strlen(p); + putcache(f->mb, f->m); + } + default: + i = fileinfo(f->mb, f->m, t, &p); + output: + if(off < i){ + if(off + cnt > i) + cnt = i - off; + if(cnt > sizeof mbuf) + cnt = sizeof mbuf; + memmove(mbuf, p + off, cnt); + rhdr.count = cnt; + } + break; } + 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; +char* +modflags(Mailbox *mb, Message *m, char *p) +{ + char *err; + uchar f; + + f = m->flags; + if(err = txflags(p, &f)) + return err; + if(f != m->flags){ + if(mb->modflags != nil) + mb->modflags(mb, m, f); + m->flags = f; + m->cstate |= Cidxstale; } return nil; } @@ -981,87 +1311,141 @@ rread(Fid *f) char* rwrite(Fid *f) { - char *err; - char *token[1024]; - int t, n; - String *file; + char *argvbuf[1024], **argv, file[Pathlen], *err, *v0; + int i, t, argc, flags; + Message *m; t = FILE(f->qid.path); rhdr.count = thdr.count; + sanefid(f); + 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; + argv = argvbuf; 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) + memset(argvbuf, 0, sizeof argvbuf); + argc = tokenize(thdr.data, argv, nelem(argvbuf) - 1); + if(argc == 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(argv[0], "open") == 0 || strcmp(argv[0], "create") == 0){ + if(argc == 1 || argc > 3) + return Ebadargs; + mboxpathbuf(file, sizeof file, getlog(), argv[1]); + if(argc == 3){ + if(strchr(argv[2], '/') != nil) + return "/ not allowed in mailbox name"; + }else + argv[2] = nil; + flags = 0; + if(strcmp(argv[0], "create") == 0) + flags |= DMcreate; + return newmbox(file, argv[2], flags, 0); } - if(strcmp(token[0], "close") == 0){ - if(n < 2) + if(strcmp(argv[0], "close") == 0){ + if(argc < 2) return nil; - freembox(token[1]); + for(i = 1; i < argc; i++) + freembox(argv[i]); return nil; } - if(strcmp(token[0], "delete") == 0){ - if(n < 3) + if(strcmp(argv[0], "delete") == 0){ + if(argc < 3) return nil; - delmessages(n-1, &token[1]); + delmessages(argc - 1, argv + 1); return nil; } + if(strcmp(argv[0], "flag") == 0){ + if(argc < 3) + return nil; + return flagmessages(argc - 1, argv + 1); + } + if(strcmp(argv[0], "remove") == 0){ + v0 = argv0; + flags = 0; + ARGBEGIN{ + default: + argv0 = v0; + return Ebadargs; + case 'r': + flags |= Rrecur; + break; + case 't': + flags |= Rtrunc; + break; + }ARGEND + argv0 = v0; + if(argc == 0) + return Ebadargs; + for(; *argv; argv++){ + mboxpathbuf(file, sizeof file, getlog(), *argv); + if(err = newmbox(file, nil, 0, 0)) + return err; +// if(!mb->remove) +// return "remove not implemented"; + if(err = removembox(file, flags)) + return err; + } + return 0; + } + if(strcmp(argv[0], "rename") == 0){ + v0 = argv0; + flags = 0; + ARGBEGIN{ + case 't': + flags |= Rtrunc; + break; + }ARGEND + argv0 = v0; + if(argc != 2) + return Ebadargs; + return mboxrename(argv[0], argv[1], flags); + } 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) + argc = tokenize(thdr.data, argv, nelem(argvbuf)); + if(argc == 0) return Ebadctl; - return (*f->mb->ctl)(f->mb, n, token); + return f->mb->ctl(f->mb, argc, argv); } + break; + case Qflags: + /* + * modifying flags on subparts is a little strange. + */ + if(!f->mb || !f->m) + break; + m = gettopmsg(f->mb, f->m); + err = modflags(f->mb, m, thdr.data); +// premature optimization? flags not written immediately. +// if(err == nil && f->m->cstate&Cidxstale) +// wridxfile(f->mb); /* syncmbox(f->mb, 1); */ + return err; } return Eperm; } -char * +char* rclunk(Fid *f) { Mailbox *mb; - f->busy = 0; +sanefid(f); + f->busy = 1; + /* coherence(); */ + f->fid = -1; f->open = 0; - if(f->mtop != nil){ + if(f->mtop){ qlock(f->mb); msgdecref(f->mb, f->mtop); qunlock(f->mb); } + if(f->m) + msgdecref(f->mb, gettopmsg(f->mb, f->m)); f->m = f->mtop = nil; mb = f->mb; if(mb != nil){ @@ -1071,17 +1455,18 @@ rclunk(Fid *f) mboxdecref(mb); qunlock(&mbllock); } - f->fid = -1; + f->busy = 0; return 0; } char * rremove(Fid *f) { +sanefid(f); if(f->m != nil){ if(f->m->deleted == 0) mailplumb(f->mb, f->m, 1); - f->m->deleted = 1; + f->m->deleted = Deleted; } return rclunk(f); } @@ -1091,6 +1476,7 @@ rstat(Fid *f) { Dir d; +sanefid(f); if(FILE(f->qid.path) == Qmbox){ qlock(f->mb); syncmbox(f->mb, 1); @@ -1102,13 +1488,13 @@ rstat(Fid *f) return 0; } -char * +char* rwstat(Fid*) { return Eperm; } -Fid * +Fid* newfid(int fid) { Fid *f, *ff; @@ -1152,33 +1538,44 @@ io(void) int n; /* start a process to watch the mailboxes*/ - if(plumbing){ + if(plumbing || biffing) switch(rfork(RFPROC|RFMEM)){ case -1: /* oh well */ break; case 0: reader(); - exits(nil); + exits(""); default: break; } - } - while((n = read9pmsg(mfd[0], mdata, messagesize)) != 0){ + 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) - error("mount read"); - if(convM2S(mdata, n, &thdr) != n) - error("convM2S format error"); + return; + if(convM2S(mdata, n, &thdr) == 0) + continue; - if(debug) + if(Dflag) 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)); + err = fcalls[thdr.type](newfid(thdr.fid)); if(err){ rhdr.type = Rerror; rhdr.ename = err; @@ -1187,14 +1584,16 @@ io(void) rhdr.fid = thdr.fid; } rhdr.tag = thdr.tag; - if(debug) - fprint(2, "%s:->%F\n", argv0, &rhdr);/**/ + if(Dflag) + fprint(2, "%s:->%F\n", argv0, &rhdr); n = convS2M(&rhdr, mdata, messagesize); if(write(mfd[1], mdata, n) != n) error("mount write"); } } +static char *readerargv[] = {"upas/fs", "plumbing", 0}; + void reader(void) { @@ -1202,13 +1601,14 @@ reader(void) Dir *d; Mailbox *mb; + setname(readerargv); 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){ + if(mb->waketime != 0 && t >= mb->waketime){ qlock(mb); mb->waketime = 0; break; @@ -1256,8 +1656,8 @@ newid(void) void error(char *s) { - postnote(PNGROUP, getpid(), "die yankee pig dog"); - fprint(2, "%s: %s: %r\n", argv0, s); + syskillpg(getpid()); + eprint("upas/fs: fatal error: %s: %r\n", s); exits(s); } @@ -1266,13 +1666,13 @@ typedef struct Ignorance Ignorance; struct Ignorance { Ignorance *next; - char *str; /* string */ - int partial; /* true if not exact match */ + char *str; + int len; }; Ignorance *ignorance; /* - * read the file of headers to ignore + * read the file of headers to ignore */ void readignore(void) @@ -1288,15 +1688,13 @@ readignore(void) if(b == 0) return; while(p = Brdline(b, '\n')){ - p[Blinelen(b)-1] = 0; + 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 = emalloc(sizeof *i); + i->len = strlen(p); i->str = strdup(p); if(i->str == 0){ free(i); @@ -1315,159 +1713,37 @@ ignore(char *p) readignore(); for(i = ignorance; i != nil; i = i->next) - if(cistrncmp(i->str, p, i->partial) == 0) + if(cistrncmp(i->str, p, i->len) == 0) return 1; return 0; } int -hdrlen(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?= -int -rfc2047convert(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 line -String* -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; -} - -int readheader(Message *m, char *buf, int off, int cnt) { - char *p, *e; - int n, ns; - char *to = buf; - String *s; + char *s, *end, *se, *p, *e, *to; + int n, ns, salloc; + to = buf; p = m->header; e = m->hend; - s = nil; + s = emalloc(salloc = 2048); + end = s + salloc; - // copy in good headers + /* copy in good headers */ while(cnt > 0 && p < e){ n = hdrlen(p, e); + assert(n > 0); if(ignore(p)){ p += n; continue; } - - // rfc2047 processing - s = stringconvert(s, p, n); - ns = s_len(s); + if(n + 1 > salloc){ + s = erealloc(s, salloc = n + 1); + end = s + salloc; + } + se = rfc2047(s, end, p, n, 0); + ns = se - s; if(off > 0){ if(ns <= off){ off -= ns; @@ -1478,34 +1754,16 @@ readheader(Message *m, char *buf, int off, int cnt) } if(ns > cnt) ns = cnt; - memmove(to, s_to_c(s)+off, ns); + memmove(to, s + off, ns); to += ns; p += n; cnt -= ns; off = 0; } - - s_free(s); + free(s); return to - buf; } -int -headerlen(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; uint @@ -1545,6 +1803,7 @@ henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb) int h; Hash *hp, **l; +//if(m)sanemsg(m); qlock(&hashlock); h = hash(ppath, name); for(l = &htab[h]; *l != nil; l = &(*l)->next){ @@ -1595,25 +1854,43 @@ hashmboxrefs(Mailbox *mb) int refs = 0; qlock(&hashlock); - for(h = 0; h < Hsize; h++){ + for(h = 0; h < Hsize; h++) for(hp = htab[h]; hp != nil; hp = hp->next) if(hp->mb == mb) refs++; - } qunlock(&hashlock); return refs; } void +checkmboxrefs(void) +{ + int refs; + Mailbox *mb; + +// qlock(&mbllock); + for(mb = mbl; mb; mb = mb->next){ + qlock(mb); + refs = fidmboxrefs(mb) + 1; + if(refs != mb->refs){ + eprint("%s:%s ref mismatch got %d expected %d\n", mb->name, mb->path, refs, mb->refs); + abort(); + } + qunlock(mb); + } +// qunlock(&mbllock); +} + +void post(char *name, char *envname, int srvfd) { - int fd; char buf[32]; + int fd; fd = create(name, OWRITE, 0600); if(fd < 0) error("post failed"); - sprint(buf, "%d",srvfd); + snprint(buf, sizeof buf, "%d", srvfd); if(write(fd, buf, strlen(buf)) != strlen(buf)) error("srv write"); close(fd); |