pack.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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)
  22. #define U16PUT(p,v) (p)[0]=(v)>>8;(p)[1]=(v)
  23. #define U32PUT(p,v) (p)[0]=(v)>>24;(p)[1]=(v)>>16;(p)[2]=(v)>>8;(p)[3]=(v)
  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 0;
  32. nn = U16GET(*p);
  33. *p += 2;
  34. *n -= 2;
  35. if(nn > *n)
  36. return 0;
  37. *s = vtMemAlloc(nn+1);
  38. memmove(*s, *p, nn);
  39. (*s)[nn] = 0;
  40. *p += nn;
  41. *n -= nn;
  42. return 1;
  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 1;
  62. }
  63. magic = U32GET(p);
  64. if(magic != MetaMagic && magic != MetaMagic+1) {
  65. vtSetError("bad meta block magic");
  66. return 0;
  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. vtSetError("bad meta block size");
  75. return 0;
  76. }
  77. p += MetaHeaderSize;
  78. n -= MetaHeaderSize;
  79. USED(p);
  80. if(n < mb->maxindex*MetaIndexSize) {
  81. vtSetError("truncated meta block 2");
  82. return 0;
  83. }
  84. return 1;
  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. vtSetError("bad meta entry index");
  140. return 0;
  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. vtSetError("corrupted entry in meta block");
  148. return 0;
  149. }
  150. if(eo+en > mb->size) {
  151. vtSetError("truncated meta block");
  152. return 0;
  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. vtSetError("corrupted meta block entry");
  158. return 0;
  159. }
  160. me->p = p;
  161. me->size = en;
  162. return 1;
  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(void *s0, void *s1)
  213. {
  214. 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 = vtMemAlloc(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. vtMemFree(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. vtMemFree(mc);
  292. return mb->buf + o;
  293. }
  294. o = mc[i].offset + mc[i].size;
  295. }
  296. if(mb->maxsize - o >= n) {
  297. vtMemFree(mc);
  298. return mb->buf + o;
  299. }
  300. /* compact and return off the end */
  301. mbCompact(mb, mc);
  302. vtMemFree(mc);
  303. assert(mb->maxsize - mb->size >= n);
  304. return mb->buf + mb->size;
  305. }
  306. int
  307. vdSize(VacDir *dir)
  308. {
  309. int n;
  310. /* constant part */
  311. n = 4 + /* magic */
  312. 2 + /* version */
  313. 4 + /* entry */
  314. 4 + /* guid */
  315. 4 + /* mentry */
  316. 4 + /* mgen */
  317. 8 + /* qid */
  318. 4 + /* mtime */
  319. 4 + /* mcount */
  320. 4 + /* ctime */
  321. 4 + /* atime */
  322. 4 + /* mode */
  323. 0;
  324. /* strings */
  325. n += 2 + strlen(dir->elem);
  326. n += 2 + strlen(dir->uid);
  327. n += 2 + strlen(dir->gid);
  328. n += 2 + strlen(dir->mid);
  329. /* optional sections */
  330. if(dir->qidSpace) {
  331. n += 3 + /* option header */
  332. 8 + /* qidOffset */
  333. 8; /* qid Max */
  334. }
  335. return n;
  336. }
  337. void
  338. vdPack(VacDir *dir, MetaEntry *me)
  339. {
  340. uchar *p;
  341. ulong t32;
  342. p = me->p;
  343. U32PUT(p, DirMagic);
  344. U16PUT(p+4, 9); /* version */
  345. p += 6;
  346. p += stringPack(dir->elem, p);
  347. U32PUT(p, dir->entry);
  348. U32PUT(p+4, dir->gen);
  349. U32PUT(p+8, dir->mentry);
  350. U32PUT(p+12, dir->mgen);
  351. U64PUT(p+16, dir->qid, t32);
  352. p += 24;
  353. p += stringPack(dir->uid, p);
  354. p += stringPack(dir->gid, p);
  355. p += stringPack(dir->mid, p);
  356. U32PUT(p, dir->mtime);
  357. U32PUT(p+4, dir->mcount);
  358. U32PUT(p+8, dir->ctime);
  359. U32PUT(p+12, dir->atime);
  360. U32PUT(p+16, dir->mode);
  361. p += 5*4;
  362. if(dir->qidSpace) {
  363. U8PUT(p, DirQidSpaceEntry);
  364. U16PUT(p+1, 2*8);
  365. p += 3;
  366. U64PUT(p, dir->qidOffset, t32);
  367. U64PUT(p+8, dir->qidMax, t32);
  368. }
  369. assert(p == me->p + me->size);
  370. }
  371. int
  372. vdUnpack(VacDir *dir, MetaEntry *me)
  373. {
  374. int t, nn, n, version;
  375. uchar *p;
  376. p = me->p;
  377. n = me->size;
  378. memset(dir, 0, sizeof(VacDir));
  379. if(0)print("vdUnpack\n");
  380. /* magic */
  381. if(n < 4 || U32GET(p) != DirMagic)
  382. goto Err;
  383. p += 4;
  384. n -= 4;
  385. if(0)print("vdUnpack: got magic\n");
  386. /* version */
  387. if(n < 2)
  388. goto Err;
  389. version = U16GET(p);
  390. if(version < 7 || version > 9)
  391. goto Err;
  392. p += 2;
  393. n -= 2;
  394. if(0)print("vdUnpack: got version\n");
  395. /* elem */
  396. if(!stringUnpack(&dir->elem, &p, &n))
  397. goto Err;
  398. if(0)print("vdUnpack: got elem\n");
  399. /* entry */
  400. if(n < 4)
  401. goto Err;
  402. dir->entry = U32GET(p);
  403. p += 4;
  404. n -= 4;
  405. if(0)print("vdUnpack: got entry\n");
  406. if(version < 9) {
  407. dir->gen = 0;
  408. dir->mentry = dir->entry+1;
  409. dir->mgen = 0;
  410. } else {
  411. if(n < 3*4)
  412. goto Err;
  413. dir->gen = U32GET(p);
  414. dir->mentry = U32GET(p+4);
  415. dir->mgen = U32GET(p+8);
  416. p += 3*4;
  417. n -= 3*4;
  418. }
  419. if(0)print("vdUnpack: got gen etc\n");
  420. /* size is gotten from DirEntry */
  421. /* qid */
  422. if(n < 8)
  423. goto Err;
  424. dir->qid = U64GET(p);
  425. p += 8;
  426. n -= 8;
  427. if(0)print("vdUnpack: got qid\n");
  428. /* skip replacement */
  429. if(version == 7) {
  430. if(n < VtScoreSize)
  431. goto Err;
  432. p += VtScoreSize;
  433. n -= VtScoreSize;
  434. }
  435. /* uid */
  436. if(!stringUnpack(&dir->uid, &p, &n))
  437. goto Err;
  438. /* gid */
  439. if(!stringUnpack(&dir->gid, &p, &n))
  440. goto Err;
  441. /* mid */
  442. if(!stringUnpack(&dir->mid, &p, &n))
  443. goto Err;
  444. if(0)print("vdUnpack: got ids\n");
  445. if(n < 5*4)
  446. goto Err;
  447. dir->mtime = U32GET(p);
  448. dir->mcount = U32GET(p+4);
  449. dir->ctime = U32GET(p+8);
  450. dir->atime = U32GET(p+12);
  451. dir->mode = U32GET(p+16);
  452. p += 5*4;
  453. n -= 5*4;
  454. if(0)print("vdUnpack: got times\n");
  455. /* optional meta data */
  456. while(n > 0) {
  457. if(n < 3)
  458. goto Err;
  459. t = p[0];
  460. nn = U16GET(p+1);
  461. p += 3;
  462. n -= 3;
  463. if(n < nn)
  464. goto Err;
  465. switch(t) {
  466. case DirPlan9Entry:
  467. /* not valid in version >= 9 */
  468. if(version >= 9)
  469. break;
  470. if(dir->plan9 || nn != 12)
  471. goto Err;
  472. dir->plan9 = 1;
  473. dir->p9path = U64GET(p);
  474. dir->p9version = U32GET(p+8);
  475. if(dir->mcount == 0)
  476. dir->mcount = dir->p9version;
  477. break;
  478. case DirGenEntry:
  479. /* not valid in version >= 9 */
  480. if(version >= 9)
  481. break;
  482. break;
  483. case DirQidSpaceEntry:
  484. if(dir->qidSpace || nn != 16)
  485. goto Err;
  486. dir->qidSpace = 1;
  487. dir->qidOffset = U64GET(p);
  488. dir->qidMax = U64GET(p+8);
  489. break;
  490. }
  491. p += nn;
  492. n -= nn;
  493. }
  494. if(0)print("vdUnpack: got options\n");
  495. if(p != me->p + me->size)
  496. goto Err;
  497. if(0)print("vdUnpack: correct size\n");
  498. return 1;
  499. Err:
  500. if(0)print("vdUnpack: XXXXXXXXXXXX EbadMeta\n");
  501. vtSetError(EBadMeta);
  502. vdCleanup(dir);
  503. return 0;
  504. }