10 * Vac file system. This is a simplified version of the same code in Fossil.
12 * The locking order in the tree is upward: a thread can hold the lock
13 * for a VacFile and then acquire the lock of f->up (the parent),
16 * A vac file is one or two venti files. Plain data files are one venti file,
17 * while directores are two: a venti data file containing traditional
18 * directory entries, and a venti directory file containing venti
19 * directory entries. The traditional directory entries in the data file
20 * contain integers indexing into the venti directory entry file.
21 * It's a little complicated, but it makes the data usable by standard
22 * tools like venti/copy.
26 static int filemetaflush(VacFile*, char*);
30 VacFs *fs; /* immutable */
32 /* meta data for file: protected by the lk in the parent */
33 int ref; /* holds this data structure up */
35 int partial; /* file was never really open */
36 int removed; /* file has been removed */
37 int dirty; /* dir is dirty with respect to meta data in block */
38 u32int boff; /* block offset within msource for this file's metadata */
39 VacDir dir; /* metadata for this file */
40 VacFile *up; /* parent file */
41 VacFile *next; /* sibling */
43 RWLock lk; /* lock for the following */
44 VtFile *source; /* actual data */
45 VtFile *msource; /* metadata for children in a directory */
46 VacFile *down; /* children */
49 uvlong qidoffset; /* qid offset */
57 f = vtmallocz(sizeof(VacFile));
68 vtfileclose(f->source);
69 vtfileclose(f->msource);
71 memset(f, ~0, sizeof *f); /* paranoia */
82 || ((f->dir.mode & ModeDir) && f->msource == nil)){
101 fileunlock(VacFile *f)
107 filerlock(VacFile *f)
110 if(chksource(f) < 0){
118 filerunlock(VacFile *f)
124 * The file metadata, like f->dir and f->ref,
125 * are synchronized via the parent's lock.
126 * This is why locking order goes up.
129 filemetalock(VacFile *f)
131 assert(f->up != nil);
136 filemetaunlock(VacFile *f)
142 vacfilegetid(VacFile *f)
145 return f->qidoffset + f->dir.qid;
149 vacfilegetqidoffset(VacFile *f)
155 vacfilegetmcount(VacFile *f)
160 mcount = f->dir.mcount;
166 vacfilegetmode(VacFile *f)
177 vacfileisdir(VacFile *f)
180 return (f->dir.mode & ModeDir) != 0;
184 vacfileisroot(VacFile *f)
186 return f == f->fs->root;
190 * The files are reference counted, and while the reference
191 * is bigger than zero, each file can be found in its parent's
192 * f->down list (chains via f->next), so that multiple threads
193 * end up sharing a VacFile* when referring to the same file.
195 * Each VacFile holds a reference to its parent.
198 vacfileincref(VacFile *vf)
208 vacfiledecref(VacFile *f)
210 VacFile *p, *q, **qq;
213 /* never linked in */
226 assert(f->down == nil);
228 if(f->source && vtfilelock(f->source, -1) >= 0){
229 vtfileflush(f->source);
230 vtfileunlock(f->source);
232 if(f->msource && vtfilelock(f->msource, -1) >= 0){
233 vtfileflush(f->msource);
234 vtfileunlock(f->msource);
238 * Flush f's directory information to the cache.
240 filemetaflush(f, nil);
244 for(q = *qq; q; q = *qq){
260 * Construct a vacfile for the root of a vac tree, given the
261 * venti file for the root information. That venti file is a
262 * directory file containing VtEntries for three more venti files:
263 * the two venti files making up the root directory, and a
264 * third venti file that would be the metadata half of the
267 * Fossil generates slightly different vac files, due to a now
268 * impossible-to-change bug, which contain a VtEntry
269 * for just one venti file, that itself contains the expected
270 * three directory entries. Sigh.
273 _vacfileroot(VacFs *fs, VtFile *r)
278 VtFile *r0, *r1, *r2;
291 if(vtfilelock(r, -1) < 0)
293 r0 = vtfileopen(r, 0, fs->mode);
295 fprint(2, "r0 %p\n", r0);
298 r2 = vtfileopen(r, 2, fs->mode);
300 fprint(2, "r2 %p\n", r2);
303 * some vac files (e.g., from fossil)
304 * have an extra layer of indirection.
306 rerrstr(err, sizeof err);
307 if(!redirected && strstr(err, "not active")){
315 r1 = vtfileopen(r, 1, fs->mode);
317 fprint(2, "r1 %p\n", r1);
325 root = filealloc(fs);
336 if(vtfilelock(mr->msource, VtOREAD) < 0)
338 b = vtfileblock(mr->msource, 0, VtOREAD);
339 vtfileunlock(mr->msource);
343 if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
346 meunpack(&me, &mb, 0);
347 if(vdunpack(&root->dir, &me) < 0)
371 * Vac directories are a sequence of metablocks, each of which
372 * contains a bunch of metaentries sorted by file name.
373 * The whole sequence isn't sorted, though, so you still have
374 * to look at every block to find a given name.
375 * Dirlookup looks in f for an element name elem.
376 * It returns a new VacFile with the dir, boff, and mode
377 * filled in, but the sources (venti files) are not, and f is
378 * not yet linked into the tree. These details must be taken
379 * care of by the caller.
381 * f must be locked, f->msource must not.
384 dirlookup(VacFile *f, char *elem)
396 if(vtfilelock(meta, -1) < 0)
398 nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
399 for(bo=0; bo<nb; bo++){
400 b = vtfileblock(meta, bo, VtOREAD);
403 if(mbunpack(&mb, b->data, meta->dsize) < 0)
405 if(mbsearch(&mb, elem, &i, &me) >= 0){
406 ff = filealloc(f->fs);
407 if(vdunpack(&ff->dir, &me) < 0){
411 ff->qidoffset = f->qidoffset + ff->dir.qidoffset;
430 * Open the venti file at offset in the directory f->source.
434 fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
438 if((r = vtfileopen(f->source, offset, mode)) == nil)
447 if(r->dir != dir && r->mode != -1){
456 vacfilegetparent(VacFile *f)
459 return vacfileincref(f);
460 return vacfileincref(f->up);
464 * Given an unlocked vacfile (directory) f,
465 * return the vacfile named elem in f.
466 * Interprets . and .. as a convenience to callers.
469 vacfilewalk(VacFile *f, char *elem)
478 if(!vacfileisdir(f)){
483 if(strcmp(elem, ".") == 0)
484 return vacfileincref(f);
486 if(strcmp(elem, "..") == 0)
487 return vacfilegetparent(f);
492 for(ff = f->down; ff; ff=ff->next){
493 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
499 ff = dirlookup(f, elem);
503 if(ff->dir.mode & ModeSnapshot)
506 if(vtfilelock(f->source, f->mode) < 0)
508 if(ff->dir.mode & ModeDir){
509 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
510 ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
511 if(ff->source == nil || ff->msource == nil)
514 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
515 if(ff->source == nil)
518 vtfileunlock(f->source);
520 /* link in and up parent ref count */
530 vtfileunlock(f->source);
539 * Open a path in the vac file system:
540 * just walk each element one at a time.
543 vacfileopen(VacFs *fs, char *path)
546 char *p, elem[VtMaxStringSize], *opath;
553 for(p = path; *p && *p != '/'; p++)
557 if(n > VtMaxStringSize){
558 werrstr("%s: element too long", EBadPath);
561 memmove(elem, path, n);
563 ff = vacfilewalk(f, elem);
565 werrstr("%.*s: %r", utfnlen(opath, p-opath), opath);
582 * Extract the score for the bn'th block in f.
585 vacfileblockscore(VacFile *f, u32int bn, u8int *score)
594 if(vtfilelock(f->source, VtOREAD) < 0)
599 size = vtfilegetsize(s);
600 if((uvlong)bn*dsize >= size)
602 ret = vtfileblockscore(f->source, bn, score);
605 vtfileunlock(f->source);
614 vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
624 if(vtfilelock(f->source, VtOREAD) < 0){
628 n = vtfileread(f->source, buf, cnt, offset);
629 vtfileunlock(f->source);
635 getentry(VtFile *f, VtEntry *e)
637 if(vtfilelock(f, VtOREAD) < 0)
639 if(vtfilegetentry(f, e) < 0){
644 if(vtglobaltolocal(e->score) != NilBlock){
645 werrstr("internal error - data not on venti");
652 * Get the VtEntries for the data contained in f.
655 vacfilegetentries(VacFile *f, VtEntry *e, VtEntry *me)
659 if(e && getentry(f->source, e) < 0){
664 if(f->msource == nil)
665 memset(me, 0, sizeof *me);
666 else if(getentry(f->msource, me) < 0){
676 * Get the file's size.
679 vacfilegetsize(VacFile *f, uvlong *size)
683 if(vtfilelock(f->source, VtOREAD) < 0){
687 *size = vtfilegetsize(f->source);
688 vtfileunlock(f->source);
697 * A VacDirEnum is a buffer containing directory entries.
698 * Directory entries contain malloced strings and need to
699 * be cleaned up with vdcleanup. The invariant in the
700 * VacDirEnum is that the directory entries between
701 * vde->i and vde->n are owned by the vde and need to
702 * be cleaned up if it is closed. Those from 0 up to vde->i
703 * have been handed to the reader, and the reader must
704 * take care of calling vdcleanup as appropriate.
712 if(!vacfileisdir(f)){
718 * There might be changes to this directory's children
719 * that have not been flushed out into the cache yet.
720 * Those changes are only available if we look at the
721 * VacFile structures directory. But the directory reader
722 * is going to read the cache blocks directly, so update them.
726 for(p=f->down; p; p=p->next)
727 filemetaflush(p, nil);
730 vde = vtmallocz(sizeof(VacDirEnum));
731 vde->file = vacfileincref(f);
737 * Figure out the size of the directory entry at offset.
738 * The rest of the metadata is kept in the data half,
739 * but since venti has to track the data size anyway,
740 * we just use that one and avoid updating the directory
741 * each time the file size changes.
744 direntrysize(VtFile *s, ulong offset, ulong gen, uvlong *size)
751 epb = s->dsize/VtEntrySize;
755 b = vtfileblock(s, bn, VtOREAD);
758 if(vtentryunpack(&e, b->data, offset) < 0)
761 /* dangling entries are returned as zero size */
762 if(!(e.flags & VtEntryActive) || e.gen != gen)
775 * Fill in vde with a new batch of directory entries.
778 vdefill(VacDirEnum *vde)
781 VtFile *meta, *source;
789 for(i=vde->i; i<vde->n; i++)
790 vdcleanup(vde->buf+i);
801 b = vtfileblock(meta, vde->boff, VtOREAD);
804 if(mbunpack(&mb, b->data, meta->dsize) < 0)
808 vde->buf = vtmalloc(n * sizeof(VacDir));
812 meunpack(&me, &mb, i);
813 if(vdunpack(de, &me) < 0)
816 if(!(de->mode & ModeDir))
817 if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
829 * Read a single directory entry from vde into de.
830 * Returns -1 on error, 0 on EOF, and 1 on success.
831 * When it returns 1, it becomes the caller's responsibility
832 * to call vdcleanup(de) to free the strings contained
833 * inside, or else to call vdunread to give it back.
836 vderead(VacDirEnum *vde, VacDir *de)
846 if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
851 nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
853 while(vde->i >= vde->n){
858 if(vdefill(vde) < 0){
864 memmove(de, vde->buf + vde->i, sizeof(VacDir));
869 vtfileunlock(f->source);
870 vtfileunlock(f->msource);
877 * "Unread" the last directory entry that was read,
878 * so that the next vderead will return the same one.
879 * If the caller calls vdeunread(vde) it should not call
880 * vdcleanup on the entry being "unread".
883 vdeunread(VacDirEnum *vde)
893 * Close the enumerator.
896 vdeclose(VacDirEnum *vde)
901 /* free the strings */
902 for(i=vde->i; i<vde->n; i++)
903 vdcleanup(vde->buf+i);
905 vacfiledecref(vde->file);
911 * On to mutation. If the vac file system has been opened
912 * read-write, then the files and directories can all be edited.
913 * Changes are kept in the in-memory cache until flushed out
914 * to venti, so we must be careful to explicitly flush data
915 * that we're not likely to modify again.
917 * Each VacFile has its own copy of its VacDir directory entry
918 * in f->dir, but otherwise the cache is the authoratative source
919 * for data. Thus, for the most part, it suffices if we just
920 * call vtfileflushbefore and vtfileflush when we modify things.
921 * There are a few places where we have to remember to write
922 * changed VacDirs back into the cache. If f->dir *is* out of sync,
923 * then f->dirty should be set.
925 * The metadata in a directory is, to venti, a plain data file,
926 * but as mentioned above it is actually a sequence of
927 * MetaBlocks that contain sorted lists of VacDir entries.
928 * The filemetaxxx routines manipulate that stream.
932 * Find space in fp for the directory entry dir (not yet written to disk)
933 * and write it to disk, returning NilBlock on failure,
934 * or the block number on success.
936 * Start is a suggested block number to try.
937 * The caller must have filemetalock'ed f and have
938 * vtfilelock'ed f->up->msource.
941 filemetaalloc(VacFile *fp, VacDir *dir, u32int start)
953 n = vdsize(dir, VacDirVersion);
955 /* Look for a block with room for a new entry of size n. */
956 nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
957 if(start == NilBlock){
966 for(bo=start; bo<nb; bo++){
967 if((b = vtfileblock(ms, bo, VtOREAD)) == nil)
969 if(mbunpack(&mb, b->data, ms->dsize) < 0)
971 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
972 if(n <= nn && mb.nindex < mb.maxindex){
973 /* reopen for writing */
975 if((b = vtfileblock(ms, bo, VtORDWR)) == nil)
977 mbunpack(&mb, b->data, ms->dsize);
983 /* No block found, extend the file by one metablock. */
984 vtfileflushbefore(ms, nb*(uvlong)ms->dsize);
985 if((b = vtfileblock(ms, nb, VtORDWR)) == nil)
987 vtfilesetsize(ms, (nb+1)*ms->dsize);
988 mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
991 /* Now we have a block; allocate space to write the entry. */
994 /* mballoc might have changed block */
1000 /* Figure out where to put the index entry, and write it. */
1001 mbsearch(&mb, dir->elem, &i, &me);
1002 assert(me.p == nil); /* not already there */
1005 vdpack(dir, &me, VacDirVersion);
1006 mbinsert(&mb, i, &me);
1017 * Update f's directory entry in the block cache.
1018 * We look for the directory entry by name;
1019 * if we're trying to rename the file, oelem is the old name.
1021 * Assumes caller has filemetalock'ed f.
1024 filemetaflush(VacFile *f, char *oelem)
1037 oelem = f->dir.elem;
1040 * Locate f's old metadata in the parent's metadata file.
1041 * We know which block it was in, but not exactly where
1045 if(vtfilelock(fp->msource, -1) < 0)
1047 /* can happen if source is clri'ed out from under us */
1048 if(f->boff == NilBlock)
1050 b = vtfileblock(fp->msource, f->boff, VtORDWR);
1053 if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1055 if(mbsearch(&mb, oelem, &i, &me) < 0)
1059 * Check whether we can resize the entry and keep it
1062 n = vdsize(&f->dir, VacDirVersion);
1063 if(mbresize(&mb, &me, n) >= 0){
1064 /* Okay, can be done without moving to another block. */
1066 /* Remove old data */
1067 mbdelete(&mb, i, &me);
1069 /* Find new location if renaming */
1070 if(strcmp(f->dir.elem, oelem) != 0)
1071 mbsearch(&mb, f->dir.elem, &i, &me2);
1073 /* Pack new data into new location. */
1074 vdpack(&f->dir, &me, VacDirVersion);
1075 vdunpack(&f->dir, &me);
1076 mbinsert(&mb, i, &me);
1081 vtfileunlock(fp->msource);
1087 * The entry must be moved to another block.
1088 * This can only really happen on renames that
1089 * make the name very long.
1092 /* Allocate a spot in a new block. */
1093 if((bo = filemetaalloc(fp, &f->dir, f->boff+1)) == NilBlock){
1094 /* mbresize above might have modified block */
1100 /* Now we're committed. Delete entry in old block. */
1101 mbdelete(&mb, i, &me);
1104 vtfileunlock(fp->msource);
1112 vtfileunlock(fp->msource);
1117 * Remove the directory entry for f.
1120 filemetaremove(VacFile *f)
1132 if(vtfilelock(fp->msource, VtORDWR) < 0)
1134 b = vtfileblock(fp->msource, f->boff, VtORDWR);
1138 if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1140 if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
1142 mbdelete(&mb, i, &me);
1145 vtfileunlock(fp->msource);
1155 vtfileunlock(fp->msource);
1162 * That was far too much effort for directory entries.
1163 * Now we can write code that *does* things.
1167 * Flush all data associated with f out of the cache and onto venti.
1168 * If recursive is set, flush f's children too.
1169 * Vacfiledecref knows how to flush source and msource too.
1172 vacfileflush(VacFile *f, int recursive)
1178 if(f->mode == VtOREAD)
1183 if(filemetaflush(f, nil) < 0)
1191 * Lock order prevents us from flushing kids while holding
1192 * lock, so make a list and then flush without the lock.
1198 for(p=f->down; p; p=p->next)
1200 kids = vtmalloc(nkids*sizeof(VacFile*));
1202 for(p=f->down; p; p=p->next){
1209 for(i=0; i<nkids; i++){
1210 if(vacfileflush(kids[i], 1) < 0)
1212 vacfiledecref(kids[i]);
1219 * Now we can flush our own data.
1221 vtfilelock(f->source, -1);
1222 if(vtfileflush(f->source) < 0)
1224 vtfileunlock(f->source);
1226 vtfilelock(f->msource, -1);
1227 if(vtfileflush(f->msource) < 0)
1229 vtfileunlock(f->msource);
1237 * Create a new file named elem in fp with the given mode.
1238 * The mode can be changed later except for the ModeDir bit.
1241 vacfilecreate(VacFile *fp, char *elem, ulong mode)
1245 VtFile *pr, *r, *mr;
1249 if(filelock(fp) < 0)
1253 * First, look to see that there's not a file in memory
1254 * with the same name.
1256 for(ff = fp->down; ff; ff=ff->next){
1257 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
1265 * Next check the venti blocks.
1267 ff = dirlookup(fp, elem);
1274 * By the way, you can't create in a read-only file system.
1277 if(pr->mode != VtORDWR){
1283 * Okay, time to actually create something. Lock the two
1284 * halves of the directory and create a file.
1286 if(vtfilelock2(fp->source, fp->msource, -1) < 0)
1288 ff = filealloc(fp->fs);
1289 ff->qidoffset = fp->qidoffset; /* hopefully fp->qidoffset == 0 */
1294 if((r = vtfilecreate(pr, pr->psize, pr->dsize, type)) == nil)
1297 if((mr = vtfilecreate(pr, pr->psize, pr->dsize, VtDataType)) == nil)
1301 * Fill in the directory entry and write it to disk.
1304 dir->elem = vtstrdup(elem);
1305 dir->entry = r->offset;
1308 dir->mentry = mr->offset;
1309 dir->mgen = mr->gen;
1312 if(_vacfsnextqid(fp->fs, &dir->qid) < 0)
1314 dir->uid = vtstrdup(fp->dir.uid);
1315 dir->gid = vtstrdup(fp->dir.gid);
1316 dir->mid = vtstrdup("");
1317 dir->mtime = time(0L);
1319 dir->ctime = dir->mtime;
1320 dir->atime = dir->mtime;
1322 if((bo = filemetaalloc(fp, &ff->dir, NilBlock)) == NilBlock)
1326 * Now we're committed.
1328 vtfileunlock(fp->source);
1329 vtfileunlock(fp->msource);
1334 /* Link into tree. */
1335 ff->next = fp->down;
1343 vtfilelock(ff->source, -1);
1344 vtfileunlock(ff->source);
1350 vtfileunlock(fp->source);
1351 vtfileunlock(fp->msource);
1368 * Change the size of the file f.
1371 vacfilesetsize(VacFile *f, uvlong size)
1373 if(vacfileisdir(f)){
1381 if(f->source->mode != VtORDWR){
1385 if(vtfilelock(f->source, -1) < 0)
1387 if(vtfilesetsize(f->source, size) < 0){
1388 vtfileunlock(f->source);
1391 vtfileunlock(f->source);
1404 vacfilewrite(VacFile *f, void *buf, int cnt, vlong offset)
1406 if(vacfileisdir(f)){
1412 if(f->source->mode != VtORDWR){
1417 werrstr(EBadOffset);
1421 if(vtfilelock(f->source, -1) < 0)
1423 if(f->dir.mode & ModeAppend)
1424 offset = vtfilegetsize(f->source);
1425 if(vtfilewrite(f->source, buf, cnt, offset) != cnt
1426 || vtfileflushbefore(f->source, offset) < 0){
1427 vtfileunlock(f->source);
1430 vtfileunlock(f->source);
1440 * Set (!) the VtEntry for the data contained in f.
1441 * This let's us efficiently copy data from one file to another.
1444 vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me)
1448 vacfileflush(f, 0); /* flush blocks to venti, since we won't see them again */
1450 if(!(e->flags&VtEntryActive)){
1451 werrstr("missing entry for source");
1454 if(me && !(me->flags&VtEntryActive))
1456 if(f->msource && !me){
1457 werrstr("missing entry for msource");
1460 if(me && !f->msource){
1461 werrstr("no msource to set");
1467 if(f->source->mode != VtORDWR
1468 || (f->msource && f->msource->mode != VtORDWR)){
1473 if(vtfilelock2(f->source, f->msource, -1) < 0){
1478 if(vtfilesetentry(f->source, e) < 0)
1480 else if(me && vtfilesetentry(f->msource, me) < 0)
1483 vtfileunlock(f->source);
1485 vtfileunlock(f->msource);
1491 * Get the directory entry for f.
1494 vacfilegetdir(VacFile *f, VacDir *dir)
1496 if(filerlock(f) < 0)
1500 vdcopy(dir, &f->dir);
1503 if(!vacfileisdir(f)){
1504 if(vtfilelock(f->source, VtOREAD) < 0){
1508 dir->size = vtfilegetsize(f->source);
1509 vtfileunlock(f->source);
1517 * Set the directory entry for f.
1520 vacfilesetdir(VacFile *f, VacDir *dir)
1527 /* can not set permissions for the root */
1528 if(vacfileisroot(f)){
1537 if(f->source->mode != VtORDWR){
1542 /* On rename, check new name does not already exist */
1543 if(strcmp(f->dir.elem, dir->elem) != 0){
1544 for(ff = f->up->down; ff; ff=ff->next){
1545 if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
1550 ff = dirlookup(f->up, dir->elem);
1556 werrstr(""); /* "failed" dirlookup poisoned it */
1560 if(vtfilelock2(f->source, f->msource, -1) < 0)
1562 if(!vacfileisdir(f)){
1563 size = vtfilegetsize(f->source);
1564 if(size != dir->size){
1565 if(vtfilesetsize(f->source, dir->size) < 0){
1566 vtfileunlock(f->source);
1568 vtfileunlock(f->msource);
1573 /* ... now commited to changing it. */
1574 vtfileunlock(f->source);
1576 vtfileunlock(f->msource);
1579 if(strcmp(f->dir.elem, dir->elem) != 0){
1580 oelem = f->dir.elem;
1581 f->dir.elem = vtstrdup(dir->elem);
1584 if(strcmp(f->dir.uid, dir->uid) != 0){
1586 f->dir.uid = vtstrdup(dir->uid);
1589 if(strcmp(f->dir.gid, dir->gid) != 0){
1591 f->dir.gid = vtstrdup(dir->gid);
1594 f->dir.mtime = dir->mtime;
1595 f->dir.atime = dir->atime;
1597 mask = ~(ModeDir|ModeSnapshot);
1598 f->dir.mode &= ~mask;
1599 f->dir.mode |= mask & dir->mode;
1602 if(filemetaflush(f, oelem) < 0){
1604 goto Err; /* that sucks */
1619 * Set the qid space.
1622 vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
1628 if(f->source->mode != VtORDWR){
1634 f->dir.qidspace = 1;
1635 f->dir.qidoffset = offset;
1636 f->dir.qidmax = max;
1638 ret = filemetaflush(f, nil);
1645 * Check that the file is empty, returning 0 if it is.
1646 * Returns -1 on error (and not being empty is an error).
1649 filecheckempty(VacFile *f)
1657 n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
1659 b = vtfileblock(r, i, VtOREAD);
1662 if(mbunpack(&mb, b->data, r->dsize) < 0)
1678 * Remove the vac file f.
1681 vacfileremove(VacFile *f)
1685 /* Cannot remove the root */
1686 if(vacfileisroot(f)){
1693 if(f->source->mode != VtORDWR){
1697 if(vtfilelock2(f->source, f->msource, -1) < 0)
1699 if(vacfileisdir(f) && filecheckempty(f)<0)
1702 for(ff=f->down; ff; ff=ff->next)
1703 assert(ff->removed);
1705 vtfileremove(f->source);
1708 vtfileremove(f->msource);
1713 if(filemetaremove(f) < 0)
1718 vtfileunlock(f->source);
1720 vtfileunlock(f->msource);
1727 * Vac file system format.
1729 static char EBadVacFormat[] = "bad format for vac file";
1732 vacfsalloc(VtConn *z, int bsize, int ncache, int mode)
1736 fs = vtmallocz(sizeof(VacFs));
1740 fs->cache = vtcachealloc(z, bsize, ncache);
1745 readscore(int fd, uchar score[VtScoreSize])
1747 char buf[45], *pref;
1750 n = readn(fd, buf, sizeof(buf)-1);
1751 if(n < sizeof(buf)-1) {
1752 werrstr("short read");
1757 if(vtparsescore(buf, &pref, score) < 0){
1758 werrstr(EBadVacFormat);
1761 if(pref==nil || strcmp(pref, "vac") != 0) {
1762 werrstr("not a vac file");
1769 vacfsopen(VtConn *z, char *file, int mode, int ncache)
1772 uchar score[VtScoreSize];
1775 if(vtparsescore(file, &prefix, score) >= 0){
1776 if(strcmp(prefix, "vac") != 0){
1777 werrstr("not a vac file");
1781 fd = open(file, OREAD);
1784 if(readscore(fd, score) < 0){
1790 return vacfsopenscore(z, score, mode, ncache);
1794 vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache)
1799 uchar buf[VtRootSize];
1804 n = vtread(z, score, VtRootType, buf, VtRootSize);
1807 if(n != VtRootSize){
1808 werrstr("vtread on root too short");
1812 if(vtrootunpack(&rt, buf) < 0)
1815 if(strcmp(rt.type, "vac") != 0) {
1816 werrstr("not a vac root");
1820 fs = vacfsalloc(z, rt.blocksize, ncache, mode);
1821 memmove(fs->score, score, VtScoreSize);
1824 memmove(e.score, rt.score, VtScoreSize);
1826 e.psize = (rt.blocksize/VtEntrySize)*VtEntrySize;
1827 e.dsize = rt.blocksize;
1829 e.flags = VtEntryActive;
1830 e.size = 3*VtEntrySize;
1833 if((r = vtfileopenroot(fs->cache, &e)) == nil)
1836 fprint(2, "r %p\n", r);
1837 root = _vacfileroot(fs, r);
1839 fprint(2, "root %p\n", root);
1847 vacfiledecref(root);
1853 vacfsmode(VacFs *fs)
1859 vacfsgetroot(VacFs *fs)
1861 return vacfileincref(fs->root);
1865 vacfsgetblocksize(VacFs *fs)
1871 vacfsgetscore(VacFs *fs, u8int *score)
1873 memmove(score, fs->score, VtScoreSize);
1878 _vacfsnextqid(VacFs *fs, uvlong *qid)
1886 vacfsjumpqid(VacFs *fs, uvlong step)
1892 * Set *maxqid to the maximum qid expected in this file system.
1893 * In newer vac archives, the maximum qid is stored in the
1894 * qidspace VacDir annotation. In older vac archives, the root
1895 * got created last, so it had the maximum qid.
1898 vacfsgetmaxqid(VacFs *fs, uvlong *maxqid)
1902 if(vacfilegetdir(fs->root, &vd) < 0)
1905 *maxqid = vd.qidmax;
1914 vacfsclose(VacFs *fs)
1917 vacfiledecref(fs->root);
1919 vtcachefree(fs->cache);
1924 * Create a fresh vac fs.
1927 vacfscreate(VtConn *z, int bsize, int ncache)
1931 uchar buf[VtEntrySize], metascore[VtScoreSize];
1939 if((fs = vacfsalloc(z, bsize, ncache, VtORDWR)) == nil)
1943 * Fake up an empty vac fs.
1945 psize = bsize/VtEntrySize*VtEntrySize;
1946 f = vtfilecreateroot(fs->cache, psize, bsize, VtDirType);
1947 vtfilelock(f, VtORDWR);
1949 /* Write metablock containing root directory VacDir. */
1950 b = vtcacheallocblock(fs->cache, VtDataType);
1951 mbinit(&mb, b->data, bsize, bsize/BytesPerEntry);
1952 memset(&vd, 0, sizeof vd);
1954 vd.mode = 0777|ModeDir;
1958 me.size = vdsize(&vd, VacDirVersion);
1959 me.p = mballoc(&mb, me.size);
1960 vdpack(&vd, &me, VacDirVersion);
1961 mbinsert(&mb, 0, &me);
1964 memmove(metascore, b->score, VtScoreSize);
1967 /* First entry: empty venti directory stream. */
1968 memset(&e, 0, sizeof e);
1969 e.flags = VtEntryActive;
1973 memmove(e.score, vtzeroscore, VtScoreSize);
1974 vtentrypack(&e, buf, 0);
1975 vtfilewrite(f, buf, VtEntrySize, 0);
1977 /* Second entry: empty metadata stream. */
1978 e.type = VtDataType;
1979 vtentrypack(&e, buf, 0);
1980 vtfilewrite(f, buf, VtEntrySize, VtEntrySize);
1982 /* Third entry: metadata stream with root directory. */
1983 memmove(e.score, metascore, VtScoreSize);
1985 vtentrypack(&e, buf, 0);
1986 vtfilewrite(f, buf, VtEntrySize, VtEntrySize*2);
1991 /* Now open it as a vac fs. */
1992 fs->root = _vacfileroot(fs, f);
1993 if(fs->root == nil){
1994 werrstr("vacfileroot: %r");
2003 vacfssync(VacFs *fs)
2010 /* Sync the entire vacfs to disk. */
2011 if(vacfileflush(fs->root, 1) < 0)
2013 if(vtfilelock(fs->root->up->msource, -1) < 0)
2015 if(vtfileflush(fs->root->up->msource) < 0){
2016 vtfileunlock(fs->root->up->msource);
2019 vtfileunlock(fs->root->up->msource);
2021 /* Prepare the dir stream for the root block. */
2022 if(getentry(fs->root->source, &e) < 0)
2024 vtentrypack(&e, buf, 0);
2025 if(getentry(fs->root->msource, &e) < 0)
2027 vtentrypack(&e, buf, 1);
2028 if(getentry(fs->root->up->msource, &e) < 0)
2030 vtentrypack(&e, buf, 2);
2032 f = vtfilecreateroot(fs->cache, fs->bsize, fs->bsize, VtDirType);
2033 vtfilelock(f, VtORDWR);
2034 if(vtfilewrite(f, buf, 3*VtEntrySize, 0) < 0
2035 || vtfileflush(f) < 0){
2041 if(getentry(f, &e) < 0){
2047 /* Build a root block. */
2048 memset(&root, 0, sizeof root);
2049 strcpy(root.type, "vac");
2050 strcpy(root.name, fs->name);
2051 memmove(root.score, e.score, VtScoreSize);
2052 root.blocksize = fs->bsize;
2053 memmove(root.prev, fs->score, VtScoreSize);
2054 vtrootpack(&root, buf);
2055 if(vtwrite(fs->z, fs->score, VtRootType, buf, VtRootSize) < 0){
2056 werrstr("writing root: %r");
2059 if(vtsync(fs->z) < 0)