fs.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683
  1. #include "common.h"
  2. #include <auth.h>
  3. #include <fcall.h>
  4. #include <libsec.h>
  5. #include "dat.h"
  6. enum
  7. {
  8. OPERM = 0x3, // mask of all permission types in open mode
  9. };
  10. typedef struct Fid Fid;
  11. struct Fid
  12. {
  13. Qid qid;
  14. short busy;
  15. short open;
  16. int fid;
  17. Fid *next;
  18. Mailbox *mb;
  19. Message *m;
  20. Message *mtop; // top level message
  21. //finger pointers to speed up reads of large directories
  22. long foff; // offset/DIRLEN of finger
  23. Message *fptr; // pointer to message at off
  24. int fvers; // mailbox version when finger was saved
  25. };
  26. ulong path; // incremented for each new file
  27. Fid *fids;
  28. int mfd[2];
  29. char user[Elemlen];
  30. int messagesize = 4*1024*IOHDRSZ;
  31. uchar mdata[8*1024*IOHDRSZ];
  32. uchar mbuf[8*1024*IOHDRSZ];
  33. Fcall thdr;
  34. Fcall rhdr;
  35. int fflg;
  36. char *mntpt;
  37. int biffing;
  38. int plumbing = 1;
  39. QLock mbllock;
  40. Mailbox *mbl;
  41. Fid *newfid(int);
  42. void error(char*);
  43. void io(void);
  44. void *erealloc(void*, ulong);
  45. void *emalloc(ulong);
  46. void usage(void);
  47. void reader(void);
  48. int readheader(Message*, char*, int, int);
  49. int cistrncmp(char*, char*, int);
  50. int tokenconvert(String*, char*, int);
  51. String* stringconvert(String*, char*, int);
  52. void post(char*, char*, int);
  53. char *rflush(Fid*), *rauth(Fid*),
  54. *rattach(Fid*), *rwalk(Fid*),
  55. *ropen(Fid*), *rcreate(Fid*),
  56. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  57. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*),
  58. *rversion(Fid*);
  59. char *(*fcalls[])(Fid*) = {
  60. [Tflush] rflush,
  61. [Tversion] rversion,
  62. [Tauth] rauth,
  63. [Tattach] rattach,
  64. [Twalk] rwalk,
  65. [Topen] ropen,
  66. [Tcreate] rcreate,
  67. [Tread] rread,
  68. [Twrite] rwrite,
  69. [Tclunk] rclunk,
  70. [Tremove] rremove,
  71. [Tstat] rstat,
  72. [Twstat] rwstat,
  73. };
  74. char Eperm[] = "permission denied";
  75. char Enotdir[] = "not a directory";
  76. char Enoauth[] = "upas/fs: authentication not required";
  77. char Enotexist[] = "file does not exist";
  78. char Einuse[] = "file in use";
  79. char Eexist[] = "file exists";
  80. char Enotowner[] = "not owner";
  81. char Eisopen[] = "file already open for I/O";
  82. char Excl[] = "exclusive use file already open";
  83. char Ename[] = "illegal name";
  84. char Ebadctl[] = "unknown control message";
  85. char *dirtab[] =
  86. {
  87. [Qdir] ".",
  88. [Qbody] "body",
  89. [Qbcc] "bcc",
  90. [Qcc] "cc",
  91. [Qdate] "date",
  92. [Qdigest] "digest",
  93. [Qdisposition] "disposition",
  94. [Qfilename] "filename",
  95. [Qfrom] "from",
  96. [Qheader] "header",
  97. [Qinfo] "info",
  98. [Qinreplyto] "inreplyto",
  99. [Qlines] "lines",
  100. [Qmimeheader] "mimeheader",
  101. [Qmessageid] "messageid",
  102. [Qraw] "raw",
  103. [Qrawunix] "rawunix",
  104. [Qrawbody] "rawbody",
  105. [Qrawheader] "rawheader",
  106. [Qreplyto] "replyto",
  107. [Qsender] "sender",
  108. [Qsubject] "subject",
  109. [Qto] "to",
  110. [Qtype] "type",
  111. [Qunixdate] "unixdate",
  112. [Qunixheader] "unixheader",
  113. [Qctl] "ctl",
  114. [Qmboxctl] "ctl",
  115. };
  116. enum
  117. {
  118. Hsize= 1277,
  119. };
  120. Hash *htab[Hsize];
  121. int debug;
  122. int fflag;
  123. int logging;
  124. void
  125. usage(void)
  126. {
  127. fprint(2, "usage: %s [-b -m mountpoint]\n", argv0);
  128. exits("usage");
  129. }
  130. void
  131. notifyf(void *a, char *s)
  132. {
  133. USED(a);
  134. if(strncmp(s, "interrupt", 9) == 0)
  135. noted(NCONT);
  136. noted(NDFLT);
  137. }
  138. void
  139. main(int argc, char *argv[])
  140. {
  141. int p[2], std, nodflt;
  142. char maildir[128];
  143. char mbox[128];
  144. char *mboxfile, *err;
  145. char srvfile[64];
  146. int srvpost;
  147. rfork(RFNOTEG);
  148. mntpt = nil;
  149. fflag = 0;
  150. mboxfile = nil;
  151. std = 0;
  152. nodflt = 0;
  153. srvpost = 0;
  154. ARGBEGIN{
  155. case 'b':
  156. biffing = 1;
  157. break;
  158. case 'f':
  159. fflag = 1;
  160. mboxfile = ARGF();
  161. break;
  162. case 'm':
  163. mntpt = ARGF();
  164. break;
  165. case 'd':
  166. debug = 1;
  167. break;
  168. case 'p':
  169. plumbing = 0;
  170. break;
  171. case 's':
  172. srvpost = 1;
  173. break;
  174. case 'l':
  175. logging = 1;
  176. break;
  177. case 'n':
  178. nodflt = 1;
  179. break;
  180. default:
  181. usage();
  182. }ARGEND
  183. if(pipe(p) < 0)
  184. error("pipe failed");
  185. mfd[0] = p[0];
  186. mfd[1] = p[0];
  187. notify(notifyf);
  188. strcpy(user, getuser());
  189. if(mntpt == nil){
  190. snprint(maildir, sizeof(maildir), "/mail/fs");
  191. mntpt = maildir;
  192. }
  193. if(mboxfile == nil && !nodflt){
  194. snprint(mbox, sizeof(mbox), "/mail/box/%s/mbox", user);
  195. mboxfile = mbox;
  196. std = 1;
  197. }
  198. if(debug)
  199. fmtinstall('F', fcallfmt);
  200. if(mboxfile != nil){
  201. err = newmbox(mboxfile, "mbox", std);
  202. if(err != nil)
  203. sysfatal("opening mailbox: %s", err);
  204. }
  205. switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG|RFREND)){
  206. case -1:
  207. error("fork");
  208. case 0:
  209. henter(PATH(0, Qtop), dirtab[Qctl],
  210. (Qid){PATH(0, Qctl), 0, QTFILE}, nil, nil);
  211. close(p[1]);
  212. io();
  213. postnote(PNGROUP, getpid(), "die yankee pig dog");
  214. break;
  215. default:
  216. close(p[0]); /* don't deadlock if child fails */
  217. if(srvpost){
  218. sprint(srvfile, "/srv/upasfs.%s", user);
  219. post(srvfile, "upasfs", p[1]);
  220. } else {
  221. if(mount(p[1], -1, mntpt, MREPL, "") < 0)
  222. error("mount failed");
  223. }
  224. }
  225. exits(0);
  226. }
  227. static int
  228. fileinfo(Message *m, int t, char **pp)
  229. {
  230. char *p;
  231. int len;
  232. p = "";
  233. len = 0;
  234. switch(t){
  235. case Qbody:
  236. p = m->body;
  237. len = m->bend - m->body;
  238. break;
  239. case Qbcc:
  240. if(m->bcc822){
  241. p = s_to_c(m->bcc822);
  242. len = strlen(p);
  243. }
  244. break;
  245. case Qcc:
  246. if(m->cc822){
  247. p = s_to_c(m->cc822);
  248. len = strlen(p);
  249. }
  250. break;
  251. case Qdisposition:
  252. switch(m->disposition){
  253. case Dinline:
  254. p = "inline";
  255. break;
  256. case Dfile:
  257. p = "file";
  258. break;
  259. }
  260. len = strlen(p);
  261. break;
  262. case Qdate:
  263. if(m->date822){
  264. p = s_to_c(m->date822);
  265. len = strlen(p);
  266. } else if(m->unixdate != nil){
  267. p = s_to_c(m->unixdate);
  268. len = strlen(p);
  269. }
  270. break;
  271. case Qfilename:
  272. if(m->filename){
  273. p = s_to_c(m->filename);
  274. len = strlen(p);
  275. }
  276. break;
  277. case Qinreplyto:
  278. if(m->inreplyto822){
  279. p = s_to_c(m->inreplyto822);
  280. len = strlen(p);
  281. }
  282. break;
  283. case Qmessageid:
  284. if(m->messageid822){
  285. p = s_to_c(m->messageid822);
  286. len = strlen(p);
  287. }
  288. break;
  289. case Qfrom:
  290. if(m->from822){
  291. p = s_to_c(m->from822);
  292. len = strlen(p);
  293. } else if(m->unixfrom != nil){
  294. p = s_to_c(m->unixfrom);
  295. len = strlen(p);
  296. }
  297. break;
  298. case Qheader:
  299. p = m->header;
  300. len = headerlen(m);
  301. break;
  302. case Qlines:
  303. p = m->lines;
  304. if(*p == 0)
  305. countlines(m);
  306. len = strlen(m->lines);
  307. break;
  308. case Qraw:
  309. p = m->start;
  310. if(strncmp(m->start, "From ", 5) == 0){
  311. p = strchr(p, '\n');
  312. if(p == nil)
  313. p = m->start;
  314. else
  315. p++;
  316. }
  317. len = m->end - p;
  318. break;
  319. case Qrawunix:
  320. p = m->start;
  321. len = m->end - p;
  322. break;
  323. case Qrawbody:
  324. p = m->rbody;
  325. len = m->rbend - p;
  326. break;
  327. case Qrawheader:
  328. p = m->header;
  329. len = m->hend - p;
  330. break;
  331. case Qmimeheader:
  332. p = m->mheader;
  333. len = m->mhend - p;
  334. break;
  335. case Qreplyto:
  336. p = nil;
  337. if(m->replyto822 != nil){
  338. p = s_to_c(m->replyto822);
  339. len = strlen(p);
  340. } else if(m->from822 != nil){
  341. p = s_to_c(m->from822);
  342. len = strlen(p);
  343. } else if(m->sender822 != nil){
  344. p = s_to_c(m->sender822);
  345. len = strlen(p);
  346. } else if(m->unixfrom != nil){
  347. p = s_to_c(m->unixfrom);
  348. len = strlen(p);
  349. }
  350. break;
  351. case Qsender:
  352. if(m->sender822){
  353. p = s_to_c(m->sender822);
  354. len = strlen(p);
  355. }
  356. break;
  357. case Qsubject:
  358. p = nil;
  359. if(m->subject822){
  360. p = s_to_c(m->subject822);
  361. len = strlen(p);
  362. }
  363. break;
  364. case Qto:
  365. if(m->to822){
  366. p = s_to_c(m->to822);
  367. len = strlen(p);
  368. }
  369. break;
  370. case Qtype:
  371. if(m->type){
  372. p = s_to_c(m->type);
  373. len = strlen(p);
  374. }
  375. break;
  376. case Qunixdate:
  377. if(m->unixdate){
  378. p = s_to_c(m->unixdate);
  379. len = strlen(p);
  380. }
  381. break;
  382. case Qunixheader:
  383. if(m->unixheader){
  384. p = s_to_c(m->unixheader);
  385. len = s_len(m->unixheader);
  386. }
  387. break;
  388. case Qdigest:
  389. if(m->sdigest){
  390. p = s_to_c(m->sdigest);
  391. len = strlen(p);
  392. }
  393. break;
  394. }
  395. *pp = p;
  396. return len;
  397. }
  398. int infofields[] = {
  399. Qfrom,
  400. Qto,
  401. Qcc,
  402. Qreplyto,
  403. Qunixdate,
  404. Qsubject,
  405. Qtype,
  406. Qdisposition,
  407. Qfilename,
  408. Qdigest,
  409. Qbcc,
  410. Qinreplyto,
  411. Qdate,
  412. Qsender,
  413. Qmessageid,
  414. Qlines,
  415. -1,
  416. };
  417. static int
  418. readinfo(Message *m, char *buf, long off, int count)
  419. {
  420. char *p;
  421. int len, i, n;
  422. String *s;
  423. s = s_new();
  424. len = 0;
  425. for(i = 0; len < count && infofields[i] >= 0; i++){
  426. n = fileinfo(m, infofields[i], &p);
  427. s = stringconvert(s, p, n);
  428. s_append(s, "\n");
  429. p = s_to_c(s);
  430. n = strlen(p);
  431. if(off > 0){
  432. if(off >= n){
  433. off -= n;
  434. continue;
  435. }
  436. p += off;
  437. n -= off;
  438. off = 0;
  439. }
  440. if(n > count - len)
  441. n = count - len;
  442. if(buf)
  443. memmove(buf+len, p, n);
  444. len += n;
  445. }
  446. s_free(s);
  447. return len;
  448. }
  449. static void
  450. mkstat(Dir *d, Mailbox *mb, Message *m, int t)
  451. {
  452. char *p;
  453. d->uid = user;
  454. d->gid = user;
  455. d->muid = user;
  456. d->mode = 0444;
  457. d->qid.vers = 0;
  458. d->qid.type = QTFILE;
  459. d->type = 0;
  460. d->dev = 0;
  461. if(mb != nil && mb->d != nil){
  462. d->atime = mb->d->atime;
  463. d->mtime = mb->d->mtime;
  464. } else {
  465. d->atime = time(0);
  466. d->mtime = d->atime;
  467. }
  468. switch(t){
  469. case Qtop:
  470. d->name = ".";
  471. d->mode = DMDIR|0555;
  472. d->atime = d->mtime = time(0);
  473. d->length = 0;
  474. d->qid.path = PATH(0, Qtop);
  475. d->qid.type = QTDIR;
  476. break;
  477. case Qmbox:
  478. d->name = mb->name;
  479. d->mode = DMDIR|0555;
  480. d->length = 0;
  481. d->qid.path = PATH(mb->id, Qmbox);
  482. d->qid.type = QTDIR;
  483. d->qid.vers = mb->vers;
  484. break;
  485. case Qdir:
  486. d->name = m->name;
  487. d->mode = DMDIR|0555;
  488. d->length = 0;
  489. d->qid.path = PATH(m->id, Qdir);
  490. d->qid.type = QTDIR;
  491. break;
  492. case Qctl:
  493. d->name = dirtab[t];
  494. d->mode = 0666;
  495. d->atime = d->mtime = time(0);
  496. d->length = 0;
  497. d->qid.path = PATH(0, Qctl);
  498. break;
  499. case Qmboxctl:
  500. d->name = dirtab[t];
  501. d->mode = 0222;
  502. d->atime = d->mtime = time(0);
  503. d->length = 0;
  504. d->qid.path = PATH(mb->id, Qmboxctl);
  505. break;
  506. case Qinfo:
  507. d->name = dirtab[t];
  508. d->length = readinfo(m, nil, 0, 1<<30);
  509. d->qid.path = PATH(m->id, t);
  510. break;
  511. default:
  512. d->name = dirtab[t];
  513. d->length = fileinfo(m, t, &p);
  514. d->qid.path = PATH(m->id, t);
  515. break;
  516. }
  517. }
  518. char*
  519. rversion(Fid*)
  520. {
  521. Fid *f;
  522. if(thdr.msize < 256)
  523. return "max messagesize too small";
  524. if(thdr.msize < messagesize)
  525. messagesize = thdr.msize;
  526. rhdr.msize = messagesize;
  527. if(strncmp(thdr.version, "9P2000", 6) != 0)
  528. return "unknown 9P version";
  529. else
  530. rhdr.version = "9P2000";
  531. for(f = fids; f; f = f->next)
  532. if(f->busy)
  533. rclunk(f);
  534. return nil;
  535. }
  536. char*
  537. rauth(Fid*)
  538. {
  539. return Enoauth;
  540. }
  541. char*
  542. rflush(Fid *f)
  543. {
  544. USED(f);
  545. return 0;
  546. }
  547. char*
  548. rattach(Fid *f)
  549. {
  550. f->busy = 1;
  551. f->m = nil;
  552. f->mb = nil;
  553. f->qid.path = PATH(0, Qtop);
  554. f->qid.type = QTDIR;
  555. f->qid.vers = 0;
  556. rhdr.qid = f->qid;
  557. if(strcmp(thdr.uname, user) != 0)
  558. return Eperm;
  559. return 0;
  560. }
  561. static Fid*
  562. doclone(Fid *f, int nfid)
  563. {
  564. Fid *nf;
  565. nf = newfid(nfid);
  566. if(nf->busy)
  567. return nil;
  568. nf->busy = 1;
  569. nf->open = 0;
  570. nf->m = f->m;
  571. nf->mtop = f->mtop;
  572. nf->mb = f->mb;
  573. if(f->mb != nil)
  574. mboxincref(f->mb);
  575. if(f->mtop != nil){
  576. qlock(f->mb);
  577. msgincref(f->mtop);
  578. qunlock(f->mb);
  579. }
  580. nf->qid = f->qid;
  581. return nf;
  582. }
  583. char*
  584. dowalk(Fid *f, char *name)
  585. {
  586. int t;
  587. Mailbox *omb, *mb;
  588. char *rv, *p;
  589. Hash *h;
  590. t = FILE(f->qid.path);
  591. rv = Enotexist;
  592. omb = f->mb;
  593. if(omb)
  594. qlock(omb);
  595. else
  596. qlock(&mbllock);
  597. // this must catch everything except . and ..
  598. retry:
  599. h = hlook(f->qid.path, name);
  600. if(h != nil){
  601. f->mb = h->mb;
  602. f->m = h->m;
  603. switch(t){
  604. case Qtop:
  605. if(f->mb != nil)
  606. mboxincref(f->mb);
  607. break;
  608. case Qmbox:
  609. if(f->m){
  610. msgincref(f->m);
  611. f->mtop = f->m;
  612. }
  613. break;
  614. }
  615. f->qid = h->qid;
  616. rv = nil;
  617. } else if((p = strchr(name, '.')) != nil && *name != '.'){
  618. *p = 0;
  619. goto retry;
  620. }
  621. if(omb)
  622. qunlock(omb);
  623. else
  624. qunlock(&mbllock);
  625. if(rv == nil)
  626. return rv;
  627. if(strcmp(name, ".") == 0)
  628. return nil;
  629. if(f->qid.type != QTDIR)
  630. return Enotdir;
  631. if(strcmp(name, "..") == 0){
  632. switch(t){
  633. case Qtop:
  634. f->qid.path = PATH(0, Qtop);
  635. f->qid.type = QTDIR;
  636. f->qid.vers = 0;
  637. break;
  638. case Qmbox:
  639. f->qid.path = PATH(0, Qtop);
  640. f->qid.type = QTDIR;
  641. f->qid.vers = 0;
  642. qlock(&mbllock);
  643. mb = f->mb;
  644. f->mb = nil;
  645. mboxdecref(mb);
  646. qunlock(&mbllock);
  647. break;
  648. case Qdir:
  649. qlock(f->mb);
  650. if(f->m->whole == f->mb->root){
  651. f->qid.path = PATH(f->mb->id, Qmbox);
  652. f->qid.type = QTDIR;
  653. f->qid.vers = f->mb->d->qid.vers;
  654. msgdecref(f->mb, f->mtop);
  655. f->m = f->mtop = nil;
  656. } else {
  657. f->m = f->m->whole;
  658. f->qid.path = PATH(f->m->id, Qdir);
  659. f->qid.type = QTDIR;
  660. }
  661. qunlock(f->mb);
  662. break;
  663. }
  664. rv = nil;
  665. }
  666. return rv;
  667. }
  668. char*
  669. rwalk(Fid *f)
  670. {
  671. Fid *nf;
  672. char *rv;
  673. int i;
  674. if(f->open)
  675. return Eisopen;
  676. rhdr.nwqid = 0;
  677. nf = nil;
  678. /* clone if requested */
  679. if(thdr.newfid != thdr.fid){
  680. nf = doclone(f, thdr.newfid);
  681. if(nf == nil)
  682. return "new fid in use";
  683. f = nf;
  684. }
  685. /* if it's just a clone, return */
  686. if(thdr.nwname == 0 && nf != nil)
  687. return nil;
  688. /* walk each element */
  689. rv = nil;
  690. for(i = 0; i < thdr.nwname; i++){
  691. rv = dowalk(f, thdr.wname[i]);
  692. if(rv != nil){
  693. if(nf != nil)
  694. rclunk(nf);
  695. break;
  696. }
  697. rhdr.wqid[i] = f->qid;
  698. }
  699. rhdr.nwqid = i;
  700. /* we only error out if no walk */
  701. if(i > 0)
  702. rv = nil;
  703. return rv;
  704. }
  705. char *
  706. ropen(Fid *f)
  707. {
  708. int file;
  709. if(f->open)
  710. return Eisopen;
  711. file = FILE(f->qid.path);
  712. if(thdr.mode != OREAD)
  713. if(file != Qctl && file != Qmboxctl)
  714. return Eperm;
  715. // make sure we've decoded
  716. if(file == Qbody){
  717. if(f->m->decoded == 0)
  718. decode(f->m);
  719. if(f->m->converted == 0)
  720. convert(f->m);
  721. }
  722. rhdr.iounit = 0;
  723. rhdr.qid = f->qid;
  724. f->open = 1;
  725. return 0;
  726. }
  727. char *
  728. rcreate(Fid*)
  729. {
  730. return Eperm;
  731. }
  732. int
  733. readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
  734. {
  735. Dir d;
  736. int m, n;
  737. long pos;
  738. Mailbox *mb;
  739. n = 0;
  740. pos = 0;
  741. mkstat(&d, nil, nil, Qctl);
  742. m = convD2M(&d, &buf[n], blen);
  743. if(off <= pos){
  744. if(m <= BIT16SZ || m > cnt)
  745. return 0;
  746. n += m;
  747. cnt -= m;
  748. }
  749. pos += m;
  750. for(mb = mbl; mb != nil; mb = mb->next){
  751. mkstat(&d, mb, nil, Qmbox);
  752. m = convD2M(&d, &buf[n], blen-n);
  753. if(off <= pos){
  754. if(m <= BIT16SZ || m > cnt)
  755. break;
  756. n += m;
  757. cnt -= m;
  758. }
  759. pos += m;
  760. }
  761. return n;
  762. }
  763. int
  764. readmboxdir(Fid *f, uchar *buf, long off, int cnt, int blen)
  765. {
  766. Dir d;
  767. int n, m;
  768. long pos;
  769. Message *msg;
  770. n = 0;
  771. if(f->mb->ctl){
  772. mkstat(&d, f->mb, nil, Qmboxctl);
  773. m = convD2M(&d, &buf[n], blen);
  774. if(off == 0){
  775. if(m <= BIT16SZ || m > cnt){
  776. f->fptr = nil;
  777. return 0;
  778. }
  779. n += m;
  780. cnt -= m;
  781. } else
  782. off -= m;
  783. }
  784. // to avoid n**2 reads of the directory, use a saved finger pointer
  785. if(f->mb->vers == f->fvers && off >= f->foff && f->fptr != nil){
  786. msg = f->fptr;
  787. pos = f->foff;
  788. } else {
  789. msg = f->mb->root->part;
  790. pos = 0;
  791. }
  792. for(; cnt > 0 && msg != nil; msg = msg->next){
  793. // act like deleted files aren't there
  794. if(msg->deleted)
  795. continue;
  796. mkstat(&d, f->mb, msg, Qdir);
  797. m = convD2M(&d, &buf[n], blen-n);
  798. if(off <= pos){
  799. if(m <= BIT16SZ || m > cnt)
  800. break;
  801. n += m;
  802. cnt -= m;
  803. }
  804. pos += m;
  805. }
  806. // save a finger pointer for next read of the mbox directory
  807. f->foff = pos;
  808. f->fptr = msg;
  809. f->fvers = f->mb->vers;
  810. return n;
  811. }
  812. int
  813. readmsgdir(Fid *f, uchar *buf, long off, int cnt, int blen)
  814. {
  815. Dir d;
  816. int i, n, m;
  817. long pos;
  818. Message *msg;
  819. n = 0;
  820. pos = 0;
  821. for(i = 0; i < Qmax; i++){
  822. mkstat(&d, f->mb, f->m, i);
  823. m = convD2M(&d, &buf[n], blen-n);
  824. if(off <= pos){
  825. if(m <= BIT16SZ || m > cnt)
  826. return n;
  827. n += m;
  828. cnt -= m;
  829. }
  830. pos += m;
  831. }
  832. for(msg = f->m->part; msg != nil; msg = msg->next){
  833. mkstat(&d, f->mb, msg, Qdir);
  834. m = convD2M(&d, &buf[n], blen-n);
  835. if(off <= pos){
  836. if(m <= BIT16SZ || m > cnt)
  837. break;
  838. n += m;
  839. cnt -= m;
  840. }
  841. pos += m;
  842. }
  843. return n;
  844. }
  845. char*
  846. rread(Fid *f)
  847. {
  848. long off;
  849. int t, i, n, cnt;
  850. char *p;
  851. rhdr.count = 0;
  852. off = thdr.offset;
  853. cnt = thdr.count;
  854. if(cnt > messagesize - IOHDRSZ)
  855. cnt = messagesize - IOHDRSZ;
  856. rhdr.data = (char*)mbuf;
  857. t = FILE(f->qid.path);
  858. if(f->qid.type & QTDIR){
  859. if(t == Qtop) {
  860. qlock(&mbllock);
  861. n = readtopdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  862. qunlock(&mbllock);
  863. } else if(t == Qmbox) {
  864. qlock(f->mb);
  865. if(off == 0)
  866. syncmbox(f->mb, 1);
  867. n = readmboxdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  868. qunlock(f->mb);
  869. } else if(t == Qmboxctl) {
  870. n = 0;
  871. } else {
  872. n = readmsgdir(f, mbuf, off, cnt, messagesize - IOHDRSZ);
  873. }
  874. rhdr.count = n;
  875. return nil;
  876. }
  877. if(FILE(f->qid.path) == Qheader){
  878. rhdr.count = readheader(f->m, (char*)mbuf, off, cnt);
  879. return nil;
  880. }
  881. if(FILE(f->qid.path) == Qinfo){
  882. rhdr.count = readinfo(f->m, (char*)mbuf, off, cnt);
  883. return nil;
  884. }
  885. i = fileinfo(f->m, FILE(f->qid.path), &p);
  886. if(off < i){
  887. if((off + cnt) > i)
  888. cnt = i - off;
  889. memmove(mbuf, p + off, cnt);
  890. rhdr.count = cnt;
  891. }
  892. return nil;
  893. }
  894. char*
  895. rwrite(Fid *f)
  896. {
  897. char *err;
  898. char *token[1024];
  899. int t, n;
  900. String *file;
  901. t = FILE(f->qid.path);
  902. rhdr.count = thdr.count;
  903. switch(t){
  904. case Qctl:
  905. if(thdr.count == 0)
  906. return Ebadctl;
  907. if(thdr.data[thdr.count-1] == '\n')
  908. thdr.data[thdr.count-1] = 0;
  909. else
  910. thdr.data[thdr.count] = 0;
  911. n = tokenize(thdr.data, token, nelem(token));
  912. if(n == 0)
  913. return Ebadctl;
  914. if(strcmp(token[0], "open") == 0){
  915. file = s_new();
  916. switch(n){
  917. case 1:
  918. err = Ebadctl;
  919. break;
  920. case 2:
  921. mboxpath(token[1], getlog(), file, 0);
  922. err = newmbox(s_to_c(file), nil, 0);
  923. break;
  924. default:
  925. mboxpath(token[1], getlog(), file, 0);
  926. if(strchr(token[2], '/') != nil)
  927. err = "/ not allowed in mailbox name";
  928. else
  929. err = newmbox(s_to_c(file), token[2], 0);
  930. break;
  931. }
  932. s_free(file);
  933. return err;
  934. }
  935. if(strcmp(token[0], "close") == 0){
  936. if(n < 2)
  937. return nil;
  938. freembox(token[1]);
  939. return nil;
  940. }
  941. if(strcmp(token[0], "delete") == 0){
  942. if(n < 3)
  943. return nil;
  944. delmessages(n-1, &token[1]);
  945. return nil;
  946. }
  947. return Ebadctl;
  948. case Qmboxctl:
  949. if(f->mb && f->mb->ctl){
  950. if(thdr.count == 0)
  951. return Ebadctl;
  952. if(thdr.data[thdr.count-1] == '\n')
  953. thdr.data[thdr.count-1] = 0;
  954. else
  955. thdr.data[thdr.count] = 0;
  956. n = tokenize(thdr.data, token, nelem(token));
  957. if(n == 0)
  958. return Ebadctl;
  959. return (*f->mb->ctl)(f->mb, n, token);
  960. }
  961. }
  962. return Eperm;
  963. }
  964. char *
  965. rclunk(Fid *f)
  966. {
  967. Mailbox *mb;
  968. f->busy = 0;
  969. f->open = 0;
  970. if(f->mtop != nil){
  971. qlock(f->mb);
  972. msgdecref(f->mb, f->mtop);
  973. qunlock(f->mb);
  974. }
  975. f->m = f->mtop = nil;
  976. mb = f->mb;
  977. if(mb != nil){
  978. f->mb = nil;
  979. assert(mb->refs > 0);
  980. qlock(&mbllock);
  981. mboxdecref(mb);
  982. qunlock(&mbllock);
  983. }
  984. f->fid = -1;
  985. return 0;
  986. }
  987. char *
  988. rremove(Fid *f)
  989. {
  990. if(f->m != nil){
  991. if(f->m->deleted == 0)
  992. mailplumb(f->mb, f->m, 1);
  993. f->m->deleted = 1;
  994. }
  995. return rclunk(f);
  996. }
  997. char *
  998. rstat(Fid *f)
  999. {
  1000. Dir d;
  1001. if(FILE(f->qid.path) == Qmbox){
  1002. qlock(f->mb);
  1003. syncmbox(f->mb, 1);
  1004. qunlock(f->mb);
  1005. }
  1006. mkstat(&d, f->mb, f->m, FILE(f->qid.path));
  1007. rhdr.nstat = convD2M(&d, mbuf, messagesize - IOHDRSZ);
  1008. rhdr.stat = mbuf;
  1009. return 0;
  1010. }
  1011. char *
  1012. rwstat(Fid*)
  1013. {
  1014. return Eperm;
  1015. }
  1016. Fid *
  1017. newfid(int fid)
  1018. {
  1019. Fid *f, *ff;
  1020. ff = 0;
  1021. for(f = fids; f; f = f->next)
  1022. if(f->fid == fid)
  1023. return f;
  1024. else if(!ff && !f->busy)
  1025. ff = f;
  1026. if(ff){
  1027. ff->fid = fid;
  1028. ff->fptr = nil;
  1029. return ff;
  1030. }
  1031. f = emalloc(sizeof *f);
  1032. f->fid = fid;
  1033. f->fptr = nil;
  1034. f->next = fids;
  1035. fids = f;
  1036. return f;
  1037. }
  1038. int
  1039. fidmboxrefs(Mailbox *mb)
  1040. {
  1041. Fid *f;
  1042. int refs = 0;
  1043. for(f = fids; f; f = f->next){
  1044. if(f->mb == mb)
  1045. refs++;
  1046. }
  1047. return refs;
  1048. }
  1049. void
  1050. io(void)
  1051. {
  1052. char *err;
  1053. int n;
  1054. /* start a process to watch the mailboxes*/
  1055. if(plumbing){
  1056. switch(rfork(RFPROC|RFMEM)){
  1057. case -1:
  1058. /* oh well */
  1059. break;
  1060. case 0:
  1061. reader();
  1062. exits(nil);
  1063. default:
  1064. break;
  1065. }
  1066. }
  1067. for(;;){
  1068. /*
  1069. * reading from a pipe or a network device
  1070. * will give an error after a few eof reads
  1071. * however, we cannot tell the difference
  1072. * between a zero-length read and an interrupt
  1073. * on the processes writing to us,
  1074. * so we wait for the error
  1075. */
  1076. checkmboxrefs();
  1077. n = read9pmsg(mfd[0], mdata, messagesize);
  1078. if(n == 0)
  1079. continue;
  1080. if(n < 0)
  1081. return;
  1082. if(convM2S(mdata, n, &thdr) == 0)
  1083. continue;
  1084. if(debug)
  1085. fprint(2, "%s:<-%F\n", argv0, &thdr);
  1086. rhdr.data = (char*)mdata + messagesize;
  1087. if(!fcalls[thdr.type])
  1088. err = "bad fcall type";
  1089. else
  1090. err = (*fcalls[thdr.type])(newfid(thdr.fid));
  1091. if(err){
  1092. rhdr.type = Rerror;
  1093. rhdr.ename = err;
  1094. }else{
  1095. rhdr.type = thdr.type + 1;
  1096. rhdr.fid = thdr.fid;
  1097. }
  1098. rhdr.tag = thdr.tag;
  1099. if(debug)
  1100. fprint(2, "%s:->%F\n", argv0, &rhdr);/**/
  1101. n = convS2M(&rhdr, mdata, messagesize);
  1102. if(write(mfd[1], mdata, n) != n)
  1103. error("mount write");
  1104. }
  1105. }
  1106. void
  1107. reader(void)
  1108. {
  1109. ulong t;
  1110. Dir *d;
  1111. Mailbox *mb;
  1112. sleep(15*1000);
  1113. for(;;){
  1114. t = time(0);
  1115. qlock(&mbllock);
  1116. for(mb = mbl; mb != nil; mb = mb->next){
  1117. assert(mb->refs > 0);
  1118. if(mb->waketime != 0 && t > mb->waketime){
  1119. qlock(mb);
  1120. mb->waketime = 0;
  1121. break;
  1122. }
  1123. d = dirstat(mb->path);
  1124. if(d == nil)
  1125. continue;
  1126. qlock(mb);
  1127. if(mb->d)
  1128. if(d->qid.path != mb->d->qid.path
  1129. || d->qid.vers != mb->d->qid.vers){
  1130. free(d);
  1131. break;
  1132. }
  1133. qunlock(mb);
  1134. free(d);
  1135. }
  1136. qunlock(&mbllock);
  1137. if(mb != nil){
  1138. syncmbox(mb, 1);
  1139. qunlock(mb);
  1140. } else
  1141. sleep(15*1000);
  1142. }
  1143. }
  1144. int
  1145. newid(void)
  1146. {
  1147. int rv;
  1148. static int id;
  1149. static Lock idlock;
  1150. lock(&idlock);
  1151. rv = ++id;
  1152. unlock(&idlock);
  1153. return rv;
  1154. }
  1155. void
  1156. error(char *s)
  1157. {
  1158. postnote(PNGROUP, getpid(), "die yankee pig dog");
  1159. fprint(2, "%s: %s: %r\n", argv0, s);
  1160. exits(s);
  1161. }
  1162. typedef struct Ignorance Ignorance;
  1163. struct Ignorance
  1164. {
  1165. Ignorance *next;
  1166. char *str; /* string */
  1167. int partial; /* true if not exact match */
  1168. };
  1169. Ignorance *ignorance;
  1170. /*
  1171. * read the file of headers to ignore
  1172. */
  1173. void
  1174. readignore(void)
  1175. {
  1176. char *p;
  1177. Ignorance *i;
  1178. Biobuf *b;
  1179. if(ignorance != nil)
  1180. return;
  1181. b = Bopen("/mail/lib/ignore", OREAD);
  1182. if(b == 0)
  1183. return;
  1184. while(p = Brdline(b, '\n')){
  1185. p[Blinelen(b)-1] = 0;
  1186. while(*p && (*p == ' ' || *p == '\t'))
  1187. p++;
  1188. if(*p == '#')
  1189. continue;
  1190. i = malloc(sizeof(Ignorance));
  1191. if(i == 0)
  1192. break;
  1193. i->partial = strlen(p);
  1194. i->str = strdup(p);
  1195. if(i->str == 0){
  1196. free(i);
  1197. break;
  1198. }
  1199. i->next = ignorance;
  1200. ignorance = i;
  1201. }
  1202. Bterm(b);
  1203. }
  1204. int
  1205. ignore(char *p)
  1206. {
  1207. Ignorance *i;
  1208. readignore();
  1209. for(i = ignorance; i != nil; i = i->next)
  1210. if(cistrncmp(i->str, p, i->partial) == 0)
  1211. return 1;
  1212. return 0;
  1213. }
  1214. int
  1215. hdrlen(char *p, char *e)
  1216. {
  1217. char *ep;
  1218. ep = p;
  1219. do {
  1220. ep = strchr(ep, '\n');
  1221. if(ep == nil){
  1222. ep = e;
  1223. break;
  1224. }
  1225. ep++;
  1226. if(ep >= e){
  1227. ep = e;
  1228. break;
  1229. }
  1230. } while(*ep == ' ' || *ep == '\t');
  1231. return ep - p;
  1232. }
  1233. // rfc2047 non-ascii
  1234. typedef struct Charset Charset;
  1235. struct Charset {
  1236. char *name;
  1237. int len;
  1238. int convert;
  1239. char *tcsname;
  1240. } charsets[] =
  1241. {
  1242. { "us-ascii", 8, 1, nil, },
  1243. { "utf-8", 5, 0, nil, },
  1244. { "iso-8859-1", 10, 1, nil, },
  1245. { "iso-8859-2", 10, 2, "8859-2", },
  1246. { "big5", 4, 2, "big5", },
  1247. { "iso-2022-jp", 11, 2, "jis", },
  1248. { "windows-1251", 12, 2, "cp1251"},
  1249. { "koi8-r", 6, 2, "koi8"},
  1250. };
  1251. int
  1252. rfc2047convert(String *s, char *token, int len)
  1253. {
  1254. char decoded[1024];
  1255. char utfbuf[2*1024];
  1256. int i;
  1257. char *e, *x;
  1258. if(len == 0)
  1259. return -1;
  1260. e = token+len-2;
  1261. token += 2;
  1262. // bail if we don't understand the character set
  1263. for(i = 0; i < nelem(charsets); i++)
  1264. if(cistrncmp(charsets[i].name, token, charsets[i].len) == 0)
  1265. if(token[charsets[i].len] == '?'){
  1266. token += charsets[i].len + 1;
  1267. break;
  1268. }
  1269. if(i >= nelem(charsets))
  1270. return -1;
  1271. // bail if it doesn't fit
  1272. if(e-token > sizeof(decoded)-1)
  1273. return -1;
  1274. // bail if we don't understand the encoding
  1275. if(cistrncmp(token, "b?", 2) == 0){
  1276. token += 2;
  1277. len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);
  1278. decoded[len] = 0;
  1279. } else if(cistrncmp(token, "q?", 2) == 0){
  1280. token += 2;
  1281. len = decquoted(decoded, token, e, 1);
  1282. if(len > 0 && decoded[len-1] == '\n')
  1283. len--;
  1284. decoded[len] = 0;
  1285. } else
  1286. return -1;
  1287. switch(charsets[i].convert){
  1288. case 0:
  1289. s_append(s, decoded);
  1290. break;
  1291. case 1:
  1292. latin1toutf(utfbuf, decoded, decoded+len);
  1293. s_append(s, utfbuf);
  1294. break;
  1295. case 2:
  1296. if(xtoutf(charsets[i].tcsname, &x, decoded, decoded+len) <= 0){
  1297. s_append(s, decoded);
  1298. } else {
  1299. s_append(s, x);
  1300. free(x);
  1301. }
  1302. break;
  1303. }
  1304. return 0;
  1305. }
  1306. char*
  1307. rfc2047start(char *start, char *end)
  1308. {
  1309. int quests;
  1310. if(*--end != '=')
  1311. return nil;
  1312. if(*--end != '?')
  1313. return nil;
  1314. quests = 0;
  1315. for(end--; end >= start; end--){
  1316. switch(*end){
  1317. case '=':
  1318. if(quests == 3 && *(end+1) == '?')
  1319. return end;
  1320. break;
  1321. case '?':
  1322. ++quests;
  1323. break;
  1324. case ' ':
  1325. case '\t':
  1326. case '\n':
  1327. case '\r':
  1328. /* can't have white space in a token */
  1329. return nil;
  1330. }
  1331. }
  1332. return nil;
  1333. }
  1334. // convert a header line
  1335. String*
  1336. stringconvert(String *s, char *uneaten, int len)
  1337. {
  1338. char *token;
  1339. char *p;
  1340. int i;
  1341. s = s_reset(s);
  1342. p = uneaten;
  1343. for(i = 0; i < len; i++){
  1344. if(*p++ == '='){
  1345. token = rfc2047start(uneaten, p);
  1346. if(token != nil){
  1347. s_nappend(s, uneaten, token-uneaten);
  1348. if(rfc2047convert(s, token, p - token) < 0)
  1349. s_nappend(s, token, p - token);
  1350. uneaten = p;
  1351. }
  1352. }
  1353. }
  1354. if(p > uneaten)
  1355. s_nappend(s, uneaten, p-uneaten);
  1356. return s;
  1357. }
  1358. int
  1359. readheader(Message *m, char *buf, int off, int cnt)
  1360. {
  1361. char *p, *e;
  1362. int n, ns;
  1363. char *to = buf;
  1364. String *s;
  1365. p = m->header;
  1366. e = m->hend;
  1367. s = nil;
  1368. // copy in good headers
  1369. while(cnt > 0 && p < e){
  1370. n = hdrlen(p, e);
  1371. if(ignore(p)){
  1372. p += n;
  1373. continue;
  1374. }
  1375. // rfc2047 processing
  1376. s = stringconvert(s, p, n);
  1377. ns = s_len(s);
  1378. if(off > 0){
  1379. if(ns <= off){
  1380. off -= ns;
  1381. p += n;
  1382. continue;
  1383. }
  1384. ns -= off;
  1385. }
  1386. if(ns > cnt)
  1387. ns = cnt;
  1388. memmove(to, s_to_c(s)+off, ns);
  1389. to += ns;
  1390. p += n;
  1391. cnt -= ns;
  1392. off = 0;
  1393. }
  1394. s_free(s);
  1395. return to - buf;
  1396. }
  1397. int
  1398. headerlen(Message *m)
  1399. {
  1400. char buf[1024];
  1401. int i, n;
  1402. if(m->hlen >= 0)
  1403. return m->hlen;
  1404. for(n = 0; ; n += i){
  1405. i = readheader(m, buf, n, sizeof(buf));
  1406. if(i <= 0)
  1407. break;
  1408. }
  1409. m->hlen = n;
  1410. return n;
  1411. }
  1412. QLock hashlock;
  1413. uint
  1414. hash(ulong ppath, char *name)
  1415. {
  1416. uchar *p;
  1417. uint h;
  1418. h = 0;
  1419. for(p = (uchar*)name; *p; p++)
  1420. h = h*7 + *p;
  1421. h += ppath;
  1422. return h % Hsize;
  1423. }
  1424. Hash*
  1425. hlook(ulong ppath, char *name)
  1426. {
  1427. int h;
  1428. Hash *hp;
  1429. qlock(&hashlock);
  1430. h = hash(ppath, name);
  1431. for(hp = htab[h]; hp != nil; hp = hp->next)
  1432. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1433. qunlock(&hashlock);
  1434. return hp;
  1435. }
  1436. qunlock(&hashlock);
  1437. return nil;
  1438. }
  1439. void
  1440. henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
  1441. {
  1442. int h;
  1443. Hash *hp, **l;
  1444. qlock(&hashlock);
  1445. h = hash(ppath, name);
  1446. for(l = &htab[h]; *l != nil; l = &(*l)->next){
  1447. hp = *l;
  1448. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1449. hp->m = m;
  1450. hp->mb = mb;
  1451. hp->qid = qid;
  1452. qunlock(&hashlock);
  1453. return;
  1454. }
  1455. }
  1456. *l = hp = emalloc(sizeof(*hp));
  1457. hp->m = m;
  1458. hp->mb = mb;
  1459. hp->qid = qid;
  1460. hp->name = name;
  1461. hp->ppath = ppath;
  1462. qunlock(&hashlock);
  1463. }
  1464. void
  1465. hfree(ulong ppath, char *name)
  1466. {
  1467. int h;
  1468. Hash *hp, **l;
  1469. qlock(&hashlock);
  1470. h = hash(ppath, name);
  1471. for(l = &htab[h]; *l != nil; l = &(*l)->next){
  1472. hp = *l;
  1473. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1474. hp->mb = nil;
  1475. *l = hp->next;
  1476. free(hp);
  1477. break;
  1478. }
  1479. }
  1480. qunlock(&hashlock);
  1481. }
  1482. int
  1483. hashmboxrefs(Mailbox *mb)
  1484. {
  1485. int h;
  1486. Hash *hp;
  1487. int refs = 0;
  1488. qlock(&hashlock);
  1489. for(h = 0; h < Hsize; h++){
  1490. for(hp = htab[h]; hp != nil; hp = hp->next)
  1491. if(hp->mb == mb)
  1492. refs++;
  1493. }
  1494. qunlock(&hashlock);
  1495. return refs;
  1496. }
  1497. void
  1498. checkmboxrefs(void)
  1499. {
  1500. int f, refs;
  1501. Mailbox *mb;
  1502. qlock(&mbllock);
  1503. for(mb=mbl; mb; mb=mb->next){
  1504. qlock(mb);
  1505. refs = (f=fidmboxrefs(mb))+1;
  1506. if(refs != mb->refs){
  1507. fprint(2, "mbox %s %s ref mismatch actual %d (%d+1) expected %d\n", mb->name, mb->path, refs, f, mb->refs);
  1508. abort();
  1509. }
  1510. qunlock(mb);
  1511. }
  1512. qunlock(&mbllock);
  1513. }
  1514. void
  1515. post(char *name, char *envname, int srvfd)
  1516. {
  1517. int fd;
  1518. char buf[32];
  1519. fd = create(name, OWRITE, 0600);
  1520. if(fd < 0)
  1521. error("post failed");
  1522. sprint(buf, "%d",srvfd);
  1523. if(write(fd, buf, strlen(buf)) != strlen(buf))
  1524. error("srv write");
  1525. close(fd);
  1526. putenv(envname, name);
  1527. }