sacfs.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include "sac.h"
  6. #include "sacfs.h"
  7. /*
  8. * Rather than reading /adm/users, which is a lot of work for
  9. * a toy program, we assume all groups have the form
  10. * NNN:user:user:
  11. * meaning that each user is the leader of his own group.
  12. */
  13. enum
  14. {
  15. OPERM = 0x3, /* mask of all permission types in open mode */
  16. Nram = 512,
  17. OffsetSize = 4, /* size in bytes of an offset */
  18. CacheSize = 20,
  19. };
  20. typedef struct Fid Fid;
  21. typedef struct Path Path;
  22. typedef struct Sac Sac;
  23. typedef struct Cache Cache;
  24. struct Fid
  25. {
  26. short busy;
  27. short open;
  28. int fid;
  29. char *user;
  30. Qid qid;
  31. Sac *sac;
  32. Fid *next;
  33. };
  34. struct Sac
  35. {
  36. SacDir;
  37. Path *path;
  38. };
  39. struct Path
  40. {
  41. int ref;
  42. Path *up;
  43. long blocks;
  44. int entry;
  45. int nentry;
  46. };
  47. struct Cache
  48. {
  49. long block;
  50. ulong age;
  51. uchar *data;
  52. };
  53. enum
  54. {
  55. Pexec = 1,
  56. Pwrite = 2,
  57. Pread = 4,
  58. Pother = 1,
  59. Pgroup = 8,
  60. Powner = 64,
  61. };
  62. Fid *fids;
  63. uchar *data;
  64. int mfd[2];
  65. char user[NAMELEN];
  66. char mdata[MAXMSG+MAXFDATA];
  67. Fcall rhdr;
  68. Fcall thdr;
  69. int blocksize;
  70. Sac root;
  71. Cache cache[CacheSize];
  72. ulong cacheage;
  73. Fid * newfid(int);
  74. void sacstat(SacDir*, char*);
  75. void error(char*);
  76. void io(void);
  77. void *erealloc(void*, ulong);
  78. void *emalloc(ulong);
  79. void usage(void);
  80. int perm(Fid*, Sac*, int);
  81. ulong getl(void *p);
  82. void init(char*);
  83. Sac *saccpy(Sac *s);
  84. Sac *saclookup(Sac *s, char *name);
  85. int sacdirread(Sac *s, char *p, long off, long cnt);
  86. void loadblock(void *buf, uchar *offset, int blocksize);
  87. void sacfree(Sac*);
  88. char *rflush(Fid*), *rnop(Fid*), *rsession(Fid*),
  89. *rattach(Fid*), *rclone(Fid*), *rwalk(Fid*),
  90. *rclwalk(Fid*), *ropen(Fid*), *rcreate(Fid*),
  91. *rread(Fid*), *rwrite(Fid*), *rclunk(Fid*),
  92. *rremove(Fid*), *rstat(Fid*), *rwstat(Fid*);
  93. char *(*fcalls[])(Fid*) = {
  94. [Tflush] rflush,
  95. [Tsession] rsession,
  96. [Tnop] rnop,
  97. [Tattach] rattach,
  98. [Tclone] rclone,
  99. [Twalk] rwalk,
  100. [Tclwalk] rclwalk,
  101. [Topen] ropen,
  102. [Tcreate] rcreate,
  103. [Tread] rread,
  104. [Twrite] rwrite,
  105. [Tclunk] rclunk,
  106. [Tremove] rremove,
  107. [Tstat] rstat,
  108. [Twstat] rwstat,
  109. };
  110. char Eperm[] = "permission denied";
  111. char Enotdir[] = "not a directory";
  112. char Enoauth[] = "no authentication in ramfs";
  113. char Enotexist[] = "file does not exist";
  114. char Einuse[] = "file in use";
  115. char Eexist[] = "file exists";
  116. char Enotowner[] = "not owner";
  117. char Eisopen[] = "file already open for I/O";
  118. char Excl[] = "exclusive use file already open";
  119. char Ename[] = "illegal name";
  120. char Erdonly[] = "read only file system";
  121. int debug;
  122. void
  123. notifyf(void *a, char *s)
  124. {
  125. USED(a);
  126. if(strncmp(s, "interrupt", 9) == 0)
  127. noted(NCONT);
  128. noted(NDFLT);
  129. }
  130. void
  131. main(int argc, char *argv[])
  132. {
  133. char *defmnt;
  134. int p[2];
  135. char buf[12];
  136. int fd;
  137. int stdio = 0;
  138. defmnt = "/n/c:";
  139. ARGBEGIN{
  140. case 'd':
  141. debug = 1;
  142. break;
  143. case 'i':
  144. defmnt = 0;
  145. stdio = 1;
  146. mfd[0] = 0;
  147. mfd[1] = 1;
  148. break;
  149. case 's':
  150. defmnt = 0;
  151. break;
  152. case 'm':
  153. defmnt = ARGF();
  154. break;
  155. default:
  156. usage();
  157. }ARGEND
  158. if(argc != 1)
  159. usage();
  160. init(argv[0]);
  161. if(pipe(p) < 0)
  162. error("pipe failed");
  163. if(!stdio){
  164. mfd[0] = p[0];
  165. mfd[1] = p[0];
  166. if(defmnt == 0){
  167. fd = create("#s/sacfs", OWRITE, 0666);
  168. if(fd < 0)
  169. error("create of /srv/sacfs failed");
  170. sprint(buf, "%d", p[1]);
  171. if(write(fd, buf, strlen(buf)) < 0)
  172. error("writing /srv/sacfs");
  173. }
  174. }
  175. if(debug)
  176. fmtinstall('F', fcallconv);
  177. switch(rfork(RFFDG|RFPROC|RFNAMEG|RFNOTEG)){
  178. case -1:
  179. error("fork");
  180. case 0:
  181. close(p[1]);
  182. io();
  183. break;
  184. default:
  185. close(p[0]); /* don't deadlock if child fails */
  186. if(defmnt && mount(p[1], defmnt, MREPL|MCREATE, "") < 0)
  187. error("mount failed");
  188. }
  189. exits(0);
  190. }
  191. char*
  192. rnop(Fid *f)
  193. {
  194. USED(f);
  195. return 0;
  196. }
  197. char*
  198. rsession(Fid *unused)
  199. {
  200. Fid *f;
  201. USED(unused);
  202. for(f = fids; f; f = f->next)
  203. if(f->busy)
  204. rclunk(f);
  205. memset(thdr.authid, 0, sizeof(thdr.authid));
  206. memset(thdr.authdom, 0, sizeof(thdr.authdom));
  207. memset(thdr.chal, 0, sizeof(thdr.chal));
  208. return 0;
  209. }
  210. char*
  211. rflush(Fid *f)
  212. {
  213. USED(f);
  214. return 0;
  215. }
  216. char*
  217. rattach(Fid *f)
  218. {
  219. /* no authentication! */
  220. f->busy = 1;
  221. f->qid = (Qid){getl(root.qid), 0};
  222. f->sac = saccpy(&root);
  223. thdr.qid = f->qid;
  224. if(rhdr.uname[0])
  225. f->user = strdup(rhdr.uname);
  226. else
  227. f->user = "none";
  228. return 0;
  229. }
  230. char*
  231. rclone(Fid *f)
  232. {
  233. Fid *nf;
  234. if(f->open)
  235. return Eisopen;
  236. if(f->busy == 0)
  237. return Enotexist;
  238. nf = newfid(rhdr.newfid);
  239. nf->busy = 1;
  240. nf->open = 0;
  241. nf->qid = f->qid;
  242. nf->sac = saccpy(f->sac);
  243. nf->user = strdup(f->user);
  244. return 0;
  245. }
  246. char*
  247. rwalk(Fid *f)
  248. {
  249. char *name;
  250. Sac *sac;
  251. if((f->qid.path & CHDIR) == 0)
  252. return Enotdir;
  253. if(f->busy == 0)
  254. return Enotexist;
  255. name = rhdr.name;
  256. sac = f->sac;
  257. if(strcmp(name, ".") == 0){
  258. thdr.qid = f->qid;
  259. return 0;
  260. }
  261. if(!perm(f, sac, Pexec))
  262. return Eperm;
  263. sac = saclookup(sac, name);
  264. if(sac == nil)
  265. return Enotexist;
  266. f->sac = sac;
  267. f->qid = (Qid){getl(sac->qid), 0};
  268. thdr.qid = f->qid;
  269. return 0;
  270. }
  271. char *
  272. rclwalk(Fid *f)
  273. {
  274. Fid *nf;
  275. char *err;
  276. nf = newfid(rhdr.newfid);
  277. nf->busy = 1;
  278. nf->sac = saccpy(f->sac);
  279. nf->user = strdup(f->user);
  280. if(err = rwalk(nf))
  281. rclunk(nf);
  282. return err;
  283. }
  284. char *
  285. ropen(Fid *f)
  286. {
  287. int mode, trunc;
  288. if(f->open)
  289. return Eisopen;
  290. if(f->busy == 0)
  291. return Enotexist;
  292. mode = rhdr.mode;
  293. if(f->qid.path & CHDIR){
  294. if(mode != OREAD)
  295. return Eperm;
  296. thdr.qid = f->qid;
  297. return 0;
  298. }
  299. if(mode & ORCLOSE)
  300. return Erdonly;
  301. trunc = mode & OTRUNC;
  302. mode &= OPERM;
  303. if(mode==OWRITE || mode==ORDWR || trunc)
  304. return Erdonly;
  305. if(mode==OREAD)
  306. if(!perm(f, f->sac, Pread))
  307. return Eperm;
  308. if(mode==OEXEC)
  309. if(!perm(f, f->sac, Pexec))
  310. return Eperm;
  311. thdr.qid = f->qid;
  312. f->open = 1;
  313. return 0;
  314. }
  315. char *
  316. rcreate(Fid *f)
  317. {
  318. if(f->open)
  319. return Eisopen;
  320. if(f->busy == 0)
  321. return Enotexist;
  322. return Erdonly;
  323. }
  324. char*
  325. rread(Fid *f)
  326. {
  327. Sac *sac;
  328. char *buf, *buf2;
  329. long off;
  330. int n, cnt, i, j;
  331. uchar *blocks;
  332. long length;
  333. if(f->busy == 0)
  334. return Enotexist;
  335. sac = f->sac;
  336. thdr.count = 0;
  337. off = rhdr.offset;
  338. buf = thdr.data;
  339. cnt = rhdr.count;
  340. if(f->qid.path & CHDIR){
  341. cnt = (rhdr.count/DIRLEN)*DIRLEN;
  342. if(off%DIRLEN)
  343. return "i/o error";
  344. thdr.count = sacdirread(sac, buf, off, cnt);
  345. return 0;
  346. }
  347. length = getl(sac->length);
  348. if(off >= length) {
  349. rhdr.count = 0;
  350. return 0;
  351. }
  352. if(cnt > length-off)
  353. cnt = length-off;
  354. thdr.count = cnt;
  355. if(cnt == 0)
  356. return 0;
  357. blocks = data + getl(sac->blocks);
  358. buf2 = malloc(blocksize);
  359. if(buf2 == nil)
  360. sysfatal("malloc failed");
  361. while(cnt > 0) {
  362. i = off/blocksize;
  363. n = blocksize;
  364. if(n > length-i*blocksize)
  365. n = length-i*blocksize;
  366. loadblock(buf2, blocks+i*OffsetSize, n);
  367. j = off-i*blocksize;
  368. n = blocksize-j;
  369. if(n > cnt)
  370. n = cnt;
  371. memmove(buf, buf2+j, n);
  372. cnt -= n;
  373. off += n;
  374. buf += n;
  375. }
  376. free(buf2);
  377. return 0;
  378. }
  379. char*
  380. rwrite(Fid *f)
  381. {
  382. if(f->busy == 0)
  383. return Enotexist;
  384. return Erdonly;
  385. }
  386. char *
  387. rclunk(Fid *f)
  388. {
  389. f->busy = 0;
  390. f->open = 0;
  391. free(f->user);
  392. sacfree(f->sac);
  393. return 0;
  394. }
  395. char *
  396. rremove(Fid *f)
  397. {
  398. f->busy = 0;
  399. f->open = 0;
  400. free(f->user);
  401. sacfree(f->sac);
  402. return Erdonly;
  403. }
  404. char *
  405. rstat(Fid *f)
  406. {
  407. if(f->busy == 0)
  408. return Enotexist;
  409. sacstat(f->sac, thdr.stat);
  410. return 0;
  411. }
  412. char *
  413. rwstat(Fid *f)
  414. {
  415. if(f->busy == 0)
  416. return Enotexist;
  417. return Erdonly;
  418. }
  419. Sac*
  420. saccpy(Sac *s)
  421. {
  422. Sac *ss;
  423. ss = emalloc(sizeof(Sac));
  424. *ss = *s;
  425. if(ss->path)
  426. ss->path->ref++;
  427. return ss;
  428. }
  429. Path *
  430. pathalloc(Path *p, long blocks, int entry, int nentry)
  431. {
  432. Path *pp = emalloc(sizeof(Path));
  433. pp->ref = 1;
  434. pp->blocks = blocks;
  435. pp->entry = entry;
  436. pp->nentry = nentry;
  437. pp->up = p;
  438. return pp;
  439. }
  440. void
  441. pathfree(Path *p)
  442. {
  443. if(p == nil)
  444. return;
  445. p->ref--;
  446. if(p->ref > 0)
  447. return;
  448. pathfree(p->up);
  449. free(p);
  450. }
  451. void
  452. sacfree(Sac *s)
  453. {
  454. pathfree(s->path);
  455. free(s);
  456. }
  457. void
  458. sacstat(SacDir *s, char *buf)
  459. {
  460. Dir dir;
  461. memmove(dir.name, s->name, NAMELEN);
  462. dir.qid = (Qid){getl(s->qid), 0};
  463. dir.mode = getl(s->mode);
  464. dir.length = getl(s->length);
  465. if(dir.mode &CHDIR)
  466. dir.length *= DIRLEN;
  467. memmove(dir.uid, s->uid, NAMELEN);
  468. memmove(dir.gid, s->gid, NAMELEN);
  469. dir.atime = getl(s->atime);
  470. dir.mtime = getl(s->mtime);
  471. convD2M(&dir, buf);
  472. }
  473. void
  474. loadblock(void *buf, uchar *offset, int blocksize)
  475. {
  476. long block, n;
  477. ulong age;
  478. int i, j;
  479. block = getl(offset);
  480. if(block < 0) {
  481. block = -block;
  482. cacheage++;
  483. // age has wraped
  484. if(cacheage == 0) {
  485. for(i=0; i<CacheSize; i++)
  486. cache[i].age = 0;
  487. }
  488. j = 0;
  489. age = cache[0].age;
  490. for(i=0; i<CacheSize; i++) {
  491. if(cache[i].age < age) {
  492. age = cache[i].age;
  493. j = i;
  494. }
  495. if(cache[i].block != block)
  496. continue;
  497. memmove(buf, cache[i].data, blocksize);
  498. cache[i].age = cacheage;
  499. return;
  500. }
  501. n = getl(offset+OffsetSize);
  502. if(n < 0)
  503. n = -n;
  504. n -= block;
  505. if(unsac(buf, data+block, blocksize, n)<0)
  506. sysfatal("unsac failed!\n");
  507. memmove(cache[j].data, buf, blocksize);
  508. cache[j].age = cacheage;
  509. cache[j].block = block;
  510. } else {
  511. memmove(buf, data+block, blocksize);
  512. }
  513. }
  514. Sac*
  515. sacparent(Sac *s)
  516. {
  517. uchar *blocks;
  518. SacDir *buf;
  519. int per, i, n;
  520. Path *p;
  521. p = s->path;
  522. if(p == nil || p->up == nil) {
  523. pathfree(p);
  524. *s = root;
  525. return s;
  526. }
  527. p = p->up;
  528. blocks = data + p->blocks;
  529. per = blocksize/sizeof(SacDir);
  530. i = p->entry/per;
  531. n = per;
  532. if(n > p->nentry-i*per)
  533. n = p->nentry-i*per;
  534. buf = emalloc(per*sizeof(SacDir));
  535. loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir));
  536. s->SacDir = buf[p->entry-i*per];
  537. free(buf);
  538. p->ref++;
  539. pathfree(s->path);
  540. s->path = p;
  541. return s;
  542. }
  543. int
  544. sacdirread(Sac *s, char *p, long off, long cnt)
  545. {
  546. uchar *blocks;
  547. SacDir *buf;
  548. int iblock, per, i, j, ndir, n;
  549. blocks = data + getl(s->blocks);
  550. per = blocksize/sizeof(SacDir);
  551. ndir = getl(s->length);
  552. off /= DIRLEN;
  553. cnt /= DIRLEN;
  554. if(off >= ndir)
  555. return 0;
  556. if(cnt > ndir-off)
  557. cnt = ndir-off;
  558. iblock = -1;
  559. buf = emalloc(per*sizeof(SacDir));
  560. for(i=off; i<off+cnt; i++) {
  561. j = i/per;
  562. if(j != iblock) {
  563. n = per;
  564. if(n > ndir-j*per)
  565. n = ndir-j*per;
  566. loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
  567. iblock = j;
  568. }
  569. sacstat(buf+i-j*per, p);
  570. p += DIRLEN;
  571. }
  572. free(buf);
  573. return cnt*DIRLEN;
  574. }
  575. Sac*
  576. saclookup(Sac *s, char *name)
  577. {
  578. int ndir;
  579. int top, bot, i, j, k, n, per;
  580. uchar *blocks;
  581. SacDir *buf;
  582. int iblock;
  583. SacDir *sd;
  584. if(strcmp(name, "..") == 0)
  585. return sacparent(s);
  586. blocks = data + getl(s->blocks);
  587. per = blocksize/sizeof(SacDir);
  588. ndir = getl(s->length);
  589. buf = malloc(per*sizeof(SacDir));
  590. if(buf == nil)
  591. sysfatal("malloc failed");
  592. iblock = -1;
  593. if(1) {
  594. // linear search
  595. for(i=0; i<ndir; i++) {
  596. j = i/per;
  597. if(j != iblock) {
  598. n = per;
  599. if(n > ndir-j*per)
  600. n = ndir-j*per;
  601. loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
  602. iblock = j;
  603. }
  604. sd = buf+i-j*per;
  605. k = strcmp(name, sd->name);
  606. if(k == 0) {
  607. s->path = pathalloc(s->path, getl(s->blocks), i, ndir);
  608. s->SacDir = *sd;
  609. free(buf);
  610. return s;
  611. }
  612. }
  613. free(buf);
  614. return 0;
  615. }
  616. // binary search
  617. top = ndir;
  618. bot = 0;
  619. while(bot != top){
  620. i = (bot+top)>>1;
  621. j = i/per;
  622. if(j != iblock) {
  623. n = per;
  624. if(n > ndir-j*per)
  625. n = ndir-j*per;
  626. loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
  627. iblock = j;
  628. }
  629. j *= per;
  630. sd = buf+i-j;
  631. k = strcmp(name, sd->name);
  632. if(k == 0) {
  633. s->path = pathalloc(s->path, getl(s->blocks), i, ndir);
  634. s->SacDir = *sd;
  635. free(buf);
  636. }
  637. if(k < 0) {
  638. top = i;
  639. sd = buf;
  640. if(strcmp(name, sd->name) < 0)
  641. top = j;
  642. } else {
  643. bot = i+1;
  644. if(ndir-j < per)
  645. i = ndir-j;
  646. else
  647. i = per;
  648. sd = buf+i-1;
  649. if(strcmp(name, sd->name) > 0)
  650. bot = j+i;
  651. }
  652. }
  653. return 0;
  654. }
  655. Fid *
  656. newfid(int fid)
  657. {
  658. Fid *f, *ff;
  659. ff = 0;
  660. for(f = fids; f; f = f->next)
  661. if(f->fid == fid)
  662. return f;
  663. else if(!ff && !f->busy)
  664. ff = f;
  665. if(ff){
  666. ff->fid = fid;
  667. return ff;
  668. }
  669. f = emalloc(sizeof *f);
  670. memset(f, 0 , sizeof(Fid));
  671. f->fid = fid;
  672. f->next = fids;
  673. fids = f;
  674. return f;
  675. }
  676. void
  677. io(void)
  678. {
  679. char *err;
  680. int n;
  681. for(;;){
  682. /*
  683. * reading from a pipe or a network device
  684. * will give an error after a few eof reads
  685. * however, we cannot tell the difference
  686. * between a zero-length read and an interrupt
  687. * on the processes writing to us,
  688. * so we wait for the error
  689. */
  690. n = read(mfd[0], mdata, sizeof mdata);
  691. if(n == 0)
  692. continue;
  693. if(n < 0)
  694. error("mount read");
  695. if(convM2S(mdata, &rhdr, n) == 0)
  696. continue;
  697. if(debug)
  698. fprint(2, "sacfs:<-%F\n", &rhdr);
  699. thdr.data = mdata + MAXMSG;
  700. if(!fcalls[rhdr.type])
  701. err = "bad fcall type";
  702. else
  703. err = (*fcalls[rhdr.type])(newfid(rhdr.fid));
  704. if(err){
  705. thdr.type = Rerror;
  706. strncpy(thdr.ename, err, ERRLEN);
  707. }else{
  708. thdr.type = rhdr.type + 1;
  709. thdr.fid = rhdr.fid;
  710. }
  711. thdr.tag = rhdr.tag;
  712. if(debug)
  713. fprint(2, "ramfs:->%F\n", &thdr);/**/
  714. n = convS2M(&thdr, mdata);
  715. if(write(mfd[1], mdata, n) != n)
  716. error("mount write");
  717. }
  718. }
  719. int
  720. perm(Fid *f, Sac *s, int p)
  721. {
  722. ulong perm = getl(s->mode);
  723. if((p*Pother) & perm)
  724. return 1;
  725. if(strcmp(f->user, s->gid)==0 && ((p*Pgroup) & perm))
  726. return 1;
  727. if(strcmp(f->user, s->uid)==0 && ((p*Powner) & perm))
  728. return 1;
  729. return 0;
  730. }
  731. void
  732. init(char *file)
  733. {
  734. SacHeader *hdr;
  735. Dir dir;
  736. int fd;
  737. int i;
  738. uchar *p;
  739. notify(notifyf);
  740. strcpy(user, getuser());
  741. if(dirstat(file, &dir) < 0)
  742. error("bad file");
  743. data = emalloc(dir.length);
  744. fd = open(file, OREAD);
  745. if(fd < 0)
  746. error("opening file");
  747. if(read(fd, data, dir.length) < dir.length)
  748. error("reading file");
  749. hdr = (SacHeader*)data;
  750. if(getl(hdr->magic) != Magic)
  751. error("bad magic");
  752. if(getl(hdr->length) != (ulong)(dir.length))
  753. error("bad length");
  754. blocksize = getl(hdr->blocksize);
  755. root.SacDir = *(SacDir*)(data + sizeof(SacHeader));
  756. p = malloc(CacheSize*blocksize);
  757. if(p == nil)
  758. error("allocating cache");
  759. for(i=0; i<CacheSize; i++) {
  760. cache[i].data = p;
  761. p += blocksize;
  762. }
  763. }
  764. void
  765. error(char *s)
  766. {
  767. fprint(2, "%s: %s: %r\n", argv0, s);
  768. exits(s);
  769. }
  770. void *
  771. emalloc(ulong n)
  772. {
  773. void *p;
  774. p = malloc(n);
  775. if(!p)
  776. error("out of memory");
  777. return p;
  778. }
  779. void *
  780. erealloc(void *p, ulong n)
  781. {
  782. p = realloc(p, n);
  783. if(!p)
  784. error("out of memory");
  785. return p;
  786. }
  787. void
  788. usage(void)
  789. {
  790. fprint(2, "usage: %s [-i infd outfd] [-s] [-m mountpoint] sacfsfile\n", argv0);
  791. exits("usage");
  792. }
  793. ulong
  794. getl(void *p)
  795. {
  796. uchar *a = p;
  797. return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
  798. }