1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651 |
- #include "common.h"
- #include <auth.h>
- #include <fcall.h>
- #include <libsec.h>
- #include <ctype.h>
- #include "dat.h"
- enum
- {
- OPERM = 0x3, // mask of all permission types in open mode
- };
- typedef struct Fid Fid;
- struct Fid
- {
- Qid qid;
- short busy;
- short open;
- int fid;
- Fid *next;
- Mailbox *mb;
- Message *m;
- 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
- };
- 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);
- void *erealloc(void*, ulong);
- 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*),
- *rattach(Fid*), *rwalk(Fid*),
- *ropen(Fid*), *rcreate(Fid*),
- *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
- *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
- *rversion(Fid*);
- char *(*fcalls[])(Fid*) = {
- [Tflush] rflush,
- [Tversion] rversion,
- [Tauth] rauth,
- [Tattach] rattach,
- [Twalk] rwalk,
- [Topen] ropen,
- [Tcreate] rcreate,
- [Tread] rread,
- [Twrite] rwrite,
- [Tclunk] rclunk,
- [Tremove] rremove,
- [Tstat] rstat,
- [Twstat] rwstat,
- };
- char Eperm[] = "permission denied";
- char Enotdir[] = "not a directory";
- char Enoauth[] = "upas/fs: authentication not required";
- char Enotexist[] = "file does not exist";
- char Einuse[] = "file in use";
- char Eexist[] = "file exists";
- char Enotowner[] = "not owner";
- 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 *dirtab[] =
- {
- [Qdir] ".",
- [Qbody] "body",
- [Qbcc] "bcc",
- [Qcc] "cc",
- [Qdate] "date",
- [Qdigest] "digest",
- [Qdisposition] "disposition",
- [Qfilename] "filename",
- [Qfrom] "from",
- [Qheader] "header",
- [Qinfo] "info",
- [Qinreplyto] "inreplyto",
- [Qlines] "lines",
- [Qmimeheader] "mimeheader",
- [Qmessageid] "messageid",
- [Qraw] "raw",
- [Qrawunix] "rawunix",
- [Qrawbody] "rawbody",
- [Qrawheader] "rawheader",
- [Qreplyto] "replyto",
- [Qsender] "sender",
- [Qsubject] "subject",
- [Qto] "to",
- [Qtype] "type",
- [Qunixdate] "unixdate",
- [Qunixheader] "unixheader",
- [Qctl] "ctl",
- [Qmboxctl] "ctl",
- };
- enum
- {
- Hsize= 1277,
- };
- Hash *htab[Hsize];
- int debug;
- int fflag;
- int logging;
- void
- usage(void)
- {
- fprint(2, "usage: upas/fs [-bdlnps] [-f mboxfile] [-m mountpoint]\n");
- exits("usage");
- }
- void
- notifyf(void *a, char *s)
- {
- USED(a);
- if(strncmp(s, "interrupt", 9) == 0)
- noted(NCONT);
- noted(NDFLT);
- }
- void
- main(int argc, char *argv[])
- {
- int p[2], std, nodflt;
- char maildir[128];
- char mbox[128];
- char *mboxfile, *err;
- char srvfile[64];
- int srvpost;
- rfork(RFNOTEG);
- mntpt = nil;
- fflag = 0;
- mboxfile = nil;
- std = 0;
- nodflt = 0;
- srvpost = 0;
- ARGBEGIN{
- case 'b':
- biffing = 1;
- break;
- case 'f':
- fflag = 1;
- mboxfile = EARGF(usage());
- break;
- case 'm':
- mntpt = EARGF(usage());
- break;
- case 'd':
- debug = 1;
- break;
- case 'p':
- plumbing = 0;
- break;
- case 's':
- srvpost = 1;
- break;
- case 'l':
- logging = 1;
- break;
- case 'n':
- nodflt = 1;
- break;
- default:
- usage();
- }ARGEND
- if(argc)
- usage();
- if(pipe(p) < 0)
- error("pipe failed");
- mfd[0] = p[0];
- mfd[1] = p[0];
- notify(notifyf);
- strcpy(user, getuser());
- if(mntpt == nil){
- snprint(maildir, sizeof(maildir), "/mail/fs");
- mntpt = maildir;
- }
- if(mboxfile == nil && !nodflt){
- 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)
- sysfatal("opening mailbox: %s", err);
- }
- switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){
- case -1:
- error("fork");
- case 0:
- henter(PATH(0, Qtop), dirtab[Qctl],
- (Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil);
- close(p[1]);
- io();
- postnote(PNGROUP, getpid(), "die yankee pig dog");
- break;
- default:
- close(p[0]); /* don't deadlock if child fails */
- if(srvpost){
- sprint(srvfile, "/srv/upasfs.%s", user);
- post(srvfile, "upasfs", p[1]);
- } else {
- if(mount(p[1], -1, mntpt, MREPL, "") < 0)
- error("mount failed");
- }
- }
- exits(0);
- }
- static int
- fileinfo(Message *m, int t, char **pp)
- {
- char *p;
- int len;
- p = "";
- len = 0;
- switch(t){
- case Qbody:
- p = m->body;
- len = m->bend - m->body;
- break;
- case Qbcc:
- if(m->bcc822){
- p = s_to_c(m->bcc822);
- len = strlen(p);
- }
- break;
- case Qcc:
- if(m->cc822){
- p = s_to_c(m->cc822);
- len = strlen(p);
- }
- break;
- case Qdisposition:
- switch(m->disposition){
- case Dinline:
- p = "inline";
- break;
- case Dfile:
- 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);
- }
- break;
- case Qfilename:
- if(m->filename){
- p = s_to_c(m->filename);
- len = strlen(p);
- }
- break;
- case Qinreplyto:
- if(m->inreplyto822){
- p = s_to_c(m->inreplyto822);
- len = strlen(p);
- }
- break;
- case Qmessageid:
- if(m->messageid822){
- p = s_to_c(m->messageid822);
- len = strlen(p);
- }
- 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);
- }
- break;
- case Qheader:
- p = m->header;
- len = headerlen(m);
- break;
- case Qlines:
- p = m->lines;
- if(*p == 0)
- countlines(m);
- len = strlen(m->lines);
- break;
- case Qraw:
- 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;
- break;
- case Qrawunix:
- p = m->start;
- len = m->end - p;
- break;
- case Qrawbody:
- p = m->rbody;
- len = m->rbend - p;
- break;
- case Qrawheader:
- p = m->header;
- len = m->hend - p;
- break;
- case Qmimeheader:
- 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);
- }
- break;
- case Qsender:
- if(m->sender822){
- p = s_to_c(m->sender822);
- len = strlen(p);
- }
- break;
- case Qsubject:
- p = nil;
- if(m->subject822){
- p = s_to_c(m->subject822);
- len = strlen(p);
- }
- break;
- case Qto:
- if(m->to822){
- p = s_to_c(m->to822);
- len = strlen(p);
- }
- break;
- case Qtype:
- if(m->type){
- p = s_to_c(m->type);
- len = strlen(p);
- }
- break;
- case Qunixdate:
- if(m->unixdate){
- p = s_to_c(m->unixdate);
- len = strlen(p);
- }
- break;
- case Qunixheader:
- if(m->unixheader){
- p = s_to_c(m->unixheader);
- len = s_len(m->unixheader);
- }
- break;
- case Qdigest:
- if(m->sdigest){
- p = s_to_c(m->sdigest);
- len = strlen(p);
- }
- break;
- }
- *pp = p;
- return len;
- }
- int infofields[] = {
- Qfrom,
- Qto,
- Qcc,
- Qreplyto,
- Qunixdate,
- Qsubject,
- Qtype,
- Qdisposition,
- Qfilename,
- Qdigest,
- Qbcc,
- Qinreplyto,
- Qdate,
- Qsender,
- Qmessageid,
- Qlines,
- -1,
- };
- static int
- readinfo(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;
- n -= off;
- off = 0;
- }
- if(n > count - len)
- n = count - len;
- if(buf)
- memmove(buf+len, p, n);
- len += n;
- }
- s_free(s);
- return len;
- }
- static void
- mkstat(Dir *d, Mailbox *mb, Message *m, int t)
- {
- char *p;
- d->uid = user;
- d->gid = user;
- d->muid = user;
- d->mode = 0444;
- d->qid.vers = 0;
- 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 {
- d->atime = time(0);
- d->mtime = d->atime;
- }
- switch(t){
- case Qtop:
- d->name = ".";
- d->mode = DMDIR|0555;
- d->atime = d->mtime = time(0);
- d->length = 0;
- d->qid.path = PATH(0, Qtop);
- d->qid.type = QTDIR;
- break;
- case Qmbox:
- d->name = mb->name;
- d->mode = DMDIR|0555;
- d->length = 0;
- d->qid.path = PATH(mb->id, Qmbox);
- d->qid.type = QTDIR;
- d->qid.vers = mb->vers;
- break;
- case Qdir:
- d->name = m->name;
- d->mode = DMDIR|0555;
- d->length = 0;
- d->qid.path = PATH(m->id, Qdir);
- d->qid.type = QTDIR;
- break;
- case Qctl:
- d->name = dirtab[t];
- d->mode = 0666;
- d->atime = d->mtime = time(0);
- d->length = 0;
- d->qid.path = PATH(0, Qctl);
- break;
- case Qmboxctl:
- d->name = dirtab[t];
- d->mode = 0222;
- d->atime = d->mtime = time(0);
- d->length = 0;
- d->qid.path = PATH(mb->id, Qmboxctl);
- break;
- case Qinfo:
- d->name = dirtab[t];
- d->length = readinfo(m, nil, 0, 1<<30);
- d->qid.path = PATH(m->id, t);
- break;
- default:
- d->name = dirtab[t];
- d->length = fileinfo(m, t, &p);
- d->qid.path = PATH(m->id, t);
- break;
- }
- }
- char*
- rversion(Fid*)
- {
- Fid *f;
- if(thdr.msize < 256)
- return "max messagesize too small";
- if(thdr.msize < messagesize)
- messagesize = thdr.msize;
- rhdr.msize = messagesize;
- if(strncmp(thdr.version, "9P2000", 6) != 0)
- return "unknown 9P version";
- else
- rhdr.version = "9P2000";
- for(f = fids; f; f = f->next)
- if(f->busy)
- rclunk(f);
- return nil;
- }
- char*
- rauth(Fid*)
- {
- return Enoauth;
- }
- char*
- rflush(Fid *f)
- {
- USED(f);
- return 0;
- }
- char*
- rattach(Fid *f)
- {
- f->busy = 1;
- f->m = nil;
- f->mb = nil;
- f->qid.path = PATH(0, Qtop);
- f->qid.type = QTDIR;
- f->qid.vers = 0;
- rhdr.qid = f->qid;
- if(strcmp(thdr.uname, user) != 0)
- return Eperm;
- return 0;
- }
- static Fid*
- doclone(Fid *f, int nfid)
- {
- Fid *nf;
- nf = newfid(nfid);
- if(nf->busy)
- 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);
- }
- nf->qid = f->qid;
- return nf;
- }
- char*
- dowalk(Fid *f, char *name)
- {
- int t;
- Mailbox *omb, *mb;
- char *rv, *p;
- Hash *h;
- t = FILE(f->qid.path);
- rv = Enotexist;
- omb = f->mb;
- if(omb)
- qlock(omb);
- else
- qlock(&mbllock);
- // this must catch everything except . and ..
- retry:
- h = hlook(f->qid.path, name);
- if(h != nil){
- f->mb = h->mb;
- f->m = h->m;
- switch(t){
- case Qtop:
- if(f->mb != nil)
- mboxincref(f->mb);
- break;
- case Qmbox:
- if(f->m){
- msgincref(f->m);
- f->mtop = f->m;
- }
- break;
- }
- f->qid = h->qid;
- rv = nil;
- } else if((p = strchr(name, '.')) != nil && *name != '.'){
- *p = 0;
- goto retry;
- }
- if(omb)
- qunlock(omb);
- else
- qunlock(&mbllock);
- if(rv == nil)
- return rv;
- if(strcmp(name, ".") == 0)
- return nil;
- if(f->qid.type != QTDIR)
- return Enotdir;
- if(strcmp(name, "..") == 0){
- switch(t){
- case Qtop:
- f->qid.path = PATH(0, Qtop);
- f->qid.type = QTDIR;
- f->qid.vers = 0;
- break;
- case Qmbox:
- f->qid.path = PATH(0, Qtop);
- f->qid.type = QTDIR;
- f->qid.vers = 0;
- qlock(&mbllock);
- mb = f->mb;
- f->mb = nil;
- mboxdecref(mb);
- qunlock(&mbllock);
- break;
- case Qdir:
- qlock(f->mb);
- if(f->m->whole == f->mb->root){
- 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);
- f->m = f->mtop = nil;
- } else {
- f->m = f->m->whole;
- f->qid.path = PATH(f->m->id, Qdir);
- f->qid.type = QTDIR;
- }
- qunlock(f->mb);
- break;
- }
- rv = nil;
- }
- return rv;
- }
- char*
- rwalk(Fid *f)
- {
- Fid *nf;
- char *rv;
- int i;
- if(f->open)
- return Eisopen;
- rhdr.nwqid = 0;
- nf = nil;
- /* clone if requested */
- if(thdr.newfid != thdr.fid){
- nf = doclone(f, thdr.newfid);
- if(nf == nil)
- return "new fid in use";
- f = nf;
- }
- /* if it's just a clone, return */
- if(thdr.nwname == 0 && nf != nil)
- return nil;
- /* walk each element */
- rv = nil;
- for(i = 0; i < thdr.nwname; i++){
- rv = dowalk(f, thdr.wname[i]);
- if(rv != nil){
- if(nf != nil)
- rclunk(nf);
- break;
- }
- rhdr.wqid[i] = f->qid;
- }
- rhdr.nwqid = i;
- /* we only error out if no walk */
- if(i > 0)
- rv = nil;
- return rv;
- }
- 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)
- return Eperm;
- // make sure we've decoded
- if(file == Qbody){
- if(f->m->decoded == 0)
- decode(f->m);
- if(f->m->converted == 0)
- convert(f->m);
- }
- rhdr.iounit = 0;
- rhdr.qid = f->qid;
- f->open = 1;
- return 0;
- }
- char *
- rcreate(Fid*)
- {
- return Eperm;
- }
- int
- readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
- {
- Dir d;
- int m, n;
- long pos;
- Mailbox *mb;
- n = 0;
- pos = 0;
- mkstat(&d, nil, nil, Qctl);
- m = convD2M(&d, &buf[n], blen);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- return 0;
- n += m;
- cnt -= m;
- }
- pos += m;
-
- for(mb = mbl; mb != nil; mb = mb->next){
- mkstat(&d, mb, nil, Qmbox);
- m = convD2M(&d, &buf[n], blen-n);
- if(off <= pos){
- if(m <= BIT16SZ || m > cnt)
- break;
- n += m;
- cnt -= m;
- }
- pos += m;
- }
- return n;
- }
- int
- readmboxdir(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;
- }
- int
- readmsgdir(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;
- }
- 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)
- {
- 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");
- }
- }
- void
- reader(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);
- }
- }
- int
- newid(void)
- {
- int rv;
- static int id;
- static Lock idlock;
- lock(&idlock);
- rv = ++id;
- unlock(&idlock);
- return rv;
- }
- void
- error(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
- */
- void
- readignore(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);
- }
- int
- ignore(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;
- }
- 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;
- 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;
- }
- 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
- hash(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;
- }
- void
- henter(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);
- }
- void
- hfree(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);
- }
- int
- hashmboxrefs(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;
- }
- void
- checkmboxrefs(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);
- }
- void
- post(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);
- }
|