chk.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. #include "all.h"
  2. /* augmented Dentry */
  3. typedef struct {
  4. Dentry *d;
  5. Off qpath;
  6. int ns;
  7. } Extdentry;
  8. static char* abits;
  9. static long sizabits;
  10. static char* qbits;
  11. static long sizqbits;
  12. static char* name;
  13. static long sizname;
  14. static Off fstart;
  15. static Off fsize;
  16. static Off nfiles;
  17. static Off maxq;
  18. static Device* dev;
  19. static Off ndup;
  20. static Off nused;
  21. static Off nfdup;
  22. static Off nqbad;
  23. static Off nfree;
  24. static Off nbad;
  25. static int mod;
  26. static int flags;
  27. static int ronly;
  28. static int cwflag;
  29. static Devsize sbaddr;
  30. static Devsize oldblock;
  31. static int depth;
  32. static int maxdepth;
  33. static uchar *lowstack, *startstack;
  34. /* local prototypes */
  35. static int amark(Off);
  36. static void* chkalloc(ulong);
  37. static void ckfreelist(Superb*);
  38. static int fmark(Off);
  39. static int fsck(Dentry*);
  40. static int ftest(Off);
  41. static Dentry* maked(Off, int, Off);
  42. static void missing(void);
  43. static void mkfreelist(Superb*);
  44. static void modd(Off, int, Dentry*);
  45. static void qmark(Off);
  46. static void trfreelist(Superb*);
  47. static void xaddfree(Device*, Off, Superb*, Iobuf*);
  48. static void xflush(Device*, Superb*, Iobuf*);
  49. static void xread(Off, Off);
  50. static Iobuf* xtag(Off, int, Off);
  51. static void *
  52. chkalloc(ulong n)
  53. {
  54. char *p = mallocz(n, 1);
  55. if (p == nil)
  56. panic("chkalloc: out of memory");
  57. return p;
  58. }
  59. void
  60. chkfree(void *p)
  61. {
  62. free(p);
  63. }
  64. /*
  65. * check flags
  66. */
  67. enum
  68. {
  69. Crdall = (1<<0), /* read all files */
  70. Ctag = (1<<1), /* rebuild tags */
  71. Cpfile = (1<<2), /* print files */
  72. Cpdir = (1<<3), /* print directories */
  73. Cfree = (1<<4), /* rebuild free list */
  74. // Csetqid = (1<<5), /* resequence qids */
  75. Cream = (1<<6), /* clear all bad tags */
  76. Cbad = (1<<7), /* clear all bad blocks */
  77. Ctouch = (1<<8), /* touch old dir and indir */
  78. Ctrim = (1<<9), /* trim fsize back to fit when checking free list */
  79. };
  80. static struct {
  81. char* option;
  82. long flag;
  83. } ckoption[] = {
  84. "rdall", Crdall,
  85. "tag", Ctag,
  86. "pfile", Cpfile,
  87. "pdir", Cpdir,
  88. "free", Cfree,
  89. // "setqid", Csetqid,
  90. "ream", Cream,
  91. "bad", Cbad,
  92. "touch", Ctouch,
  93. "trim", Ctrim,
  94. 0,
  95. };
  96. void
  97. cmd_check(int argc, char *argv[])
  98. {
  99. long f, i, flag;
  100. Off raddr;
  101. Filsys *fs;
  102. Iobuf *p;
  103. Superb *sb;
  104. Dentry *d;
  105. flag = 0;
  106. for(i=1; i<argc; i++) {
  107. for(f=0; ckoption[f].option; f++)
  108. if(strcmp(argv[i], ckoption[f].option) == 0)
  109. goto found;
  110. print("unknown check option %s\n", argv[i]);
  111. for(f=0; ckoption[f].option; f++)
  112. print("\t%s\n", ckoption[f].option);
  113. return;
  114. found:
  115. flag |= ckoption[f].flag;
  116. }
  117. fs = cons.curfs;
  118. dev = fs->dev;
  119. ronly = (dev->type == Devro);
  120. cwflag = (dev->type == Devcw) | (dev->type == Devro);
  121. if(!ronly)
  122. wlock(&mainlock); /* check */
  123. flags = flag;
  124. name = abits = qbits = nil; /* in case of goto */
  125. sbaddr = superaddr(dev);
  126. raddr = getraddr(dev);
  127. p = xtag(sbaddr, Tsuper, QPSUPER);
  128. if(!p)
  129. goto out;
  130. sb = (Superb*)p->iobuf;
  131. fstart = 2;
  132. cons.noage = 1;
  133. /* 200 is slop since qidgen is likely to be a little bit low */
  134. sizqbits = (sb->qidgen+200 + 7) / 8;
  135. qbits = chkalloc(sizqbits);
  136. fsize = sb->fsize;
  137. sizabits = (fsize-fstart + 7)/8;
  138. abits = chkalloc(sizabits);
  139. sizname = 4000;
  140. name = chkalloc(sizname);
  141. sizname -= NAMELEN+10; /* for safety */
  142. mod = 0;
  143. nfree = 0;
  144. nfdup = 0;
  145. nused = 0;
  146. nbad = 0;
  147. ndup = 0;
  148. nqbad = 0;
  149. depth = 0;
  150. maxdepth = 0;
  151. if(flags & Ctouch) {
  152. /* round fsize down to start of current side */
  153. int s;
  154. Devsize dsize;
  155. oldblock = 0;
  156. for (s = 0; dsize = wormsizeside(dev, s),
  157. dsize > 0 && oldblock + dsize < fsize; s++)
  158. oldblock += dsize;
  159. print("oldblock = %lld\n", (Wideoff)oldblock);
  160. }
  161. amark(sbaddr);
  162. if(cwflag) {
  163. amark(sb->roraddr);
  164. amark(sb->next);
  165. }
  166. print("checking filsys: %s\n", fs->name);
  167. nfiles = 0;
  168. maxq = 0;
  169. d = maked(raddr, 0, QPROOT);
  170. if(d) {
  171. amark(raddr);
  172. if(fsck(d))
  173. modd(raddr, 0, d);
  174. chkfree(d);
  175. depth--;
  176. if(depth)
  177. print("depth not zero on return\n");
  178. }
  179. if(flags & Cfree)
  180. if(cwflag)
  181. trfreelist(sb);
  182. else
  183. mkfreelist(sb);
  184. if(sb->qidgen < maxq)
  185. print("qid generator low path=%lld maxq=%lld\n",
  186. (Wideoff)sb->qidgen, (Wideoff)maxq);
  187. if(!(flags & Cfree))
  188. ckfreelist(sb);
  189. if(mod) {
  190. sb->qidgen = maxq;
  191. print("file system was modified\n");
  192. settag(p, Tsuper, QPNONE);
  193. }
  194. print("nfiles = %lld\n", (Wideoff)nfiles);
  195. print("fsize = %lld\n", (Wideoff)fsize);
  196. print("nused = %lld\n", (Wideoff)nused);
  197. print("ndup = %lld\n", (Wideoff)ndup);
  198. print("nfree = %lld\n", (Wideoff)nfree);
  199. print("tfree = %lld\n", (Wideoff)sb->tfree);
  200. print("nfdup = %lld\n", (Wideoff)nfdup);
  201. print("nmiss = %lld\n", (Wideoff)fsize-fstart-nused-nfree);
  202. print("nbad = %lld\n", (Wideoff)nbad);
  203. print("nqbad = %lld\n", (Wideoff)nqbad);
  204. print("maxq = %lld\n", (Wideoff)maxq);
  205. print("base stack=%llud\n", (vlong)startstack);
  206. /* high-water mark of stack usage */
  207. print("high stack=%llud\n", (vlong)lowstack);
  208. print("deepest recursion=%d\n", maxdepth-1); /* one-origin */
  209. if(!cwflag)
  210. missing();
  211. out:
  212. cons.noage = 0;
  213. putbuf(p);
  214. chkfree(name);
  215. chkfree(abits);
  216. chkfree(qbits);
  217. name = abits = qbits = nil;
  218. if(!ronly)
  219. wunlock(&mainlock);
  220. }
  221. /*
  222. * if *blkp is already allocated and Cbad is set, zero it.
  223. * returns *blkp if it's free, else 0.
  224. */
  225. static Off
  226. blkck(Off *blkp, int *flgp)
  227. {
  228. Off a = *blkp;
  229. if(amark(a)) {
  230. if(flags & Cbad) {
  231. *blkp = 0;
  232. *flgp |= Bmod;
  233. }
  234. a = 0;
  235. }
  236. return a;
  237. }
  238. /*
  239. * if a block address within a Dentry, *blkp, is already allocated
  240. * and Cbad is set, zero it.
  241. * stores 0 into *resp if already allocated, else stores *blkp.
  242. * returns dmod count.
  243. */
  244. static int
  245. daddrck(Off *blkp, Off *resp)
  246. {
  247. int dmod = 0;
  248. if(amark(*blkp)) {
  249. if(flags & Cbad) {
  250. *blkp = 0;
  251. dmod++;
  252. }
  253. *resp = 0;
  254. } else
  255. *resp = *blkp;
  256. return dmod;
  257. }
  258. /*
  259. * under Ctouch, read block `a' if it's in range.
  260. * returns dmod count.
  261. */
  262. static int
  263. touch(Off a)
  264. {
  265. if((flags&Ctouch) && a < oldblock) {
  266. Iobuf *pd = getbuf(dev, a, Brd|Bmod);
  267. if(pd)
  268. putbuf(pd);
  269. return 1;
  270. }
  271. return 0;
  272. }
  273. /*
  274. * if d is a directory, touch it and check all its entries in block a.
  275. * if not, under Crdall, read a.
  276. * returns dmod count.
  277. */
  278. static int
  279. dirck(Extdentry *ed, Off a)
  280. {
  281. int k, dmod = 0;
  282. if(ed->d->mode & DDIR) {
  283. dmod += touch(a);
  284. for(k=0; k<DIRPERBUF; k++) {
  285. Dentry *nd = maked(a, k, ed->qpath);
  286. if(nd == nil)
  287. break;
  288. if(fsck(nd)) {
  289. modd(a, k, nd);
  290. dmod++;
  291. }
  292. chkfree(nd);
  293. depth--;
  294. name[ed->ns] = 0;
  295. }
  296. } else if(flags & Crdall)
  297. xread(a, ed->qpath);
  298. return dmod;
  299. }
  300. /*
  301. * touch a, check a's tag for Tind1, Tind2, etc.
  302. * if the tag is right, validate each block number in the indirect block,
  303. * and check each block (mostly in case we are reading a huge directory).
  304. */
  305. static int
  306. indirck(Extdentry *ed, Off a, int tag)
  307. {
  308. int i, dmod = 0;
  309. Iobuf *p1;
  310. if (a == 0)
  311. return dmod;
  312. dmod = touch(a);
  313. if (p1 = xtag(a, tag, ed->qpath)) {
  314. for(i=0; i<INDPERBUF; i++) {
  315. a = blkck(&((Off *)p1->iobuf)[i], &p1->flags);
  316. if (a)
  317. /*
  318. * check each block named in this
  319. * indirect(^n) block (a).
  320. */
  321. if (tag == Tind1)
  322. dmod += dirck(ed, a);
  323. else
  324. dmod += indirck(ed, a, tag-1);
  325. }
  326. putbuf(p1);
  327. }
  328. return dmod;
  329. }
  330. static int
  331. indiraddrck(Extdentry *ed, Off *indirp, int tag)
  332. {
  333. int dmod;
  334. Off a;
  335. dmod = daddrck(indirp, &a);
  336. return dmod + indirck(ed, a, tag);
  337. }
  338. /* if result is true, *d was modified */
  339. static int
  340. fsck(Dentry *d)
  341. {
  342. int i, dmod;
  343. Extdentry edent;
  344. depth++;
  345. if(depth >= maxdepth)
  346. maxdepth = depth;
  347. if (lowstack == nil)
  348. startstack = lowstack = (uchar *)&edent;
  349. /* more precise check, assumes downward-growing stack */
  350. if ((uchar *)&edent < lowstack)
  351. lowstack = (uchar *)&edent;
  352. /* check that entry is allocated */
  353. if(!(d->mode & DALLOC))
  354. return 0;
  355. nfiles++;
  356. /* we stash qpath & ns in an Extdentry for eventual use by dirck() */
  357. memset(&edent, 0, sizeof edent);
  358. edent.d = d;
  359. /* check name */
  360. edent.ns = strlen(name);
  361. i = strlen(d->name);
  362. if(i >= NAMELEN) {
  363. d->name[NAMELEN-1] = 0;
  364. print("%s->name (%s) not terminated\n", name, d->name);
  365. return 0;
  366. }
  367. edent.ns += i;
  368. if(edent.ns >= sizname) {
  369. print("%s->name (%s) name too large\n", name, d->name);
  370. return 0;
  371. }
  372. strcat(name, d->name);
  373. if(d->mode & DDIR) {
  374. if(edent.ns > 1) {
  375. strcat(name, "/");
  376. edent.ns++;
  377. }
  378. if(flags & Cpdir) {
  379. print("%s\n", name);
  380. prflush();
  381. }
  382. } else if(flags & Cpfile) {
  383. print("%s\n", name);
  384. prflush();
  385. }
  386. /* check qid */
  387. edent.qpath = d->qid.path & ~QPDIR;
  388. qmark(edent.qpath);
  389. if(edent.qpath > maxq)
  390. maxq = edent.qpath;
  391. /* check direct blocks (the common case) */
  392. dmod = 0;
  393. {
  394. Off a;
  395. for(i=0; i<NDBLOCK; i++) {
  396. dmod += daddrck(&d->dblock[i], &a);
  397. if (a)
  398. dmod += dirck(&edent, a);
  399. }
  400. }
  401. /* check indirect^n blocks, if any */
  402. for (i = 0; i < NIBLOCK; i++)
  403. dmod += indiraddrck(&edent, &d->iblocks[i], Tind1+i);
  404. return dmod;
  405. }
  406. enum { XFEN = FEPERBUF + 6 };
  407. typedef struct {
  408. int flag;
  409. int count;
  410. int next;
  411. Off addr[XFEN];
  412. } Xfree;
  413. static void
  414. xaddfree(Device *dev, Off a, Superb *sb, Iobuf *p)
  415. {
  416. Xfree *x;
  417. x = (Xfree*)p->iobuf;
  418. if(x->count < XFEN) {
  419. x->addr[x->count] = a;
  420. x->count++;
  421. return;
  422. }
  423. if(!x->flag) {
  424. memset(&sb->fbuf, 0, sizeof(sb->fbuf));
  425. sb->fbuf.free[0] = 0L;
  426. sb->fbuf.nfree = 1;
  427. sb->tfree = 0;
  428. x->flag = 1;
  429. }
  430. addfree(dev, a, sb);
  431. }
  432. static void
  433. xflush(Device *dev, Superb *sb, Iobuf *p)
  434. {
  435. int i;
  436. Xfree *x;
  437. x = (Xfree*)p->iobuf;
  438. if(!x->flag) {
  439. memset(&sb->fbuf, 0, sizeof(sb->fbuf));
  440. sb->fbuf.free[0] = 0L;
  441. sb->fbuf.nfree = 1;
  442. sb->tfree = 0;
  443. }
  444. for(i=0; i<x->count; i++)
  445. addfree(dev, x->addr[i], sb);
  446. }
  447. /*
  448. * make freelist
  449. * from existing freelist
  450. * (cw devices)
  451. */
  452. static void
  453. trfreelist(Superb *sb)
  454. {
  455. Off a, n;
  456. int i;
  457. Iobuf *p, *xp;
  458. Fbuf *fb;
  459. xp = getbuf(devnone, Cckbuf, 0);
  460. memset(xp->iobuf, 0, BUFSIZE);
  461. fb = &sb->fbuf;
  462. p = 0;
  463. for(;;) {
  464. n = fb->nfree;
  465. if(n < 0 || n > FEPERBUF)
  466. break;
  467. for(i=1; i<n; i++) {
  468. a = fb->free[i];
  469. if(a && !ftest(a))
  470. xaddfree(dev, a, sb, xp);
  471. }
  472. a = fb->free[0];
  473. if(!a)
  474. break;
  475. if(ftest(a))
  476. break;
  477. xaddfree(dev, a, sb, xp);
  478. if(p)
  479. putbuf(p);
  480. p = xtag(a, Tfree, QPNONE);
  481. if(!p)
  482. break;
  483. fb = (Fbuf*)p->iobuf;
  484. }
  485. if(p)
  486. putbuf(p);
  487. xflush(dev, sb, xp);
  488. putbuf(xp);
  489. mod++;
  490. print("%lld blocks free\n", (Wideoff)sb->tfree);
  491. }
  492. static void
  493. ckfreelist(Superb *sb)
  494. {
  495. Off a, lo, hi;
  496. int n, i;
  497. Iobuf *p;
  498. Fbuf *fb;
  499. strcpy(name, "free list");
  500. print("check %s\n", name);
  501. fb = &sb->fbuf;
  502. a = sbaddr;
  503. p = 0;
  504. lo = 0;
  505. hi = 0;
  506. for(;;) {
  507. n = fb->nfree;
  508. if(n < 0 || n > FEPERBUF) {
  509. print("check: nfree bad %lld\n", (Wideoff)a);
  510. break;
  511. }
  512. for(i=1; i<n; i++) {
  513. a = fb->free[i];
  514. if(a && !fmark(a)) {
  515. if(!lo || lo > a)
  516. lo = a;
  517. if(!hi || hi < a)
  518. hi = a;
  519. }
  520. }
  521. a = fb->free[0];
  522. if(!a)
  523. break;
  524. if(fmark(a))
  525. break;
  526. if(!lo || lo > a)
  527. lo = a;
  528. if(!hi || hi < a)
  529. hi = a;
  530. if(p)
  531. putbuf(p);
  532. p = xtag(a, Tfree, QPNONE);
  533. if(!p)
  534. break;
  535. fb = (Fbuf*)p->iobuf;
  536. }
  537. if(p)
  538. putbuf(p);
  539. if (flags & Ctrim) {
  540. fsize = hi--; /* fsize = hi + 1 */
  541. sb->fsize = fsize;
  542. mod++;
  543. print("set fsize to %lld\n", (Wideoff)fsize);
  544. }
  545. print("lo = %lld; hi = %lld\n", (Wideoff)lo, (Wideoff)hi);
  546. }
  547. /*
  548. * make freelist from scratch
  549. */
  550. static void
  551. mkfreelist(Superb *sb)
  552. {
  553. Off a;
  554. int i, b;
  555. if(ronly) {
  556. print("cant make freelist on ronly device\n");
  557. return;
  558. }
  559. strcpy(name, "free list");
  560. memset(&sb->fbuf, 0, sizeof(sb->fbuf));
  561. sb->fbuf.free[0] = 0L;
  562. sb->fbuf.nfree = 1;
  563. sb->tfree = 0;
  564. for(a=fsize-fstart-1; a >= 0; a--) {
  565. i = a/8;
  566. if(i < 0 || i >= sizabits)
  567. continue;
  568. b = 1 << (a&7);
  569. if(abits[i] & b)
  570. continue;
  571. addfree(dev, fstart+a, sb);
  572. }
  573. print("%lld blocks free\n", (Wideoff)sb->tfree);
  574. mod++;
  575. }
  576. static Dentry*
  577. maked(Off a, int s, Off qpath)
  578. {
  579. Iobuf *p;
  580. Dentry *d, *d1;
  581. p = xtag(a, Tdir, qpath);
  582. if(!p)
  583. return 0;
  584. d = getdir(p, s);
  585. d1 = chkalloc(sizeof(Dentry));
  586. memmove(d1, d, sizeof(Dentry));
  587. putbuf(p);
  588. return d1;
  589. }
  590. static void
  591. modd(Off a, int s, Dentry *d1)
  592. {
  593. Iobuf *p;
  594. Dentry *d;
  595. if(!(flags & Cbad))
  596. return;
  597. p = getbuf(dev, a, Brd);
  598. d = getdir(p, s);
  599. if(!d) {
  600. if(p)
  601. putbuf(p);
  602. return;
  603. }
  604. memmove(d, d1, sizeof(Dentry));
  605. p->flags |= Bmod;
  606. putbuf(p);
  607. }
  608. static void
  609. xread(Off a, Off qpath)
  610. {
  611. Iobuf *p;
  612. p = xtag(a, Tfile, qpath);
  613. if(p)
  614. putbuf(p);
  615. }
  616. static Iobuf*
  617. xtag(Off a, int tag, Off qpath)
  618. {
  619. Iobuf *p;
  620. if(a == 0)
  621. return 0;
  622. p = getbuf(dev, a, Brd);
  623. if(!p) {
  624. print("check: \"%s\": xtag: p null\n", name);
  625. if(flags & (Cream|Ctag)) {
  626. p = getbuf(dev, a, Bmod);
  627. if(p) {
  628. memset(p->iobuf, 0, RBUFSIZE);
  629. settag(p, tag, qpath);
  630. mod++;
  631. return p;
  632. }
  633. }
  634. return 0;
  635. }
  636. if(checktag(p, tag, qpath)) {
  637. print("check: \"%s\": xtag: checktag\n", name);
  638. if(flags & (Cream|Ctag)) {
  639. if(flags & Cream)
  640. memset(p->iobuf, 0, RBUFSIZE);
  641. settag(p, tag, qpath);
  642. mod++;
  643. return p;
  644. }
  645. return p;
  646. }
  647. return p;
  648. }
  649. static int
  650. amark(Off a)
  651. {
  652. Off i;
  653. int b;
  654. if(a < fstart || a >= fsize) {
  655. if(a == 0)
  656. return 0;
  657. print("check: \"%s\": range %lld\n",
  658. name, (Wideoff)a);
  659. nbad++;
  660. return 1;
  661. }
  662. a -= fstart;
  663. i = a/8;
  664. b = 1 << (a&7);
  665. if(abits[i] & b) {
  666. if(!ronly)
  667. if(ndup < 10)
  668. print("check: \"%s\": address dup %lld\n",
  669. name, (Wideoff)fstart+a);
  670. else if(ndup == 10)
  671. print("...");
  672. ndup++;
  673. return 1;
  674. }
  675. abits[i] |= b;
  676. nused++;
  677. return 0;
  678. }
  679. static int
  680. fmark(Off a)
  681. {
  682. Off i;
  683. int b;
  684. if(a < fstart || a >= fsize) {
  685. print("check: \"%s\": range %lld\n",
  686. name, (Wideoff)a);
  687. nbad++;
  688. return 1;
  689. }
  690. a -= fstart;
  691. i = a/8;
  692. b = 1 << (a&7);
  693. if(abits[i] & b) {
  694. print("check: \"%s\": address dup %lld\n",
  695. name, (Wideoff)fstart+a);
  696. nfdup++;
  697. return 1;
  698. }
  699. abits[i] |= b;
  700. nfree++;
  701. return 0;
  702. }
  703. static int
  704. ftest(Off a)
  705. {
  706. Off i;
  707. int b;
  708. if(a < fstart || a >= fsize)
  709. return 1;
  710. a -= fstart;
  711. i = a/8;
  712. b = 1 << (a&7);
  713. if(abits[i] & b)
  714. return 1;
  715. abits[i] |= b;
  716. return 0;
  717. }
  718. static void
  719. missing(void)
  720. {
  721. Off a, i;
  722. int b, n;
  723. n = 0;
  724. for(a=fsize-fstart-1; a>=0; a--) {
  725. i = a/8;
  726. b = 1 << (a&7);
  727. if(!(abits[i] & b)) {
  728. print("missing: %lld\n", (Wideoff)fstart+a);
  729. n++;
  730. }
  731. if(n > 10) {
  732. print(" ...\n");
  733. break;
  734. }
  735. }
  736. }
  737. static void
  738. qmark(Off qpath)
  739. {
  740. int b;
  741. Off i;
  742. i = qpath/8;
  743. b = 1 << (qpath&7);
  744. if(i < 0 || i >= sizqbits) {
  745. nqbad++;
  746. if(nqbad < 20)
  747. print("check: \"%s\": qid out of range %llux\n",
  748. name, (Wideoff)qpath);
  749. return;
  750. }
  751. if((qbits[i] & b) && !ronly) {
  752. nqbad++;
  753. if(nqbad < 20)
  754. print("check: \"%s\": qid dup %llux\n", name,
  755. (Wideoff)qpath);
  756. }
  757. qbits[i] |= b;
  758. }