pack.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. #include "stdinc.h"
  2. #include "vac.h"
  3. #include "dat.h"
  4. #include "fns.h"
  5. #include "error.h"
  6. typedef struct MetaChunk MetaChunk;
  7. struct MetaChunk {
  8. ushort offset;
  9. ushort size;
  10. ushort index;
  11. };
  12. static int stringunpack(char **s, uchar **p, int *n);
  13. /*
  14. * integer conversion routines
  15. */
  16. #define U8GET(p) ((p)[0])
  17. #define U16GET(p) (((p)[0]<<8)|(p)[1])
  18. #define U32GET(p) (((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3])
  19. #define U48GET(p) (((uvlong)U16GET(p)<<32)|(uvlong)U32GET((p)+2))
  20. #define U64GET(p) (((uvlong)U32GET(p)<<32)|(uvlong)U32GET((p)+4))
  21. #define U8PUT(p,v) (p)[0]=(v)&0xFF
  22. #define U16PUT(p,v) (p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF
  23. #define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF
  24. #define U48PUT(p,v,t32) t32=(v)>>32;U16PUT(p,t32);t32=(v);U32PUT((p)+2,t32)
  25. #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
  26. static int
  27. stringunpack(char **s, uchar **p, int *n)
  28. {
  29. int nn;
  30. if(*n < 2)
  31. return -1;
  32. nn = U16GET(*p);
  33. *p += 2;
  34. *n -= 2;
  35. if(nn > *n)
  36. return -1;
  37. *s = vtmalloc(nn+1);
  38. memmove(*s, *p, nn);
  39. (*s)[nn] = 0;
  40. *p += nn;
  41. *n -= nn;
  42. return 0;
  43. }
  44. static int
  45. stringpack(char *s, uchar *p)
  46. {
  47. int n;
  48. n = strlen(s);
  49. U16PUT(p, n);
  50. memmove(p+2, s, n);
  51. return n+2;
  52. }
  53. int
  54. mbunpack(MetaBlock *mb, uchar *p, int n)
  55. {
  56. u32int magic;
  57. mb->maxsize = n;
  58. mb->buf = p;
  59. if(n == 0) {
  60. memset(mb, 0, sizeof(MetaBlock));
  61. return 0;
  62. }
  63. magic = U32GET(p);
  64. if(magic != MetaMagic && magic != MetaMagic+1) {
  65. werrstr("bad meta block magic");
  66. return -1;
  67. }
  68. mb->size = U16GET(p+4);
  69. mb->free = U16GET(p+6);
  70. mb->maxindex = U16GET(p+8);
  71. mb->nindex = U16GET(p+10);
  72. mb->unbotch = (magic == MetaMagic+1);
  73. if(mb->size > n) {
  74. werrstr("bad meta block size");
  75. return -1;
  76. }
  77. p += MetaHeaderSize;
  78. n -= MetaHeaderSize;
  79. USED(p);
  80. if(n < mb->maxindex*MetaIndexSize) {
  81. werrstr("truncated meta block 2");
  82. return -1;
  83. }
  84. return 0;
  85. }
  86. void
  87. mbpack(MetaBlock *mb)
  88. {
  89. uchar *p;
  90. p = mb->buf;
  91. U32PUT(p, MetaMagic);
  92. U16PUT(p+4, mb->size);
  93. U16PUT(p+6, mb->free);
  94. U16PUT(p+8, mb->maxindex);
  95. U16PUT(p+10, mb->nindex);
  96. }
  97. void
  98. mbdelete(MetaBlock *mb, int i, MetaEntry *me)
  99. {
  100. uchar *p;
  101. int n;
  102. assert(i < mb->nindex);
  103. if(me->p - mb->buf + me->size == mb->size)
  104. mb->size -= me->size;
  105. else
  106. mb->free += me->size;
  107. p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
  108. n = (mb->nindex-i-1)*MetaIndexSize;
  109. memmove(p, p+MetaIndexSize, n);
  110. memset(p+n, 0, MetaIndexSize);
  111. mb->nindex--;
  112. }
  113. void
  114. mbinsert(MetaBlock *mb, int i, MetaEntry *me)
  115. {
  116. uchar *p;
  117. int o, n;
  118. assert(mb->nindex < mb->maxindex);
  119. o = me->p - mb->buf;
  120. n = me->size;
  121. if(o+n > mb->size) {
  122. mb->free -= mb->size - o;
  123. mb->size = o + n;
  124. } else
  125. mb->free -= n;
  126. p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
  127. n = (mb->nindex-i)*MetaIndexSize;
  128. memmove(p+MetaIndexSize, p, n);
  129. U16PUT(p, me->p - mb->buf);
  130. U16PUT(p+2, me->size);
  131. mb->nindex++;
  132. }
  133. int
  134. meunpack(MetaEntry *me, MetaBlock *mb, int i)
  135. {
  136. uchar *p;
  137. int eo, en;
  138. if(i < 0 || i >= mb->nindex) {
  139. werrstr("bad meta entry index");
  140. return -1;
  141. }
  142. p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
  143. eo = U16GET(p);
  144. en = U16GET(p+2);
  145. if(0)print("eo = %d en = %d\n", eo, en);
  146. if(eo < MetaHeaderSize + mb->maxindex*MetaIndexSize) {
  147. werrstr("corrupted entry in meta block");
  148. return -1;
  149. }
  150. if(eo+en > mb->size) {
  151. werrstr("truncated meta block");
  152. return -1;
  153. }
  154. p = mb->buf + eo;
  155. /* make sure entry looks ok and includes an elem name */
  156. if(en < 8 || U32GET(p) != DirMagic || en < 8 + U16GET(p+6)) {
  157. werrstr("corrupted meta block entry");
  158. return -1;
  159. }
  160. me->p = p;
  161. me->size = en;
  162. return 0;
  163. }
  164. /* assumes a small amount of checking has been done in mbentry */
  165. int
  166. mecmp(MetaEntry *me, char *s)
  167. {
  168. int n;
  169. uchar *p;
  170. p = me->p;
  171. p += 6;
  172. n = U16GET(p);
  173. p += 2;
  174. assert(n + 8 < me->size);
  175. while(n > 0) {
  176. if(*s == 0)
  177. return -1;
  178. if(*p < (uchar)*s)
  179. return -1;
  180. if(*p > (uchar)*s)
  181. return 1;
  182. p++;
  183. s++;
  184. n--;
  185. }
  186. return *s != 0;
  187. }
  188. int
  189. mecmpnew(MetaEntry *me, char *s)
  190. {
  191. int n;
  192. uchar *p;
  193. p = me->p;
  194. p += 6;
  195. n = U16GET(p);
  196. p += 2;
  197. assert(n + 8 < me->size);
  198. while(n > 0) {
  199. if(*s == 0)
  200. return 1;
  201. if(*p < (uchar)*s)
  202. return -1;
  203. if(*p > (uchar)*s)
  204. return 1;
  205. p++;
  206. s++;
  207. n--;
  208. }
  209. return -(*s != 0);
  210. }
  211. static int
  212. offsetcmp(const void *s0, const void *s1)
  213. {
  214. const MetaChunk *mc0, *mc1;
  215. mc0 = s0;
  216. mc1 = s1;
  217. if(mc0->offset < mc1->offset)
  218. return -1;
  219. if(mc0->offset > mc1->offset)
  220. return 1;
  221. return 0;
  222. }
  223. static MetaChunk *
  224. metachunks(MetaBlock *mb)
  225. {
  226. MetaChunk *mc;
  227. int oo, o, n, i;
  228. uchar *p;
  229. mc = vtmalloc(mb->nindex*sizeof(MetaChunk));
  230. p = mb->buf + MetaHeaderSize;
  231. for(i = 0; i<mb->nindex; i++) {
  232. mc[i].offset = U16GET(p);
  233. mc[i].size = U16GET(p+2);
  234. mc[i].index = i;
  235. p += MetaIndexSize;
  236. }
  237. qsort(mc, mb->nindex, sizeof(MetaChunk), offsetcmp);
  238. /* check block looks ok */
  239. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  240. o = oo;
  241. n = 0;
  242. for(i=0; i<mb->nindex; i++) {
  243. o = mc[i].offset;
  244. n = mc[i].size;
  245. if(o < oo)
  246. goto Err;
  247. oo += n;
  248. }
  249. if(o+n <= mb->size)
  250. goto Err;
  251. if(mb->size - oo != mb->free)
  252. goto Err;
  253. return mc;
  254. Err:
  255. vtfree(mc);
  256. return nil;
  257. }
  258. static void
  259. mbcompact(MetaBlock *mb, MetaChunk *mc)
  260. {
  261. int oo, o, n, i;
  262. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  263. for(i=0; i<mb->nindex; i++) {
  264. o = mc[i].offset;
  265. n = mc[i].size;
  266. if(o != oo) {
  267. memmove(mb->buf + oo, mb->buf + o, n);
  268. U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
  269. }
  270. oo += n;
  271. }
  272. mb->size = oo;
  273. mb->free = 0;
  274. }
  275. uchar *
  276. mballoc(MetaBlock *mb, int n)
  277. {
  278. int i, o;
  279. MetaChunk *mc;
  280. /* off the end */
  281. if(mb->maxsize - mb->size >= n)
  282. return mb->buf + mb->size;
  283. /* check if possible */
  284. if(mb->maxsize - mb->size + mb->free < n)
  285. return nil;
  286. mc = metachunks(mb);
  287. /* look for hole */
  288. o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  289. for(i=0; i<mb->nindex; i++) {
  290. if(mc[i].offset - o >= n) {
  291. vtfree(mc);
  292. return mb->buf + o;
  293. }
  294. o = mc[i].offset + mc[i].size;
  295. }
  296. if(mb->maxsize - o >= n) {
  297. vtfree(mc);
  298. return mb->buf + o;
  299. }
  300. /* compact and return off the end */
  301. mbcompact(mb, mc);
  302. vtfree(mc);
  303. assert(mb->maxsize - mb->size >= n);
  304. return mb->buf + mb->size;
  305. }
  306. int
  307. vdsize(VacDir *dir, int version)
  308. {
  309. int n;
  310. if(version < 8 || version > 9)
  311. sysfatal("bad version %d in vdpack", version);
  312. /* constant part */
  313. n = 4 + /* magic */
  314. 2 + /* version */
  315. 4 + /* entry */
  316. 8 + /* qid */
  317. 4 + /* mtime */
  318. 4 + /* mcount */
  319. 4 + /* ctime */
  320. 4 + /* atime */
  321. 4 + /* mode */
  322. 0;
  323. if(version == 9){
  324. n += 4 + /* gen */
  325. 4 + /* mentry */
  326. 4 + /* mgen */
  327. 0;
  328. }
  329. /* strings */
  330. n += 2 + strlen(dir->elem);
  331. n += 2 + strlen(dir->uid);
  332. n += 2 + strlen(dir->gid);
  333. n += 2 + strlen(dir->mid);
  334. /* optional sections */
  335. if(version < 9 && dir->plan9) {
  336. n += 3 + /* option header */
  337. 8 + /* path */
  338. 4; /* version */
  339. }
  340. if(dir->qidspace) {
  341. n += 3 + /* option header */
  342. 8 + /* qid offset */
  343. 8; /* qid max */
  344. }
  345. if(version < 9 && dir->gen) {
  346. n += 3 + /* option header */
  347. 4; /* gen */
  348. }
  349. return n;
  350. }
  351. void
  352. vdpack(VacDir *dir, MetaEntry *me, int version)
  353. {
  354. uchar *p;
  355. ulong t32;
  356. if(version < 8 || version > 9)
  357. sysfatal("bad version %d in vdpack", version);
  358. p = me->p;
  359. U32PUT(p, DirMagic);
  360. U16PUT(p+4, version); /* version */
  361. p += 6;
  362. p += stringpack(dir->elem, p);
  363. U32PUT(p, dir->entry);
  364. p += 4;
  365. if(version == 9){
  366. U32PUT(p, dir->gen);
  367. U32PUT(p+4, dir->mentry);
  368. U32PUT(p+8, dir->mgen);
  369. p += 12;
  370. }
  371. U64PUT(p, dir->qid, t32);
  372. p += 8;
  373. p += stringpack(dir->uid, p);
  374. p += stringpack(dir->gid, p);
  375. p += stringpack(dir->mid, p);
  376. U32PUT(p, dir->mtime);
  377. U32PUT(p+4, dir->mcount);
  378. U32PUT(p+8, dir->ctime);
  379. U32PUT(p+12, dir->atime);
  380. U32PUT(p+16, dir->mode);
  381. p += 5*4;
  382. if(dir->plan9 && version < 9) {
  383. U8PUT(p, DirPlan9Entry);
  384. U16PUT(p+1, 8+4);
  385. p += 3;
  386. U64PUT(p, dir->p9path, t32);
  387. U32PUT(p+8, dir->p9version);
  388. p += 12;
  389. }
  390. if(dir->qidspace) {
  391. U8PUT(p, DirQidSpaceEntry);
  392. U16PUT(p+1, 2*8);
  393. p += 3;
  394. U64PUT(p, dir->qidoffset, t32);
  395. U64PUT(p+8, dir->qidmax, t32);
  396. p += 16;
  397. }
  398. if(dir->gen && version < 9) {
  399. U8PUT(p, DirGenEntry);
  400. U16PUT(p+1, 4);
  401. p += 3;
  402. U32PUT(p, dir->gen);
  403. p += 4;
  404. }
  405. assert(p == me->p + me->size);
  406. }
  407. int
  408. vdunpack(VacDir *dir, MetaEntry *me)
  409. {
  410. int t, nn, n, version;
  411. uchar *p;
  412. p = me->p;
  413. n = me->size;
  414. memset(dir, 0, sizeof(VacDir));
  415. /* magic */
  416. if(n < 4 || U32GET(p) != DirMagic)
  417. goto Err;
  418. p += 4;
  419. n -= 4;
  420. /* version */
  421. if(n < 2)
  422. goto Err;
  423. version = U16GET(p);
  424. if(version < 7 || version > 9)
  425. goto Err;
  426. p += 2;
  427. n -= 2;
  428. /* elem */
  429. if(stringunpack(&dir->elem, &p, &n) < 0)
  430. goto Err;
  431. /* entry */
  432. if(n < 4)
  433. goto Err;
  434. dir->entry = U32GET(p);
  435. p += 4;
  436. n -= 4;
  437. if(version < 9) {
  438. dir->gen = 0;
  439. dir->mentry = dir->entry+1;
  440. dir->mgen = 0;
  441. } else {
  442. if(n < 3*4)
  443. goto Err;
  444. dir->gen = U32GET(p);
  445. dir->mentry = U32GET(p+4);
  446. dir->mgen = U32GET(p+8);
  447. p += 3*4;
  448. n -= 3*4;
  449. }
  450. /* size is gotten from DirEntry */
  451. /* qid */
  452. if(n < 8)
  453. goto Err;
  454. dir->qid = U64GET(p);
  455. p += 8;
  456. n -= 8;
  457. /* skip replacement */
  458. if(version == 7) {
  459. if(n < VtScoreSize)
  460. goto Err;
  461. p += VtScoreSize;
  462. n -= VtScoreSize;
  463. }
  464. /* uid */
  465. if(stringunpack(&dir->uid, &p, &n) < 0)
  466. goto Err;
  467. /* gid */
  468. if(stringunpack(&dir->gid, &p, &n) < 0)
  469. goto Err;
  470. /* mid */
  471. if(stringunpack(&dir->mid, &p, &n) < 0)
  472. goto Err;
  473. if(n < 5*4)
  474. goto Err;
  475. dir->mtime = U32GET(p);
  476. dir->mcount = U32GET(p+4);
  477. dir->ctime = U32GET(p+8);
  478. dir->atime = U32GET(p+12);
  479. dir->mode = U32GET(p+16);
  480. p += 5*4;
  481. n -= 5*4;
  482. /* optional meta data */
  483. while(n > 0) {
  484. if(n < 3)
  485. goto Err;
  486. t = p[0];
  487. nn = U16GET(p+1);
  488. p += 3;
  489. n -= 3;
  490. if(n < nn)
  491. goto Err;
  492. switch(t) {
  493. case DirPlan9Entry:
  494. /* not valid in version >= 9 */
  495. if(version >= 9)
  496. break;
  497. if(dir->plan9 || nn != 12)
  498. goto Err;
  499. dir->plan9 = 1;
  500. dir->p9path = U64GET(p);
  501. dir->p9version = U32GET(p+8);
  502. if(dir->mcount == 0)
  503. dir->mcount = dir->p9version;
  504. break;
  505. case DirGenEntry:
  506. /* not valid in version >= 9 */
  507. if(version >= 9)
  508. break;
  509. break;
  510. case DirQidSpaceEntry:
  511. if(dir->qidspace || nn != 16)
  512. goto Err;
  513. dir->qidspace = 1;
  514. dir->qidoffset = U64GET(p);
  515. dir->qidmax = U64GET(p+8);
  516. break;
  517. }
  518. p += nn;
  519. n -= nn;
  520. }
  521. if(p != me->p + me->size)
  522. goto Err;
  523. return 0;
  524. Err:
  525. werrstr(EBadMeta);
  526. vdcleanup(dir);
  527. return -1;
  528. }
  529. void
  530. vdcleanup(VacDir *dir)
  531. {
  532. vtfree(dir->elem);
  533. dir->elem = nil;
  534. vtfree(dir->uid);
  535. dir->uid = nil;
  536. vtfree(dir->gid);
  537. dir->gid = nil;
  538. vtfree(dir->mid);
  539. dir->mid = nil;
  540. }
  541. void
  542. vdcopy(VacDir *dst, VacDir *src)
  543. {
  544. *dst = *src;
  545. dst->elem = vtstrdup(dst->elem);
  546. dst->uid = vtstrdup(dst->uid);
  547. dst->gid = vtstrdup(dst->gid);
  548. dst->mid = vtstrdup(dst->mid);
  549. }
  550. int
  551. mbsearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
  552. {
  553. int i;
  554. int b, t, x;
  555. /* binary search within block */
  556. b = 0;
  557. t = mb->nindex;
  558. while(b < t) {
  559. i = (b+t)>>1;
  560. if(meunpack(me, mb, i) < 0)
  561. return 0;
  562. if(mb->unbotch)
  563. x = mecmpnew(me, elem);
  564. else
  565. x = mecmp(me, elem);
  566. if(x == 0) {
  567. *ri = i;
  568. return 1;
  569. }
  570. if(x < 0)
  571. b = i+1;
  572. else /* x > 0 */
  573. t = i;
  574. }
  575. assert(b == t);
  576. *ri = b; /* b is the index to insert this entry */
  577. memset(me, 0, sizeof(*me));
  578. return -1;
  579. }
  580. void
  581. mbinit(MetaBlock *mb, uchar *p, int n, int entries)
  582. {
  583. memset(mb, 0, sizeof(MetaBlock));
  584. mb->maxsize = n;
  585. mb->buf = p;
  586. mb->maxindex = entries;
  587. mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  588. }
  589. int
  590. mbresize(MetaBlock *mb, MetaEntry *me, int n)
  591. {
  592. uchar *p, *ep;
  593. /* easy case */
  594. if(n <= me->size){
  595. me->size = n;
  596. return 0;
  597. }
  598. /* try and expand entry */
  599. p = me->p + me->size;
  600. ep = mb->buf + mb->maxsize;
  601. while(p < ep && *p == 0)
  602. p++;
  603. if(n <= p - me->p){
  604. me->size = n;
  605. return 0;
  606. }
  607. p = mballoc(mb, n);
  608. if(p != nil){
  609. me->p = p;
  610. me->size = n;
  611. return 0;
  612. }
  613. return -1;
  614. }