vac.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. #include "stdinc.h"
  2. typedef struct MetaChunk MetaChunk;
  3. struct MetaChunk {
  4. ushort offset;
  5. ushort size;
  6. ushort index;
  7. };
  8. static int stringUnpack(char **s, uchar **p, int *n);
  9. static int meCmp(MetaEntry*, char *s);
  10. static int meCmpOld(MetaEntry*, char *s);
  11. static char EBadMeta[] = "corrupted meta data";
  12. static char ENoFile[] = "file does not exist";
  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. mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
  55. {
  56. int i;
  57. int b, t, x;
  58. if(0)fprint(2, "mbSearch %s\n", elem);
  59. /* binary search within block */
  60. b = 0;
  61. t = mb->nindex;
  62. while(b < t){
  63. i = (b+t)>>1;
  64. meUnpack(me, mb, i);
  65. if(mb->botch)
  66. x = meCmpOld(me, elem);
  67. else
  68. x = meCmp(me, elem);
  69. if(x == 0){
  70. *ri = i;
  71. return 1;
  72. }
  73. if(x < 0)
  74. b = i+1;
  75. else /* x > 0 */
  76. t = i;
  77. }
  78. assert(b == t);
  79. *ri = b; /* b is the index to insert this entry */
  80. memset(me, 0, sizeof(*me));
  81. vtSetError(ENoFile);
  82. return 0;
  83. }
  84. void
  85. mbInit(MetaBlock *mb, uchar *p, int n, int ne)
  86. {
  87. memset(p, 0, n);
  88. mb->maxsize = n;
  89. mb->maxindex = ne;
  90. mb->nindex = 0;
  91. mb->free = 0;
  92. mb->size = MetaHeaderSize + ne*MetaIndexSize;
  93. mb->buf = p;
  94. mb->botch = 0;
  95. }
  96. int
  97. mbUnpack(MetaBlock *mb, uchar *p, int n)
  98. {
  99. u32int magic;
  100. int i;
  101. int eo, en, omin;
  102. uchar *q;
  103. mb->maxsize = n;
  104. mb->buf = p;
  105. if(n == 0){
  106. memset(mb, 0, sizeof(MetaBlock));
  107. return 1;
  108. }
  109. magic = U32GET(p);
  110. if(magic != MetaMagic && magic != MetaMagic-1)
  111. goto Err;
  112. mb->size = U16GET(p+4);
  113. mb->free = U16GET(p+6);
  114. mb->maxindex = U16GET(p+8);
  115. mb->nindex = U16GET(p+10);
  116. mb->botch = magic != MetaMagic;
  117. if(mb->size > n)
  118. goto Err;
  119. omin = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  120. if(n < omin)
  121. goto Err;
  122. p += MetaHeaderSize;
  123. /* check the index table - ensures that meUnpack and meCmp never fail */
  124. for(i=0; i<mb->nindex; i++){
  125. eo = U16GET(p);
  126. en = U16GET(p+2);
  127. if(eo < omin || eo+en > mb->size || en < 8)
  128. goto Err;
  129. q = mb->buf + eo;
  130. if(U32GET(q) != DirMagic)
  131. goto Err;
  132. p += 4;
  133. }
  134. return 1;
  135. Err:
  136. vtSetError(EBadMeta);
  137. return 0;
  138. }
  139. void
  140. mbPack(MetaBlock *mb)
  141. {
  142. uchar *p;
  143. p = mb->buf;
  144. assert(!mb->botch);
  145. U32PUT(p, MetaMagic);
  146. U16PUT(p+4, mb->size);
  147. U16PUT(p+6, mb->free);
  148. U16PUT(p+8, mb->maxindex);
  149. U16PUT(p+10, mb->nindex);
  150. }
  151. void
  152. mbDelete(MetaBlock *mb, int i)
  153. {
  154. uchar *p;
  155. int n;
  156. MetaEntry me;
  157. assert(i < mb->nindex);
  158. meUnpack(&me, mb, i);
  159. memset(me.p, 0, me.size);
  160. if(me.p - mb->buf + me.size == mb->size)
  161. mb->size -= me.size;
  162. else
  163. mb->free += me.size;
  164. p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
  165. n = (mb->nindex-i-1)*MetaIndexSize;
  166. memmove(p, p+MetaIndexSize, n);
  167. memset(p+n, 0, MetaIndexSize);
  168. mb->nindex--;
  169. }
  170. void
  171. mbInsert(MetaBlock *mb, int i, MetaEntry *me)
  172. {
  173. uchar *p;
  174. int o, n;
  175. assert(mb->nindex < mb->maxindex);
  176. o = me->p - mb->buf;
  177. n = me->size;
  178. if(o+n > mb->size){
  179. mb->free -= mb->size - o;
  180. mb->size = o + n;
  181. }else
  182. mb->free -= n;
  183. p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
  184. n = (mb->nindex-i)*MetaIndexSize;
  185. memmove(p+MetaIndexSize, p, n);
  186. U16PUT(p, me->p - mb->buf);
  187. U16PUT(p+2, me->size);
  188. mb->nindex++;
  189. }
  190. int
  191. mbResize(MetaBlock *mb, MetaEntry *me, int n)
  192. {
  193. uchar *p, *ep;
  194. /* easy case */
  195. if(n <= me->size){
  196. me->size = n;
  197. return 1;
  198. }
  199. /* try and expand entry */
  200. p = me->p + me->size;
  201. ep = mb->buf + mb->maxsize;
  202. while(p < ep && *p == 0)
  203. p++;
  204. if(n <= p - me->p){
  205. me->size = n;
  206. return 1;
  207. }
  208. p = mbAlloc(mb, n);
  209. if(p != nil){
  210. me->p = p;
  211. me->size = n;
  212. return 1;
  213. }
  214. return 0;
  215. }
  216. void
  217. meUnpack(MetaEntry *me, MetaBlock *mb, int i)
  218. {
  219. uchar *p;
  220. int eo, en;
  221. assert(i >= 0 && i < mb->nindex);
  222. p = mb->buf + MetaHeaderSize + i*MetaIndexSize;
  223. eo = U16GET(p);
  224. en = U16GET(p+2);
  225. me->p = mb->buf + eo;
  226. me->size = en;
  227. /* checked by mbUnpack */
  228. assert(me->size >= 8);
  229. }
  230. /* assumes a small amount of checking has been done in mbEntry */
  231. static int
  232. meCmp(MetaEntry *me, char *s)
  233. {
  234. int n;
  235. uchar *p;
  236. p = me->p;
  237. /* skip magic & version */
  238. p += 6;
  239. n = U16GET(p);
  240. p += 2;
  241. if(n > me->size - 8)
  242. n = me->size - 8;
  243. while(n > 0){
  244. if(*s == 0)
  245. return 1;
  246. if(*p < (uchar)*s)
  247. return -1;
  248. if(*p > (uchar)*s)
  249. return 1;
  250. p++;
  251. s++;
  252. n--;
  253. }
  254. return -(*s != 0);
  255. }
  256. /*
  257. * This is the old and broken meCmp.
  258. * This cmp routine reverse the sense of the comparison
  259. * when one string is a prefix of the other.
  260. * In other words, it put "ab" after "abc" rather
  261. * than before. This behaviour is ok; binary search
  262. * and sort still work. However, it is goes against
  263. * the usual convention.
  264. */
  265. static int
  266. meCmpOld(MetaEntry *me, char *s)
  267. {
  268. int n;
  269. uchar *p;
  270. p = me->p;
  271. /* skip magic & version */
  272. p += 6;
  273. n = U16GET(p);
  274. p += 2;
  275. if(n > me->size - 8)
  276. n = me->size - 8;
  277. while(n > 0){
  278. if(*s == 0)
  279. return -1;
  280. if(*p < (uchar)*s)
  281. return -1;
  282. if(*p > (uchar)*s)
  283. return 1;
  284. p++;
  285. s++;
  286. n--;
  287. }
  288. return *s != 0;
  289. }
  290. static int
  291. offsetCmp(void *s0, void *s1)
  292. {
  293. MetaChunk *mc0, *mc1;
  294. mc0 = s0;
  295. mc1 = s1;
  296. if(mc0->offset < mc1->offset)
  297. return -1;
  298. if(mc0->offset > mc1->offset)
  299. return 1;
  300. return 0;
  301. }
  302. static MetaChunk *
  303. metaChunks(MetaBlock *mb)
  304. {
  305. MetaChunk *mc;
  306. int oo, o, n, i;
  307. uchar *p;
  308. mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk));
  309. p = mb->buf + MetaHeaderSize;
  310. for(i = 0; i<mb->nindex; i++){
  311. mc[i].offset = U16GET(p);
  312. mc[i].size = U16GET(p+2);
  313. mc[i].index = i;
  314. p += MetaIndexSize;
  315. }
  316. qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp);
  317. /* check block looks ok */
  318. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  319. o = oo;
  320. n = 0;
  321. for(i=0; i<mb->nindex; i++){
  322. o = mc[i].offset;
  323. n = mc[i].size;
  324. if(o < oo)
  325. goto Err;
  326. oo += n;
  327. }
  328. if(o+n > mb->size)
  329. goto Err;
  330. if(mb->size - oo != mb->free)
  331. goto Err;
  332. return mc;
  333. Err:
  334. fprint(2, "metaChunks failed!\n");
  335. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  336. for(i=0; i<mb->nindex; i++){
  337. fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size);
  338. oo += mc[i].size;
  339. }
  340. fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo);
  341. vtSetError(EBadMeta);
  342. vtMemFree(mc);
  343. return nil;
  344. }
  345. static void
  346. mbCompact(MetaBlock *mb, MetaChunk *mc)
  347. {
  348. int oo, o, n, i;
  349. oo = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  350. for(i=0; i<mb->nindex; i++){
  351. o = mc[i].offset;
  352. n = mc[i].size;
  353. if(o != oo){
  354. memmove(mb->buf + oo, mb->buf + o, n);
  355. U16PUT(mb->buf + MetaHeaderSize + mc[i].index*MetaIndexSize, oo);
  356. }
  357. oo += n;
  358. }
  359. mb->size = oo;
  360. mb->free = 0;
  361. }
  362. uchar *
  363. mbAlloc(MetaBlock *mb, int n)
  364. {
  365. int i, o;
  366. MetaChunk *mc;
  367. /* off the end */
  368. if(mb->maxsize - mb->size >= n)
  369. return mb->buf + mb->size;
  370. /* check if possible */
  371. if(mb->maxsize - mb->size + mb->free < n)
  372. return nil;
  373. mc = metaChunks(mb);
  374. if(mc == nil){
  375. fprint(2, "mbAlloc: metaChunks failed: %r\n");
  376. return nil;
  377. }
  378. /* look for hole */
  379. o = MetaHeaderSize + mb->maxindex*MetaIndexSize;
  380. for(i=0; i<mb->nindex; i++){
  381. if(mc[i].offset - o >= n){
  382. vtMemFree(mc);
  383. return mb->buf + o;
  384. }
  385. o = mc[i].offset + mc[i].size;
  386. }
  387. if(mb->maxsize - o >= n){
  388. vtMemFree(mc);
  389. return mb->buf + o;
  390. }
  391. /* compact and return off the end */
  392. mbCompact(mb, mc);
  393. vtMemFree(mc);
  394. if(mb->maxsize - mb->size < n){
  395. vtSetError(EBadMeta);
  396. return nil;
  397. }
  398. return mb->buf + mb->size;
  399. }
  400. int
  401. deSize(DirEntry *dir)
  402. {
  403. int n;
  404. /* constant part */
  405. n = 4 + /* magic */
  406. 2 + /* version */
  407. 4 + /* entry */
  408. 4 + /* guid */
  409. 4 + /* mentry */
  410. 4 + /* mgen */
  411. 8 + /* qid */
  412. 4 + /* mtime */
  413. 4 + /* mcount */
  414. 4 + /* ctime */
  415. 4 + /* atime */
  416. 4 + /* mode */
  417. 0;
  418. /* strings */
  419. n += 2 + strlen(dir->elem);
  420. n += 2 + strlen(dir->uid);
  421. n += 2 + strlen(dir->gid);
  422. n += 2 + strlen(dir->mid);
  423. /* optional sections */
  424. if(dir->qidSpace){
  425. n += 3 + /* option header */
  426. 8 + /* qidOffset */
  427. 8; /* qid Max */
  428. }
  429. return n;
  430. }
  431. void
  432. dePack(DirEntry *dir, MetaEntry *me)
  433. {
  434. uchar *p;
  435. ulong t32;
  436. p = me->p;
  437. U32PUT(p, DirMagic);
  438. U16PUT(p+4, 9); /* version */
  439. p += 6;
  440. p += stringPack(dir->elem, p);
  441. U32PUT(p, dir->entry);
  442. U32PUT(p+4, dir->gen);
  443. U32PUT(p+8, dir->mentry);
  444. U32PUT(p+12, dir->mgen);
  445. U64PUT(p+16, dir->qid, t32);
  446. p += 24;
  447. p += stringPack(dir->uid, p);
  448. p += stringPack(dir->gid, p);
  449. p += stringPack(dir->mid, p);
  450. U32PUT(p, dir->mtime);
  451. U32PUT(p+4, dir->mcount);
  452. U32PUT(p+8, dir->ctime);
  453. U32PUT(p+12, dir->atime);
  454. U32PUT(p+16, dir->mode);
  455. p += 5*4;
  456. if(dir->qidSpace){
  457. U8PUT(p, DeQidSpace);
  458. U16PUT(p+1, 2*8);
  459. p += 3;
  460. U64PUT(p, dir->qidOffset, t32);
  461. U64PUT(p+8, dir->qidMax, t32);
  462. p += 16;
  463. }
  464. assert(p == me->p + me->size);
  465. }
  466. int
  467. deUnpack(DirEntry *dir, MetaEntry *me)
  468. {
  469. int t, nn, n, version;
  470. uchar *p;
  471. p = me->p;
  472. n = me->size;
  473. memset(dir, 0, sizeof(DirEntry));
  474. if(0)print("deUnpack\n");
  475. /* magic */
  476. if(n < 4 || U32GET(p) != DirMagic)
  477. goto Err;
  478. p += 4;
  479. n -= 4;
  480. if(0)print("deUnpack: got magic\n");
  481. /* version */
  482. if(n < 2)
  483. goto Err;
  484. version = U16GET(p);
  485. if(version < 7 || version > 9)
  486. goto Err;
  487. p += 2;
  488. n -= 2;
  489. if(0)print("deUnpack: got version\n");
  490. /* elem */
  491. if(!stringUnpack(&dir->elem, &p, &n))
  492. goto Err;
  493. if(0)print("deUnpack: got elem\n");
  494. /* entry */
  495. if(n < 4)
  496. goto Err;
  497. dir->entry = U32GET(p);
  498. p += 4;
  499. n -= 4;
  500. if(0)print("deUnpack: got entry\n");
  501. if(version < 9){
  502. dir->gen = 0;
  503. dir->mentry = dir->entry+1;
  504. dir->mgen = 0;
  505. }else{
  506. if(n < 3*4)
  507. goto Err;
  508. dir->gen = U32GET(p);
  509. dir->mentry = U32GET(p+4);
  510. dir->mgen = U32GET(p+8);
  511. p += 3*4;
  512. n -= 3*4;
  513. }
  514. if(0)print("deUnpack: got gen etc\n");
  515. /* size is gotten from VtEntry */
  516. dir->size = 0;
  517. /* qid */
  518. if(n < 8)
  519. goto Err;
  520. dir->qid = U64GET(p);
  521. p += 8;
  522. n -= 8;
  523. if(0)print("deUnpack: got qid\n");
  524. /* skip replacement */
  525. if(version == 7){
  526. if(n < VtScoreSize)
  527. goto Err;
  528. p += VtScoreSize;
  529. n -= VtScoreSize;
  530. }
  531. /* uid */
  532. if(!stringUnpack(&dir->uid, &p, &n))
  533. goto Err;
  534. /* gid */
  535. if(!stringUnpack(&dir->gid, &p, &n))
  536. goto Err;
  537. /* mid */
  538. if(!stringUnpack(&dir->mid, &p, &n))
  539. goto Err;
  540. if(0)print("deUnpack: got ids\n");
  541. if(n < 5*4)
  542. goto Err;
  543. dir->mtime = U32GET(p);
  544. dir->mcount = U32GET(p+4);
  545. dir->ctime = U32GET(p+8);
  546. dir->atime = U32GET(p+12);
  547. dir->mode = U32GET(p+16);
  548. p += 5*4;
  549. n -= 5*4;
  550. if(0)print("deUnpack: got times\n");
  551. /* optional meta data */
  552. while(n > 0){
  553. if(n < 3)
  554. goto Err;
  555. t = p[0];
  556. nn = U16GET(p+1);
  557. p += 3;
  558. n -= 3;
  559. if(n < nn)
  560. goto Err;
  561. switch(t){
  562. case DePlan9:
  563. /* not valid in version >= 9 */
  564. if(version >= 9)
  565. break;
  566. if(dir->plan9 || nn != 12)
  567. goto Err;
  568. dir->plan9 = 1;
  569. dir->p9path = U64GET(p);
  570. dir->p9version = U32GET(p+8);
  571. if(dir->mcount == 0)
  572. dir->mcount = dir->p9version;
  573. break;
  574. case DeGen:
  575. /* not valid in version >= 9 */
  576. if(version >= 9)
  577. break;
  578. break;
  579. case DeQidSpace:
  580. if(dir->qidSpace || nn != 16)
  581. goto Err;
  582. dir->qidSpace = 1;
  583. dir->qidOffset = U64GET(p);
  584. dir->qidMax = U64GET(p+8);
  585. break;
  586. }
  587. p += nn;
  588. n -= nn;
  589. }
  590. if(0)print("deUnpack: got options\n");
  591. if(p != me->p + me->size)
  592. goto Err;
  593. if(0)print("deUnpack: correct size\n");
  594. return 1;
  595. Err:
  596. if(0)print("deUnpack: XXXXXXXXXXXX EBadMeta\n");
  597. vtSetError(EBadMeta);
  598. deCleanup(dir);
  599. return 0;
  600. }
  601. void
  602. deCleanup(DirEntry *dir)
  603. {
  604. vtMemFree(dir->elem);
  605. dir->elem = nil;
  606. vtMemFree(dir->uid);
  607. dir->uid = nil;
  608. vtMemFree(dir->gid);
  609. dir->gid = nil;
  610. vtMemFree(dir->mid);
  611. dir->mid = nil;
  612. }
  613. void
  614. deCopy(DirEntry *dst, DirEntry *src)
  615. {
  616. *dst = *src;
  617. dst->elem = vtStrDup(src->elem);
  618. dst->uid = vtStrDup(src->uid);
  619. dst->gid = vtStrDup(src->gid);
  620. dst->mid = vtStrDup(src->mid);
  621. }