fs.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679
  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(d->qid.path != mb->d->qid.path
  1128. || d->qid.vers != mb->d->qid.vers){
  1129. free(d);
  1130. break;
  1131. }
  1132. qunlock(mb);
  1133. free(d);
  1134. }
  1135. qunlock(&mbllock);
  1136. if(mb != nil){
  1137. syncmbox(mb, 1);
  1138. qunlock(mb);
  1139. } else
  1140. sleep(15*1000);
  1141. }
  1142. }
  1143. int
  1144. newid(void)
  1145. {
  1146. int rv;
  1147. static int id;
  1148. static Lock idlock;
  1149. lock(&idlock);
  1150. rv = ++id;
  1151. unlock(&idlock);
  1152. return rv;
  1153. }
  1154. void
  1155. error(char *s)
  1156. {
  1157. postnote(PNGROUP, getpid(), "die yankee pig dog");
  1158. fprint(2, "%s: %s: %r\n", argv0, s);
  1159. exits(s);
  1160. }
  1161. typedef struct Ignorance Ignorance;
  1162. struct Ignorance
  1163. {
  1164. Ignorance *next;
  1165. char *str; /* string */
  1166. int partial; /* true if not exact match */
  1167. };
  1168. Ignorance *ignorance;
  1169. /*
  1170. * read the file of headers to ignore
  1171. */
  1172. void
  1173. readignore(void)
  1174. {
  1175. char *p;
  1176. Ignorance *i;
  1177. Biobuf *b;
  1178. if(ignorance != nil)
  1179. return;
  1180. b = Bopen("/mail/lib/ignore", OREAD);
  1181. if(b == 0)
  1182. return;
  1183. while(p = Brdline(b, '\n')){
  1184. p[Blinelen(b)-1] = 0;
  1185. while(*p && (*p == ' ' || *p == '\t'))
  1186. p++;
  1187. if(*p == '#')
  1188. continue;
  1189. i = malloc(sizeof(Ignorance));
  1190. if(i == 0)
  1191. break;
  1192. i->partial = strlen(p);
  1193. i->str = strdup(p);
  1194. if(i->str == 0){
  1195. free(i);
  1196. break;
  1197. }
  1198. i->next = ignorance;
  1199. ignorance = i;
  1200. }
  1201. Bterm(b);
  1202. }
  1203. int
  1204. ignore(char *p)
  1205. {
  1206. Ignorance *i;
  1207. readignore();
  1208. for(i = ignorance; i != nil; i = i->next)
  1209. if(cistrncmp(i->str, p, i->partial) == 0)
  1210. return 1;
  1211. return 0;
  1212. }
  1213. int
  1214. hdrlen(char *p, char *e)
  1215. {
  1216. char *ep;
  1217. ep = p;
  1218. do {
  1219. ep = strchr(ep, '\n');
  1220. if(ep == nil){
  1221. ep = e;
  1222. break;
  1223. }
  1224. ep++;
  1225. if(ep >= e){
  1226. ep = e;
  1227. break;
  1228. }
  1229. } while(*ep == ' ' || *ep == '\t');
  1230. return ep - p;
  1231. }
  1232. // rfc2047 non-ascii
  1233. typedef struct Charset Charset;
  1234. struct Charset {
  1235. char *name;
  1236. int len;
  1237. int convert;
  1238. char *tcsname;
  1239. } charsets[] =
  1240. {
  1241. { "us-ascii", 8, 1, nil, },
  1242. { "utf-8", 5, 0, nil, },
  1243. { "iso-8859-1", 10, 1, nil, },
  1244. { "iso-8859-2", 10, 2, "8859-2", },
  1245. { "big5", 4, 2, "big5", },
  1246. };
  1247. int
  1248. rfc2047convert(String *s, char *token, int len)
  1249. {
  1250. char decoded[1024];
  1251. char utfbuf[2*1024];
  1252. int i;
  1253. char *e, *x;
  1254. if(len == 0)
  1255. return -1;
  1256. e = token+len-2;
  1257. token += 2;
  1258. // bail if we don't understand the character set
  1259. for(i = 0; i < nelem(charsets); i++)
  1260. if(cistrncmp(charsets[i].name, token, charsets[i].len) == 0)
  1261. if(token[charsets[i].len] == '?'){
  1262. token += charsets[i].len + 1;
  1263. break;
  1264. }
  1265. if(i >= nelem(charsets))
  1266. return -1;
  1267. // bail if it doesn't fit
  1268. if(e-token > sizeof(decoded)-1)
  1269. return -1;
  1270. // bail if we don't understand the encoding
  1271. if(cistrncmp(token, "b?", 2) == 0){
  1272. token += 2;
  1273. len = dec64((uchar*)decoded, sizeof(decoded), token, e-token);
  1274. decoded[len] = 0;
  1275. } else if(cistrncmp(token, "q?", 2) == 0){
  1276. token += 2;
  1277. len = decquoted(decoded, token, e);
  1278. if(len > 0 && decoded[len-1] == '\n')
  1279. len--;
  1280. decoded[len] = 0;
  1281. } else
  1282. return -1;
  1283. switch(charsets[i].convert){
  1284. case 0:
  1285. s_append(s, decoded);
  1286. break;
  1287. case 1:
  1288. latin1toutf(utfbuf, decoded, decoded+len);
  1289. s_append(s, utfbuf);
  1290. break;
  1291. case 2:
  1292. if(xtoutf(charsets[i].tcsname, &x, decoded, decoded+len) <= 0){
  1293. s_append(s, decoded);
  1294. } else {
  1295. s_append(s, x);
  1296. free(x);
  1297. }
  1298. break;
  1299. }
  1300. return 0;
  1301. }
  1302. char*
  1303. rfc2047start(char *start, char *end)
  1304. {
  1305. int quests;
  1306. if(*--end != '=')
  1307. return nil;
  1308. if(*--end != '?')
  1309. return nil;
  1310. quests = 0;
  1311. for(end--; end >= start; end--){
  1312. switch(*end){
  1313. case '=':
  1314. if(quests == 3 && *(end+1) == '?')
  1315. return end;
  1316. break;
  1317. case '?':
  1318. ++quests;
  1319. break;
  1320. case ' ':
  1321. case '\t':
  1322. case '\n':
  1323. case '\r':
  1324. /* can't have white space in a token */
  1325. return nil;
  1326. }
  1327. }
  1328. return nil;
  1329. }
  1330. // convert a header line
  1331. String*
  1332. stringconvert(String *s, char *uneaten, int len)
  1333. {
  1334. char *token;
  1335. char *p;
  1336. int i;
  1337. s = s_reset(s);
  1338. p = uneaten;
  1339. for(i = 0; i < len; i++){
  1340. if(*p++ == '='){
  1341. token = rfc2047start(uneaten, p);
  1342. if(token != nil){
  1343. s_nappend(s, uneaten, token-uneaten);
  1344. if(rfc2047convert(s, token, p - token) < 0)
  1345. s_nappend(s, token, p - token);
  1346. uneaten = p;
  1347. }
  1348. }
  1349. }
  1350. if(p > uneaten)
  1351. s_nappend(s, uneaten, p-uneaten);
  1352. return s;
  1353. }
  1354. int
  1355. readheader(Message *m, char *buf, int off, int cnt)
  1356. {
  1357. char *p, *e;
  1358. int n, ns;
  1359. char *to = buf;
  1360. String *s;
  1361. p = m->header;
  1362. e = m->hend;
  1363. s = nil;
  1364. // copy in good headers
  1365. while(cnt > 0 && p < e){
  1366. n = hdrlen(p, e);
  1367. if(ignore(p)){
  1368. p += n;
  1369. continue;
  1370. }
  1371. // rfc2047 processing
  1372. s = stringconvert(s, p, n);
  1373. ns = s_len(s);
  1374. if(off > 0){
  1375. if(ns <= off){
  1376. off -= ns;
  1377. p += n;
  1378. continue;
  1379. }
  1380. ns -= off;
  1381. }
  1382. if(ns > cnt)
  1383. ns = cnt;
  1384. memmove(to, s_to_c(s)+off, ns);
  1385. to += ns;
  1386. p += n;
  1387. cnt -= ns;
  1388. off = 0;
  1389. }
  1390. s_free(s);
  1391. return to - buf;
  1392. }
  1393. int
  1394. headerlen(Message *m)
  1395. {
  1396. char buf[1024];
  1397. int i, n;
  1398. if(m->hlen >= 0)
  1399. return m->hlen;
  1400. for(n = 0; ; n += i){
  1401. i = readheader(m, buf, n, sizeof(buf));
  1402. if(i <= 0)
  1403. break;
  1404. }
  1405. m->hlen = n;
  1406. return n;
  1407. }
  1408. QLock hashlock;
  1409. uint
  1410. hash(ulong ppath, char *name)
  1411. {
  1412. uchar *p;
  1413. uint h;
  1414. h = 0;
  1415. for(p = (uchar*)name; *p; p++)
  1416. h = h*7 + *p;
  1417. h += ppath;
  1418. return h % Hsize;
  1419. }
  1420. Hash*
  1421. hlook(ulong ppath, char *name)
  1422. {
  1423. int h;
  1424. Hash *hp;
  1425. qlock(&hashlock);
  1426. h = hash(ppath, name);
  1427. for(hp = htab[h]; hp != nil; hp = hp->next)
  1428. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1429. qunlock(&hashlock);
  1430. return hp;
  1431. }
  1432. qunlock(&hashlock);
  1433. return nil;
  1434. }
  1435. void
  1436. henter(ulong ppath, char *name, Qid qid, Message *m, Mailbox *mb)
  1437. {
  1438. int h;
  1439. Hash *hp, **l;
  1440. qlock(&hashlock);
  1441. h = hash(ppath, name);
  1442. for(l = &htab[h]; *l != nil; l = &(*l)->next){
  1443. hp = *l;
  1444. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1445. hp->m = m;
  1446. hp->mb = mb;
  1447. hp->qid = qid;
  1448. qunlock(&hashlock);
  1449. return;
  1450. }
  1451. }
  1452. *l = hp = emalloc(sizeof(*hp));
  1453. hp->m = m;
  1454. hp->mb = mb;
  1455. hp->qid = qid;
  1456. hp->name = name;
  1457. hp->ppath = ppath;
  1458. qunlock(&hashlock);
  1459. }
  1460. void
  1461. hfree(ulong ppath, char *name)
  1462. {
  1463. int h;
  1464. Hash *hp, **l;
  1465. qlock(&hashlock);
  1466. h = hash(ppath, name);
  1467. for(l = &htab[h]; *l != nil; l = &(*l)->next){
  1468. hp = *l;
  1469. if(ppath == hp->ppath && strcmp(name, hp->name) == 0){
  1470. hp->mb = nil;
  1471. *l = hp->next;
  1472. free(hp);
  1473. break;
  1474. }
  1475. }
  1476. qunlock(&hashlock);
  1477. }
  1478. int
  1479. hashmboxrefs(Mailbox *mb)
  1480. {
  1481. int h;
  1482. Hash *hp;
  1483. int refs = 0;
  1484. qlock(&hashlock);
  1485. for(h = 0; h < Hsize; h++){
  1486. for(hp = htab[h]; hp != nil; hp = hp->next)
  1487. if(hp->mb == mb)
  1488. refs++;
  1489. }
  1490. qunlock(&hashlock);
  1491. return refs;
  1492. }
  1493. void
  1494. checkmboxrefs(void)
  1495. {
  1496. int f, refs;
  1497. Mailbox *mb;
  1498. qlock(&mbllock);
  1499. for(mb=mbl; mb; mb=mb->next){
  1500. qlock(mb);
  1501. refs = (f=fidmboxrefs(mb))+1;
  1502. if(refs != mb->refs){
  1503. fprint(2, "mbox %s %s ref mismatch actual %d (%d+1) expected %d\n", mb->name, mb->path, refs, f, mb->refs);
  1504. abort();
  1505. }
  1506. qunlock(mb);
  1507. }
  1508. qunlock(&mbllock);
  1509. }
  1510. void
  1511. post(char *name, char *envname, int srvfd)
  1512. {
  1513. int fd;
  1514. char buf[32];
  1515. fd = create(name, OWRITE, 0600);
  1516. if(fd < 0)
  1517. error("post failed");
  1518. sprint(buf, "%d",srvfd);
  1519. if(write(fd, buf, strlen(buf)) != strlen(buf))
  1520. error("srv write");
  1521. close(fd);
  1522. putenv(envname, name);
  1523. }