summaryrefslogtreecommitdiff
path: root/sys/src/cmd/upas/fs/plan9.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/src/cmd/upas/fs/plan9.c')
-rw-r--r--sys/src/cmd/upas/fs/plan9.c475
1 files changed, 260 insertions, 215 deletions
diff --git a/sys/src/cmd/upas/fs/plan9.c b/sys/src/cmd/upas/fs/plan9.c
index 171b15617..1d65a62e0 100644
--- a/sys/src/cmd/upas/fs/plan9.c
+++ b/sys/src/cmd/upas/fs/plan9.c
@@ -1,151 +1,188 @@
#include "common.h"
-#include <ctype.h>
-#include <plumb.h>
#include <libsec.h>
#include "dat.h"
-enum {
- Buffersize = 64*1024,
-};
+typedef struct {
+ Biobuf *in;
+ char *shift;
+} Inbuf;
-typedef struct Inbuf Inbuf;
-struct Inbuf
+/*
+ * parse a Unix style header
+ */
+static int
+memtotm(char *p, int n, Tm *t)
+{
+ char buf[128];
+
+ if(n > sizeof buf - 1)
+ n = sizeof buf -1;
+ memcpy(buf, p, n);
+ buf[n] = 0;
+ return strtotm(buf, t);
+}
+
+static int
+chkunix0(char *s, int n)
+{
+ char *p;
+ Tm tm;
+
+ if(n > 256)
+ return -1;
+ if((p = memchr(s, ' ', n)) == nil)
+ return -1;
+ if(memtotm(p, n - (p - s), &tm) < 0)
+ return -1;
+ if(tm2sec(&tm) < 1000000)
+ return -1;
+ return 0;
+}
+
+static int
+chkunix(char *s, int n)
{
- int fd;
- uchar *lim;
- uchar *rptr;
- uchar *wptr;
- uchar data[Buffersize+7];
-};
+ int r;
+
+ r = chkunix0(s, n);
+ if(r == -1)
+ eprint("plan9: warning naked from [%.*s]\n", n, s);
+ return r;
+}
+
+static char*
+parseunix(Message *m)
+{
+ char *s, *p, *q;
+ int l;
+ Tm tm;
+
+ l = m->header - m->start;
+ m->unixheader = smprint("%.*s", l, m->start);
+ s = m->start + 5;
+ if((p = strchr(s, ' ')) == nil)
+ return s;
+ *p = 0;
+ m->unixfrom = strdup(s);
+ *p++ = ' ';
+ if(q = strchr(p, '\n'))
+ *q = 0;
+ if(strtotm(p, &tm) < 0)
+ return p;
+ if(q)
+ *q = '\n';
+ m->fileid = (uvlong)tm2sec(&tm) << 8;
+ return 0;
+}
static void
-addtomessage(Message *m, uchar *p, int n, int done)
+addtomessage(Message *m, char *p, int n)
{
int i, len;
- // add to message (+1 in malloc is for a trailing NUL)
+ if(n == 0)
+ return;
+ /* add to message (+1 in malloc is for a trailing NUL) */
if(m->lim - m->end < n){
if(m->start != nil){
- i = m->end-m->start;
- if(done)
- len = i + n;
- else
- len = (4*(i+n))/3;
+ i = m->end - m->start;
+ len = (4*(i + n))/3;
m->start = erealloc(m->start, len + 1);
m->end = m->start + i;
} else {
- if(done)
- len = n;
- else
- len = 2*n;
+ len = 2*n;
m->start = emalloc(len + 1);
m->end = m->start;
}
m->lim = m->start + len;
- *m->lim = '\0';
+ *m->lim = 0;
}
memmove(m->end, p, n);
m->end += n;
- *m->end = '\0';
+ *m->end = 0;
}
-//
-// read in a single message
-//
+/*
+ * read in a single message
+ */
static int
-readmessage(Message *m, Inbuf *inb)
+okmsg(Mailbox *mb, Message *m, Inbuf *b)
{
- int i, n, done;
- uchar *p, *np;
- char sdigest[SHA1dlen*2+1];
- char tmp[64];
-
- for(done = 0; !done;){
- n = inb->wptr - inb->rptr;
- if(n < 6){
- if(n)
- memmove(inb->data, inb->rptr, n);
- inb->rptr = inb->data;
- inb->wptr = inb->rptr + n;
- i = read(inb->fd, inb->wptr, Buffersize);
- if(i < 0){
- if(fd2path(inb->fd, tmp, sizeof tmp) < 0)
- strcpy(tmp, "unknown mailbox");
- fprint(2, "error reading '%s': %r\n", tmp);
- return -1;
- }
- if(i == 0){
- if(n != 0)
- addtomessage(m, inb->rptr, n, 1);
- if(m->end == m->start)
- return -1;
- break;
- }
- inb->wptr += i;
- }
-
- // look for end of message
- for(p = inb->rptr; p < inb->wptr; p = np+1){
- // first part of search for '\nFrom '
- np = memchr(p, '\n', inb->wptr - p);
- if(np == nil){
- p = inb->wptr;
- break;
- }
-
- /*
- * if we've found a \n but there's
- * not enough room for '\nFrom ', don't do
- * the comparison till we've read in more.
- */
- if(inb->wptr - np < 6){
- p = np;
- break;
- }
-
- if(strncmp((char*)np, "\nFrom ", 6) == 0){
- done = 1;
- p = np+1;
- break;
- }
- }
+ char e[ERRMAX], buf[128];
- // add to message (+ 1 in malloc is for a trailing null)
- n = p - inb->rptr;
- addtomessage(m, inb->rptr, n, done);
- inb->rptr += n;
+ rerrstr(e, sizeof e);
+ if(strlen(e)){
+ if(fd2path(Bfildes(b->in), buf, sizeof buf) < 0)
+ strcpy(buf, "unknown mailbox");
+ eprint("plan9: error reading %s: %r\n", buf);
+ return -1;
}
-
- // if it doesn't start with a 'From ', this ain't a mailbox
- if(strncmp(m->start, "From ", 5) != 0)
+ if(m->end == m->start)
return -1;
-
- // dump trailing newline, make sure there's a trailing null
- // (helps in body searches)
- if(*(m->end-1) == '\n')
+ if(m->end[-1] == '\n')
m->end--;
*m->end = 0;
+ m->size = m->end - m->start;
+ if(m->size >= Maxmsg)
+ return -1;
m->bend = m->rbend = m->end;
+ if(m->digest == 0)
+ digestmessage(mb, m);
+ return 0;
+}
- // digest message
- sha1((uchar*)m->start, m->end - m->start, m->digest, nil);
- for(i = 0; i < SHA1dlen; i++)
- sprint(sdigest+2*i, "%2.2ux", m->digest[i]);
- m->sdigest = s_copy(sdigest);
+static char*
+inbread(Inbuf *b)
+{
+ if(b->shift)
+ return b->shift;
+ return b->shift = Brdline(b->in, '\n');
+}
- return 0;
+void
+inbconsume(Inbuf *b)
+{
+ b->shift = 0;
}
+/*
+ * bug: very long line with From at the buffer break.
+ */
+static int
+readmessage(Mailbox *mb, Message *m, Inbuf *b)
+{
+ char *s, *n;
+ long l, state;
+
+ werrstr("");
+ state = 0;
+ for(;;){
+ s = inbread(b);
+ if(s == 0)
+ break;
+ n = s + (l = Blinelen(b->in)) - 1;
+ if(l >= 28 + 7 && n[0] == '\n')
+ if(strncmp(s, "From ", 5) == 0)
+ if(!chkunix(s + 5, l - 5))
+ if(++state == 2)
+ break;
+ if(state == 0)
+ return -1;
+ addtomessage(m, s, l);
+ inbconsume(b);
+ }
+ return okmsg(mb, m, b);
+}
-// throw out deleted messages. return number of freshly deleted messages
+/* throw out deleted messages. return number of freshly deleted messages */
int
purgedeleted(Mailbox *mb)
{
Message *m, *next;
int newdels;
- // forget about what's no longer in the mailbox
+ /* forget about what's no longer in the mailbox */
newdels = 0;
for(m = mb->root->part; m != nil; m = next){
next = m->next;
@@ -158,44 +195,51 @@ purgedeleted(Mailbox *mb)
return newdels;
}
-//
-// read in the mailbox and parse into messages.
-//
+static void
+mergemsg(Message *m, Message *x)
+{
+ assert(m->start == 0);
+ m->mallocd = 1;
+ m->inmbox = 1;
+ m->lim = x->lim;
+ m->start = x->start;
+ m->end = x->end;
+ m->bend = x->bend;
+ m->rbend = x->rbend;
+ x->lim = 0;
+ x->start = 0;
+ x->end = 0;
+ x->bend = 0;
+ x->rbend = 0;
+}
+
+/*
+ * read in the mailbox and parse into messages.
+ */
static char*
-_readmbox(Mailbox *mb, int doplumb, Mlock *lk)
+readmbox(Mailbox *mb, int doplumb, int *new, Mlock *lk)
{
- int fd, n;
- String *tmp;
+ char *p, *x, buf[Pathlen];
+ int nnew;
+ Biobuf *in;
Dir *d;
- static char err[Errlen];
+ Inbuf b;
Message *m, **l;
- Inbuf *inb;
- char *x;
+ static char err[ERRMAX];
l = &mb->root->part;
/*
* open the mailbox. If it doesn't exist, try the temporary one.
*/
- n = 0;
retry:
- fd = open(mb->path, OREAD);
- if(fd < 0){
- rerrstr(err, sizeof(err));
- if(strstr(err, "locked") != nil
- || strstr(err, "exclusive lock") != nil)
- if(n++ < 20){
- sleep(500); /* wait for lock to go away */
- goto retry;
- }
- if(strstr(err, "exist") != nil){
- tmp = s_copy(mb->path);
- s_append(tmp, ".tmp");
- if(sysrename(s_to_c(tmp), mb->path) == 0){
- s_free(tmp);
+ in = Bopen(mb->path, OREAD);
+ if(in == nil){
+ errstr(err, sizeof(err));
+ if(strstr(err, "exist") != 0){
+ snprint(buf, sizeof buf, "%s.tmp", mb->path);
+ if(sysrename(buf, mb->path) == 0)
goto retry;
- }
- s_free(tmp);
}
return err;
}
@@ -204,173 +248,170 @@ retry:
* a new qid.path means reread the mailbox, while
* a new qid.vers means read any new messages
*/
- d = dirfstat(fd);
+ d = dirfstat(Bfildes(in));
if(d == nil){
- close(fd);
- errstr(err, sizeof(err));
+ Bterm(in);
+ errstr(err, sizeof err);
return err;
}
if(mb->d != nil){
if(d->qid.path == mb->d->qid.path && d->qid.vers == mb->d->qid.vers){
- close(fd);
+ *new = 0;
+ Bterm(in);
free(d);
return nil;
}
if(d->qid.path == mb->d->qid.path){
while(*l != nil)
l = &(*l)->next;
- seek(fd, mb->d->length, 0);
+ Bseek(in, mb->d->length, 0);
}
free(mb->d);
}
mb->d = d;
- mb->vers++;
- henter(PATH(0, Qtop), mb->name,
- (Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
- inb = emalloc(sizeof(Inbuf));
- inb->rptr = inb->wptr = inb->data;
- inb->fd = fd;
+ memset(&b, 0, sizeof b);
+ b.in = in;
+ b.shift = 0;
- // read new messages
- snprint(err, sizeof err, "reading '%s'", mb->path);
- logmsg(err, nil);
+ /* read new messages */
+ logmsg(nil, "reading %s", mb->path);
+ nnew = 0;
for(;;){
if(lk != nil)
syslockrefresh(lk);
m = newmessage(mb->root);
m->mallocd = 1;
m->inmbox = 1;
- if(readmessage(m, inb) < 0){
- delmessage(mb, m);
- mb->root->subname--;
+ if(readmessage(mb, m, &b) < 0){
+ unnewmessage(mb, mb->root, m);
break;
}
-
- // merge mailbox versions
+ /* merge mailbox versions */
while(*l != nil){
if(memcmp((*l)->digest, m->digest, SHA1dlen) == 0){
- // matches mail we already read, discard
- logmsg("duplicate", *l);
- delmessage(mb, m);
- mb->root->subname--;
- m = nil;
- l = &(*l)->next;
+ if((*l)->start == nil){
+ logmsg(*l, "read indexed");
+ mergemsg(*l, m);
+ unnewmessage(mb, mb->root, m);
+ m = *l;
+ }else{
+ logmsg(*l, "duplicate");
+ m->inmbox = 1; /* remove it */
+ unnewmessage(mb, mb->root, m);
+ m = nil;
+ l = &(*l)->next;
+ }
break;
} else {
- // old mail no longer in box, mark deleted
- logmsg("disappeared", *l);
+ /* old mail no longer in box, mark deleted */
+ logmsg(*l, "disappeared");
if(doplumb)
mailplumb(mb, *l, 1);
(*l)->inmbox = 0;
- (*l)->deleted = 1;
+ (*l)->deleted = Disappear;
l = &(*l)->next;
}
}
if(m == nil)
continue;
-
- x = strchr(m->start, '\n');
- if(x == nil)
- m->header = m->end;
- else
+ m->header = m->end;
+ if(x = strchr(m->start, '\n'))
m->header = x + 1;
+ if(p = parseunix(m))
+ sysfatal("%s:%lld naked From in body? [%s]", mb->path, seek(Bfildes(in), 0, 1), p);
m->mheader = m->mhend = m->header;
- parseunix(m);
- parse(m, 0, mb, 0);
- logmsg("new", m);
-
+ parse(mb, m, 0, 0);
+ if(m != *l && m->deleted != Dup){
+ logmsg(m, "new");
+ newcachehash(mb, m, doplumb);
+ putcache(mb, m);
+ nnew++;
+ }
/* chain in */
*l = m;
l = &m->next;
- if(doplumb)
- mailplumb(mb, m, 0);
-
}
- logmsg("mbox read", nil);
+ logmsg(nil, "mbox read");
- // whatever is left has been removed from the mbox, mark deleted
+ /* whatever is left has been removed from the mbox, mark deleted */
while(*l != nil){
if(doplumb)
mailplumb(mb, *l, 1);
(*l)->inmbox = 0;
- (*l)->deleted = 1;
+ (*l)->deleted = Deleted;
l = &(*l)->next;
}
- close(fd);
- free(inb);
+ Bterm(in);
+ *new = nnew;
return nil;
}
static void
-_writembox(Mailbox *mb, Mlock *lk)
+writembox(Mailbox *mb, Mlock *lk)
{
- Dir *d;
- Message *m;
- String *tmp;
+ char buf[Pathlen];
int mode, errs;
Biobuf *b;
+ Dir *d;
+ Message *m;
- tmp = s_copy(mb->path);
- s_append(tmp, ".tmp");
+ snprint(buf, sizeof buf, "%s.tmp", mb->path);
/*
* preserve old files permissions, if possible
*/
- d = dirstat(mb->path);
- if(d != nil){
- mode = d->mode&0777;
+ mode = Mboxmode;
+ if(d = dirstat(mb->path)){
+ mode = d->mode & 0777;
free(d);
- } else
- mode = MBOXMODE;
+ }
- sysremove(s_to_c(tmp));
- b = sysopen(s_to_c(tmp), "alc", mode);
+ remove(buf);
+ b = sysopen(buf, "alc", mode);
if(b == 0){
- fprint(2, "can't write temporary mailbox %s: %r\n", s_to_c(tmp));
+ eprint("plan9: can't write temporary mailbox %s: %r\n", buf);
return;
}
- logmsg("writing new mbox", nil);
+ logmsg(nil, "writing new mbox");
errs = 0;
for(m = mb->root->part; m != nil; m = m->next){
if(lk != nil)
syslockrefresh(lk);
if(m->deleted)
continue;
- logmsg("writing", m);
+ logmsg(m, "writing");
if(Bwrite(b, m->start, m->end - m->start) < 0)
errs = 1;
if(Bwrite(b, "\n", 1) < 0)
errs = 1;
}
- logmsg("wrote new mbox", nil);
+ logmsg(nil, "wrote new mbox");
if(sysclose(b) < 0)
errs = 1;
if(errs){
- fprint(2, "error writing temporary mail file\n");
- s_free(tmp);
+ eprint("plan9: error writing temporary mail file\n");
return;
}
- sysremove(mb->path);
- if(sysrename(s_to_c(tmp), mb->path) < 0)
- fprint(2, "%s: can't rename %s to %s: %r\n", argv0,
- s_to_c(tmp), mb->path);
- s_free(tmp);
+ remove(mb->path);
+ if(sysrename(buf, mb->path) < 0)
+ eprint("plan9: can't rename %s to %s: %r\n",
+ buf, mb->path);
if(mb->d != nil)
free(mb->d);
mb->d = dirstat(mb->path);
}
char*
-plan9syncmbox(Mailbox *mb, int doplumb)
+plan9syncmbox(Mailbox *mb, int doplumb, int *new)
{
- Mlock *lk;
char *rv;
+ Mlock *lk;
lk = nil;
if(mb->dolock){
@@ -379,9 +420,9 @@ plan9syncmbox(Mailbox *mb, int doplumb)
return "can't lock mailbox";
}
- rv = _readmbox(mb, doplumb, lk); /* interpolate */
+ rv = readmbox(mb, doplumb, new, lk); /* interpolate */
if(purgedeleted(mb) > 0)
- _writembox(mb, lk);
+ writembox(mb, lk);
if(lk != nil)
sysunlock(lk);
@@ -389,26 +430,30 @@ plan9syncmbox(Mailbox *mb, int doplumb)
return rv;
}
-//
-// look to see if we can open this mail box
-//
+void
+plan9decache(Mailbox*, Message *m)
+{
+ m->lim = 0;
+}
+
+/*
+ * look to see if we can open this mail box
+ */
char*
plan9mbox(Mailbox *mb, char *path)
{
- static char err[Errlen];
- String *tmp;
+ char buf[Pathlen];
+ static char err[Pathlen];
if(access(path, AEXIST) < 0){
- errstr(err, sizeof(err));
- tmp = s_copy(path);
- s_append(tmp, ".tmp");
- if(access(s_to_c(tmp), AEXIST) < 0){
- s_free(tmp);
+ errstr(err, sizeof err);
+ snprint(buf, sizeof buf, "%s.tmp", path);
+ if(access(buf, AEXIST) < 0)
return err;
- }
- s_free(tmp);
}
-
mb->sync = plan9syncmbox;
+ mb->remove = localremove;
+ mb->rename = localrename;
+ mb->decache = plan9decache;
return nil;
}