pack.c 12 KB

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