static int deeFill(DirEntryEnum *dee) { int i, n; Source *meta, *source; MetaBlock mb; MetaEntry me; File *f; Block *b; DirEntry *de; /* clean up first */ for(i=dee->i; i<dee->n; i++) deCleanup(dee->buf+i); vtMemFree(dee->buf); dee->buf = nil; dee->i = 0; dee->n = 0; f = dee->file; source = f->source; meta = f->msource; b = sourceBlock(meta, dee->boff, OReadOnly); if(b == nil) goto Err; if(!mbUnpack(&mb, b->data, meta->dsize)) goto Err; n = mb.nindex; dee->buf = vtMemAlloc(n * sizeof(DirEntry)); for(i=0; i<n; i++){ de = dee->buf + i; meUnpack(&me, &mb, i); if(!deUnpack(de, &me)) goto Err; dee->n++; if(!(de->mode & ModeDir)) if(!dirEntrySize(source, de->entry, de->gen, &de->size)) goto Err; } dee->boff++; blockPut(b); return 1; Err: blockPut(b); return 0; }
int metaentrygen(void *v, Block *b, int o, Tnode **tp) { Tnode *t; MetaBlock *mb; MetaEntry me; mb = v; if(o >= mb->nindex) return -1; meUnpack(&me, mb, o); t = stringnode("MetaEntry %d bytes", mb->size); t->kid = mallocz(sizeof(t->kid[0])*1, 1); t->kid[0] = initxdirentry(&me); t->nkid = 1; *tp = t; return 1; }
void mbDelete(MetaBlock *mb, int i) { uchar *p; int n; MetaEntry me; assert(i < mb->nindex); meUnpack(&me, mb, i); memset(me.p, 0, me.size); if(me.p - mb->buf + me.size == mb->size) mb->size -= me.size; else mb->free += me.size; p = mb->buf + MetaHeaderSize + i*MetaIndexSize; n = (mb->nindex-i-1)*MetaIndexSize; memmove(p, p+MetaIndexSize, n); memset(p+n, 0, MetaIndexSize); mb->nindex--; }
int mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me) { int i; int b, t, x; if(0)fprint(2, "mbSearch %s\n", elem); /* binary search within block */ b = 0; t = mb->nindex; while(b < t){ i = (b+t)>>1; meUnpack(me, mb, i); if(mb->botch) x = meCmpOld(me, elem); else x = meCmp(me, elem); if(x == 0){ *ri = i; return 1; } if(x < 0) b = i+1; else /* x > 0 */ t = i; } assert(b == t); *ri = b; /* b is the index to insert this entry */ memset(me, 0, sizeof(*me)); vtSetError(ENoFile); return 0; }
File * fileRoot(Source *r) { Block *b; Source *r0, *r1, *r2; MetaBlock mb; MetaEntry me; File *root, *mr; Fs *fs; b = nil; root = nil; mr = nil; r1 = nil; r2 = nil; fs = r->fs; if(!sourceLock(r, -1)) return nil; r0 = sourceOpen(r, 0, fs->mode, 0); if(r0 == nil) goto Err; r1 = sourceOpen(r, 1, fs->mode, 0); if(r1 == nil) goto Err; r2 = sourceOpen(r, 2, fs->mode, 0); if(r2 == nil) goto Err; mr = fileAlloc(fs); mr->msource = r2; r2 = nil; root = fileAlloc(fs); root->boff = 0; root->up = mr; root->source = r0; r0->file = root; /* point back to source */ r0 = nil; root->msource = r1; r1 = nil; mr->down = root; if(!sourceLock(mr->msource, -1)) goto Err; b = sourceBlock(mr->msource, 0, OReadOnly); sourceUnlock(mr->msource); if(b == nil) goto Err; if(!mbUnpack(&mb, b->data, mr->msource->dsize)) goto Err; meUnpack(&me, &mb, 0); if(!deUnpack(&root->dir, &me)) goto Err; blockPut(b); sourceUnlock(r); fileRAccess(root); return root; Err: blockPut(b); if(r0) sourceClose(r0); if(r1) sourceClose(r1); if(r2) sourceClose(r2); if(mr) fileFree(mr); if(root) fileFree(root); sourceUnlock(r); return nil; }
/* * 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); }
static u32int ventiRoot(char *host, char *s) { int i, n; uchar score[VtScoreSize]; u32int addr, tag; DirEntry de; MetaBlock mb; MetaEntry me; Entry e; VtRoot root; if(!parseScore(score, s)) vtFatal("bad score '%s'", s); if((z = vtDial(host, 0)) == nil || !vtConnect(z, nil)) vtFatal("connect to venti: %R"); tag = tagGen(); addr = blockAlloc(BtDir, tag); ventiRead(score, VtRootType); if(!vtRootUnpack(&root, buf)) vtFatal("corrupted root: vtRootUnpack"); n = ventiRead(root.score, VtDirType); /* * Fossil's vac archives start with an extra layer of source, * but vac's don't. */ if(n <= 2*VtEntrySize){ if(!entryUnpack(&e, buf, 0)) vtFatal("bad root: top entry"); n = ventiRead(e.score, VtDirType); } /* * There should be three root sources (and nothing else) here. */ for(i=0; i<3; i++){ if(!entryUnpack(&e, buf, i) || !(e.flags&VtEntryActive) || e.psize < 256 || e.dsize < 256) vtFatal("bad root: entry %d", i); fprint(2, "%V\n", e.score); } if(n > 3*VtEntrySize) vtFatal("bad root: entry count"); blockWrite(PartData, addr); /* * Maximum qid is recorded in root's msource, entry #2 (conveniently in e). */ ventiRead(e.score, VtDataType); if(!mbUnpack(&mb, buf, bsize)) vtFatal("bad root: mbUnpack"); meUnpack(&me, &mb, 0); if(!deUnpack(&de, &me)) vtFatal("bad root: dirUnpack"); if(!de.qidSpace) vtFatal("bad root: no qidSpace"); qid = de.qidMax; /* * Recreate the top layer of source. */ entryInit(&e); e.flags |= VtEntryLocal|VtEntryDir; e.size = VtEntrySize*3; e.tag = tag; localToGlobal(addr, e.score); addr = blockAlloc(BtDir, RootTag); memset(buf, 0, bsize); entryPack(&e, buf, 0); blockWrite(PartData, addr); return addr; }