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 vacfilegetparent(VacFile *f)
1338 if(vacfileisroot(f))
1339 return vacfileincref(f);
1340 return vacfileincref(f->up);
1344 vacfilewrite(VacFile *file, void *buf, int n, vlong offset, char *muid)
1346 werrstr("read only file system");
1356 if(!vacfileisdir(f)){
1361 /* flush out meta data */
1364 for(p=f->down; p; p=p->next)
1365 filemetaflush2(p, nil);
1368 vde = vtmallocz(sizeof(VacDirEnum));
1369 vde->file = vacfileincref(f);
1375 direntrysize(VtFile *s, ulong elem, ulong gen, uvlong *size)
1382 epb = s->dsize/VtEntrySize;
1386 b = vtfileblock(s, bn, VtOREAD);
1389 if(vtentryunpack(&e, b->data, elem) < 0)
1392 /* hanging entries are returned as zero size */
1393 if(!(e.flags & VtEntryActive) || e.gen != gen)
1406 vdefill(VacDirEnum *vde)
1409 VtFile *meta, *source;
1416 /* clean up first */
1417 for(i=vde->i; i<vde->n; i++)
1418 vdcleanup(vde->buf+i);
1429 b = vtfileblock(meta, vde->boff, VtOREAD);
1432 if(mbunpack(&mb, b->data, meta->dsize) < 0)
1436 vde->buf = vtmalloc(n * sizeof(VacDir));
1440 meunpack(&me, &mb, i);
1441 if(vdunpack(de, &me) < 0)
1444 if(!(de->mode & ModeDir))
1445 if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
1457 vderead(VacDirEnum *vde, VacDir *de)
1464 if(filerlock(f) < 0)
1467 if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
1472 nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
1475 while(vde->i >= vde->n){
1476 if(vde->boff >= nb){
1481 if(vdefill(vde) < 0){
1487 memmove(de, vde->buf + vde->i, sizeof(VacDir));
1492 vtfileunlock(f->source);
1493 vtfileunlock(f->msource);
1502 vdeclose(VacDirEnum *vde)
1507 for(i=vde->i; i<vde->n; i++)
1508 vdcleanup(vde->buf+i);
1510 vacfiledecref(vde->file);
1515 * caller must lock f->source and f->msource
1516 * caller must NOT lock the source and msource
1517 * referenced by dir.
1520 filemetaalloc(VacFile *f, VacDir *dir, u32int start)
1535 nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
1539 for(bo=start; bo<nb; bo++){
1540 b = vtfileblock(ms, bo, VtORDWR);
1543 if(mbunpack(&mb, b->data, ms->dsize) < 0)
1545 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
1546 if(n <= nn && mb.nindex < mb.maxindex)
1552 /* add block to meta file */
1554 b = vtfileblock(ms, bo, VtORDWR);
1557 vtfilesetsize(ms, (nb+1)*ms->dsize);
1558 mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
1561 p = mballoc(&mb, n);
1563 /* mbAlloc might have changed block */
1570 mbsearch(&mb, dir->elem, &i, &me);
1571 assert(me.p == nil);
1575 mbinsert(&mb, i, &me);
1578 #ifdef notdef /* XXX */
1579 /* meta block depends on super block for qid ... */
1580 bb = cacheLocal(b->c, PartSuper, 0, VtOREAD);
1581 blockDependency(b, bb, -1, nil, nil);
1584 /* ... and one or two dir entries */
1585 epb = s->dsize/VtEntrySize;
1586 bb = vtfileblock(s, dir->entry/epb, VtOREAD);
1587 blockDependency(b, bb, -1, nil, nil);
1589 if(dir->mode & ModeDir){
1590 bb = sourceBlock(s, dir->mentry/epb, VtOREAD);
1591 blockDependency(b, bb, -1, nil, nil);
1605 chksource(VacFile *f)
1610 if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){
1618 filerlock(VacFile *f)
1620 // assert(!canwlock(&f->fs->elk));
1622 if(chksource(f) < 0){
1630 filerunlock(VacFile *f)
1636 filelock(VacFile *f)
1638 // assert(!canwlock(&f->fs->elk));
1640 if(chksource(f) < 0){
1648 fileunlock(VacFile *f)
1654 * f->source and f->msource must NOT be locked.
1655 * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2).
1656 * We have to respect that ordering.
1659 filemetalock(VacFile *f)
1661 assert(f->up != nil);
1662 // assert(!canwlock(&f->fs->elk));
1667 filemetaunlock(VacFile *f)
1669 wunlock(&f->up->lk);
1673 * f->source and f->msource must NOT be locked.
1677 fileraccess(VacFile* f)
1679 if(f->mode == VtOREAD)
1683 f->dir.atime = time(0L);
1689 * f->source and f->msource must NOT be locked.
1693 filewaccess(VacFile* f, char *mid)
1695 if(f->mode == VtOREAD)
1699 f->dir.atime = f->dir.mtime = time(0L);
1700 if(strcmp(f->dir.mid, mid) != 0){
1702 f->dir.mid = vtstrdup(mid);
1708 /*RSC: let's try this */
1709 /*presotto - lets not
1711 filewaccess(f->up, mid);
1717 markCopied(Block *b)
1722 if(globalToLocal(b->score) == NilBlock)
1725 if(!(b->l.state & BsCopied)){
1727 * We need to record that there are now pointers in
1728 * b that are not unique to b. We do this by marking
1729 * b as copied. Since we don't return the label block,
1730 * the caller can't get the dependencies right. So we have
1731 * to flush the block ourselves. This is a rare occurrence.
1734 l.state |= BsCopied;
1735 lb = _blockSetLabel(b, &l);
1737 while(!blockWrite(lb)){
1738 fprint(2, "getEntry: could not write label block\n");
1741 while(lb->iostate != BioClean && lb->iostate != BioDirty){
1742 assert(lb->iostate == BioWriting);
1743 vtSleep(lb->ioready);
1745 if(lb->iostate == BioDirty)
1752 getEntry(VtFile *r, Entry *e, int mark)
1757 memset(&e, 0, sizeof e);
1761 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtOREAD);
1764 if(!entryUnpack(e, b->data, r->offset % r->epb)){
1776 setEntry(Source *r, Entry *e)
1781 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, VtORDWR);
1782 if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);
1785 if(!entryUnpack(&oe, b->data, r->offset % r->epb)){
1790 entryPack(e, b->data, r->offset % r->epb);
1792 /* BUG b should depend on the entry pointer */
1800 /* assumes hold elk */
1802 fileSnapshot(VacFile *dst, VacFile *src, u32int epoch, int doarchive)
1806 /* add link to snapshot */
1807 if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))
1811 e.archive = doarchive;
1813 ee.archive = doarchive;
1815 if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))
1821 fileGetSources(VacFile *f, Entry *e, Entry *ee, int mark)
1823 if(!getEntry(f->source, e, mark)
1824 || !getEntry(f->msource, ee, mark))
1830 fileWalkSources(VacFile *f)
1832 if(f->mode == VtOREAD)
1834 if(!sourceLock2(f->source, f->msource, VtORDWR))
1836 vtfileunlock(f->source);
1837 vtfileunlock(f->msource);