void deCopy(DirEntry *dst, DirEntry *src) { *dst = *src; dst->elem = vtStrDup(src->elem); dst->uid = vtStrDup(src->uid); dst->gid = vtStrDup(src->gid); dst->mid = vtStrDup(src->mid); }
static User* userAlloc(char* uid, char* uname) { User *u; u = vtMemAllocZ(sizeof(User)); u->uid = vtStrDup(uid); u->uname = vtStrDup(uname); return u; }
static void rootMetaInit(Entry *e) { u32int addr; u32int tag; DirEntry de; MetaBlock mb; MetaEntry me; memset(&de, 0, sizeof(de)); de.elem = vtStrDup("root"); de.entry = 0; de.gen = 0; de.mentry = 1; de.mgen = 0; de.size = 0; de.qid = qid++; de.uid = vtStrDup("adm"); de.gid = vtStrDup("adm"); de.mid = vtStrDup("adm"); de.mtime = time(0); de.mcount = 0; de.ctime = time(0); de.atime = time(0); de.mode = ModeDir | 0555; tag = tagGen(); addr = blockAlloc(BtData, tag); /* build up meta block */ memset(buf, 0, bsize); mbInit(&mb, buf, bsize, bsize/100); me.size = deSize(&de); me.p = mbAlloc(&mb, me.size); assert(me.p != nil); dePack(&de, &me); mbInsert(&mb, 0, &me); mbPack(&mb); blockWrite(PartData, addr); deCleanup(&de); /* build up entry for meta block */ entryInit(e); e->flags |= VtEntryLocal; e->size = bsize; e->tag = tag; localToGlobal(addr, e->score); }
static int _groupAddMember(Ubox* box, User* g, char* member) { User *u; if((u = _userByUname(box, member)) == nil) return 0; if(_groupMember(box, g->uid, u->uname, 0)){ if(strcmp(g->uname, member) == 0) vtSetError("uname: '%s' always in own group", member); else vtSetError("uname: '%s' already in group '%s'", member, g->uname); return 0; } g->group = vtMemRealloc(g->group, (g->ngroup+1)*sizeof(char*)); g->group[g->ngroup] = vtStrDup(member); box->len += strlen(member); g->ngroup++; if(g->ngroup > 1) box->len++; return 1; }
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 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; }
/* * convert File* to full path name in malloced string. * this hasn't been as useful as we hoped it would be. */ char * fileName(File *f) { char *name, *pname; File *p; static char root[] = "/"; if (f == nil) return vtStrDup("/**GOK**"); p = fileGetParent(f); if (p == f) name = vtStrDup(root); else { pname = fileName(p); if (strcmp(pname, root) == 0) name = smprint("/%s", f->dir.elem); else name = smprint("%s/%s", pname, f->dir.elem); free(pname); } fileDecRef(p); return name; }
char* uidByUname(char* uname) { User *u; char *uid; vtRLock(ubox.lock); if((u = _userByUname(ubox.box, uname)) == nil){ vtRUnlock(ubox.lock); return nil; } uid = vtStrDup(u->uid); vtRUnlock(ubox.lock); return uid; }
char* unameByUid(char* uid) { User *u; char *uname; vtRLock(ubox.lock); if((u = _userByUid(ubox.box, uid)) == nil){ vtRUnlock(ubox.lock); return nil; } uname = vtStrDup(u->uname); vtRUnlock(ubox.lock); return uname; }
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; }
static void readCmdPart(char *file, char ***pcmd, int *pncmd) { char buf[1024+1], *f[1024]; char tbuf[1024]; int nf; int i, fd, n; char **cmd, *p; int ncmd; cmd = *pcmd; ncmd = *pncmd; if((fd = open(file, OREAD)) < 0) sysfatal("open %s: %r", file); if(seek(fd, 127*1024, 0) != 127*1024) sysfatal("seek %s 127kB: %r", file); n = readn(fd, buf, sizeof buf-1); if(n == 0) sysfatal("short read of %s at 127kB", file); if(n < 0) sysfatal("read %s: %r", file); buf[n] = 0; if(memcmp(buf, "fossil config\n", 6+1+6+1) != 0) sysfatal("bad config magic in %s", file); nf = getfields(buf+6+1+6+1, f, nelem(f), 1, "\n"); for(i=0; i<nf; i++){ if(f[i][0] == '#') continue; cmd = vtMemRealloc(cmd, (ncmd+1)*sizeof(char*)); /* expand argument '*' to mean current file */ if((p = strchr(f[i], '*')) && (p==f[i]||isspace(p[-1])) && (p[1]==0||isspace(p[1]))){ memmove(tbuf, f[i], p-f[i]); strecpy(tbuf+(p-f[i]), tbuf+sizeof tbuf, file); strecpy(tbuf+strlen(tbuf), tbuf+sizeof tbuf, p+1); f[i] = tbuf; } cmd[ncmd++] = vtStrDup(f[i]); } close(fd); *pcmd = cmd; *pncmd = ncmd; }
/* * f->source and f->msource must NOT be locked. * see fileMetaLock. */ static void fileWAccess(File* f, char *mid) { if(f->mode == OReadOnly) return; fileMetaLock(f); f->dir.atime = f->dir.mtime = time(0L); if(strcmp(f->dir.mid, mid) != 0){ vtMemFree(f->dir.mid); f->dir.mid = vtStrDup(mid); } f->dir.mcount++; f->dirty = 1; fileMetaUnlock(f); /*RSC: let's try this */ /*presotto - lets not if(f->up) fileWAccess(f->up, mid); */ }
int fileSetDir(File *f, DirEntry *dir, char *uid) { File *ff; char *oelem; u32int mask; u64int size; /* can not set permissions for the root */ if(fileIsRoot(f)){ vtSetError(ERoot); return 0; } if(!fileLock(f)) return 0; if(f->source->mode != OReadWrite){ vtSetError(EReadOnly); fileUnlock(f); return 0; } fileMetaLock(f); /* check new name does not already exist */ if(strcmp(f->dir.elem, dir->elem) != 0){ for(ff = f->up->down; ff; ff=ff->next){ if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){ vtSetError(EExists); goto Err; } } ff = dirLookup(f->up, dir->elem); if(ff != nil){ fileDecRef(ff); vtSetError(EExists); goto Err; } } if(!sourceLock2(f->source, f->msource, -1)) goto Err; if(!fileIsDir(f)){ size = sourceGetSize(f->source); if(size != dir->size){ if(!sourceSetSize(f->source, dir->size)){ sourceUnlock(f->source); if(f->msource) sourceUnlock(f->msource); goto Err; } /* commited to changing it now */ } } /* commited to changing it now */ if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary)) fileSetTmp(f, dir->mode&ModeTemporary); sourceUnlock(f->source); if(f->msource) sourceUnlock(f->msource); oelem = nil; if(strcmp(f->dir.elem, dir->elem) != 0){ oelem = f->dir.elem; f->dir.elem = vtStrDup(dir->elem); } if(strcmp(f->dir.uid, dir->uid) != 0){ vtMemFree(f->dir.uid); f->dir.uid = vtStrDup(dir->uid); } if(strcmp(f->dir.gid, dir->gid) != 0){ vtMemFree(f->dir.gid); f->dir.gid = vtStrDup(dir->gid); } f->dir.mtime = dir->mtime; f->dir.atime = dir->atime; //fprint(2, "mode %x %x ", f->dir.mode, dir->mode); mask = ~(ModeDir|ModeSnapshot); f->dir.mode &= ~mask; f->dir.mode |= mask & dir->mode; f->dirty = 1; //fprint(2, "->%x\n", f->dir.mode); fileMetaFlush2(f, oelem); vtMemFree(oelem); fileMetaUnlock(f); fileUnlock(f); fileWAccess(f->up, uid); return 1; Err: fileMetaUnlock(f); fileUnlock(f); return 0; }
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 int cmdUname(int argc, char* argv[]) { User *u, *up; int d, dflag, i, r; char *p, *uid, *uname; char *createfmt = "fsys main create /active/usr/%s %s %s d775"; char *usage = "usage: uname [-d] uname [uid|:uid|%%newname|=leader|+member|-member]"; dflag = 0; ARGBEGIN{ default: return cliError(usage); case 'd': dflag = 1; break; }ARGEND if(argc < 1){ if(!dflag) return cliError(usage); vtRLock(ubox.lock); uboxDump(ubox.box); vtRUnlock(ubox.lock); return 1; } uname = argv[0]; argc--; argv++; if(argc == 0){ vtRLock(ubox.lock); if((u = _userByUname(ubox.box, uname)) == nil){ vtRUnlock(ubox.lock); return 0; } consPrint("\t%U\n", u); vtRUnlock(ubox.lock); return 1; } vtLock(ubox.lock); u = _userByUname(ubox.box, uname); while(argc--){ if(argv[0][0] == '%'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } p = &argv[0][1]; if((up = _userByUname(ubox.box, p)) != nil){ vtSetError("uname: uname '%s' already exists", up->uname); vtUnlock(ubox.lock); return 0; } for(i = 0; usersMandatory[i] != nil; i++){ if(strcmp(usersMandatory[i], uname) != 0) continue; vtSetError("uname: uname '%s' is mandatory", uname); vtUnlock(ubox.lock); return 0; } d = strlen(p) - strlen(u->uname); for(up = ubox.box->head; up != nil; up = up->next){ if(up->leader != nil){ if(strcmp(up->leader, u->uname) == 0){ vtMemFree(up->leader); up->leader = vtStrDup(p); ubox.box->len += d; } } for(i = 0; i < up->ngroup; i++){ if(strcmp(up->group[i], u->uname) != 0) continue; vtMemFree(up->group[i]); up->group[i] = vtStrDup(p); ubox.box->len += d; break; } } uboxRemUser(ubox.box, u); vtMemFree(u->uname); u->uname = vtStrDup(p); uboxAddUser(ubox.box, u); } else if(argv[0][0] == '='){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ if(argv[0][1] != '\0'){ vtUnlock(ubox.lock); return 0; } } if(u->leader != nil){ ubox.box->len -= strlen(u->leader); vtMemFree(u->leader); u->leader = nil; } if(up != nil){ u->leader = vtStrDup(up->uname); ubox.box->len += strlen(u->leader); } } else if(argv[0][0] == '+'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ vtUnlock(ubox.lock); return 0; } if(!_groupAddMember(ubox.box, u, up->uname)){ vtUnlock(ubox.lock); return 0; } } else if(argv[0][0] == '-'){ if(u == nil){ vtUnlock(ubox.lock); return 0; } if((up = _userByUname(ubox.box, &argv[0][1])) == nil){ vtUnlock(ubox.lock); return 0; } if(!_groupRemMember(ubox.box, u, up->uname)){ vtUnlock(ubox.lock); return 0; } } else{ if(u != nil){ vtSetError("uname: uname '%s' already exists", u->uname); vtUnlock(ubox.lock); return 0; } uid = argv[0]; if(*uid == ':') uid++; if((u = _userByUid(ubox.box, uid)) != nil){ vtSetError("uname: uid '%s' already exists", u->uid); vtUnlock(ubox.lock); return 0; } u = userAlloc(uid, uname); uboxAddUser(ubox.box, u); if(argv[0][0] != ':'){ // should have an option for the mode and gid p = smprint(createfmt, uname, uname, uname); r = cliExec(p); vtMemFree(p); if(r == 0){ vtUnlock(ubox.lock); return 0; } } } argv++; } if(usersFileWrite(ubox.box) == 0){ vtUnlock(ubox.lock); return 0; } if(dflag) uboxDump(ubox.box); vtUnlock(ubox.lock); return 1; }
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; }
/* * 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); }
File * fileCreate(File *f, char *elem, ulong mode, char *uid) { File *ff; DirEntry *dir; Source *pr, *r, *mr; int isdir; if(!fileLock(f)) return nil; r = nil; mr = nil; for(ff = f->down; ff; ff=ff->next){ if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ ff = nil; vtSetError(EExists); goto Err1; } } ff = dirLookup(f, elem); if(ff != nil){ vtSetError(EExists); goto Err1; } pr = f->source; if(pr->mode != OReadWrite){ vtSetError(EReadOnly); goto Err1; } if(!sourceLock2(f->source, f->msource, -1)) goto Err1; ff = fileAlloc(f->fs); isdir = mode & ModeDir; r = sourceCreate(pr, pr->dsize, isdir, 0); if(r == nil) goto Err; if(isdir){ mr = sourceCreate(pr, pr->dsize, 0, r->offset); if(mr == nil) goto Err; } dir = &ff->dir; dir->elem = vtStrDup(elem); dir->entry = r->offset; dir->gen = r->gen; if(isdir){ dir->mentry = mr->offset; dir->mgen = mr->gen; } dir->size = 0; if(!fsNextQid(f->fs, &dir->qid)) goto Err; dir->uid = vtStrDup(uid); dir->gid = vtStrDup(f->dir.gid); dir->mid = vtStrDup(uid); dir->mtime = time(0L); dir->mcount = 0; dir->ctime = dir->mtime; dir->atime = dir->mtime; dir->mode = mode; ff->boff = fileMetaAlloc(f, dir, 0); if(ff->boff == NilBlock) goto Err; sourceUnlock(f->source); sourceUnlock(f->msource); ff->source = r; r->file = ff; /* point back */ ff->msource = mr; if(mode&ModeTemporary){ if(!sourceLock2(r, mr, -1)) goto Err1; fileSetTmp(ff, 1); sourceUnlock(r); if(mr) sourceUnlock(mr); } /* committed */ /* link in and up parent ref count */ ff->next = f->down; f->down = ff; ff->up = f; fileIncRef(f); fileWAccess(f, uid); fileUnlock(f); return ff; Err: sourceUnlock(f->source); sourceUnlock(f->msource); Err1: if(r){ sourceLock(r, -1); sourceRemove(r); } if(mr){ sourceLock(mr, -1); sourceRemove(mr); } if(ff) fileDecRef(ff); fileUnlock(f); return 0; }