8 * locking order is upwards. A thread can hold the lock for a VacFile
9 * and then acquire the lock of its parent
13 VacFs *fs; /* immutable */
15 /* meta data for file: protected by the lk in the parent */
16 int ref; /* holds this data structure up */
18 int partial; /* file was never really open */
19 int removed; /* file has been removed */
20 int dirty; /* dir is dirty with respect to meta data in block */
21 u32int boff; /* block offset within msource for this file's metadata */
22 VacDir dir; /* metadata for this file */
23 VacFile *up; /* parent file */
24 VacFile *next; /* sibling */
26 RWLock lk; /* lock for the following */
27 VtFile *source; /* actual data */
28 VtFile *msource; /* metadata for children in a directory */
29 VacFile *down; /* children */
33 static int filelock(VacFile*);
34 static u32int filemetaalloc(VacFile*, VacDir*, u32int);
35 static int filemetaflush2(VacFile*, char*);
36 static void filemetalock(VacFile*);
37 static void filemetaunlock(VacFile*);
38 static void fileraccess(VacFile*);
39 static int filerlock(VacFile*);
40 static void filerunlock(VacFile*);
41 static void fileunlock(VacFile*);
42 static void filewaccess(VacFile*, char*);
44 void mbinit(MetaBlock*, u8int*, uint, uint);
45 int mbsearch(MetaBlock*, char*, int*, MetaEntry*);
46 int mbresize(MetaBlock*, MetaEntry*, int);
47 VacFile *vdlookup(VacFile*, char*);
54 f = vtmallocz(sizeof(VacFile));
65 vtfileclose(f->source);
66 vtfileclose(f->msource);
68 memset(f, ~0, sizeof *f); /* paranoia */
73 * the file is locked already
74 * f->msource is unlocked
77 dirlookup(VacFile *f, char *elem)
89 if(vtfilelock(meta, -1) < 0)
91 nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
92 for(bo=0; bo<nb; bo++){
93 b = vtfileblock(meta, bo, VtOREAD);
96 if(mbunpack(&mb, b->data, meta->dsize) < 0)
98 if(mbsearch(&mb, elem, &i, &me) < 0){
99 ff = filealloc(f->fs);
100 if(vdunpack(&ff->dir, &me) < 0){
123 _vacfileroot(VacFs *fs, VtFile *r)
126 VtFile *r0, *r1, *r2;
137 if(vtfilelock(r, -1) < 0)
139 r0 = vtfileopen(r, 0, fs->mode);
142 r1 = vtfileopen(r, 1, fs->mode);
145 r2 = vtfileopen(r, 2, fs->mode);
153 root = filealloc(fs);
163 if(vtfilelock(mr->msource, -1) < 0)
165 b = vtfileblock(mr->msource, 0, VtOREAD);
166 vtfileunlock(mr->msource);
170 if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
173 meunpack(&me, &mb, 0);
174 if(vdunpack(&root->dir, &me) < 0)
199 fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
203 if(vtfilelock(f->source, mode) < 0)
205 r = vtfileopen(f->source, offset, mode);
206 vtfileunlock(f->source);
213 if(r->dir != dir && r->mode != -1){
214 fprint(2, "fileopensource: dir mismatch %d %d\n", r->dir, dir);
225 _filewalk(VacFile *f, char *elem, int partial)
236 if(!vacfileisdir(f)){
241 if(strcmp(elem, ".") == 0){
242 return vacfileincref(f);
245 if(strcmp(elem, "..") == 0){
247 return vacfileincref(f);
248 return vacfileincref(f->up);
254 for(ff = f->down; ff; ff=ff->next){
255 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
261 ff = dirlookup(f, elem);
265 if(ff->dir.mode & ModeSnapshot)
270 * Do nothing. We're opening this file only so we can clri it.
271 * Usually the sources can't be opened, hence we won't even bother.
272 * Be VERY careful with the returned file. If you hand it to a routine
273 * expecting ff->source and/or ff->msource to be non-nil, we're
274 * likely to dereference nil. FileClri should be the only routine
278 }else if(ff->dir.mode & ModeDir){
279 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
280 ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
281 if(ff->source == nil || ff->msource == nil)
284 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
285 if(ff->source == nil)
289 /* link in and up parent ref count */
305 vacfilewalk(VacFile *f, char *elem)
307 return _filewalk(f, elem, 0);
311 _fileopen(VacFs *fs, char *path, int partial)
314 char *p, elem[VtMaxStringSize], *opath;
321 for(p = path; *p && *p != '/'; p++)
325 if(n > VtMaxStringSize){
326 werrstr("%s: element too long", EBadPath);
329 memmove(elem, path, n);
331 ff = _filewalk(f, elem, partial && *p=='\0');
333 werrstr("%.*s: %R", utfnlen(opath, p-opath), opath);
350 vacfileopen(VacFs *fs, char *path)
352 return _fileopen(fs, path, 0);
357 filesettmp(VacFile *f, int istmp)
370 if(vtfilegetentry(r, &e) < 0){
371 fprint(2, "vtfilegetentry failed (cannot happen): %r\n");
375 e.flags |= VtEntryNoArchive;
377 e.flags &= ~VtEntryNoArchive;
378 if(vtfilesetentry(r, &e) < 0){
379 fprint(2, "vtfilesetentry failed (cannot happen): %r\n");
387 vacfilecreate(VacFile *f, char *elem, ulong mode, char *uid)
399 for(ff = f->down; ff; ff=ff->next){
400 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
407 ff = dirlookup(f, elem);
414 if(pr->mode != VtORDWR){
419 if(vtfilelock2(f->source, f->msource, -1) < 0)
422 ff = filealloc(f->fs);
423 isdir = mode & ModeDir;
425 r = vtfilecreate(pr, pr->dsize, isdir, 0);
429 mr = vtfilecreate(pr, pr->dsize, 0, r->offset);
435 dir->elem = vtstrdup(elem);
436 dir->entry = r->offset;
439 dir->mentry = mr->offset;
443 if(_vacfsnextqid(f->fs, &dir->qid) < 0)
445 dir->uid = vtstrdup(uid);
446 dir->gid = vtstrdup(f->dir.gid);
447 dir->mid = vtstrdup(uid);
448 dir->mtime = time(0L);
450 dir->ctime = dir->mtime;
451 dir->atime = dir->mtime;
454 ff->boff = filemetaalloc(f, dir, 0);
455 if(ff->boff == NilBlock)
458 vtfileunlock(f->source);
459 vtfileunlock(f->msource);
465 if(mode&ModeTemporary){
466 if(vtfilelock2(r, mr, -1) < 0)
477 /* link in and up parent ref count */
489 vtfileunlock(f->source);
490 vtfileunlock(f->msource);
507 vacfileblockscore(VacFile *f, u32int bn, u8int *score)
517 if(vtfilelock(f->source, VtOREAD) < 0)
522 size = vtfilegetsize(s);
523 if((uvlong)bn*dsize >= size)
525 ret = vtfileblockscore(f->source, bn, score);
528 vtfileunlock(f->source);
534 vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
539 int off, dsize, n, nn;
543 if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset);
555 if(vtfilelock(f->source, VtOREAD) < 0)
560 size = vtfilegetsize(s);
565 if(cnt > size-offset)
571 b = vtfileblock(s, bn, OREAD);
580 memmove(p, b->data+off, nn);
581 memset(p+nn, 0, nn-n);
590 return p-(uchar*)buf;
601 * Changes the file block bn to be the given block score.
602 * Very sneaky. Only used by flfmt.
605 filemapblock(VacFile *f, ulong bn, uchar score[VtScoreSize], ulong tag)
615 if(f->dir.mode & ModeDir){
620 if(f->source->mode != VtORDWR){
625 if(vtfilelock(f->source, -1) < 0)
629 b = _vtfileblock(s, bn, VtORDWR, 1, tag);
633 if(vtfilegetentry(s, &e) < 0)
635 if(b->l.type == BtDir){
636 memmove(e.score, score, VtScoreSize);
637 assert(e.tag == tag || e.tag == 0);
639 e.flags |= VtEntryLocal;
640 vtentrypack(&e, b->data, f->source->offset % f->source->epb);
642 memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize);
658 vacfilesetsize(VacFile *f, uvlong size)
665 if(f->dir.mode & ModeDir){
669 if(f->source->mode != VtORDWR){
673 if(vtfilelock(f->source, -1) < 0)
675 r = vtfilesetsize(f->source, size);
676 vtfileunlock(f->source);
683 filewrite(VacFile *f, void *buf, int cnt, vlong offset, char *uid)
692 if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset);
698 if(f->dir.mode & ModeDir){
703 if(f->source->mode != VtORDWR){
714 if(vtfilelock(f->source, -1) < 0)
719 eof = vtfilegetsize(s);
720 if(f->dir.mode & ModeAppend)
729 b = vtfileblock(s, bn, n<dsize?VtORDWR:VtOWRITE);
732 vtfilesetsize(s, offset);
735 memmove(b->data+off, p, n);
744 if(offset > eof && vtfilesetsize(s, offset) < 0)
748 return p-(uchar*)buf;
757 vacfilegetdir(VacFile *f, VacDir *dir)
763 vdcopy(dir, &f->dir);
766 if(vacfileisdir(f) < 0){
767 if(vtfilelock(f->source, VtOREAD) < 0){
771 dir->size = vtfilegetsize(f->source);
772 vtfileunlock(f->source);
780 vacfiletruncate(VacFile *f, char *uid)
790 if(f->source->mode != VtORDWR){
795 if(vtfilelock(f->source, -1) < 0){
799 if(vtfiletruncate(f->source) < 0){
800 vtfileunlock(f->source);
804 vtfileunlock(f->source);
813 vacfilesetdir(VacFile *f, VacDir *dir, char *uid)
820 /* can not set permissions for the root */
821 if(vacfileisroot(f)){
829 if(f->source->mode != VtORDWR){
837 /* check new name does not already exist */
838 if(strcmp(f->dir.elem, dir->elem) != 0){
839 for(ff = f->up->down; ff; ff=ff->next){
840 if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
846 ff = dirlookup(f->up, dir->elem);
854 if(vtfilelock2(f->source, f->msource, -1) < 0)
856 if(!vacfileisdir(f)){
857 size = vtfilegetsize(f->source);
858 if(size != dir->size){
859 if(vtfilesetsize(f->source, dir->size) < 0){
860 vtfileunlock(f->source);
862 vtfileunlock(f->msource);
865 /* commited to changing it now */
868 /* commited to changing it now */
870 if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary))
871 filesettmp(f, dir->mode&ModeTemporary);
873 vtfileunlock(f->source);
875 vtfileunlock(f->msource);
878 if(strcmp(f->dir.elem, dir->elem) != 0){
880 f->dir.elem = vtstrdup(dir->elem);
883 if(strcmp(f->dir.uid, dir->uid) != 0){
885 f->dir.uid = vtstrdup(dir->uid);
888 if(strcmp(f->dir.gid, dir->gid) != 0){
890 f->dir.gid = vtstrdup(dir->gid);
893 f->dir.mtime = dir->mtime;
894 f->dir.atime = dir->atime;
896 //fprint(2, "mode %x %x ", f->dir.mode, dir->mode);
897 mask = ~(ModeDir|ModeSnapshot);
898 f->dir.mode &= ~mask;
899 f->dir.mode |= mask & dir->mode;
901 //fprint(2, "->%x\n", f->dir.mode);
903 filemetaflush2(f, oelem);
909 filewaccess(f->up, uid);
919 vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
927 f->dir.qidoffset = offset;
929 ret = filemetaflush2(f, nil);
936 vacfilegetid(VacFile *f)
943 vacfilegetmcount(VacFile *f)
948 mcount = f->dir.mcount;
954 vacfilegetmode(VacFile *f)
965 vacfileisdir(VacFile *f)
968 return (f->dir.mode & ModeDir) != 0;
972 vacfileisroot(VacFile *f)
974 return f == f->fs->root;
978 vacfilegetsize(VacFile *f, uvlong *size)
982 if(vtfilelock(f->source, VtOREAD) < 0){
986 *size = vtfilegetsize(f->source);
987 vtfileunlock(f->source);
994 vacfilegetvtentry(VacFile *f, VtEntry *e)
998 if(vtfilelock(f->source, VtOREAD) < 0){
1002 vtfilegetentry(f->source, e);
1003 vtfileunlock(f->source);
1010 vacfilemetaflush(VacFile *f, int rec)
1017 filemetaflush2(f, nil);
1020 if(!rec || !vacfileisdir(f))
1026 for(p=f->down; p; p=p->next)
1028 kids = vtmalloc(nkids*sizeof(VacFile*));
1030 for(p=f->down; p; p=p->next){
1036 for(i=0; i<nkids; i++){
1037 vacfilemetaflush(kids[i], 1);
1038 vacfiledecref(kids[i]);
1043 /* assumes metaLock is held */
1045 filemetaflush2(VacFile *f, char *oelem)
1058 oelem = f->dir.elem;
1062 if(vtfilelock(fp->msource, -1) < 0)
1064 /* can happen if source is clri'ed out from under us */
1065 if(f->boff == NilBlock)
1067 b = vtfileblock(fp->msource, f->boff, VtORDWR);
1071 if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1073 if(mbsearch(&mb, oelem, &i, &me) < 0)
1076 n = vdsize(&f->dir);
1077 if(0)fprint(2, "old size %d new size %d\n", me.size, n);
1079 if(mbresize(&mb, &me, n) >= 0){
1080 /* fits in the block */
1081 mbdelete(&mb, i, &me);
1082 if(strcmp(f->dir.elem, oelem) != 0)
1083 mbsearch(&mb, f->dir.elem, &i, &me2);
1084 vdpack(&f->dir, &me);
1085 mbinsert(&mb, i, &me);
1089 vtfileunlock(fp->msource);
1095 * moving entry to another block
1096 * it is feasible for the fs to crash leaving two copies
1097 * of the directory entry. This is just too much work to
1098 * fix. Given that entries are only allocated in a block that
1099 * is less than PercentageFull, most modifications of meta data
1100 * will fit within the block. i.e. this code should almost
1101 * never be executed.
1103 boff = filemetaalloc(fp, &f->dir, f->boff+1);
1104 if(boff == NilBlock){
1105 /* mbResize might have modified block */
1110 fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);
1113 /* make sure deletion goes to disk after new entry */
1114 bb = vtfileblock(fp->msource, f->boff, VtORDWR);
1115 mbdelete(&mb, i, &me);
1117 // blockDependency(b, bb, -1, nil, nil);
1121 vtfileunlock(fp->msource);
1130 vtfileunlock(fp->msource);
1135 filemetaremove(VacFile *f, char *uid)
1145 filewaccess(up, uid);
1148 if(vtfilelock(up->msource, VtORDWR) < 0)
1150 b = vtfileblock(up->msource, f->boff, VtORDWR);
1154 if(mbunpack(&mb, b->data, up->msource->dsize) < 0)
1156 if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
1158 mbdelete(&mb, i, &me);
1160 vtfileunlock(up->msource);
1173 vtfileunlock(up->msource);
1179 /* assume file is locked, assume f->msource is locked */
1181 filecheckempty(VacFile *f)
1189 n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
1191 b = vtfileblock(r, i, VtORDWR);
1194 if(mbunpack(&mb, b->data, r->dsize) < 0)
1209 vacfileremove(VacFile *f, char *muid)
1213 /* can not remove the root */
1214 if(vacfileisroot(f)){
1222 if(f->source->mode != VtORDWR){
1226 if(vtfilelock2(f->source, f->msource, -1) < 0)
1228 if(vacfileisdir(f) && filecheckempty(f)<0)
1231 for(ff=f->down; ff; ff=ff->next)
1232 assert(ff->removed);
1234 vtfileremove(f->source);
1237 vtfileremove(f->msource);
1243 if(filemetaremove(f, muid) < 0)
1249 vtfileunlock(f->source);
1251 vtfileunlock(f->msource);
1258 clri(VacFile *f, char *uid)
1264 if(f->up->source->mode != VtORDWR){
1269 r = filemetaremove(f, uid);
1275 vacfileclripath(VacFs *fs, char *path, char *uid)
1277 return clri(_fileopen(fs, path, 1), uid);
1281 vacfileclri(VacFile *dir, char *elem, char *uid)
1283 return clri(_filewalk(dir, elem, 1), uid);
1287 vacfileincref(VacFile *vf)
1290 assert(vf->ref > 0);
1297 vacfiledecref(VacFile *f)
1299 VacFile *p, *q, **qq;
1302 /* never linked in */
1303 assert(f->ref == 1);
1314 assert(f->ref == 0);
1315 assert(f->down == nil);
1317 filemetaflush2(f, nil);
1321 for(q = *qq; q; q = *qq){
1336 filegetparent(VacFile *f)
1338 if(vacfileisroot(f))
1339 return vacfileincref(f);
1340 return vacfileincref(f->up);
1349 if(!vacfileisdir(f)){
1354 /* flush out meta data */
1357 for(p=f->down; p; p=p->next)
1358 filemetaflush2(p, nil);
1361 vde = vtmallocz(sizeof(VacDirEnum));
1362 vde->file = vacfileincref(f);
1368 direntrysize(VtFile *s, ulong elem, ulong gen, uvlong *size)
1375 epb = s->dsize/VtEntrySize;
1379 b = vtfileblock(s, bn, VtOREAD);
1382 if(vtentryunpack(&e, b->data, elem) < 0)
1385 /* hanging entries are returned as zero size */
1386 if(!(e.flags & VtEntryActive) || e.gen != gen)
1399 vdefill(VacDirEnum *vde)
1402 VtFile *meta, *source;
1409 /* clean up first */
1410 for(i=vde->i; i<vde->n; i++)
1411 vdcleanup(vde->buf+i);
1422 b = vtfileblock(meta, vde->boff, VtOREAD);
1425 if(mbunpack(&mb, b->data, meta->dsize) < 0)
1429 vde->buf = vtmalloc(n * sizeof(VacDir));
1433 meunpack(&me, &mb, i);
1434 if(vdunpack(de, &me) < 0)
1437 if(!(de->mode & ModeDir))
1438 if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
1450 vderead(VacDirEnum *vde, VacDir *de)
1457 if(filerlock(f) < 0)
1460 if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
1465 nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
1468 while(vde->i >= vde->n){
1469 if(vde->boff >= nb){
1474 if(vdefill(vde) < 0){
1480 memmove(de, vde->buf + vde->i, sizeof(VacDir));
1485 vtfileunlock(f->source);
1486 vtfileunlock(f->msource);
1495 vdeclose(VacDirEnum *vde)
1500 for(i=vde->i; i<vde->n; i++)
1501 vdcleanup(vde->buf+i);
1503 vacfiledecref(vde->file);
1508 * caller must lock f->source and f->msource
1509 * caller must NOT lock the source and msource
1510 * referenced by dir.
1513 filemetaalloc(VacFile *f, VacDir *dir, u32int start)
1528 nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
1532 for(bo=start; bo<nb; bo++){
1533 b = vtfileblock(ms, bo, VtORDWR);
1536 if(mbunpack(&mb, b->data, ms->dsize) < 0)
1538 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
1539 if(n <= nn && mb.nindex < mb.maxindex)
1545 /* add block to meta file */
1547 b = vtfileblock(ms, bo, VtORDWR);
1550 vtfilesetsize(ms, (nb+1)*ms->dsize);
1551 mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
1554 p = mballoc(&mb, n);
1556 /* mbAlloc might have changed block */
1563 mbsearch(&mb, dir->elem, &i, &me);
1564 assert(me.p == nil);
1568 mbinsert(&mb, i, &me);
1571 #ifdef notdef /* XXX */
1572 /* meta block depends on super block for qid ... */
1573 bb = cacheLocal(b->c, PartSuper, 0, VtOREAD);
1574 blockDependency(b, bb, -1, nil, nil);
1577 /* ... and one or two dir entries */
1578 epb = s->dsize/VtEntrySize;
1579 bb = vtfileblock(s, dir->entry/epb, VtOREAD);
1580 blockDependency(b, bb, -1, nil, nil);
1582 if(dir->mode & ModeDir){
1583 bb = sourceBlock(s, dir->mentry/epb, VtOREAD);
1584 blockDependency(b, bb, -1, nil, nil);
1598 chksource(VacFile *f)
1603 if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){
1611 filerlock(VacFile *f)
1613 // assert(!canwlock(&f->fs->elk));
1615 if(chksource(f) < 0){
1623 filerunlock(VacFile *f)
1629 filelock(VacFile *f)
1631 // assert(!canwlock(&f->fs->elk));
1633 if(chksource(f) < 0){
1641 fileunlock(VacFile *f)
1647 * f->source and f->msource must NOT be locked.
1648 * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2).
1649 * We have to respect that ordering.
1652 filemetalock(VacFile *f)
1654 assert(f->up != nil);
1655 // assert(!canwlock(&f->fs->elk));
1660 filemetaunlock(VacFile *f)
1662 wunlock(&f->up->lk);
1666 * f->source and f->msource must NOT be locked.
1670 fileraccess(VacFile* f)
1672 if(f->mode == VtOREAD)
1676 f->dir.atime = time(0L);
1682 * f->source and f->msource must NOT be locked.
1686 filewaccess(VacFile* f, char *mid)
1688 if(f->mode == VtOREAD)
1692 f->dir.atime = f->dir.mtime = time(0L);
1693 if(strcmp(f->dir.mid, mid) != 0){
1695 f->dir.mid = vtstrdup(mid);
1701 /*RSC: let's try this */
1702 /*presotto - lets not
1704 filewaccess(f->up, mid);
1710 markCopied(Block *b)
1715 if(globalToLocal(b->score) == NilBlock)
1718 if(!(b->l.state & BsCopied)){
1720 * We need to record that there are now pointers in
1721 * b that are not unique to b. We do this by marking
1722 * b as copied. Since we don't return the label block,
1723 * the caller can't get the dependencies right. So we have
1724 * to flush the block ourselves. This is a rare occurrence.
1727 l.state |= BsCopied;
1728 lb = _blockSetLabel(b, &l);
1730 while(!blockWrite(lb)){
1731 fprint(2, "getEntry: could not write label block\n");
1734 while(lb->iostate != BioClean && lb->iostate != BioDirty){
1735 assert(lb->iostate == BioWriting);
1736 vtSleep(lb->ioready);
1738 if(lb->iostate == BioDirty)
1745 getEntry(VtFile *r, Entry *e, int mark)
1750 memset(&e, 0, sizeof e);
1754 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtOREAD);
1757 if(!entryUnpack(e, b->data, r->offset % r->epb)){
1769 setEntry(Source *r, Entry *e)
1774 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtORDWR);
1775 if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);
1778 if(!entryUnpack(&oe, b->data, r->offset % r->epb)){
1783 entryPack(e, b->data, r->offset % r->epb);
1785 /* BUG b should depend on the entry pointer */
1793 /* assumes hold elk */
1795 fileSnapshot(VacFile *dst, VacFile *src, u32int epoch, int doarchive)
1799 /* add link to snapshot */
1800 if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))
1804 e.archive = doarchive;
1806 ee.archive = doarchive;
1808 if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))
1814 fileGetSources(VacFile *f, Entry *e, Entry *ee, int mark)
1816 if(!getEntry(f->source, e, mark)
1817 || !getEntry(f->msource, ee, mark))
1823 fileWalkSources(VacFile *f)
1825 if(f->mode == VtOREAD)
1827 if(!sourceLock2(f->source, f->msource, VtORDWR))
1829 vtfileunlock(f->source);
1830 vtfileunlock(f->msource);