diff options
Diffstat (limited to 'sys/src/cmd/upas/fs/chkidx.c')
-rw-r--r-- | sys/src/cmd/upas/fs/chkidx.c | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/sys/src/cmd/upas/fs/chkidx.c b/sys/src/cmd/upas/fs/chkidx.c new file mode 100644 index 000000000..8b0a1545b --- /dev/null +++ b/sys/src/cmd/upas/fs/chkidx.c @@ -0,0 +1,416 @@ +#include "common.h" +#include <auth.h> +#include <libsec.h> +#include <bin.h> +#include "dat.h" + +#define idprint(...) if(1) fprint(2, __VA_ARGS__); else {} +enum{ + Maxver = 10, +}; +static char *magictab[Maxver] = { +[4] "idx magic v4\n", +[7] "idx magic v7\n", +}; +static int fieldstab[Maxver] = { +[4] 19, +[7] 21, +}; + +static char *magic; +static int Idxfields; +static int lineno; +static int idxver; + +int +newid(void) +{ + static int id; + + return ++id; +} + +void* +emalloc(ulong n) +{ + void *p; + + p = mallocz(n, 1); + if(!p) + sysfatal("malloc %lud: %r", n); + setmalloctag(p, getcallerpc(&n)); + return p; +} + +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 +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); +} + +static Mailbox* +shellmailbox(char *path) +{ + Mailbox *mb; + + mb = malloc(sizeof *mb); + if(mb == 0) + sysfatal("malloc"); + memset(mb, 0, sizeof *mb); + snprint(mb->path, sizeof mb->path, "%s", path); + mb->id = newid(); + mb->root = newmessage(nil); + mb->mtree = mkavltree(mtreecmp); + return mb; +} + +void +shellmailboxfree(Mailbox*) +{ +} + +Message* +newmessage(Message *parent) +{ + static int id; + Message *m; + +// msgallocd++; + + m = mallocz(sizeof *m, 1); + if(m == 0) + sysfatal("malloc"); + m->disposition = Dnone; +// m->type = newrefs("text/plain"); +// m->charset = newrefs("iso-8859-1"); + m->cstate = Cidxstale; + m->flags = Frecent; + m->id = newid(); + if(parent) + snprint(m->name, sizeof m->name, "%d", ++(parent->subname)); + if(parent == nil) + parent = m; + m->whole = parent; + m->hlen = -1; + return m; +} + +void +unnewmessage(Mailbox *mb, Message *parent, Message *m) +{ + assert(parent->subname > 0); +// delmessage(mb, m); + USED(mb, m); + parent->subname -= 1; +} + + +static int +validmessage(Mailbox *mb, Message *m, int level) +{ + if(level){ + if(m->digest != 0) + goto lose; + if(m->fileid <= 1000000ull<<8) + if(m->fileid != 0) + goto lose; + }else{ + if(m->digest == 0) + goto lose; + if(m->size == 0) + goto lose; + if(m->fileid <= 1000000ull<<8) + goto lose; + if(mtreefind(mb, m->digest)) + goto lose; + } + return 1; +lose: + fprint(2, "invalid cache[%d] %#A size %ld %D\n", level, m->digest, m->size, m->fileid); + return 0; +} + +static char* +∫(char *x) +{ + if(x && *x) + return x; + return nil; +} + +static char* +brdstr(Biobuf *b, int c, int eat) +{ + char *s; + + s = Brdstr(b, c, eat); + if(s) + lineno++; + return s; +} + +static int +nibble(int c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c < 0x20) + c += 0x20; + if(c >= 'a' && c <= 'f') + return c - 'a'+10; + return 0xff; +} + +static uchar* +hackdigest(char *s) +{ + uchar t[SHA1dlen]; + int i; + + if(strcmp(s, "-") == 0) + return 0; + if(strlen(s) != 2*SHA1dlen){ + fprint(2, "bad digest %s\n", s); + return 0; + } + for(i = 0; i < SHA1dlen; i++) + t[i] = nibble(s[2*i])<<4 | nibble(s[2*i + 1]); + memmove(s, t, SHA1dlen); + return (uchar*)s; +} + +static Message* +findmessage(Mailbox *, Message *parent, int n) +{ + Message *m; + + for(m = parent->part; m; m = m->next) + if(!m->digest && n-- == 0) + return m; + return 0; +} + +static uvlong +rdfileid(char *s, int level) +{ + char *p; + uvlong uv; + + uv = strtoul(s, &p, 0); + if((level == 0 && uv < 1000000) || *p != '.') + return 0; + return uv<<8 | strtoul(p + 1, 0, 10); +} + +static int +rdidx(Biobuf *b, Mailbox *mb, Message *parent, int npart, int level) +{ + char *f[50 + 1], *s; + uchar *digest; + int n, nparts, good, bad, redux; + Message *m, **ll, *l; + + bad = good = redux = 0; + ll = &parent->part; + nparts = npart; + for(; npart != 0 && (s = brdstr(b, '\n', 1)); npart--){ +//if(lineno>18&&lineno<25)idprint("%d: %d [%s]\n", lineno, level, s); + n = tokenize(s, f, nelem(f)); + if(n != Idxfields){ + print("%d: bad line\n", lineno); + bad++; + free(s); + continue; + } + digest = hackdigest(f[0]); + if(level == 0){ + if(digest == 0) + idprint("%d: no digest\n", lineno); + m = mtreefind(mb, digest); + }else{ + m = findmessage(mb, parent, nparts - npart); + if(m == 0){ + // idprint("can't find message\n"); + } + } + if(m){ + /* + * read in mutable information. + * currently this is only flags + */ + idprint("%d seen before %d... %.2ux", level, m->id, m->cstate); + redux++; + m->flags |= strtoul(f[1], 0, 16); + m->cstate &= ~Cidxstale; + m->cstate |= Cidx; + idprint("→%.2ux\n", m->cstate); + free(s); + + if(m->nparts) + rdidx(b, mb, m, m->nparts, level + 1); + ll = &m->next; + continue; + } + m = newmessage(parent); +//if(lineno>18&&lineno<25)idprint("%d: %d %d %A\n", lineno, level, m->id, digest); +// idprint("%d new %d %#A \n", level, m->id, digest); + m->digest = digest; + m->flags = strtoul(f[1], 0, 16); + m->fileid = rdfileid(f[2], level); + m->lines = atoi(f[3]); + m->ffrom = ∫(f[4]); + m->from = ∫(f[5]); + m->to = ∫(f[6]); + m->cc = ∫(f[7]); + m->bcc = ∫(f[8]); + m->replyto = ∫(f[9]); + m->messageid = ∫(f[10]); + m->subject = ∫(f[11]); + m->sender = ∫(f[12]); + m->inreplyto = ∫(f[13]); +// m->type = newrefs(f[14]); + m->disposition = atoi(f[15]); + m->size = strtoul(f[16], 0, 0); + m->rawbsize = strtoul(f[17], 0, 0); + switch(idxver){ + case 4: + m->nparts = strtoul(f[18], 0, 0); + case 7: + m->ibadchars = strtoul(f[18], 0, 0); + m->idxaux = ∫(f[19]); + m->nparts = strtoul(f[20], 0, 0); + } + m->cstate &= ~Cidxstale; + m->cstate |= Cidx; + m->str = s; +// free(s); + if(!validmessage(mb, m, level)){ + /* + * if this was an okay message, and somebody + * wrote garbage to the index file, we lose the msg. + */ + print("%d: !validmessage\n", lineno); + bad++; + unnewmessage(mb, parent, m); + continue; + } + if(level == 0) + m->inmbox = 1; +// cachehash(mb, m); /* hokey */ + l = *ll; + *ll = m; + ll = &m->next; + *ll = l; + good++; + + if(m->nparts){ +// fprint(2, "%d: %d parts [%s]\n", lineno, m->nparts, f[18]); + rdidx(b, mb, m, m->nparts, level + 1); + } + } + if(level == 0) + print("idx: %d %d %d\n", good, bad, redux); + return 0; +} + +static int +verscmp(Biobuf *b) +{ + char *s; + int i; + + if((s = brdstr(b, '\n', 0)) == 0) + return -1; + for(i = 0; i < Maxver; i++) + if(magictab[i]) + if(strcmp(s, magictab[i]) == 0) + break; + free(s); + if(i == Maxver) + return -1; + idxver = i; + magic = magictab[i]; + Idxfields = fieldstab[i]; + fprint(2, "version %d\n", i); + return 0; +} + +int +mbvers(Biobuf *b) +{ + char *s; + + if(s = brdstr(b, '\n', 1)){ + free(s); + return 0; + } + return -1; +} + +int +ckidxfile(Mailbox *mb) +{ + char buf[Pathlen + 4]; + int r; + Biobuf *b; + + snprint(buf, sizeof buf, "%s", mb->path); + b = Bopen(buf, OREAD); + if(b == nil) + return -1; + if(verscmp(b) == -1) + return -1; + if(idxver >= 7) + mbvers(b); + r = rdidx(b, mb, mb->root, -1, 0); + Bterm(b); + return r; +} + +static char *bargv[] = {"/fd/0", 0}; + +void +main(int argc, char **argv) +{ + Mailbox *mb; + + fmtinstall('A', Afmt); + fmtinstall('D', Dfmt); + ARGBEGIN{ + }ARGEND + if(*argv == 0) + argv = bargv; + for(; *argv; argv++){ + mb = shellmailbox(*argv); + lineno = 0; + if(ckidxfile(mb) == -1) + fprint(2, "%s: %r\n", *argv); + shellmailboxfree(mb); + } + exits(""); +} |