depend.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <thread.h>
  6. #include <bio.h>
  7. typedef struct Dfile Dfile;
  8. typedef struct Fid Fid;
  9. typedef struct File File;
  10. typedef struct Fs Fs;
  11. typedef struct Request Request;
  12. typedef struct Symbol Symbol;
  13. typedef struct Tardir Tardir;
  14. extern int threadrforkflag = RFNAMEG;
  15. enum{
  16. Nstat = 1024, /* plenty for this application */
  17. MAXSIZE = 8192+IOHDRSZ,
  18. };
  19. int messagesize = MAXSIZE;
  20. void
  21. fatal(char *fmt, ...)
  22. {
  23. va_list arg;
  24. char buf[1024];
  25. write(2, "depend: ", 8);
  26. va_start(arg, fmt);
  27. vseprint(buf, buf+1024, fmt, arg);
  28. va_end(arg);
  29. write(2, buf, strlen(buf));
  30. write(2, "\n", 1);
  31. threadexitsall(fmt);
  32. }
  33. enum
  34. {
  35. Nfidhash= 64,
  36. Ndfhash= 128,
  37. };
  38. struct Symbol
  39. {
  40. Symbol *next; /* hash list chaining */
  41. char *sym;
  42. int fno; /* file symbol is defined in */
  43. };
  44. /* source file */
  45. struct File
  46. {
  47. QLock;
  48. char *name;
  49. Symbol *ref;
  50. uchar *refvec; /* files resolving the references */
  51. uint len; /* length of file */
  52. uint tarlen; /* length of tar file */
  53. uint mode;
  54. uint mtime;
  55. int use;
  56. int fd;
  57. };
  58. /* .depend file */
  59. struct Dfile
  60. {
  61. Lock;
  62. int use; /* use count */
  63. int old; /* true if this is an superceded dfile */
  64. File *file; /* files */
  65. int nfile; /* number of files */
  66. int flen; /* length of file table */
  67. Symbol **dhash; /* hash table of symbols */
  68. int hlen; /* length of hash table */
  69. Dfile *next; /* hash chain */
  70. char *path; /* path name of dependency file */
  71. Qid qid; /* qid of the dependency file */
  72. };
  73. struct Fid
  74. {
  75. Fid *next;
  76. int fid;
  77. int ref;
  78. int attached;
  79. int open;
  80. Qid qid;
  81. char *path;
  82. Dfile *df;
  83. Symbol *dp;
  84. int fd;
  85. Dir *dir;
  86. int ndir;
  87. int dirindex;
  88. };
  89. struct Request
  90. {
  91. Request *next;
  92. Fid *fid;
  93. Fcall f;
  94. uchar buf[1];
  95. };
  96. enum
  97. {
  98. Tblocksize= 512, /* tar block size */
  99. Tnamesize= 100, /* tar name size */
  100. };
  101. struct Tardir
  102. {
  103. char name[Tnamesize];
  104. char mode[8];
  105. char uid[8];
  106. char gid[8];
  107. char size[12];
  108. char mtime[12];
  109. char chksum[8];
  110. char linkflag;
  111. char linkname[Tnamesize];
  112. };
  113. struct Fs
  114. {
  115. Lock;
  116. int fd; /* to kernel mount point */
  117. Fid *hash[Nfidhash];
  118. char *root;
  119. Qid rootqid;
  120. };
  121. struct Fsarg
  122. {
  123. Fs *fs;
  124. int fd;
  125. char *root;
  126. };
  127. extern void fsrun(void*);
  128. extern Fid* fsgetfid(Fs*, int);
  129. extern void fsputfid(Fs*, Fid*);
  130. extern void fsreply(Fs*, Request*, char*);
  131. extern void fsversion(Fs*, Request*, Fid*);
  132. extern void fsauth(Fs*, Request*, Fid*);
  133. extern void fsflush(Fs*, Request*, Fid*);
  134. extern void fsattach(Fs*, Request*, Fid*);
  135. extern void fswalk(Fs*, Request*, Fid*);
  136. extern void fsopen(Fs*, Request*, Fid*);
  137. extern void fscreate(Fs*, Request*, Fid*);
  138. extern void fsread(Fs*, Request*, Fid*);
  139. extern void fswrite(Fs*, Request*, Fid*);
  140. extern void fsclunk(Fs*, Request*, Fid*);
  141. extern void fsremove(Fs*, Request*, Fid*);
  142. extern void fsstat(Fs*, Request*, Fid*);
  143. extern void fswstat(Fs*, Request*, Fid*);
  144. void (*fcall[])(Fs*, Request*, Fid*) =
  145. {
  146. [Tflush] fsflush,
  147. [Tversion] fsversion,
  148. [Tauth] fsauth,
  149. [Tattach] fsattach,
  150. [Twalk] fswalk,
  151. [Topen] fsopen,
  152. [Tcreate] fscreate,
  153. [Tread] fsread,
  154. [Twrite] fswrite,
  155. [Tclunk] fsclunk,
  156. [Tremove] fsremove,
  157. [Tstat] fsstat,
  158. [Twstat] fswstat
  159. };
  160. char Eperm[] = "permission denied";
  161. char Eexist[] = "file does not exist";
  162. char Enotdir[] = "not a directory";
  163. char Eisopen[] = "file already open";
  164. char Enofid[] = "no such fid";
  165. char mallocerr[] = "malloc: %r";
  166. char Etoolong[] = "name too long";
  167. char *dependlog = "depend";
  168. int debug;
  169. Dfile *dfhash[Ndfhash]; /* dependency file hash */
  170. QLock dfhlock[Ndfhash];
  171. QLock iolock;
  172. Request* allocreq(int);
  173. Dfile* getdf(char*);
  174. void releasedf(Dfile*);
  175. Symbol* dfsearch(Dfile*, char*);
  176. void dfresolve(Dfile*, int);
  177. char* mkpath(char*, char*);
  178. int mktar(Dfile*, Symbol*, uchar*, uint, int);
  179. void closetar(Dfile*, Symbol*);
  180. void*
  181. emalloc(uint n)
  182. {
  183. void *p;
  184. p = malloc(n);
  185. if(p == nil)
  186. fatal(mallocerr);
  187. memset(p, 0, n);
  188. return p;
  189. }
  190. void *
  191. erealloc(void *ReallocP, int ReallocN)
  192. {
  193. if(ReallocN == 0)
  194. ReallocN = 1;
  195. if(!ReallocP)
  196. ReallocP = emalloc(ReallocN);
  197. else if(!(ReallocP = realloc(ReallocP, ReallocN)))
  198. fatal("unable to allocate %d bytes",ReallocN);
  199. return(ReallocP);
  200. }
  201. char*
  202. estrdup(char *s)
  203. {
  204. char *d, *d0;
  205. if(!s)
  206. return 0;
  207. d = d0 = emalloc(strlen(s)+1);
  208. while(*d++ = *s++)
  209. ;
  210. return d0;
  211. }
  212. /*
  213. * mount the user interface and start one request processor
  214. * per CPU
  215. */
  216. void
  217. realmain(void *a)
  218. {
  219. Fs *fs;
  220. int pfd[2];
  221. int srv;
  222. char service[128];
  223. struct Fsarg fsarg;
  224. int argc;
  225. char **argv;
  226. argc = (int)((void**)a)[0];
  227. argv = ((void**)a)[1];
  228. fmtinstall('F', fcallfmt);
  229. ARGBEGIN{
  230. case 'd':
  231. debug++;
  232. break;
  233. }ARGEND
  234. if(argc != 2){
  235. fprint(2, "usage: %s [-d] svc-name directory", argv0);
  236. exits("usage");
  237. }
  238. snprint(service, sizeof service, "#s/%s", argv[0]);
  239. if(argv[1][0] != '/')
  240. fatal("directory must be rooted");
  241. if(pipe(pfd) < 0)
  242. fatal("opening pipe: %r");
  243. /* Typically mounted before /srv exists */
  244. srv = create(service, OWRITE, 0666);
  245. if(srv < 0)
  246. fatal("post: %r");
  247. fprint(srv, "%d", pfd[1]);
  248. close(srv);
  249. close(pfd[1]);
  250. time(nil); /* open fd for time before losing / */
  251. if(bind(argv[1], "/", MREPL) == 0)
  252. fatal("can't bind %s to /", argv[1]);
  253. fs = emalloc(sizeof(Fs));
  254. fsarg.fs = fs;
  255. fsarg.fd = pfd[0];
  256. fsarg.root = argv[1];
  257. proccreate(fsrun, &fsarg, 16*1024);
  258. proccreate(fsrun, &fsarg, 16*1024);
  259. fsrun(&fsarg);
  260. exits(nil);
  261. }
  262. void
  263. threadmain(int argc, char *argv[])
  264. {
  265. static void *a[2];
  266. a[0] = (void*)argc;
  267. a[1] = argv;
  268. rfork(RFNAMEG);
  269. proccreate(realmain, a, 16*1024);
  270. }
  271. char*
  272. mkpath(char *dir, char *file)
  273. {
  274. int len;
  275. char *path;
  276. len = strlen(dir) + 1;
  277. if(file != nil)
  278. len += strlen(file) + 1;
  279. path = emalloc(len);
  280. if(file != nil)
  281. sprint(path, "%s/%s", dir, file);
  282. else
  283. sprint(path, "%s", dir);
  284. return path;
  285. }
  286. void
  287. fsrun(void *a)
  288. {
  289. struct Fsarg *fsarg;
  290. Fs* fs;
  291. char *root;
  292. int n, t;
  293. Request *r;
  294. Fid *f;
  295. Dir *d;
  296. fsarg = a;
  297. fs = fsarg->fs;
  298. fs->fd = fsarg->fd;
  299. root = fsarg->root;
  300. d = dirstat("/");
  301. if(d == nil)
  302. fatal("root %s inaccessible: %r", root);
  303. fs->rootqid = d->qid;
  304. free(d);
  305. for(;;){
  306. r = allocreq(messagesize);
  307. qlock(&iolock);
  308. n = read9pmsg(fs->fd, r->buf, messagesize);
  309. qunlock(&iolock);
  310. if(n <= 0)
  311. fatal("read9pmsg error: %r");
  312. if(convM2S(r->buf, n, &r->f) == 0){
  313. fprint(2, "can't convert %ux %ux %ux\n", r->buf[0],
  314. r->buf[1], r->buf[2]);
  315. free(r);
  316. continue;
  317. }
  318. f = fsgetfid(fs, r->f.fid);
  319. r->fid = f;
  320. if(debug)
  321. fprint(2, "%F path %llux\n", &r->f, f->qid.path);
  322. t = r->f.type;
  323. r->f.type++;
  324. (*fcall[t])(fs, r, f);
  325. fsputfid(fs, f);
  326. }
  327. }
  328. /*
  329. * any request that can get queued for a delayed reply
  330. */
  331. Request*
  332. allocreq(int bufsize)
  333. {
  334. Request *r;
  335. r = emalloc(sizeof(Request)+bufsize);
  336. r->next = nil;
  337. return r;
  338. }
  339. Fid*
  340. fsgetfid(Fs *fs, int fid)
  341. {
  342. Fid *f, *nf;
  343. lock(fs);
  344. for(f = fs->hash[fid%Nfidhash]; f; f = f->next){
  345. if(f->fid == fid){
  346. f->ref++;
  347. unlock(fs);
  348. return f;
  349. }
  350. }
  351. nf = emalloc(sizeof(Fid));
  352. nf->next = fs->hash[fid%Nfidhash];
  353. fs->hash[fid%Nfidhash] = nf;
  354. nf->fid = fid;
  355. nf->ref = 1;
  356. nf->fd = -1;
  357. unlock(fs);
  358. return nf;
  359. }
  360. void
  361. fsputfid(Fs *fs, Fid *f)
  362. {
  363. Fid **l, *nf;
  364. lock(fs);
  365. if(--f->ref > 0){
  366. unlock(fs);
  367. return;
  368. }
  369. for(l = &fs->hash[f->fid%Nfidhash]; nf = *l; l = &nf->next)
  370. if(nf == f){
  371. *l = f->next;
  372. break;
  373. }
  374. unlock(fs);
  375. free(f);
  376. }
  377. void
  378. fsreply(Fs *fs, Request *r, char *err)
  379. {
  380. int n;
  381. uchar buf[MAXSIZE];
  382. if(err){
  383. r->f.type = Rerror;
  384. r->f.ename = err;
  385. }
  386. if(debug)
  387. fprint(2, "%F path %llux\n", &r->f, r->fid->qid.path);
  388. n = convS2M(&r->f, buf, messagesize);
  389. if(n == 0)
  390. fatal("bad convS2M");
  391. if(write(fs->fd, buf, n) != n)
  392. fatal("unmounted");
  393. free(r);
  394. }
  395. void
  396. fsversion(Fs *fs, Request *r, Fid*)
  397. {
  398. if(r->f.msize < 256){
  399. fsreply(fs, r, "version: bad message size");
  400. return;
  401. }
  402. if(messagesize > r->f.msize)
  403. messagesize = r->f.msize;
  404. r->f.msize = messagesize;
  405. r->f.version = "9P2000";
  406. fsreply(fs, r, nil);
  407. }
  408. void
  409. fsauth(Fs *fs, Request *r, Fid*)
  410. {
  411. fsreply(fs, r, "depend: authentication not required");
  412. }
  413. void
  414. fsflush(Fs*, Request*, Fid*)
  415. {
  416. }
  417. void
  418. fsattach(Fs *fs, Request *r, Fid *f)
  419. {
  420. f->qid = fs->rootqid;
  421. f->path = strdup("/");
  422. f->df = getdf(mkpath(f->path, ".depend"));
  423. /* hold down the fid till the clunk */
  424. f->attached = 1;
  425. lock(fs);
  426. f->ref++;
  427. unlock(fs);
  428. r->f.qid = f->qid;
  429. fsreply(fs, r, nil);
  430. }
  431. void
  432. fswalk(Fs *fs, Request *r, Fid *f)
  433. {
  434. Fid *nf;
  435. char *name, *tmp;
  436. int i, nqid, nwname;
  437. char errbuf[ERRMAX], *err;
  438. Qid qid[MAXWELEM];
  439. Dfile *lastdf;
  440. char *path, *npath;
  441. Dir *d;
  442. Symbol *dp;
  443. if(f->attached == 0){
  444. fsreply(fs, r, Eexist);
  445. return;
  446. }
  447. if(f->fd >= 0 || f->open)
  448. fatal("walk of an open file");
  449. nf = nil;
  450. if(r->f.newfid != r->f.fid){
  451. nf = fsgetfid(fs, r->f.newfid);
  452. nf->attached = 1;
  453. nf->open = f->open;
  454. nf->path = strdup(f->path);
  455. nf->qid = f->qid;
  456. nf->dp = f->dp;
  457. nf->fd = f->fd;
  458. nf->df = f->df;
  459. if(nf->df){
  460. lock(nf->df);
  461. nf->df->use++;
  462. unlock(nf->df);
  463. }
  464. if(r->f.nwname == 0){
  465. r->f.nwqid = 0;
  466. fsreply(fs, r, nil);
  467. return;
  468. }
  469. f = nf;
  470. }
  471. err = nil;
  472. path = strdup(f->path);
  473. if(path == nil)
  474. fatal(mallocerr);
  475. nqid = 0;
  476. nwname = r->f.nwname;
  477. lastdf = f->df;
  478. if(nwname > 0){
  479. for(; nqid<nwname; nqid++){
  480. name = r->f.wname[nqid];
  481. if(strcmp(name, ".") == 0){
  482. Noop:
  483. if(nqid == 0)
  484. qid[nqid] = f->qid;
  485. else
  486. qid[nqid] = qid[nqid-1];
  487. continue;
  488. }
  489. if(strcmp(name, "..") == 0){
  490. name = strrchr(path, '/');
  491. if(name){
  492. if(name == path) /* at root */
  493. goto Noop;
  494. *name = '\0';
  495. }
  496. d = dirstat(path);
  497. if(d == nil){
  498. *name = '/';
  499. errstr(errbuf, sizeof errbuf);
  500. err = errbuf;
  501. break;
  502. }
  503. Directory:
  504. qid[nqid] = d->qid;
  505. free(d);
  506. releasedf(lastdf);
  507. lastdf = getdf(mkpath(path, ".depend"));
  508. continue;
  509. }
  510. npath = mkpath(path, name);
  511. free(path);
  512. path = npath;
  513. d = dirstat(path);
  514. if(d !=nil && (d->qid.type & QTDIR))
  515. goto Directory;
  516. free(d);
  517. qid[nqid].type = QTFILE;
  518. qid[nqid].path = 0;
  519. qid[nqid].vers = 0;
  520. dp = dfsearch(lastdf, name);
  521. if(dp == nil){
  522. tmp = strdup(name);
  523. if(tmp == nil)
  524. fatal("mallocerr");
  525. i = strlen(tmp);
  526. if(i > 4 && strcmp(&tmp[i-4], ".tar") == 0){
  527. tmp[i-4] = 0;
  528. dp = dfsearch(lastdf, tmp);
  529. }
  530. free(tmp);
  531. }
  532. if(dp == nil){
  533. err = Eexist;
  534. break;
  535. }
  536. qid[nqid].path = (uint)dp;
  537. qid[nqid].vers = 0;
  538. }
  539. if(nqid == 0 && err == nil)
  540. err = "file does not exist";
  541. }
  542. /* for error or partial success, put the cloned fid back*/
  543. if(nf!=nil && (err != nil || nqid < nwname)){
  544. releasedf(nf->df);
  545. nf->df = nil;
  546. fsputfid(fs, nf);
  547. }
  548. if(err == nil){
  549. /* return (possibly short) list of qids */
  550. for(i=0; i<nqid; i++)
  551. r->f.wqid[i] = qid[i];
  552. r->f.nwqid = nqid;
  553. /* for full success, advance f */
  554. if(nqid > 0 && nqid == nwname){
  555. free(f->path);
  556. f->path = path;
  557. path = nil;
  558. f->qid = qid[nqid-1];
  559. f->dp = (Symbol*)f->qid.path;
  560. if(f->df != lastdf){
  561. releasedf(f->df);
  562. f->df = lastdf;
  563. lastdf = nil;
  564. }
  565. }
  566. }
  567. releasedf(lastdf);
  568. free(path);
  569. fsreply(fs, r, err);
  570. }
  571. #ifdef adf
  572. void
  573. fsclone(Fs *fs, Request *r, Fid *f)
  574. {
  575. Fid *nf;
  576. if(f->attached == 0){
  577. fsreply(fs, r, Eexist);
  578. return;
  579. }
  580. nf = fsgetfid(fs, r->f.newfid);
  581. nf->attached = 1;
  582. nf->open = f->open;
  583. nf->path = strdup(f->path);
  584. nf->qid = f->qid;
  585. nf->dp = f->dp;
  586. nf->fd = f->fd;
  587. nf->df = f->df;
  588. if(nf->df){
  589. lock(nf->df);
  590. nf->df->use++;
  591. unlock(nf->df);
  592. }
  593. fsreply(fs, r, nil);
  594. }
  595. void
  596. fswalk(Fs *fs, Request *r, Fid *f)
  597. {
  598. char *name;
  599. int i;
  600. Dir d;
  601. char errbuf[ERRLEN];
  602. char *path;
  603. Symbol *dp;
  604. if(f->attached == 0){
  605. fsreply(fs, r, Enofid);
  606. return;
  607. }
  608. if(f->fd >= 0 || f->open)
  609. fatal("walk of an open file");
  610. name = r->f.name;
  611. if(strcmp(name, ".") == 0){
  612. fsreply(fs, r, nil);
  613. return;
  614. }
  615. if(strcmp(name, "..") == 0){
  616. name = strrchr(f->path, '/');
  617. if(name){
  618. if(name == f->path){
  619. fsreply(fs, r, nil);
  620. return;
  621. }
  622. *name = 0;
  623. }
  624. if(dirstat(f->path, &d) < 0){
  625. *name = '/';
  626. errstr(errbuf);
  627. fsreply(fs, r, errbuf);
  628. return;
  629. }
  630. r->f.qid = f->qid = d.qid;
  631. releasedf(f->df);
  632. f->df = getdf(mkpath(f->path, ".depend"));
  633. fsreply(fs, r, nil);
  634. return;
  635. }
  636. path = mkpath(f->path, name);
  637. if(dirstat(path, &d) < 0 || (d.qid.path & CHDIR) == 0){
  638. dp = dfsearch(f->df, name);
  639. if(dp == nil){
  640. i = strlen(name);
  641. if(i > 4 && strcmp(&name[i-4], ".tar") == 0){
  642. name[i-4] = 0;
  643. dp = dfsearch(f->df, name);
  644. }
  645. }
  646. if(dp == nil){
  647. fsreply(fs, r, Eexist);
  648. free(path);
  649. return;
  650. }
  651. f->dp = dp;
  652. d.qid.path = (uint)dp;
  653. d.qid.vers = 0;
  654. }
  655. free(f->path);
  656. f->path = path;
  657. if(d.qid.path & CHDIR){
  658. releasedf(f->df);
  659. f->df = getdf(mkpath(f->path, ".depend"));
  660. }
  661. r->f.qid = f->qid = d.qid;
  662. fsreply(fs, r, nil);
  663. }
  664. #endif
  665. void
  666. fsopen(Fs *fs, Request *r, Fid *f)
  667. {
  668. int mode;
  669. char errbuf[ERRMAX];
  670. if(f->attached == 0){
  671. fsreply(fs, r, Enofid);
  672. return;
  673. }
  674. if(f->open){
  675. fsreply(fs, r, Eisopen);
  676. return;
  677. }
  678. mode = r->f.mode & 3;
  679. if(mode != OREAD){
  680. fsreply(fs, r, Eperm);
  681. return;
  682. }
  683. if(f->qid.type & QTDIR){
  684. f->fd = open(f->path, OREAD);
  685. if(f->fd < 0){
  686. errstr(errbuf, sizeof errbuf);
  687. fsreply(fs, r, errbuf);
  688. return;
  689. }
  690. }
  691. f->open = 1;
  692. r->f.qid = f->qid;
  693. fsreply(fs, r, nil);
  694. }
  695. void
  696. fscreate(Fs *fs, Request *r, Fid*)
  697. {
  698. fsreply(fs, r, Eperm);
  699. }
  700. void
  701. fsread(Fs *fs, Request *r, Fid *f)
  702. {
  703. int i, n, len,skip;
  704. Dir d;
  705. Symbol *dp;
  706. char buf[512];
  707. if(f->attached == 0){
  708. fsreply(fs, r, Enofid);
  709. return;
  710. }
  711. if(r->f.count < 0){
  712. fsreply(fs, r, "bad read count");
  713. return;
  714. }
  715. if(f->qid.type & QTDIR){
  716. n = 0;
  717. if(f->dir == nil){
  718. f->ndir = dirreadall(f->fd, &f->dir);
  719. f->dirindex = 0;
  720. }
  721. if(f->dir == nil)
  722. goto Return;
  723. if(r->f.offset == 0) /* seeking to zero is permitted */
  724. f->dirindex = 0;
  725. for(; f->dirindex < f->ndir; f->dirindex++){
  726. if((f->dir[f->dirindex].qid.type & QTDIR) == 0)
  727. continue;
  728. len = convD2M(&f->dir[f->dirindex], r->buf+n, r->f.count-n);
  729. if(len <= BIT16SZ)
  730. goto Return;
  731. n += len;
  732. }
  733. skip = f->dirindex - f->ndir; /* # depend records already read */
  734. if(f->df){
  735. for(i = 0; i < f->df->hlen; i++)
  736. for(dp = f->df->dhash[i]; dp; dp = dp->next){
  737. if(skip-- > 0)
  738. continue;
  739. snprint(buf, sizeof buf, "%s.tar", dp->sym);
  740. d.name = buf;
  741. d.uid = "none";
  742. d.gid = "none";
  743. d.muid = "none";
  744. d.qid.type = QTFILE;
  745. d.qid.path = (uint)dp;
  746. d.qid.vers = 0;
  747. d.length = f->df->file[dp->fno].tarlen;
  748. d.mode = 0444;
  749. d.mtime = time(nil);
  750. d.atime = time(nil);
  751. len = convD2M(&d, r->buf + n, r->f.count - n);
  752. if(len <= BIT16SZ)
  753. goto Return;
  754. n += len;
  755. f->dirindex++;
  756. }
  757. }
  758. } else
  759. n = mktar(f->df, f->dp, r->buf, r->f.offset, r->f.count);
  760. Return:
  761. r->f.data = (char*)r->buf;
  762. r->f.count = n;
  763. fsreply(fs, r, nil);
  764. }
  765. void
  766. fswrite(Fs *fs, Request *r, Fid*)
  767. {
  768. fsreply(fs, r, Eperm);
  769. }
  770. void
  771. fsclunk(Fs *fs, Request *r, Fid *f)
  772. {
  773. if(f->attached == 0){
  774. fsreply(fs, r, Enofid);
  775. return;
  776. }
  777. if(f->fd >= 0){
  778. close(f->fd);
  779. f->fd = -1;
  780. }
  781. if((f->qid.type & QTDIR) == 0)
  782. closetar(f->df, f->dp);
  783. releasedf(f->df);
  784. f->df = nil;
  785. free(f->dir);
  786. f->dir = nil;
  787. fsreply(fs, r, nil);
  788. fsputfid(fs, f);
  789. }
  790. void
  791. fsremove(Fs *fs, Request *r, Fid*)
  792. {
  793. fsreply(fs, r, Eperm);
  794. }
  795. void
  796. fsstat(Fs *fs, Request *r, Fid *f)
  797. {
  798. char err[ERRMAX];
  799. Dir d;
  800. Symbol *dp;
  801. int n;
  802. uchar statbuf[Nstat];
  803. if(f->qid.type & QTDIR)
  804. n = stat(f->path, statbuf, sizeof statbuf);
  805. else {
  806. dp = f->dp;
  807. d.name = dp->sym;
  808. d.uid = "none";
  809. d.gid = "none";
  810. d.muid = "none";
  811. d.qid.type = QTFILE;
  812. d.qid.path = (uint)dp;
  813. d.qid.vers = 0;
  814. d.length = f->df->file[dp->fno].tarlen;
  815. d.mode = 0444;
  816. d.mtime = time(nil);
  817. d.atime = time(nil);
  818. n = convD2M(&d, statbuf, sizeof statbuf);
  819. }
  820. if(n <= BIT16SZ){
  821. errstr(err, sizeof err);
  822. fsreply(fs, r, err);
  823. } else {
  824. r->f.stat = statbuf;
  825. r->f.nstat = n;
  826. fsreply(fs, r, nil);
  827. }
  828. }
  829. void
  830. fswstat(Fs *fs, Request *r, Fid*)
  831. {
  832. fsreply(fs, r, Eperm);
  833. }
  834. /*
  835. * string hash
  836. */
  837. uint
  838. shash(char *str, int len)
  839. {
  840. uint hash;
  841. char *val;
  842. hash = 0;
  843. for(val = str; *val; val++)
  844. hash = (hash*13) + *val-'a';
  845. return hash % len;
  846. }
  847. /*
  848. * free info about a dependency file
  849. */
  850. void
  851. freedf(Dfile *df)
  852. {
  853. int i;
  854. Symbol *dp, *next;
  855. lock(df);
  856. df->old = 1;
  857. if(df->use){
  858. unlock(df);
  859. return;
  860. }
  861. unlock(df); /* we're no longer referenced */
  862. for(i = 0; i < df->nfile; i++)
  863. free(df->file[i].name);
  864. free(df->file[i].refvec);
  865. free(df->file);
  866. df->file = nil;
  867. for(i = 0; i < df->hlen; i++)
  868. for(dp = df->dhash[i]; dp != nil; dp = next){
  869. next = dp->next;
  870. free(dp);
  871. }
  872. free(df->path);
  873. free(df);
  874. free(df->dhash);
  875. df->dhash = nil;
  876. }
  877. /*
  878. * crack a dependency file
  879. */
  880. void
  881. newsym(char *name, int fno, Symbol **l)
  882. {
  883. Symbol *dp;
  884. dp = emalloc(sizeof(Symbol));
  885. dp->sym = strdup(name);
  886. if(dp->sym == nil)
  887. fatal("mallocerr");
  888. dp->next = *l;
  889. dp->fno = fno;
  890. *l = dp;
  891. }
  892. int
  893. awk(Biobuf *b, char **field, int n)
  894. {
  895. char *line;
  896. int i;
  897. while(line = Brdline(b, '\n')){
  898. line[Blinelen(b)-1] = 0;
  899. while(*line == ' ' || *line == '\t')
  900. *line++ = 0;
  901. for(i = 0; i < n; i++){
  902. if(*line == 0 || *line == '#')
  903. break;
  904. field[i] = line;
  905. while(*line && *line != ' ' && *line != '\t')
  906. line++;
  907. while(*line == ' ' || *line == '\t')
  908. *line++ = 0;
  909. }
  910. if(i)
  911. return i;
  912. }
  913. return 0;
  914. }
  915. void
  916. crackdf(Dfile *df, Biobuf *b, uint len, char *dpath)
  917. {
  918. char *name;
  919. char *field[3];
  920. char path[512];
  921. int n, inc, ok, npath;
  922. Symbol **l, *dp, *next;
  923. File *f, *ef;
  924. Dir *d;
  925. inc = 32;
  926. df->flen = inc;
  927. df->file = emalloc(df->flen*sizeof(File));
  928. df->nfile = 0;
  929. df->hlen = 1 + len/8;
  930. df->dhash = emalloc(df->hlen*sizeof(Symbol*));
  931. l = nil;
  932. while((n = awk(b, field, 3)) > 0){
  933. if(n != 2)
  934. continue;
  935. name = field[1];
  936. switch(*field[0]){
  937. case 'F':
  938. if(df->flen == df->nfile){
  939. df->flen += inc;
  940. df->file = realloc(df->file, df->flen*sizeof(File));
  941. if(df->file == nil)
  942. fatal(mallocerr);
  943. memset(&df->file[df->nfile], 0, inc*sizeof(File));
  944. }
  945. f = &df->file[df->nfile++];
  946. f->name = strdup(name);
  947. l = &f->ref;
  948. /* fall through and define as a symbol */
  949. case 'D':
  950. if(l == nil)
  951. continue;
  952. newsym(name, df->nfile-1, &(df->dhash[shash(name, df->hlen)]));
  953. break;
  954. case 'R':
  955. if(l == nil)
  956. continue;
  957. newsym(name, 0, l);
  958. break;
  959. }
  960. }
  961. ef = &df->file[df->nfile];
  962. /* stat the files to get sizes */
  963. npath = strlen(dpath);
  964. if(npath+1+1 >= sizeof path)
  965. fatal(Etoolong);
  966. memmove(path, dpath, npath+1); /* include NUL */
  967. name = strrchr(path, '/') + 1;
  968. for(f = df->file; f < ef; f++){
  969. n = strlen(f->name);
  970. if(npath+1+n+3+1 > sizeof path)
  971. fatal(Etoolong);
  972. memmove(name, f->name, n+1); /* include NUL */
  973. ok = access(path, AEXIST);
  974. if(ok < 0){
  975. strcpy(name+n, ".Z");
  976. ok = access(path, AEXIST);
  977. if(ok < 0){
  978. strcpy(name+n, ".gz");
  979. ok = access(path, AEXIST);
  980. }
  981. }
  982. if(ok >= 0){
  983. free(f->name);
  984. f->name = strdup(name);
  985. if(f->name == nil)
  986. fatal(mallocerr);
  987. }
  988. d = dirstat(path);
  989. if(d){
  990. f->len = d->length;
  991. f->mode = d->mode;
  992. f->mtime = d->mtime;
  993. free(d);
  994. }else{
  995. f->len = 0;
  996. f->mode = 0;
  997. f->mtime = 0;
  998. }
  999. f->fd = -1;
  1000. }
  1001. /* resolve all file references */
  1002. for(f = df->file; f < ef; f++)
  1003. dfresolve(df, f-df->file);
  1004. /* free the referenced symbols, don't need them anymore */
  1005. for(f = df->file; f < ef; f++){
  1006. f->tarlen += 2*Tblocksize; /* tars trailing 0 blocks */
  1007. for(dp = f->ref; dp != nil; dp = next){
  1008. next = dp->next;
  1009. free(dp);
  1010. }
  1011. f->ref = nil;
  1012. }
  1013. }
  1014. /*
  1015. * get a cracked dependency file
  1016. */
  1017. Dfile*
  1018. getdf(char *path)
  1019. {
  1020. Dfile *df, **l;
  1021. QLock *lk;
  1022. Dir *d;
  1023. int i, fd;
  1024. Biobuf *b;
  1025. i = shash(path, Ndfhash);
  1026. l = &dfhash[i];
  1027. lk = &dfhlock[i];
  1028. qlock(lk);
  1029. for(df = *l; df; df = *l){
  1030. if(strcmp(path, df->path) == 0)
  1031. break;
  1032. l = &df->next;
  1033. }
  1034. d = dirstat(path);
  1035. if(df){
  1036. if(d!=nil && d->qid.type == df->qid.type && d->qid.vers == df->qid.vers && d->qid.vers == df->qid.vers){
  1037. free(path);
  1038. lock(df);
  1039. df->use++;
  1040. unlock(df);
  1041. goto Return;
  1042. }
  1043. *l = df->next;
  1044. freedf(df);
  1045. }
  1046. fd = open(path, OREAD);
  1047. if(d == nil || fd < 0){
  1048. close(fd);
  1049. goto Return;
  1050. }
  1051. df = emalloc(sizeof(*df));
  1052. b = emalloc(sizeof(Biobuf));
  1053. Binit(b, fd, OREAD);
  1054. df->qid = d->qid;
  1055. df->path = path;
  1056. crackdf(df, b, d->length, path);
  1057. Bterm(b);
  1058. free(b);
  1059. df->next = *l;
  1060. *l = df;
  1061. df->use = 1;
  1062. Return:
  1063. qunlock(lk);
  1064. free(d);
  1065. return df;
  1066. }
  1067. /*
  1068. * stop using a dependency file. Free it if it is no longer linked in.
  1069. */
  1070. void
  1071. releasedf(Dfile *df)
  1072. {
  1073. Dfile **l, *d;
  1074. QLock *lk;
  1075. int i;
  1076. if(df == nil)
  1077. return;
  1078. /* remove from hash chain */
  1079. i = shash(df->path, Ndfhash);
  1080. l = &dfhash[i];
  1081. lk = &dfhlock[i];
  1082. qlock(lk);
  1083. lock(df);
  1084. df->use--;
  1085. if(df->old == 0 || df->use > 0){
  1086. unlock(df);
  1087. qunlock(lk);
  1088. return;
  1089. }
  1090. for(d = *l; d; d = *l){
  1091. if(d == df){
  1092. *l = d->next;
  1093. break;
  1094. }
  1095. l = &d->next;
  1096. }
  1097. unlock(df);
  1098. qunlock(lk);
  1099. /* now we know it is unreferenced, remove it */
  1100. freedf(df);
  1101. }
  1102. /*
  1103. * search a dependency file for a symbol
  1104. */
  1105. Symbol*
  1106. dfsearch(Dfile *df, char *name)
  1107. {
  1108. Symbol *dp;
  1109. if(df == nil)
  1110. return nil;
  1111. for(dp = df->dhash[shash(name, df->hlen)]; dp; dp = dp->next)
  1112. if(strcmp(dp->sym, name) == 0)
  1113. return dp;
  1114. return nil;
  1115. }
  1116. /*
  1117. * resolve a single file into a vector of referenced files and the sum of their
  1118. * lengths
  1119. */
  1120. /* set a bit in the referenced file vector */
  1121. int
  1122. set(uchar *vec, int fno)
  1123. {
  1124. if(vec[fno/8] & (1<<(fno&7)))
  1125. return 1;
  1126. vec[fno/8] |= 1<<(fno&7);
  1127. return 0;
  1128. }
  1129. /* merge two referenced file vectors */
  1130. void
  1131. merge(uchar *vec, uchar *ovec, int nfile)
  1132. {
  1133. nfile = (nfile+7)/8;
  1134. while(nfile-- > 0)
  1135. *vec++ |= *ovec++;
  1136. }
  1137. uint
  1138. res(Dfile *df, uchar *vec, int fno)
  1139. {
  1140. File *f;
  1141. Symbol *rp, *dp;
  1142. int len;
  1143. f = &df->file[fno];
  1144. if(set(vec, fno))
  1145. return 0; /* already set */
  1146. if(f->refvec != nil){
  1147. merge(vec, f->refvec, df->nfile); /* we've descended here before */
  1148. return f->tarlen;
  1149. }
  1150. len = 0;
  1151. for(rp = f->ref; rp; rp = rp->next){
  1152. dp = dfsearch(df, rp->sym);
  1153. if(dp == nil)
  1154. continue;
  1155. len += res(df, vec, dp->fno);
  1156. }
  1157. return len + Tblocksize + ((f->len + Tblocksize - 1)/Tblocksize)*Tblocksize;
  1158. }
  1159. void
  1160. dfresolve(Dfile *df, int fno)
  1161. {
  1162. uchar *vec;
  1163. File *f;
  1164. f = &df->file[fno];
  1165. vec = emalloc((df->nfile+7)/8);
  1166. f->tarlen = res(df, vec, fno);
  1167. f->refvec = vec;
  1168. }
  1169. /*
  1170. * make the tar directory block for a file
  1171. */
  1172. uchar*
  1173. mktardir(File *f)
  1174. {
  1175. uchar *ep;
  1176. Tardir *tp;
  1177. uint sum;
  1178. uchar *p, *cp;
  1179. p = emalloc(Tblocksize);
  1180. tp = (Tardir*)p;
  1181. strcpy(tp->name, f->name);
  1182. sprint(tp->mode, "%6o ", f->mode & 0777);
  1183. sprint(tp->uid, "%6o ", 0);
  1184. sprint(tp->gid, "%6o ", 0);
  1185. sprint(tp->size, "%11o ", f->len);
  1186. sprint(tp->mtime, "%11o ", f->mtime);
  1187. /* calculate checksum */
  1188. memset(tp->chksum, ' ', sizeof(tp->chksum));
  1189. sum = 0;
  1190. ep = p + Tblocksize;
  1191. for (cp = p; cp < ep; cp++)
  1192. sum += *cp;
  1193. sprint(tp->chksum, "%6o", sum);
  1194. return p;
  1195. }
  1196. /*
  1197. * manage open files
  1198. */
  1199. int
  1200. getfile(Dfile *df, File *f)
  1201. {
  1202. int n;
  1203. char path[512], *name;
  1204. qlock(f);
  1205. f->use++;
  1206. if(f->fd < 0){
  1207. name = strrchr(df->path, '/') + 1;
  1208. n = snprint(path, sizeof path, "%.*s/%s", (int)(name-df->path), df->path, f->name);
  1209. if(n >= sizeof path - UTFmax){
  1210. syslog(0, dependlog, "path name too long: %.20s.../%.20s...", df->path, f->name);
  1211. return -1;
  1212. }
  1213. f->fd = open(path, OREAD);
  1214. if(f->fd < 0)
  1215. syslog(0, dependlog, "can't open %s: %r", path);
  1216. }
  1217. return f->fd;
  1218. }
  1219. void
  1220. releasefile(File *f)
  1221. {
  1222. --f->use;
  1223. qunlock(f);
  1224. }
  1225. void
  1226. closefile(File *f)
  1227. {
  1228. qlock(f);
  1229. if(f->use == 0){
  1230. close(f->fd);
  1231. f->fd = -1;
  1232. }
  1233. qunlock(f);
  1234. }
  1235. /*
  1236. * return a block of a tar file
  1237. */
  1238. int
  1239. mktar(Dfile *df, Symbol *dp, uchar *area, uint offset, int len)
  1240. {
  1241. int fd, i, j, n, off;
  1242. uchar *p, *buf;
  1243. uchar *vec;
  1244. File *f;
  1245. f = &df->file[dp->fno];
  1246. vec = f->refvec;
  1247. p = area;
  1248. /* find file */
  1249. for(i = 0; i < df->nfile && len > 0; i++){
  1250. if((vec[i/8] & (1<<(i&7))) == 0)
  1251. continue;
  1252. f = &df->file[i];
  1253. n = Tblocksize + ((f->len + Tblocksize - 1)/Tblocksize)*Tblocksize;
  1254. if(offset >= n){
  1255. offset -= n;
  1256. continue;
  1257. }
  1258. if(offset < Tblocksize){
  1259. buf = mktardir(f);
  1260. if(offset + len > Tblocksize)
  1261. j = Tblocksize - offset;
  1262. else
  1263. j = len;
  1264. //if(debug)fprint(2, "reading %d bytes dir of %s\n", j, f->name);
  1265. memmove(p, buf+offset, j);
  1266. p += j;
  1267. len -= j;
  1268. offset += j;
  1269. free(buf);
  1270. }
  1271. if(len <= 0)
  1272. break;
  1273. off = offset - Tblocksize;
  1274. if(off >= 0 && off < f->len){
  1275. if(off + len > f->len)
  1276. j = f->len - off;
  1277. else
  1278. j = len;
  1279. fd = getfile(df, f);
  1280. if(fd >= 0){
  1281. //if(debug)fprint(2, "reading %d bytes from offset %d of %s\n", j, off, f->name);
  1282. if(pread(fd, p, j, off) != j)
  1283. syslog(0, dependlog, "%r reading %d bytes from offset %d of %s", j, off, f->name);
  1284. }
  1285. releasefile(f);
  1286. p += j;
  1287. len -= j;
  1288. offset += j;
  1289. }
  1290. if(len <= 0)
  1291. break;
  1292. if(offset < n){
  1293. if(offset + len > n)
  1294. j = n - offset;
  1295. else
  1296. j = len;
  1297. //if(debug)fprint(2, "filling %d bytes after %s\n", j, f->name);
  1298. memset(p, 0, j);
  1299. p += j;
  1300. len -= j;
  1301. }
  1302. offset = 0;
  1303. }
  1304. /* null blocks at end of tar file */
  1305. if(offset < 2*Tblocksize && len > 0){
  1306. if(offset + len > 2*Tblocksize)
  1307. j = 2*Tblocksize - offset;
  1308. else
  1309. j = len;
  1310. //if(debug)fprint(2, "filling %d bytes at end\n", j);
  1311. memset(p, 0, j);
  1312. p += j;
  1313. }
  1314. return p - area;
  1315. }
  1316. /*
  1317. * close the files making up a tar file
  1318. */
  1319. void
  1320. closetar(Dfile *df, Symbol *dp)
  1321. {
  1322. int i;
  1323. uchar *vec;
  1324. File *f;
  1325. f = &df->file[dp->fno];
  1326. vec = f->refvec;
  1327. /* find file */
  1328. for(i = 0; i < df->nfile; i++){
  1329. if((vec[i/8] & (1<<(i&7))) == 0)
  1330. continue;
  1331. closefile(&df->file[i]);
  1332. }
  1333. }