shithub: riscv

Download patch

ref: 508b796b2719e6c8275a2a1b737c9798d380d25f
parent: 163dccbac04a3c9ab132005ebb4a96a0e0baec0b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Mar 14 19:06:39 EDT 2017

upas/fs: fix more locking bugs, remove debugging clutter, remove planb mbox code

--- a/sys/src/cmd/upas/fs/fs.c
+++ b/sys/src/cmd/upas/fs/fs.c
@@ -173,31 +173,6 @@
 	}
 }
 
-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)
 {
@@ -427,7 +402,7 @@
 	}
 
 	if(mboxfile != nil)
-		if(err = newmbox(mboxfile, "mbox", 0, 0))
+		if(err = newmbox(mboxfile, "mbox", 0, nil))
 			sysfatal("opening %s: %s", mboxfile, err);
 
 	switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){
@@ -856,18 +831,19 @@
 		return nil;
 	nf->busy = 1;
 	nf->open = 0;
-	if(nf->mb = f->mb)
+	nf->mb = f->mb;
+	if(nf->mb){
+		qlock(nf->mb);
 		mboxincref(nf->mb);
+	}
 	if(nf->m = f->m)
 		msgincref(gettopmsg(nf->mb, nf->m));
-	if(nf->mtop = f->mtop){
-		qlock(nf->mb);
+	if(nf->mtop = f->mtop)
 		msgincref(nf->mtop);
+	nf->qid = f->qid;
+	if(nf->mb){
 		qunlock(nf->mb);
 	}
-	nf->qid = f->qid;
-sanefid(nf);
-sanefid(f);
 	return nf;
 }
 
@@ -889,21 +865,18 @@
 {
 	char *rv, *p;
 	int t, t1;
-	Mailbox *omb, *mb;
+	Mailbox *mb;
 	Hash *h;
 
 	t = FILE(f->qid.path);
 	rv = Enotexist;
 
-	omb = f->mb;
-	if(omb)
-		qlock(omb);
-	else
-		qlock(&mbllock);
+	qlock(&mbllock);
+	if(f->mb)
+		qlock(f->mb);
 
 	/* this must catch everything except . and .. */
 retry:
-sanefid(f);
 	t1 = FILE(f->qid.path);
 	if((t1 == Qmbox || t1 == Qdir) && *name >= 'a' && *name <= 'z'){
 		h = hlook(f->qid.path, "xxx");		/* sleezy speedup */
@@ -915,8 +888,12 @@
 	if(h != nil){
 		if(f->m)
 			msgdecref(f->mb, gettopmsg(f->mb, f->m));
-		if(f->mb && f->mb != h->mb)
+		if(f->mb && f->mb != h->mb){
+			qunlock(f->mb);
 			mboxdecref(f->mb);
+		}
+		if(h->mb && h->mb != f->mb)
+			qlock(h->mb);
 		f->mb = h->mb;
 		f->m = h->m;
 		if(f->m)
@@ -923,7 +900,7 @@
 			msgincref(gettopmsg(f->mb, f->m));
 		switch(t){
 		case Qtop:
-			if(f->mb != nil)
+			if(f->mb)
 				mboxincref(f->mb);
 			break;
 		case Qmbox:
@@ -936,7 +913,6 @@
 		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 != '.'){
 		*p = 0;
@@ -943,10 +919,10 @@
 		goto retry;
 	}
 
-	if(omb)
-		qunlock(omb);
-	else
-		qunlock(&mbllock);
+	if(f->mb)
+		qunlock(f->mb);
+	qunlock(&mbllock);
+
 	if(rv == nil)
 		return rv;
 
@@ -967,9 +943,9 @@
 			f->qid.path = PATH(0, Qtop);
 			f->qid.type = QTDIR;
 			f->qid.vers = 0;
-			qlock(&mbllock);
 			mb = f->mb;
 			f->mb = nil;
+			qlock(&mbllock);
 			mboxdecref(mb);
 			qunlock(&mbllock);
 			break;
@@ -1003,7 +979,6 @@
 	char *rv;
 	int i;
 
-sanefid(f);
 	if(f->open)
 		return Eisopen;
 
@@ -1038,7 +1013,6 @@
 	/* we only error out if no walk */
 	if(i > 0)
 		rv = nil;
-sanefid(f);
 	return rv;
 }
 
@@ -1056,10 +1030,12 @@
 
 	/* make sure we've decoded */
 	if(file == Qbody){
+		qlock(f->mb);
 		cachebody(f->mb, f->m);
 		decode(f->m);
 		convert(f->m);
 		putcache(f->mb, f->m);
+		qunlock(f->mb);
 	}
 
 	rhdr.iounit = 0;
@@ -1082,6 +1058,8 @@
 	long pos;
 	Mailbox *mb;
 
+	qlock(&mbllock);
+
 	n = 0;
 	pos = 0;
 	mkstat(&d, nil, nil, Qctl);
@@ -1088,7 +1066,7 @@
 	m = convD2M(&d, &buf[n], blen);
 	if(off <= pos){
 		if(m <= BIT16SZ || m > cnt)
-			return 0;
+			goto out;
 		n += m;
 		cnt -= m;
 	}
@@ -1095,7 +1073,9 @@
 	pos += m;
 		
 	for(mb = mbl; mb != nil; mb = mb->next){
+		qlock(mb);
 		mkstat(&d, mb, nil, Qmbox);
+		qunlock(mb);
 		m = convD2M(&d, &buf[n], blen - n);
 		if(off <= pos){
 			if(m <= BIT16SZ || m > cnt)
@@ -1105,6 +1085,8 @@
 		}
 		pos += m;
 	}
+out:
+	qlock(&mbllock);
 	return n;
 }
 
@@ -1116,6 +1098,10 @@
 	long pos;
 	Message *msg;
 
+	qlock(f->mb);
+	if(off == 0)
+		syncmbox(f->mb, 1);
+
 	n = 0;
 	if(f->mb->ctl){
 		mkstat(&d, f->mb, nil, Qmboxctl);
@@ -1123,7 +1109,7 @@
 		if(off == 0){
 			if(m <= BIT16SZ || m > cnt){
 				f->fptr = nil;
-				return 0;
+				goto out;
 			}
 			n += m;
 			cnt -= m;
@@ -1160,7 +1146,8 @@
 	f->foff = pos;
 	f->fptr = msg;
 	f->fvers = f->mb->vers;
-
+out:
+	qunlock(f->mb);
 	return n;
 }
 
@@ -1172,6 +1159,7 @@
 	long pos;
 	Message *msg;
 
+	qlock(f->mb);
 	n = 0;
 	pos = 0;
 	for(i = 0; i < Qmax; i++){
@@ -1179,7 +1167,7 @@
 		m = convD2M(&d, &buf[n], blen - n);
 		if(off <= pos){
 			if(m <= BIT16SZ || m > cnt)
-				return n;
+				goto out;
 			n += m;
 			cnt -= m;
 		}
@@ -1196,7 +1184,8 @@
 		}
 		pos += m;
 	}
-
+out:
+	qunlock(f->mb);
 	return n;
 }
 
@@ -1223,20 +1212,13 @@
 		cnt = messagesize - IOHDRSZ;
 	rhdr.data = (char*)mbuf;
 
-sanefid(f);
 	t = FILE(f->qid.path);
 	if(f->qid.type & QTDIR){
-		if(t == Qtop){
-			qlock(&mbllock);
+		if(t == Qtop)
 			n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
-			qunlock(&mbllock);
-		}else if(t == Qmbox) {
-			qlock(f->mb);
-			if(off == 0)
-				syncmbox(f->mb, 1);
+		else if(t == Qmbox)
 			n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
-			qunlock(f->mb);
-		}else if(t == Qmboxctl)
+		else if(t == Qmboxctl)
 			n = 0;
 		else
 			n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
@@ -1318,7 +1300,6 @@
 
 	t = FILE(f->qid.path);
 	rhdr.count = thdr.count;
-	sanefid(f);
 	if(thdr.count == 0)
 		return Ebadctl;
 	if(thdr.data[thdr.count - 1] == '\n')
@@ -1344,7 +1325,7 @@
 			flags = 0;
 			if(strcmp(argv[0], "create") == 0)
 				flags |= DMcreate;
-			return newmbox(file, argv[2], flags, 0);
+			return newmbox(file, argv[2], flags, nil);
 		}
 		if(strcmp(argv[0], "close") == 0){
 			if(argc < 2)
@@ -1383,10 +1364,8 @@
 				return Ebadargs;
 			for(; *argv; argv++){
 				mboxpathbuf(file, sizeof file, getlog(), *argv);
-				if(err = newmbox(file, nil, 0, 0))
+				if(err = newmbox(file, nil, 0, nil))
 					return err;
-//				if(!mb->remove)
-//					return "remove not implemented";
 				if(err = removembox(file, flags))
 					return err;
 			}
@@ -1437,23 +1416,22 @@
 {
 	Mailbox *mb;
 
-sanefid(f);
 	f->busy = 1;
 	/* coherence(); */
 	f->fid = -1;
 	f->open = 0;
 	mb = f->mb;
-	if(mb != nil)
+	if(mb){
 		qlock(mb);
+	}
 	if(f->mtop)
 		msgdecref(mb, f->mtop);
 	if(f->m)
 		msgdecref(mb, gettopmsg(mb, f->m));
 	f->m = f->mtop = nil;
-	if(mb != nil){
+	if(mb){
 		f->mb = nil;
 		qunlock(mb);
-		assert(mb->refs > 0);
 		qlock(&mbllock);
 		mboxdecref(mb);
 		qunlock(&mbllock);
@@ -1465,11 +1443,12 @@
 char *
 rremove(Fid *f)
 {
-sanefid(f);
 	if(f->m != nil){
-		if(f->m->deleted == 0)
+		qlock(f->mb);
+		if(!f->m->deleted)
 			mailplumb(f->mb, f->m, 1);
 		f->m->deleted = Deleted;
+		qunlock(f->mb);
 	}
 	return rclunk(f);
 }
@@ -1479,15 +1458,15 @@
 {
 	Dir d;
 
-sanefid(f);
-	if(FILE(f->qid.path) == Qmbox){
+	if(f->mb)
 		qlock(f->mb);
+	if(FILE(f->qid.path) == Qmbox)
 		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;
+	if(f->mb)
+		qunlock(f->mb);
 	return 0;
 }
 
@@ -1521,19 +1500,6 @@
 	return f;
 }
 
-int
-fidmboxrefs(Mailbox *mb)
-{
-	Fid *f;
-	int refs = 0;
-
-	for(f = fids; f; f = f->next){
-		if(f->mb == mb)
-			refs++;
-	}
-	return refs;
-}
-
 void
 io(void)
 {
@@ -1554,19 +1520,8 @@
 		}
 
 	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)
+		if(n <= 0)
 			return;
 		if(convM2S(mdata, n, &thdr) == 0)
 			continue;
@@ -1859,25 +1814,6 @@
 				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
--- a/sys/src/cmd/upas/fs/mbox.c
+++ b/sys/src/cmd/upas/fs/mbox.c
@@ -52,7 +52,6 @@
 	imap4mbox,
 	pop3mbox,
 	mdirmbox,
-//	planbmbox,
 	plan9mbox,
 };
 
@@ -66,7 +65,7 @@
 	int n, d, y, a;
 	Message *m, *next;
 
-	assert(canqlock(mb) == 0);
+	assert(!canqlock(mb));
 	a = mb->root->subname;
 	if(rdidxfile(mb, doplumb) == -2)
 		wridxfile(mb);
@@ -116,7 +115,7 @@
 	snprint(f1, sizeof f1, "%s", b);
 	err = newmbox(f0, nil, 0, &mb);
 	dprint("mboxrename %s %s -> %s\n", f0, f1, err);
-	if(!err && !mb->rename)
+	if(err == nil && mb->rename == nil)
 		err = "rename not supported";
 	if(err)
 		goto done;
@@ -147,11 +146,9 @@
 	henter(PATH(0, Qtop), mb->name,
 		(Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
 done:
-	if(!mb)
+	if(mb == nil)
 		return err;
 	qunlock(mb);
-//	if(err)
-//		mboxdecref(mb);
 	return err;
 }
 
@@ -175,6 +172,8 @@
 	int i;
 	Mailbox *mb, **l;
 
+	if(r)
+		*r = nil;
 	initheaders();
 	mb = emalloc(sizeof *mb);
 	mb->idxsem = 1;
@@ -1146,6 +1145,7 @@
 void
 msgdecref(Mailbox *mb, Message *m)
 {
+	assert(!canqlock(mb));
 	assert(m->refs > 0);
 	m->refs--;
 	if(m->refs == 0){
@@ -1201,6 +1201,7 @@
 	} else
 		qunlock(mb);
 }
+
 
 /* just space over \r.  sleezy but necessary for ms email. */
 int
--- a/sys/src/cmd/upas/fs/mkfile
+++ b/sys/src/cmd/upas/fs/mkfile
@@ -14,7 +14,6 @@
 	mdir.$O\
 	mtree.$O\
 	plan9.$O\
-	planb.$O\
 	pop3.$O\
 	ref.$O\
 	remove.$O\
--- a/sys/src/cmd/upas/fs/planb.c
+++ /dev/null
@@ -1,484 +1,0 @@
-/*
- * Plan B (mail2fs) mail box format.
- *
- * BUG: this does not reconstruct the
- * raw text for attachments.  So imap and others
- * will be unable to access any attachment using upas/fs.
- * As an aid, we add the path to the message directory
- * to the message body, so the user could build the path
- * for any attachment and open it.
- */
-
-#include "common.h"
-#include <ctype.h>
-#include <plumb.h>
-#include <libsec.h>
-#include "dat.h"
-
-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 int
-readmessage(Message *m, char *msg)
-{
-	int fd, n;
-	char *buf, *name, *p;
-	char hdr[128];
-	Dir *d;
-
-	buf = nil;
-	d = nil;
-	name = smprint("%s/raw", msg);
-	if(name == nil)
-		return -1;
-	if(m->filename != nil)
-		free(m->filename);
-	m->filename = strdup(name);
-	if(m->filename == nil)
-		sysfatal("malloc: %r");
-	fd = open(name, OREAD);
-	if(fd < 0)
-		goto Fail;
-	n = read(fd, hdr, sizeof(hdr)-1);
-	if(n <= 0)
-		goto Fail;
-	hdr[n] = 0;
-	close(fd);
-	fd = -1;
-	p = strchr(hdr, '\n');
-	if(p != nil)
-		*++p = 0;
-	if(strncmp(hdr, "From ", 5) != 0)
-		goto Fail;
-	free(name);
-	name = smprint("%s/text", msg);
-	if(name == nil)
-		goto Fail;
-	fd = open(name, OREAD);
-	if(fd < 0)
-		goto Fail;
-	d = dirfstat(fd);
-	if(d == nil)
-		goto Fail;
-	buf = malloc(strlen(hdr) + d->length + strlen(msg) + 10); /* few extra chars */
-	if(buf == nil)
-		goto Fail;
-	strcpy(buf, hdr);
-	p = buf+strlen(hdr);
-	n = readn(fd, p, d->length);
-	if(n < 0)
-		goto Fail;
-	sprint(p+n, "\n[%s]\n", msg);
-	n += 2 + strlen(msg) + 2;
-	close(fd);
-	free(name);
-	free(d);
-	free(m->start);
-	m->start = buf;
-	m->lim = m->end = p+n;
-	if(*(m->end-1) == '\n')
-		m->end--;
-	*m->end = 0;
-	m->bend = m->rbend = m->end;
-
-	return 0;
-Fail:
-	if(fd >= 0)
-		close(fd);
-	free(name);
-	free(buf);
-	free(d);
-	return -1;
-}
-
-/*
- * Deleted messages are kept as spam instead.
- */
-static void
-archive(Message *m)
-{
-	char *dir, *p, *nname;
-	Dir d;
-
-	dir = strdup(m->filename);
-	nname = nil;
-	if(dir == nil)
-		return;
-	p = strrchr(dir, '/');
-	if(p == nil)
-		goto Fail;
-	*p = 0;
-	p = strrchr(dir, '/');
-	if(p == nil)
-		goto Fail;
-	p++;
-	if(*p < '0' || *p > '9')
-		goto Fail;
-	nname = smprint("s.%s", p);
-	if(nname == nil)
-		goto Fail;
-	nulldir(&d);
-	d.name = nname;
-	dirwstat(dir, &d);
-Fail:
-	free(dir);
-	free(nname);
-}
-
-int
-purgembox(Mailbox *mb, int virtual)
-{
-	Message *m, *next;
-	int newdels;
-
-	/* forget about what's no longer in the mailbox */
-	newdels = 0;
-	for(m = mb->root->part; m != nil; m = next){
-		next = m->next;
-		if(m->deleted > 0 && m->refs == 0){
-			if(m->inmbox){
-				newdels++;
-				/*
-				 * virtual folders are virtual,
-				 * we do not archive
-				 */
-				if(virtual == 0)
-					archive(m);
-			}
-			delmessage(mb, m);
-		}
-	}
-	return newdels;
-}
-
-static int
-mustshow(char* name)
-{
-	if(isdigit(name[0]))
-		return 1;
-	if(0 && name[0] == 'a' && name[1] == '.')
-		return 1;
-	if(0 && name[0] == 's' && name[1] == '.')
-		return 1;
-	return 0;
-}
-
-static int
-readpbmessage(Mailbox *mb, char *msg, int doplumb, int *nnew)
-{
-	Message *m, **l;
-	char *x, *p;
-
-	m = newmessage(mb->root);
-	m->mallocd = 1;
-	m->inmbox = 1;
-	if(readmessage(m, msg) < 0){
-		unnewmessage(mb, mb->root, m);
-		return -1;
-	}
-	for(l = &mb->root->part; *l != nil; l = &(*l)->next)
-		if(strcmp((*l)->filename, m->filename) == 0 &&
-		    *l != m){
-			if((*l)->deleted < 0)
-				(*l)->deleted = 0;
-			delmessage(mb, m);
-			mb->root->subname--;
-			return -1;
-		}
-	m->header = m->end;
-	if(x = strchr(m->start, '\n'))
-		m->header = x + 1;
-	if(p = parseunix(m))
-		sysfatal("%s:%s naked From in body? [%s]", mb->path, (*l)->filename, p);
-	m->mheader = m->mhend = m->header;
-	parse(mb, m, 0, 0);
-	if(m != *l && m->deleted != Dup){
-		logmsg(m, "new");
-		newcachehash(mb, m, doplumb);
-		putcache(mb, m);
-		nnew[0]++;
-	}
-
-	/* chain in */
-	*l = m;
-	if(doplumb)
-		mailplumb(mb, m, 0);
-	return 0;
-}
-
-static int
-dcmp(Dir *a, Dir *b)
-{
-	char *an, *bn;
-
-	an = a->name;
-	bn = b->name;
-	if(an[0] != 0 && an[1] == '.')
-		an += 2;
-	if(bn[0] != 0 && bn[1] == '.')
-		bn += 2;
-	return strcmp(an, bn);
-}
-
-static char*
-readpbmbox(Mailbox *mb, int doplumb, int *new)
-{
-	char *month, *msg;
-	int fd, i, j, nd, nmd;
-	Dir *d, *md;
-	static char err[ERRMAX];
-
-	fd = open(mb->path, OREAD);
-	if(fd < 0){
-		errstr(err, sizeof err);
-		return err;
-	}
-	nd = dirreadall(fd, &d);
-	close(fd);
-	if(nd > 0)
-		qsort(d, nd, sizeof d[0], (int (*)(void*, void*))dcmp);
-	for(i = 0; i < nd; i++){
-		month = smprint("%s/%s", mb->path, d[i].name);
-		if(month == nil)
-			break;
-		fd = open(month, OREAD);
-		if(fd < 0){
-			fprint(2, "%s: %s: %r\n", argv0, month);
-			free(month);
-			continue;
-		}
-		md = dirfstat(fd);
-		if(md != nil && (md->qid.type & QTDIR) != 0){
-			free(md);
-			md = nil;
-			nmd = dirreadall(fd, &md);
-			for(j = 0; j < nmd; j++)
-				if(mustshow(md[j].name)){
-					msg = smprint("%s/%s", month, md[j].name);
-					readpbmessage(mb, msg, doplumb, new);
-					free(msg);
-				}
-		}
-		close(fd);
-		free(month);
-		free(md);
-		md = nil;
-	}
-	free(d);
-	return nil;
-}
-
-static char*
-readpbvmbox(Mailbox *mb, int doplumb, int *new)
-{
-	char *data, *ln, *p, *nln, *msg;
-	int fd, nr;
-	long sz;
-	Dir *d;
-	static char err[ERRMAX];
-
-	fd = open(mb->path, OREAD);
-	if(fd < 0){
-		errstr(err, sizeof err);
-		return err;
-	}
-	d = dirfstat(fd);
-	if(d == nil){
-		errstr(err, sizeof err);
-		return err;
-	}
-	sz = d->length;
-	free(d);
-	if(sz > 2 * 1024 * 1024){
-		sz = 2 * 1024 * 1024;
-		fprint(2, "upas/fs: %s: bug: folder too big\n", mb->path);
-	}
-	data = malloc(sz+1);
-	if(data == nil){
-		errstr(err, sizeof err);
-		return err;
-	}
-	nr = readn(fd, data, sz);
-	close(fd);
-	if(nr < 0){
-		errstr(err, sizeof err);
-		free(data);
-		return err;
-	}
-	data[nr] = 0;
-
-	for(ln = data; *ln != 0; ln = nln){
-		nln = strchr(ln, '\n');
-		if(nln != nil)
-			*nln++ = 0;
-		else
-			nln = ln + strlen(ln);
-		p = strchr(ln , ' ');
-		if(p != nil)
-			*p = 0;
-		p = strchr(ln, '\t');
-		if(p != nil)
-			*p = 0;
-		p = strstr(ln, "/text");
-		if(p != nil)
-			*p = 0;
-		msg = smprint("/mail/box/%s/msgs/%s", user, ln);
-		if(msg == nil){
-			fprint(2, "upas/fs: malloc: %r\n");
-			continue;
-		}
-		readpbmessage(mb, msg, doplumb, new);
-		free(msg);
-	}
-	free(data);
-	return nil;
-}
-
-static char*
-readmbox(Mailbox *mb, int doplumb, int virt, int *new)
-{
-	char *mberr;
-	int fd;
-	Dir *d;
-	Message *m;
-	static char err[128];
-
-	if(debug)
-		fprint(2, "read mbox %s\n", mb->path);
-	fd = open(mb->path, OREAD);
-	if(fd < 0){
-		errstr(err, sizeof(err));
-		return err;
-	}
-
-	d = dirfstat(fd);
-	if(d == nil){
-		close(fd);
-		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);
-			free(d);
-			return nil;
-		}
-		free(mb->d);
-	}
-	close(fd);
-	mb->d = d;
-	mb->vers++;
-	henter(PATH(0, Qtop), mb->name,
-		(Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);
-	snprint(err, sizeof err, "reading '%s'", mb->path);
-	logmsg(nil, err, nil);
-
-	for(m = mb->root->part; m != nil; m = m->next)
-		if(m->deleted == 0)
-			m->deleted = -1;
-	if(virt == 0)
-		mberr = readpbmbox(mb, doplumb, new);
-	else
-		mberr = readpbvmbox(mb, doplumb, new);
-
-	/*
-	 * messages removed from the mbox; flag them to go.
-	 */
-	for(m = mb->root->part; m != nil; m = m->next)
-		if(m->deleted < 0 && doplumb){
-			delmessage(mb, m);
-			if(doplumb)
-				mailplumb(mb, m, 1);
-		}
-	logmsg(nil, "mbox read");
-	return mberr;
-}
-
-static char*
-mbsync(Mailbox *mb, int doplumb, int *new)
-{
-	char *rv;
-
-	rv = readmbox(mb, doplumb, 0, new);
-	purgembox(mb, 0);
-	return rv;
-}
-
-static char*
-mbvsync(Mailbox *mb, int doplumb, int *new)
-{
-	char *rv;
-
-	rv = readmbox(mb, doplumb, 1, new);
-	purgembox(mb, 1);
-	return rv;
-}
-
-char*
-planbmbox(Mailbox *mb, char *path)
-{
-	char *list;
-	static char err[64];
-
-	if(access(path, AEXIST) < 0)
-		return Enotme;
-	list = smprint("%s/list", path);
-	if(access(list, AEXIST) < 0){
-		free(list);
-		return Enotme;
-	}
-	free(list);
-	mb->sync = mbsync;
-	if(debug)
-		fprint(2, "planb mbox %s\n", path);
-	return nil;
-}
-
-char*
-planbvmbox(Mailbox *mb, char *path)
-{
-	int fd, nr, i;
-	char buf[64];
-	static char err[64];
-
-	fd = open(path, OREAD);
-	if(fd < 0)
-		return Enotme;
-	nr = read(fd, buf, sizeof(buf)-1);
-	close(fd);
-	if(nr < 7)
-		return Enotme;
-	buf[nr] = 0;
-	for(i = 0; i < 6; i++)
-		if(buf[i] < '0' || buf[i] > '9')
-			return Enotme;
-	if(buf[6] != '/')
-		return Enotme;
-	mb->sync = mbvsync;
-	if(debug)
-		fprint(2, "planb virtual mbox %s\n", path);
-	return nil;
-}