/* * Walk the source tree making sure that the BtData * sources containing directory entries are okay. */ static void chkDir(Fsck *chk, char *name, Source *source, Source *meta) { int i; u32int a1, a2, nb, o; char *s, *nn; uchar *bm; Block *b, *bb; DirEntry de; Entry e1, e2; MetaBlock mb; MetaEntry me; Source *r, *mr; if(!chk->useventi && globalToLocal(source->score)==NilBlock && globalToLocal(meta->score)==NilBlock) return; if(!sourceLock2(source, meta, OReadOnly)){ warn(chk, "could not lock sources for %s: %R", name); return; } if(!sourceGetEntry(source, &e1) || !sourceGetEntry(meta, &e2)){ warn(chk, "could not load entries for %s: %R", name); return; } a1 = globalToLocal(e1.score); a2 = globalToLocal(e2.score); if((!chk->useventi && a1==NilBlock && a2==NilBlock) || (getBit(chk->smap, a1) && getBit(chk->smap, a2))){ sourceUnlock(source); sourceUnlock(meta); return; } setBit(chk->smap, a1); setBit(chk->smap, a2); bm = vtMemAllocZ(sourceGetDirSize(source)/8 + 1); nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize; for(o = 0; o < nb; o++){ b = sourceBlock(meta, o, OReadOnly); if(b == nil){ error(chk, "could not read block in meta file: %s[%ud]: %R", name, o); continue; } if(0) fprint(2, "source %V:%d block %d addr %d\n", source->score, source->offset, o, b->addr); if(b->addr != NilBlock && getBit(chk->errmap, b->addr)) warn(chk, "previously reported error in block %ux is in %s", b->addr, name); if(!mbUnpack(&mb, b->data, meta->dsize)){ error(chk, "could not unpack meta block: %s[%ud]: %R", name, o); blockPut(b); continue; } if(!chkMetaBlock(&mb)){ error(chk, "bad meta block: %s[%ud]: %R", name, o); blockPut(b); continue; } s = nil; for(i=mb.nindex-1; i>=0; i--){ meUnpack(&me, &mb, i); if(!deUnpack(&de, &me)){ error(chk, "could not unpack dir entry: %s[%ud][%d]: %R", name, o, i); continue; } if(s && strcmp(s, de.elem) <= 0) error(chk, "dir entry out of order: %s[%ud][%d] = %s last = %s", name, o, i, de.elem, s); vtMemFree(s); s = vtStrDup(de.elem); nn = smprint("%s/%s", name, de.elem); if(nn == nil){ error(chk, "out of memory"); continue; } if(chk->printdirs) if(de.mode&ModeDir) chk->print("%s/\n", nn); if(chk->printfiles) if(!(de.mode&ModeDir)) chk->print("%s\n", nn); if(!(de.mode & ModeDir)){ r = openSource(chk, source, nn, bm, de.entry, de.gen, 0, &mb, i, b); if(r != nil){ if(sourceLock(r, OReadOnly)){ scanSource(chk, nn, r); sourceUnlock(r); } sourceClose(r); } deCleanup(&de); free(nn); continue; } r = openSource(chk, source, nn, bm, de.entry, de.gen, 1, &mb, i, b); if(r == nil){ deCleanup(&de); free(nn); continue; } mr = openSource(chk, source, nn, bm, de.mentry, de.mgen, 0, &mb, i, b); if(mr == nil){ sourceClose(r); deCleanup(&de); free(nn); continue; } if(!(de.mode&ModeSnapshot) || chk->walksnapshots) chkDir(chk, nn, r, mr); sourceClose(mr); sourceClose(r); deCleanup(&de); free(nn); deCleanup(&de); } vtMemFree(s); blockPut(b); } nb = sourceGetDirSize(source); for(o=0; o<nb; o++){ if(getBit(bm, o)) continue; r = sourceOpen(source, o, OReadOnly, 0); if(r == nil) continue; warn(chk, "non referenced entry in source %s[%d]", name, o); if((bb = sourceBlock(source, o/(source->dsize/VtEntrySize), OReadOnly)) != nil){ if(bb->addr != NilBlock){ setBit(chk->errmap, bb->addr); chk->clre(chk, bb, o%(source->dsize/VtEntrySize)); chk->nclre++; } blockPut(bb); } sourceClose(r); } sourceUnlock(source); sourceUnlock(meta); vtMemFree(bm); }
Source * sourceCreate(Source *r, int dsize, int dir, uint32_t offset) { int i, epb, psize; uint32_t bn, size; Block *b; Entry e; Source *rr; assert(sourceIsLocked(r)); if(!r->dir) { vtSetError(ENotDir); return nil; } epb = r->dsize/VtEntrySize; psize = (dsize/VtScoreSize)*VtScoreSize; size = sourceGetDirSize(r); if(offset == 0) { /* * look at a random block to see if we can find an empty entry */ offset = lnrand(size+1); offset -= offset % epb; } /* try the given block and then try the last block */ for(;;) { bn = offset/epb; b = sourceBlock(r, bn, OReadWrite); if(b == nil) return nil; for(i=offset%r->epb; i<epb; i++) { entryUnpack(&e, b->data, i); if((e.flags&VtEntryActive) == 0 && e.gen != ~0) goto Found; } blockPut(b); if(offset == size) { fprint(2, "sourceCreate: cannot happen\n"); vtSetError("sourceCreate: cannot happen"); return nil; } offset = size; } Found: /* found an entry - gen already set */ e.psize = psize; e.dsize = dsize; assert(psize && dsize); e.flags = VtEntryActive; if(dir) e.flags |= VtEntryDir; e.depth = 0; e.size = 0; memmove(e.score, vtZeroScore, VtScoreSize); e.tag = 0; e.snap = 0; e.archive = 0; entryPack(&e, b->data, i); blockDirty(b); offset = bn*epb + i; if(offset+1 > size) { if(!sourceSetDirSize(r, offset+1)) { blockPut(b); return nil; } } rr = sourceAlloc(r->fs, b, r, offset, OReadWrite, 0); blockPut(b); return rr; }