void vtAttach(void) { int pid; Thread *p; static int init; static Lock lk; lock(&lk); if(!init) { rfork(RFREND); vtThreadInit(); init = 1; } unlock(&lk); pid = getpid(); p = *vtRock; if(p != nil && p->pid == pid) { p->ref++; return; } p = vtMemAllocZ(sizeof(Thread)); p->ref = 1; p->pid = pid; *vtRock = p; }
VtRendez* vtRendezAlloc(VtLock *p) { VtRendez *q; q = vtMemAllocZ(sizeof(VtRendez)); q->lk = p; setmalloctag(q, getcallerpc(&p)); return q; }
static User* userAlloc(char* uid, char* uname) { User *u; u = vtMemAllocZ(sizeof(User)); u->uid = vtStrDup(uid); u->uname = vtStrDup(uname); return u; }
int exclAlloc(Fid* fid) { ulong t; Excl *excl; assert(fid->excl == nil); t = time(0L); vtLock(ebox.lock); for(excl = ebox.head; excl != nil; excl = excl->next){ if(excl->fsys != fid->fsys || excl->path != fid->qid.path) continue; /* * Found it. * Now, check if it's timed out. * If not, return error, it's locked. * If it has timed out, zap the old * one and continue on to allocate a * a new one. */ if(excl->time >= t){ vtUnlock(ebox.lock); vtSetError("exclusive lock"); return 0; } excl->fsys = nil; } /* * Not found or timed-out. * Alloc a new one and initialise. */ excl = vtMemAllocZ(sizeof(Excl)); excl->fsys = fid->fsys; excl->path = fid->qid.path; excl->time = t+LifeTime; if(ebox.tail != nil){ excl->prev = ebox.tail; ebox.tail->next = excl; } else{ ebox.head = excl; excl->prev = nil; } ebox.tail = excl; excl->next = nil; vtUnlock(ebox.lock); fid->excl = excl; return 1; }
static File * fileAlloc(Fs *fs) { File *f; f = vtMemAllocZ(sizeof(File)); f->lk = vtLockAlloc(); f->ref = 1; f->fs = fs; f->boff = NilBlock; f->mode = fs->mode; return f; }
static WThread* getWThread(void) { WThread *w; w = *wp; if(w == nil || w->pid != getpid()){ w = vtMemAllocZ(sizeof(WThread)); *wp = w; w->pid = getpid(); } return w; }
static Srv* srvAlloc(char* service, int mode, int fd) { Dir *dir; Srv *srv; int srvfd; char *mntpnt; vtLock(sbox.lock); for(srv = sbox.head; srv != nil; srv = srv->next){ if(strcmp(srv->service, service) != 0) continue; /* * If the service exists, but is stale, * free it up and let the name be reused. */ if((dir = dirfstat(srv->srvfd)) != nil){ free(dir); vtSetError("srv: already serving '%s'", service); vtUnlock(sbox.lock); return nil; } srvFree(srv); break; } if((srvfd = srvFd(service, mode, fd, &mntpnt)) < 0){ vtUnlock(sbox.lock); return nil; } close(fd); srv = vtMemAllocZ(sizeof(Srv)); srv->srvfd = srvfd; srv->service = vtStrDup(service); srv->mntpnt = mntpnt; if(sbox.tail != nil){ srv->prev = sbox.tail; sbox.tail->next = srv; } else{ sbox.head = srv; srv->prev = nil; } sbox.tail = srv; vtUnlock(sbox.lock); return srv; }
/* * Walk through all the blocks in the write buffer. * Then we can look for ones we missed -- those are leaks. */ static void checkEpochs(Fsck *chk) { u32int e; uint nb; nb = chk->nblocks; chk->amap = vtMemAllocZ(nb/8+1); chk->emap = vtMemAllocZ(nb/8+1); chk->xmap = vtMemAllocZ(nb/8+1); chk->errmap = vtMemAllocZ(nb/8+1); for(e = chk->fs->ehi; e >= chk->fs->elo; e--){ memset(chk->emap, 0, chk->nblocks/8+1); memset(chk->xmap, 0, chk->nblocks/8+1); checkEpoch(chk, e); } checkLeak(chk); vtMemFree(chk->amap); vtMemFree(chk->emap); vtMemFree(chk->xmap); vtMemFree(chk->errmap); }
static Snap* snapInit(Fs *fs) { Snap *s; s = vtMemAllocZ(sizeof(Snap)); s->fs = fs; s->tick = periodicAlloc(snapEvent, s, 10*1000); s->lk = vtLockAlloc(); s->snapMinutes = -1; s->archMinute = -1; s->snapLife = -1; s->ignore = 5*2; /* wait five minutes for clock to stabilize */ return s; }
Periodic * periodicAlloc(void (*f)(void*), void *a, int msec) { Periodic *p; p = vtMemAllocZ(sizeof(Periodic)); p->lk = vtLockAlloc(); p->f = f; p->a = a; p->msec = msec; if(p->msec < 10) p->msec = 10; vtThread(periodicThread, p); return p; }
static Lstn* lstnAlloc(char* address, int flags) { int afd; Lstn *lstn; char dir[NETPATHLEN]; vtLock(lbox.lock); for(lstn = lbox.head; lstn != nil; lstn = lstn->next){ if(strcmp(lstn->address, address) != 0) continue; vtSetError("listen: already serving '%s'", address); vtUnlock(lbox.lock); return nil; } if((afd = announce(address, dir)) < 0){ vtSetError("listen: announce '%s': %r", address); vtUnlock(lbox.lock); return nil; } lstn = vtMemAllocZ(sizeof(Lstn)); lstn->afd = afd; lstn->address = vtStrDup(address); lstn->flags = flags; memmove(lstn->dir, dir, NETPATHLEN); if(lbox.tail != nil){ lstn->prev = lbox.tail; lbox.tail->next = lstn; } else{ lbox.head = lstn; lstn->prev = nil; } lbox.tail = lstn; vtUnlock(lbox.lock); if(vtThread(lstnListen, lstn) < 0){ vtSetError("listen: thread '%s': %r", lstn->address); lstnFree(lstn); return nil; } return lstn; }
VtSession * vtAlloc(void) { VtSession *z; z = vtMemAllocZ(sizeof(VtSession)); z->lk = vtLockAlloc(); // z->inHash = vtSha1Alloc(); z->inLock = vtLockAlloc(); z->part = packetAlloc(); // z->outHash = vtSha1Alloc(); z->outLock = vtLockAlloc(); z->fd = -1; z->uid = vtStrDup("anonymous"); z->sid = vtStrDup("anonymous"); return z; }
static WEntry* allocWEntry(void) { int i; WEntry *w; w = pool; if(w == nil){ w = vtMemAllocZ(1024*sizeof(WEntry)); for(i=0; i<1024; i++) freeWEntry(&w[i]); w = pool; } pool = w->pnext; memset(w, 0, sizeof(WEntry)); return w; }
Arch * archInit(Cache *c, Disk *disk, Fs *fs, VtSession *z) { Arch *a; a = vtMemAllocZ(sizeof(Arch)); a->c = c; a->z = z; a->fs = fs; a->blockSize = diskBlockSize(disk); a->lk = vtLockAlloc(); a->starve = vtRendezAlloc(a->lk); a->ref = 2; vtThread(archThread, a); return a; }
void fsCheck(Fsck *chk) { Block *b; Super super; checkInit(chk); b = superGet(chk->cache, &super); if(b == nil){ chk->print("could not load super block: %R"); return; } blockPut(b); chk->hint = super.active; checkEpochs(chk); chk->smap = vtMemAllocZ(chk->nblocks/8+1); checkDirs(chk); vtMemFree(chk->smap); }
static Fid* fidAlloc(void) { Fid *fid; vtLock(fbox.lock); if(fbox.nfree > 0){ fid = fbox.free; fbox.free = fid->hash; fbox.nfree--; } else{ fid = vtMemAllocZ(sizeof(Fid)); fid->lock = vtLockAlloc(); fid->alock = vtLockAlloc(); } fbox.inuse++; vtUnlock(fbox.lock); fid->con = nil; fid->fidno = NOFID; fid->ref = 0; fid->flags = 0; fid->open = FidOCreate; assert(fid->fsys == nil); assert(fid->file == nil); fid->qid = (Qid){0, 0, 0}; assert(fid->uid == nil); assert(fid->uname == nil); assert(fid->db == nil); assert(fid->excl == nil); assert(fid->rpc == nil); assert(fid->cuname == nil); fid->hash = fid->next = fid->prev = nil; return fid; }
DirEntryEnum * deeOpen(File *f) { DirEntryEnum *dee; File *p; if(!fileIsDir(f)){ vtSetError(ENotDir); fileDecRef(f); return nil; } /* flush out meta data */ if(!fileLock(f)) return nil; for(p=f->down; p; p=p->next) fileMetaFlush2(p, nil); fileUnlock(f); dee = vtMemAllocZ(sizeof(DirEntryEnum)); dee->file = fileIncRef(f); return dee; }
void * vtMemBrk(int n) { static Lock lk; static uint8_t *buf; static int nbuf; static int nchunk; int align, pad; void *p; if(n >= IdealAlignment) align = IdealAlignment; else if(n > 8) align = 8; else align = 4; lock(&lk); pad = (align - (uintptr)buf) & (align-1); if(n + pad > nbuf) { buf = vtMemAllocZ(ChunkSize); setmalloctag(buf, getcallerpc(&n)); nbuf = ChunkSize; pad = (align - (uintptr)buf) & (align-1); nchunk++; } assert(n + pad <= nbuf); p = buf + pad; buf += pad + n; nbuf -= pad + n; unlock(&lk); return p; }
Fs * fsOpen(char *file, VtSession *z, int32_t ncache, int mode) { int fd, m; uint8_t oscore[VtScoreSize]; Block *b, *bs; Disk *disk; Fs *fs; Super super; switch(mode){ default: vtSetError(EBadMode); return nil; case OReadOnly: m = OREAD; break; case OReadWrite: m = ORDWR; break; } fd = open(file, m); if(fd < 0){ vtSetError("open %s: %r", file); return nil; } bwatchInit(); disk = diskAlloc(fd); if(disk == nil){ vtSetError("diskAlloc: %R"); close(fd); return nil; } fs = vtMemAllocZ(sizeof(Fs)); fs->mode = mode; fs->name = vtStrDup(file); fs->blockSize = diskBlockSize(disk); fs->elk = vtLockAlloc(); fs->cache = cacheAlloc(disk, z, ncache, mode); if(mode == OReadWrite && z) fs->arch = archInit(fs->cache, disk, fs, z); fs->z = z; b = cacheLocal(fs->cache, PartSuper, 0, mode); if(b == nil) goto Err; if(!superUnpack(&super, b->data)){ blockPut(b); vtSetError("bad super block"); goto Err; } blockPut(b); fs->ehi = super.epochHigh; fs->elo = super.epochLow; //fprint(2, "%s: fs->ehi %d fs->elo %d active=%d\n", argv0, fs->ehi, fs->elo, super.active); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ /* * Perhaps it failed because the block is copy-on-write. * Do the copy and try again. */ if(mode == OReadOnly || strcmp(vtGetError(), EBadRoot) != 0) goto Err; b = cacheLocalData(fs->cache, super.active, BtDir, RootTag, OReadWrite, 0); if(b == nil){ vtSetError("cacheLocalData: %R"); goto Err; } if(b->l.epoch == fs->ehi){ blockPut(b); vtSetError("bad root source block"); goto Err; } b = blockCopy(b, RootTag, fs->ehi, fs->elo); if(b == nil) goto Err; localToGlobal(super.active, oscore); super.active = b->addr; bs = cacheLocal(fs->cache, PartSuper, 0, OReadWrite); if(bs == nil){ blockPut(b); vtSetError("cacheLocal: %R"); goto Err; } superPack(&super, bs->data); blockDependency(bs, b, 0, oscore, nil); blockPut(b); blockDirty(bs); blockRemoveLink(bs, globalToLocal(oscore), BtDir, RootTag, 0); blockPut(bs); fs->source = sourceRoot(fs, super.active, mode); if(fs->source == nil){ vtSetError("sourceRoot: %R"); goto Err; } } //fprint(2, "%s: got fs source\n", argv0); vtRLock(fs->elk); fs->file = fileRoot(fs->source); fs->source->file = fs->file; /* point back */ vtRUnlock(fs->elk); if(fs->file == nil){ vtSetError("fileRoot: %R"); goto Err; } //fprint(2, "%s: got file root\n", argv0); if(mode == OReadWrite){ fs->metaFlush = periodicAlloc(fsMetaFlush, fs, 1000); fs->snap = snapInit(fs); } return fs; Err: fprint(2, "%s: fsOpen error\n", argv0); fsClose(fs); return nil; }
static Source * sourceAlloc(Fs *fs, Block *b, Source *p, uint32_t offset, int mode, int issnapshot) { int epb; uint32_t epoch; char *pname = nil; Source *r; Entry e; assert(p==nil || sourceIsLocked(p)); if(p == nil) { assert(offset == 0); epb = 1; } else epb = p->dsize / VtEntrySize; if(b->l.type != BtDir) goto Bad; /* * a non-active entry is the only thing that * can legitimately happen here. all the others * get prints. */ if(!entryUnpack(&e, b->data, offset % epb)) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: entryUnpack failed\n", fs->name, pname, b->score); goto Bad; } if(!(e.flags & VtEntryActive)) { pname = sourceName(p); if(0) consPrint("%s: %s %V: sourceAlloc: not active\n", fs->name, pname, e.score); goto Bad; } if(e.psize < 256 || e.dsize < 256) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud < 256\n", fs->name, pname, e.score, e.psize, e.dsize); goto Bad; } if(e.depth < sizeToDepth(e.size, e.psize, e.dsize)) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: depth %ud size %llud " "psize %ud dsize %ud\n", fs->name, pname, e.score, e.depth, e.size, e.psize, e.dsize); goto Bad; } if((e.flags & VtEntryLocal) && e.tag == 0) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: flags %#ux tag %#ux\n", fs->name, pname, e.score, e.flags, e.tag); goto Bad; } if(e.dsize > fs->blockSize || e.psize > fs->blockSize) { pname = sourceName(p); consPrint("%s: %s %V: sourceAlloc: psize %ud or dsize %ud " "> blocksize %ud\n", fs->name, pname, e.score, e.psize, e.dsize, fs->blockSize); goto Bad; } epoch = b->l.epoch; if(mode == OReadWrite) { if(e.snap != 0) { vtSetError(ESnapRO); return nil; } } else if(e.snap != 0) { if(e.snap < fs->elo) { vtSetError(ESnapOld); return nil; } if(e.snap >= fs->ehi) goto Bad; epoch = e.snap; } r = vtMemAllocZ(sizeof(Source)); r->fs = fs; r->mode = mode; r->issnapshot = issnapshot; r->dsize = e.dsize; r->gen = e.gen; r->dir = (e.flags & VtEntryDir) != 0; r->lk = vtLockAlloc(); r->ref = 1; r->parent = p; if(p) { vtLock(p->lk); assert(mode == OReadOnly || p->mode == OReadWrite); p->ref++; vtUnlock(p->lk); } r->epoch = epoch; // consPrint("sourceAlloc: have %V be.%d fse.%d %s\n", b->score, // b->l.epoch, r->fs->ehi, mode == OReadWrite? "rw": "ro"); memmove(r->score, b->score, VtScoreSize); r->scoreEpoch = b->l.epoch; r->offset = offset; r->epb = epb; r->tag = b->l.tag; // consPrint("%s: sourceAlloc: %p -> %V %d\n", r, r->score, r->offset); return r; Bad: free(pname); vtSetError(EBadEntry); return nil; }
static int uboxInit(char* users, int len) { User *g, *u; Ubox *box, *obox; int blank, comment, i, nline, nuser; char *buf, *f[5], **line, *p, *q, *s; /* * Strip out whitespace and comments. * Note that comments are pointless, they disappear * when the server writes the database back out. */ blank = 1; comment = nline = 0; s = p = buf = vtMemAlloc(len+1); for(q = users; *q != '\0'; q++){ if(*q == '\r' || *q == '\t' || *q == ' ') continue; if(*q == '\n'){ if(!blank){ if(p != s){ *p++ = '\n'; nline++; s = p; } blank = 1; } comment = 0; continue; } if(*q == '#') comment = 1; blank = 0; if(!comment) *p++ = *q; } *p = '\0'; line = vtMemAllocZ((nline+2)*sizeof(char*)); if((i = gettokens(buf, line, nline+2, "\n")) != nline){ fprint(2, "nline %d (%d) botch\n", nline, i); vtMemFree(line); vtMemFree(buf); return 0; } /* * Everything is updated in a local Ubox until verified. */ box = vtMemAllocZ(sizeof(Ubox)); /* * First pass - check format, check for duplicates * and enter in hash buckets. */ nuser = 0; for(i = 0; i < nline; i++){ s = vtStrDup(line[i]); if(getfields(s, f, nelem(f), 0, ":") != 4){ fprint(2, "bad line '%s'\n", line[i]); vtMemFree(s); continue; } if(*f[0] == '\0' || *f[1] == '\0'){ fprint(2, "bad line '%s'\n", line[i]); vtMemFree(s); continue; } if(!validUserName(f[0])){ fprint(2, "invalid uid '%s'\n", f[0]); vtMemFree(s); continue; } if(_userByUid(box, f[0]) != nil){ fprint(2, "duplicate uid '%s'\n", f[0]); vtMemFree(s); continue; } if(!validUserName(f[1])){ fprint(2, "invalid uname '%s'\n", f[0]); vtMemFree(s); continue; } if(_userByUname(box, f[1]) != nil){ fprint(2, "duplicate uname '%s'\n", f[1]); vtMemFree(s); continue; } u = userAlloc(f[0], f[1]); uboxAddUser(box, u); line[nuser] = line[i]; nuser++; vtMemFree(s); } assert(box->nuser == nuser); /* * Second pass - fill in leader and group information. */ for(i = 0; i < nuser; i++){ s = vtStrDup(line[i]); getfields(s, f, nelem(f), 0, ":"); assert(g = _userByUname(box, f[1])); if(*f[2] != '\0'){ if((u = _userByUname(box, f[2])) == nil) g->leader = vtStrDup(g->uname); else g->leader = vtStrDup(u->uname); box->len += strlen(g->leader); } for(p = f[3]; p != nil; p = q){ if((q = utfrune(p, L',')) != nil) *q++ = '\0'; if(!_groupAddMember(box, g, p)){ // print/log error here } } vtMemFree(s); } vtMemFree(line); vtMemFree(buf); for(i = 0; usersMandatory[i] != nil; i++){ if((u = _userByUid(box, usersMandatory[i])) == nil){ vtSetError("user '%s' is mandatory", usersMandatory[i]); uboxFree(box); return 0; } if(strcmp(u->uid, u->uname) != 0){ vtSetError("uid/uname for user '%s' must match", usersMandatory[i]); uboxFree(box); return 0; } } vtLock(ubox.lock); obox = ubox.box; ubox.box = box; vtUnlock(ubox.lock); if(obox != nil) uboxFree(obox); return 1; }
void main(int argc, char *argv[]) { int fd, force; Header h; ulong bn; Entry e; char *label = "vfs"; char *host = nil; char *score = nil; u32int root; Dir *d; force = 0; ARGBEGIN{ default: usage(); case 'b': bsize = unittoull(EARGF(usage())); if(bsize == ~0) usage(); break; case 'h': host = EARGF(usage()); break; case 'i': iso9660file = EARGF(usage()); iso9660off = atoi(EARGF(usage())); break; case 'l': label = EARGF(usage()); break; case 'v': score = EARGF(usage()); break; /* * This is -y instead of -f because flchk has a * (frequently used) -f option. I type flfmt instead * of flchk all the time, and want to make it hard * to reformat my file system accidentally. */ case 'y': force = 1; break; }ARGEND if(argc != 1) usage(); if(iso9660file && score) vtFatal("cannot use -i with -v"); vtAttach(); fmtinstall('V', scoreFmt); fmtinstall('R', vtErrFmt); fmtinstall('L', labelFmt); fd = open(argv[0], ORDWR); if(fd < 0) vtFatal("could not open file: %s: %r", argv[0]); buf = vtMemAllocZ(bsize); if(pread(fd, buf, bsize, HeaderOffset) != bsize) vtFatal("could not read fs header block: %r"); if(headerUnpack(&h, buf) && !force && !confirm("fs header block already exists; are you sure?")) goto Out; if((d = dirfstat(fd)) == nil) vtFatal("dirfstat: %r"); if(d->type == 'M' && !force && !confirm("fs file is mounted via devmnt (is not a kernel device); are you sure?")) goto Out; partition(fd, bsize, &h); headerPack(&h, buf); if(pwrite(fd, buf, bsize, HeaderOffset) < bsize) vtFatal("could not write fs header: %r"); disk = diskAlloc(fd); if(disk == nil) vtFatal("could not open disk: %r"); if(iso9660file) iso9660init(fd, &h, iso9660file, iso9660off); /* zero labels */ memset(buf, 0, bsize); for(bn = 0; bn < diskSize(disk, PartLabel); bn++) blockWrite(PartLabel, bn); if(iso9660file) iso9660labels(disk, buf, blockWrite); if(score) root = ventiRoot(host, score); else{ rootMetaInit(&e); root = rootInit(&e); } superInit(label, root, vtZeroScore); diskFree(disk); if(score == nil) topLevel(argv[0]); Out: vtDetach(); exits(0); }
VtLock* vtLockAlloc(void) { return vtMemAllocZ(sizeof(VtLock)); }
/* * 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); }