int usersFileRead(char* path) { char *p; File *file; Fsys *fsys; int len, r; uvlong size; if((fsys = fsysGet("main")) == nil) return 0; fsysFsRlock(fsys); if(path == nil) path = "/active/adm/users"; r = 0; if((file = fileOpen(fsysGetFs(fsys), path)) != nil){ if(fileGetSize(file, &size)){ len = size; p = vtMemAlloc(size+1); if(fileRead(file, p, len, 0) == len){ p[len] = '\0'; r = uboxInit(p, len); } } fileDecRef(file); } fsysFsRUnlock(fsys); fsysPut(fsys); return r; }
int fileMetaFlush(File *f, int rec) { File **kids, *p; int nkids; int i, rv; fileMetaLock(f); rv = fileMetaFlush2(f, nil); fileMetaUnlock(f); if(!rec || !fileIsDir(f)) return rv; if(!fileLock(f)) return rv; nkids = 0; for(p=f->down; p; p=p->next) nkids++; kids = vtMemAlloc(nkids*sizeof(File*)); i = 0; for(p=f->down; p; p=p->next){ kids[i++] = p; p->ref++; } fileUnlock(f); for(i=0; i<nkids; i++){ rv |= fileMetaFlush(kids[i], 1); fileDecRef(kids[i]); } vtMemFree(kids); return rv; }
void * vtMemAllocZ(int size) { void *p = vtMemAlloc(size); memset(p, 0, size); setmalloctag(p, getcallerpc(&size)); return p; }
VtSha1 * vtSha1Alloc(void) { VtSha1 *s; s = vtMemAlloc(sizeof(VtSha1)); vtSha1Init(s); return s; }
static uchar* copyBlock(Block *b, u32int blockSize) { uchar *data; data = vtMemAlloc(blockSize); if(data == nil) return nil; memmove(data, b->data, blockSize); return data; }
void * vtMemRealloc(void *p, int size) { if(p == nil) return vtMemAlloc(size); p = realloc(p, size); if(p == 0) vtFatal("vtRealloc: out of memory"); setrealloctag(p, getcallerpc(&size)); return p; }
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; }
/* * Fsck that MetaBlock has reasonable header, sorted entries, */ static int chkMetaBlock(MetaBlock *mb) { MetaChunk *mc; int oo, o, n, i; uchar *p; mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk)); p = mb->buf + MetaHeaderSize; for(i = 0; i < mb->nindex; i++){ mc[i].offset = p[0]<<8 | p[1]; mc[i].size = p[2]<<8 | p[3]; mc[i].index = i; p += MetaIndexSize; } qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp); /* check block looks ok */ oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; o = oo; n = 0; for(i = 0; i < mb->nindex; i++){ o = mc[i].offset; n = mc[i].size; if(o < oo) goto Err; oo += n; } if(o+n > mb->size || mb->size - oo != mb->free) goto Err; vtMemFree(mc); return 1; Err: if(0){ fprint(2, "metaChunks failed!\n"); oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; for(i=0; i<mb->nindex; i++){ fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size); oo += mc[i].size; } fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo); } vtMemFree(mc); return 0; }
static MetaChunk * metaChunks(MetaBlock *mb) { MetaChunk *mc; int oo, o, n, i; uchar *p; mc = vtMemAlloc(mb->nindex*sizeof(MetaChunk)); p = mb->buf + MetaHeaderSize; for(i = 0; i<mb->nindex; i++){ mc[i].offset = U16GET(p); mc[i].size = U16GET(p+2); mc[i].index = i; p += MetaIndexSize; } qsort(mc, mb->nindex, sizeof(MetaChunk), offsetCmp); /* check block looks ok */ oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; o = oo; n = 0; for(i=0; i<mb->nindex; i++){ o = mc[i].offset; n = mc[i].size; if(o < oo) goto Err; oo += n; } if(o+n > mb->size) goto Err; if(mb->size - oo != mb->free) goto Err; return mc; Err: fprint(2, "metaChunks failed!\n"); oo = MetaHeaderSize + mb->maxindex*MetaIndexSize; for(i=0; i<mb->nindex; i++){ fprint(2, "\t%d: %d %d\n", i, mc[i].offset, mc[i].offset + mc[i].size); oo += mc[i].size; } fprint(2, "\tused=%d size=%d free=%d free2=%d\n", oo, mb->size, mb->free, mb->size - oo); vtSetError(EBadMeta); vtMemFree(mc); return nil; }
static int stringUnpack(char **s, uchar **p, int *n) { int nn; if(*n < 2) return 0; nn = U16GET(*p); *p += 2; *n -= 2; if(nn > *n) return 0; *s = vtMemAlloc(nn+1); memmove(*s, *p, nn); (*s)[nn] = 0; *p += nn; *n -= nn; return 1; }
int vtGetString(Packet *p, char **ret) { uint8_t buf[2]; int n; char *s; if(!packetConsume(p, buf, 2)) return 0; n = (buf[0]<<8) + buf[1]; if(n > VtMaxStringSize) { vtSetError(EBigString); return 0; } s = vtMemAlloc(n+1); setmalloctag(s, getcallerpc()); if(!packetConsume(p, (uint8_t*)s, n)) { vtMemFree(s); return 0; } s[n] = 0; *ret = s; 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; }
static int usersFileWrite(Ubox* box) { Fs *fs; User *u; int i, r; Fsys *fsys; char *p, *q, *s; File *dir, *file; if((fsys = fsysGet("main")) == nil) return 0; fsysFsRlock(fsys); fs = fsysGetFs(fsys); /* * BUG: * the owner/group/permissions need to be thought out. */ r = 0; if((dir = fileOpen(fs, "/active")) == nil) goto tidy0; if((file = fileWalk(dir, uidadm)) == nil) file = fileCreate(dir, uidadm, ModeDir|0775, uidadm); fileDecRef(dir); if(file == nil) goto tidy; dir = file; if((file = fileWalk(dir, "users")) == nil) file = fileCreate(dir, "users", 0664, uidadm); fileDecRef(dir); if(file == nil) goto tidy; if(!fileTruncate(file, uidadm)) goto tidy; p = s = vtMemAlloc(box->len+1); q = p + box->len+1; for(u = box->head; u != nil; u = u->next){ p += snprint(p, q-p, "%s:%s:", u->uid, u->uname); if(u->leader != nil) p+= snprint(p, q-p, u->leader); p += snprint(p, q-p, ":"); if(u->ngroup){ p += snprint(p, q-p, u->group[0]); for(i = 1; i < u->ngroup; i++) p += snprint(p, q-p, ",%s", u->group[i]); } p += snprint(p, q-p, "\n"); } r = fileWrite(file, s, box->len, 0, uidadm); vtMemFree(s); tidy: if(file != nil) fileDecRef(file); tidy0: fsysFsRUnlock(fsys); fsysPut(fsys); return r; }