19a747e4fSDavid du Colombier #include "stdinc.h"
29a747e4fSDavid du Colombier #include "vac.h"
39a747e4fSDavid du Colombier #include "dat.h"
49a747e4fSDavid du Colombier #include "fns.h"
59a747e4fSDavid du Colombier #include "error.h"
69a747e4fSDavid du Colombier
73be74836SDavid du Colombier #define debug 0
83be74836SDavid du Colombier
9d9306527SDavid du Colombier /*
103be74836SDavid du Colombier * Vac file system. This is a simplified version of the same code in Fossil.
113be74836SDavid du Colombier *
123be74836SDavid du Colombier * The locking order in the tree is upward: a thread can hold the lock
133be74836SDavid du Colombier * for a VacFile and then acquire the lock of f->up (the parent),
143be74836SDavid du Colombier * but not vice-versa.
153be74836SDavid du Colombier *
163be74836SDavid du Colombier * A vac file is one or two venti files. Plain data files are one venti file,
173be74836SDavid du Colombier * while directores are two: a venti data file containing traditional
183be74836SDavid du Colombier * directory entries, and a venti directory file containing venti
193be74836SDavid du Colombier * directory entries. The traditional directory entries in the data file
203be74836SDavid du Colombier * contain integers indexing into the venti directory entry file.
213be74836SDavid du Colombier * It's a little complicated, but it makes the data usable by standard
223be74836SDavid du Colombier * tools like venti/copy.
233be74836SDavid du Colombier *
24d9306527SDavid du Colombier */
25d9306527SDavid du Colombier
263be74836SDavid du Colombier static int filemetaflush(VacFile*, char*);
273be74836SDavid du Colombier
283be74836SDavid du Colombier struct VacFile
293be74836SDavid du Colombier {
303be74836SDavid du Colombier VacFs *fs; /* immutable */
313be74836SDavid du Colombier
32d9306527SDavid du Colombier /* meta data for file: protected by the lk in the parent */
33d9306527SDavid du Colombier int ref; /* holds this data structure up */
34d9306527SDavid du Colombier
353be74836SDavid du Colombier int partial; /* file was never really open */
36d9306527SDavid du Colombier int removed; /* file has been removed */
37d9306527SDavid du Colombier int dirty; /* dir is dirty with respect to meta data in block */
383be74836SDavid du Colombier u32int boff; /* block offset within msource for this file's metadata */
39d9306527SDavid du Colombier VacDir dir; /* metadata for this file */
40d9306527SDavid du Colombier VacFile *up; /* parent file */
41d9306527SDavid du Colombier VacFile *next; /* sibling */
42d9306527SDavid du Colombier
433be74836SDavid du Colombier RWLock lk; /* lock for the following */
443be74836SDavid du Colombier VtFile *source; /* actual data */
453be74836SDavid du Colombier VtFile *msource; /* metadata for children in a directory */
46d9306527SDavid du Colombier VacFile *down; /* children */
473be74836SDavid du Colombier int mode;
483be74836SDavid du Colombier
493be74836SDavid du Colombier uvlong qidoffset; /* qid offset */
50d9306527SDavid du Colombier };
51d9306527SDavid du Colombier
529a747e4fSDavid du Colombier static VacFile*
filealloc(VacFs * fs)533be74836SDavid du Colombier filealloc(VacFs *fs)
549a747e4fSDavid du Colombier {
553be74836SDavid du Colombier VacFile *f;
569a747e4fSDavid du Colombier
573be74836SDavid du Colombier f = vtmallocz(sizeof(VacFile));
583be74836SDavid du Colombier f->ref = 1;
593be74836SDavid du Colombier f->fs = fs;
603be74836SDavid du Colombier f->boff = NilBlock;
613be74836SDavid du Colombier f->mode = fs->mode;
623be74836SDavid du Colombier return f;
633be74836SDavid du Colombier }
643be74836SDavid du Colombier
653be74836SDavid du Colombier static void
filefree(VacFile * f)663be74836SDavid du Colombier filefree(VacFile *f)
673be74836SDavid du Colombier {
683be74836SDavid du Colombier vtfileclose(f->source);
693be74836SDavid du Colombier vtfileclose(f->msource);
703be74836SDavid du Colombier vdcleanup(&f->dir);
713be74836SDavid du Colombier memset(f, ~0, sizeof *f); /* paranoia */
723be74836SDavid du Colombier vtfree(f);
733be74836SDavid du Colombier }
743be74836SDavid du Colombier
753be74836SDavid du Colombier static int
chksource(VacFile * f)763be74836SDavid du Colombier chksource(VacFile *f)
773be74836SDavid du Colombier {
783be74836SDavid du Colombier if(f->partial)
793be74836SDavid du Colombier return 0;
803be74836SDavid du Colombier
813be74836SDavid du Colombier if(f->source == nil
823be74836SDavid du Colombier || ((f->dir.mode & ModeDir) && f->msource == nil)){
833be74836SDavid du Colombier werrstr(ERemoved);
843be74836SDavid du Colombier return -1;
853be74836SDavid du Colombier }
863be74836SDavid du Colombier return 0;
873be74836SDavid du Colombier }
883be74836SDavid du Colombier
893be74836SDavid du Colombier static int
filelock(VacFile * f)903be74836SDavid du Colombier filelock(VacFile *f)
913be74836SDavid du Colombier {
923be74836SDavid du Colombier wlock(&f->lk);
933be74836SDavid du Colombier if(chksource(f) < 0){
943be74836SDavid du Colombier wunlock(&f->lk);
953be74836SDavid du Colombier return -1;
963be74836SDavid du Colombier }
973be74836SDavid du Colombier return 0;
983be74836SDavid du Colombier }
993be74836SDavid du Colombier
1003be74836SDavid du Colombier static void
fileunlock(VacFile * f)1013be74836SDavid du Colombier fileunlock(VacFile *f)
1023be74836SDavid du Colombier {
1033be74836SDavid du Colombier wunlock(&f->lk);
1043be74836SDavid du Colombier }
1053be74836SDavid du Colombier
1063be74836SDavid du Colombier static int
filerlock(VacFile * f)1073be74836SDavid du Colombier filerlock(VacFile *f)
1083be74836SDavid du Colombier {
1093be74836SDavid du Colombier rlock(&f->lk);
1103be74836SDavid du Colombier if(chksource(f) < 0){
1113be74836SDavid du Colombier runlock(&f->lk);
1123be74836SDavid du Colombier return -1;
1133be74836SDavid du Colombier }
1143be74836SDavid du Colombier return 0;
1153be74836SDavid du Colombier }
1163be74836SDavid du Colombier
1173be74836SDavid du Colombier static void
filerunlock(VacFile * f)1183be74836SDavid du Colombier filerunlock(VacFile *f)
1193be74836SDavid du Colombier {
1203be74836SDavid du Colombier runlock(&f->lk);
1213be74836SDavid du Colombier }
1223be74836SDavid du Colombier
1233be74836SDavid du Colombier /*
1243be74836SDavid du Colombier * The file metadata, like f->dir and f->ref,
1253be74836SDavid du Colombier * are synchronized via the parent's lock.
1263be74836SDavid du Colombier * This is why locking order goes up.
1273be74836SDavid du Colombier */
1283be74836SDavid du Colombier static void
filemetalock(VacFile * f)1293be74836SDavid du Colombier filemetalock(VacFile *f)
1303be74836SDavid du Colombier {
1313be74836SDavid du Colombier assert(f->up != nil);
1323be74836SDavid du Colombier wlock(&f->up->lk);
1333be74836SDavid du Colombier }
1343be74836SDavid du Colombier
1353be74836SDavid du Colombier static void
filemetaunlock(VacFile * f)1363be74836SDavid du Colombier filemetaunlock(VacFile *f)
1373be74836SDavid du Colombier {
1383be74836SDavid du Colombier wunlock(&f->up->lk);
1393be74836SDavid du Colombier }
1403be74836SDavid du Colombier
1413be74836SDavid du Colombier uvlong
vacfilegetid(VacFile * f)1423be74836SDavid du Colombier vacfilegetid(VacFile *f)
1433be74836SDavid du Colombier {
1443be74836SDavid du Colombier /* immutable */
1453be74836SDavid du Colombier return f->qidoffset + f->dir.qid;
1463be74836SDavid du Colombier }
1473be74836SDavid du Colombier
1483be74836SDavid du Colombier uvlong
vacfilegetqidoffset(VacFile * f)1493be74836SDavid du Colombier vacfilegetqidoffset(VacFile *f)
1503be74836SDavid du Colombier {
1513be74836SDavid du Colombier return f->qidoffset;
1523be74836SDavid du Colombier }
1533be74836SDavid du Colombier
1543be74836SDavid du Colombier ulong
vacfilegetmcount(VacFile * f)1553be74836SDavid du Colombier vacfilegetmcount(VacFile *f)
1563be74836SDavid du Colombier {
1573be74836SDavid du Colombier ulong mcount;
1583be74836SDavid du Colombier
1593be74836SDavid du Colombier filemetalock(f);
1603be74836SDavid du Colombier mcount = f->dir.mcount;
1613be74836SDavid du Colombier filemetaunlock(f);
1623be74836SDavid du Colombier return mcount;
1633be74836SDavid du Colombier }
1643be74836SDavid du Colombier
1653be74836SDavid du Colombier ulong
vacfilegetmode(VacFile * f)1663be74836SDavid du Colombier vacfilegetmode(VacFile *f)
1673be74836SDavid du Colombier {
1683be74836SDavid du Colombier ulong mode;
1693be74836SDavid du Colombier
1703be74836SDavid du Colombier filemetalock(f);
1713be74836SDavid du Colombier mode = f->dir.mode;
1723be74836SDavid du Colombier filemetaunlock(f);
1733be74836SDavid du Colombier return mode;
1743be74836SDavid du Colombier }
1753be74836SDavid du Colombier
1763be74836SDavid du Colombier int
vacfileisdir(VacFile * f)1773be74836SDavid du Colombier vacfileisdir(VacFile *f)
1783be74836SDavid du Colombier {
1793be74836SDavid du Colombier /* immutable */
1803be74836SDavid du Colombier return (f->dir.mode & ModeDir) != 0;
1813be74836SDavid du Colombier }
1823be74836SDavid du Colombier
1833be74836SDavid du Colombier int
vacfileisroot(VacFile * f)1843be74836SDavid du Colombier vacfileisroot(VacFile *f)
1853be74836SDavid du Colombier {
1863be74836SDavid du Colombier return f == f->fs->root;
1873be74836SDavid du Colombier }
1883be74836SDavid du Colombier
1893be74836SDavid du Colombier /*
1903be74836SDavid du Colombier * The files are reference counted, and while the reference
1913be74836SDavid du Colombier * is bigger than zero, each file can be found in its parent's
1923be74836SDavid du Colombier * f->down list (chains via f->next), so that multiple threads
1933be74836SDavid du Colombier * end up sharing a VacFile* when referring to the same file.
1943be74836SDavid du Colombier *
1953be74836SDavid du Colombier * Each VacFile holds a reference to its parent.
1963be74836SDavid du Colombier */
1973be74836SDavid du Colombier VacFile*
vacfileincref(VacFile * vf)1983be74836SDavid du Colombier vacfileincref(VacFile *vf)
1993be74836SDavid du Colombier {
2003be74836SDavid du Colombier filemetalock(vf);
2013be74836SDavid du Colombier assert(vf->ref > 0);
2023be74836SDavid du Colombier vf->ref++;
2033be74836SDavid du Colombier filemetaunlock(vf);
2049a747e4fSDavid du Colombier return vf;
2059a747e4fSDavid du Colombier }
2069a747e4fSDavid du Colombier
2073be74836SDavid du Colombier int
vacfiledecref(VacFile * f)2083be74836SDavid du Colombier vacfiledecref(VacFile *f)
209d9306527SDavid du Colombier {
2103be74836SDavid du Colombier VacFile *p, *q, **qq;
211d9306527SDavid du Colombier
2123be74836SDavid du Colombier if(f->up == nil){
2133be74836SDavid du Colombier /* never linked in */
2143be74836SDavid du Colombier assert(f->ref == 1);
2153be74836SDavid du Colombier filefree(f);
2163be74836SDavid du Colombier return 0;
217d9306527SDavid du Colombier }
218d9306527SDavid du Colombier
2193be74836SDavid du Colombier filemetalock(f);
2203be74836SDavid du Colombier f->ref--;
2213be74836SDavid du Colombier if(f->ref > 0){
2223be74836SDavid du Colombier filemetaunlock(f);
2233be74836SDavid du Colombier return -1;
224e538c934SDavid du Colombier }
2253be74836SDavid du Colombier assert(f->ref == 0);
2263be74836SDavid du Colombier assert(f->down == nil);
2273be74836SDavid du Colombier
2283be74836SDavid du Colombier if(f->source && vtfilelock(f->source, -1) >= 0){
2293be74836SDavid du Colombier vtfileflush(f->source);
2303be74836SDavid du Colombier vtfileunlock(f->source);
2313be74836SDavid du Colombier }
2323be74836SDavid du Colombier if(f->msource && vtfilelock(f->msource, -1) >= 0){
2333be74836SDavid du Colombier vtfileflush(f->msource);
2343be74836SDavid du Colombier vtfileunlock(f->msource);
235d9306527SDavid du Colombier }
236d9306527SDavid du Colombier
2373be74836SDavid du Colombier /*
2383be74836SDavid du Colombier * Flush f's directory information to the cache.
2393be74836SDavid du Colombier */
2403be74836SDavid du Colombier filemetaflush(f, nil);
2413be74836SDavid du Colombier
2423be74836SDavid du Colombier p = f->up;
2433be74836SDavid du Colombier qq = &p->down;
2443be74836SDavid du Colombier for(q = *qq; q; q = *qq){
2453be74836SDavid du Colombier if(q == f)
2463be74836SDavid du Colombier break;
2473be74836SDavid du Colombier qq = &q->next;
248d9306527SDavid du Colombier }
2493be74836SDavid du Colombier assert(q != nil);
2503be74836SDavid du Colombier *qq = f->next;
2513be74836SDavid du Colombier
2523be74836SDavid du Colombier filemetaunlock(f);
2533be74836SDavid du Colombier filefree(f);
2543be74836SDavid du Colombier vacfiledecref(p);
2553be74836SDavid du Colombier return 0;
256d9306527SDavid du Colombier }
2579a747e4fSDavid du Colombier
258aedc1c01SDavid du Colombier
2593be74836SDavid du Colombier /*
2603be74836SDavid du Colombier * Construct a vacfile for the root of a vac tree, given the
2613be74836SDavid du Colombier * venti file for the root information. That venti file is a
2623be74836SDavid du Colombier * directory file containing VtEntries for three more venti files:
2633be74836SDavid du Colombier * the two venti files making up the root directory, and a
2643be74836SDavid du Colombier * third venti file that would be the metadata half of the
2653be74836SDavid du Colombier * "root's parent".
2663be74836SDavid du Colombier *
2673be74836SDavid du Colombier * Fossil generates slightly different vac files, due to a now
2683be74836SDavid du Colombier * impossible-to-change bug, which contain a VtEntry
2693be74836SDavid du Colombier * for just one venti file, that itself contains the expected
2703be74836SDavid du Colombier * three directory entries. Sigh.
2713be74836SDavid du Colombier */
2729a747e4fSDavid du Colombier VacFile*
_vacfileroot(VacFs * fs,VtFile * r)2733be74836SDavid du Colombier _vacfileroot(VacFs *fs, VtFile *r)
2749a747e4fSDavid du Colombier {
2753be74836SDavid du Colombier int redirected;
2763be74836SDavid du Colombier char err[ERRMAX];
2773be74836SDavid du Colombier VtBlock *b;
2783be74836SDavid du Colombier VtFile *r0, *r1, *r2;
2799a747e4fSDavid du Colombier MetaBlock mb;
280d9306527SDavid du Colombier MetaEntry me;
281d9306527SDavid du Colombier VacFile *root, *mr;
2829a747e4fSDavid du Colombier
2833be74836SDavid du Colombier redirected = 0;
2843be74836SDavid du Colombier Top:
2853be74836SDavid du Colombier b = nil;
286d9306527SDavid du Colombier root = nil;
287d9306527SDavid du Colombier mr = nil;
2889a747e4fSDavid du Colombier r1 = nil;
2899a747e4fSDavid du Colombier r2 = nil;
2909a747e4fSDavid du Colombier
2913be74836SDavid du Colombier if(vtfilelock(r, -1) < 0)
2923be74836SDavid du Colombier return nil;
2933be74836SDavid du Colombier r0 = vtfileopen(r, 0, fs->mode);
2943be74836SDavid du Colombier if(debug)
2953be74836SDavid du Colombier fprint(2, "r0 %p\n", r0);
2969a747e4fSDavid du Colombier if(r0 == nil)
2979a747e4fSDavid du Colombier goto Err;
2983be74836SDavid du Colombier r2 = vtfileopen(r, 2, fs->mode);
2993be74836SDavid du Colombier if(debug)
3003be74836SDavid du Colombier fprint(2, "r2 %p\n", r2);
3013be74836SDavid du Colombier if(r2 == nil){
3023be74836SDavid du Colombier /*
3033be74836SDavid du Colombier * some vac files (e.g., from fossil)
3043be74836SDavid du Colombier * have an extra layer of indirection.
3053be74836SDavid du Colombier */
3063be74836SDavid du Colombier rerrstr(err, sizeof err);
3073be74836SDavid du Colombier if(!redirected && strstr(err, "not active")){
3083be74836SDavid du Colombier redirected = 1;
3093be74836SDavid du Colombier vtfileunlock(r);
3103be74836SDavid du Colombier r = r0;
3113be74836SDavid du Colombier goto Top;
3123be74836SDavid du Colombier }
31349223a73SDavid du Colombier goto Err;
31449223a73SDavid du Colombier }
3153be74836SDavid du Colombier r1 = vtfileopen(r, 1, fs->mode);
3163be74836SDavid du Colombier if(debug)
3173be74836SDavid du Colombier fprint(2, "r1 %p\n", r1);
3183be74836SDavid du Colombier if(r1 == nil)
31949223a73SDavid du Colombier goto Err;
3209a747e4fSDavid du Colombier
3213be74836SDavid du Colombier mr = filealloc(fs);
322d9306527SDavid du Colombier mr->msource = r2;
323d9306527SDavid du Colombier r2 = nil;
324d9306527SDavid du Colombier
3253be74836SDavid du Colombier root = filealloc(fs);
3263be74836SDavid du Colombier root->boff = 0;
327d9306527SDavid du Colombier root->up = mr;
328d9306527SDavid du Colombier root->source = r0;
329d9306527SDavid du Colombier r0 = nil;
330d9306527SDavid du Colombier root->msource = r1;
331d9306527SDavid du Colombier r1 = nil;
332d9306527SDavid du Colombier
333d9306527SDavid du Colombier mr->down = root;
3343be74836SDavid du Colombier vtfileunlock(r);
335d9306527SDavid du Colombier
3363be74836SDavid du Colombier if(vtfilelock(mr->msource, VtOREAD) < 0)
3373be74836SDavid du Colombier goto Err1;
3383be74836SDavid du Colombier b = vtfileblock(mr->msource, 0, VtOREAD);
3393be74836SDavid du Colombier vtfileunlock(mr->msource);
3403be74836SDavid du Colombier if(b == nil)
3413be74836SDavid du Colombier goto Err1;
3429a747e4fSDavid du Colombier
3433be74836SDavid du Colombier if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
3443be74836SDavid du Colombier goto Err1;
345e5fc48fbSDavid du Colombier
3463be74836SDavid du Colombier meunpack(&me, &mb, 0);
3473be74836SDavid du Colombier if(vdunpack(&root->dir, &me) < 0)
3483be74836SDavid du Colombier goto Err1;
3493be74836SDavid du Colombier vtblockput(b);
3509a747e4fSDavid du Colombier
3519a747e4fSDavid du Colombier return root;
3529a747e4fSDavid du Colombier Err:
3533be74836SDavid du Colombier vtfileunlock(r);
3543be74836SDavid du Colombier Err1:
3553be74836SDavid du Colombier vtblockput(b);
3569a747e4fSDavid du Colombier if(r0)
3573be74836SDavid du Colombier vtfileclose(r0);
3589a747e4fSDavid du Colombier if(r1)
3593be74836SDavid du Colombier vtfileclose(r1);
3609a747e4fSDavid du Colombier if(r2)
3613be74836SDavid du Colombier vtfileclose(r2);
362d9306527SDavid du Colombier if(mr)
3633be74836SDavid du Colombier filefree(mr);
3649a747e4fSDavid du Colombier if(root)
3653be74836SDavid du Colombier filefree(root);
3669a747e4fSDavid du Colombier
3679a747e4fSDavid du Colombier return nil;
3689a747e4fSDavid du Colombier }
3699a747e4fSDavid du Colombier
3703be74836SDavid du Colombier /*
3713be74836SDavid du Colombier * Vac directories are a sequence of metablocks, each of which
3723be74836SDavid du Colombier * contains a bunch of metaentries sorted by file name.
3733be74836SDavid du Colombier * The whole sequence isn't sorted, though, so you still have
3743be74836SDavid du Colombier * to look at every block to find a given name.
3753be74836SDavid du Colombier * Dirlookup looks in f for an element name elem.
3763be74836SDavid du Colombier * It returns a new VacFile with the dir, boff, and mode
3773be74836SDavid du Colombier * filled in, but the sources (venti files) are not, and f is
3783be74836SDavid du Colombier * not yet linked into the tree. These details must be taken
3793be74836SDavid du Colombier * care of by the caller.
3803be74836SDavid du Colombier *
3813be74836SDavid du Colombier * f must be locked, f->msource must not.
3823be74836SDavid du Colombier */
3833be74836SDavid du Colombier static VacFile*
dirlookup(VacFile * f,char * elem)3843be74836SDavid du Colombier dirlookup(VacFile *f, char *elem)
3853be74836SDavid du Colombier {
3863be74836SDavid du Colombier int i;
3873be74836SDavid du Colombier MetaBlock mb;
3883be74836SDavid du Colombier MetaEntry me;
3893be74836SDavid du Colombier VtBlock *b;
3903be74836SDavid du Colombier VtFile *meta;
3913be74836SDavid du Colombier VacFile *ff;
3923be74836SDavid du Colombier u32int bo, nb;
3933be74836SDavid du Colombier
3943be74836SDavid du Colombier meta = f->msource;
3953be74836SDavid du Colombier b = nil;
3963be74836SDavid du Colombier if(vtfilelock(meta, -1) < 0)
3973be74836SDavid du Colombier return nil;
3983be74836SDavid du Colombier nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
3993be74836SDavid du Colombier for(bo=0; bo<nb; bo++){
4003be74836SDavid du Colombier b = vtfileblock(meta, bo, VtOREAD);
4013be74836SDavid du Colombier if(b == nil)
4023be74836SDavid du Colombier goto Err;
4033be74836SDavid du Colombier if(mbunpack(&mb, b->data, meta->dsize) < 0)
4043be74836SDavid du Colombier goto Err;
4053be74836SDavid du Colombier if(mbsearch(&mb, elem, &i, &me) >= 0){
4063be74836SDavid du Colombier ff = filealloc(f->fs);
4073be74836SDavid du Colombier if(vdunpack(&ff->dir, &me) < 0){
4083be74836SDavid du Colombier filefree(ff);
4093be74836SDavid du Colombier goto Err;
4103be74836SDavid du Colombier }
4113be74836SDavid du Colombier ff->qidoffset = f->qidoffset + ff->dir.qidoffset;
4123be74836SDavid du Colombier vtfileunlock(meta);
4133be74836SDavid du Colombier vtblockput(b);
4143be74836SDavid du Colombier ff->boff = bo;
4153be74836SDavid du Colombier ff->mode = f->mode;
4163be74836SDavid du Colombier return ff;
4173be74836SDavid du Colombier }
4183be74836SDavid du Colombier vtblockput(b);
4193be74836SDavid du Colombier b = nil;
4203be74836SDavid du Colombier }
4213be74836SDavid du Colombier werrstr(ENoFile);
4223be74836SDavid du Colombier /* fall through */
4233be74836SDavid du Colombier Err:
4243be74836SDavid du Colombier vtfileunlock(meta);
4253be74836SDavid du Colombier vtblockput(b);
4263be74836SDavid du Colombier return nil;
4273be74836SDavid du Colombier }
4283be74836SDavid du Colombier
4293be74836SDavid du Colombier /*
4303be74836SDavid du Colombier * Open the venti file at offset in the directory f->source.
4313be74836SDavid du Colombier * f is locked.
4323be74836SDavid du Colombier */
4333be74836SDavid du Colombier static VtFile *
fileopensource(VacFile * f,u32int offset,u32int gen,int dir,uint mode)4343be74836SDavid du Colombier fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
4353be74836SDavid du Colombier {
4363be74836SDavid du Colombier VtFile *r;
4373be74836SDavid du Colombier
4383be74836SDavid du Colombier if((r = vtfileopen(f->source, offset, mode)) == nil)
4393be74836SDavid du Colombier return nil;
4403be74836SDavid du Colombier if(r == nil)
4413be74836SDavid du Colombier return nil;
4423be74836SDavid du Colombier if(r->gen != gen){
4433be74836SDavid du Colombier werrstr(ERemoved);
4443be74836SDavid du Colombier vtfileclose(r);
4453be74836SDavid du Colombier return nil;
4463be74836SDavid du Colombier }
4473be74836SDavid du Colombier if(r->dir != dir && r->mode != -1){
4483be74836SDavid du Colombier werrstr(EBadMeta);
4493be74836SDavid du Colombier vtfileclose(r);
4503be74836SDavid du Colombier return nil;
4513be74836SDavid du Colombier }
4523be74836SDavid du Colombier return r;
4533be74836SDavid du Colombier }
4543be74836SDavid du Colombier
4559a747e4fSDavid du Colombier VacFile*
vacfilegetparent(VacFile * f)4563be74836SDavid du Colombier vacfilegetparent(VacFile *f)
4579a747e4fSDavid du Colombier {
4583be74836SDavid du Colombier if(vacfileisroot(f))
4593be74836SDavid du Colombier return vacfileincref(f);
4603be74836SDavid du Colombier return vacfileincref(f->up);
4613be74836SDavid du Colombier }
4629a747e4fSDavid du Colombier
4633be74836SDavid du Colombier /*
4643be74836SDavid du Colombier * Given an unlocked vacfile (directory) f,
4653be74836SDavid du Colombier * return the vacfile named elem in f.
4663be74836SDavid du Colombier * Interprets . and .. as a convenience to callers.
4673be74836SDavid du Colombier */
4683be74836SDavid du Colombier VacFile*
vacfilewalk(VacFile * f,char * elem)4693be74836SDavid du Colombier vacfilewalk(VacFile *f, char *elem)
4703be74836SDavid du Colombier {
4713be74836SDavid du Colombier VacFile *ff;
472d9306527SDavid du Colombier
4739a747e4fSDavid du Colombier if(elem[0] == 0){
4743be74836SDavid du Colombier werrstr(EBadPath);
475d9306527SDavid du Colombier return nil;
4769a747e4fSDavid du Colombier }
4779a747e4fSDavid du Colombier
4783be74836SDavid du Colombier if(!vacfileisdir(f)){
4793be74836SDavid du Colombier werrstr(ENotDir);
4803be74836SDavid du Colombier return nil;
4819a747e4fSDavid du Colombier }
4829a747e4fSDavid du Colombier
4833be74836SDavid du Colombier if(strcmp(elem, ".") == 0)
4843be74836SDavid du Colombier return vacfileincref(f);
4859a747e4fSDavid du Colombier
4863be74836SDavid du Colombier if(strcmp(elem, "..") == 0)
4873be74836SDavid du Colombier return vacfilegetparent(f);
4883be74836SDavid du Colombier
4893be74836SDavid du Colombier if(filelock(f) < 0)
490d9306527SDavid du Colombier return nil;
491d9306527SDavid du Colombier
4923be74836SDavid du Colombier for(ff = f->down; ff; ff=ff->next){
4933be74836SDavid du Colombier if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
4943be74836SDavid du Colombier ff->ref++;
495d9306527SDavid du Colombier goto Exit;
4969a747e4fSDavid du Colombier }
4979a747e4fSDavid du Colombier }
4989a747e4fSDavid du Colombier
4993be74836SDavid du Colombier ff = dirlookup(f, elem);
5003be74836SDavid du Colombier if(ff == nil)
5019a747e4fSDavid du Colombier goto Err;
5023be74836SDavid du Colombier
5033be74836SDavid du Colombier if(ff->dir.mode & ModeSnapshot)
5043be74836SDavid du Colombier ff->mode = VtOREAD;
5053be74836SDavid du Colombier
5063be74836SDavid du Colombier if(vtfilelock(f->source, f->mode) < 0)
5079a747e4fSDavid du Colombier goto Err;
5083be74836SDavid du Colombier if(ff->dir.mode & ModeDir){
5093be74836SDavid du Colombier ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
5103be74836SDavid du Colombier ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
5113be74836SDavid du Colombier if(ff->source == nil || ff->msource == nil)
5123be74836SDavid du Colombier goto Err1;
5133be74836SDavid du Colombier }else{
5143be74836SDavid du Colombier ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
5153be74836SDavid du Colombier if(ff->source == nil)
5163be74836SDavid du Colombier goto Err1;
5179a747e4fSDavid du Colombier }
5183be74836SDavid du Colombier vtfileunlock(f->source);
519d9306527SDavid du Colombier
520d9306527SDavid du Colombier /* link in and up parent ref count */
5213be74836SDavid du Colombier ff->next = f->down;
5223be74836SDavid du Colombier f->down = ff;
5233be74836SDavid du Colombier ff->up = f;
5243be74836SDavid du Colombier vacfileincref(f);
525d9306527SDavid du Colombier Exit:
5263be74836SDavid du Colombier fileunlock(f);
5273be74836SDavid du Colombier return ff;
5283be74836SDavid du Colombier
5293be74836SDavid du Colombier Err1:
5303be74836SDavid du Colombier vtfileunlock(f->source);
5319a747e4fSDavid du Colombier Err:
5323be74836SDavid du Colombier fileunlock(f);
5333be74836SDavid du Colombier if(ff != nil)
5343be74836SDavid du Colombier vacfiledecref(ff);
5359a747e4fSDavid du Colombier return nil;
5369a747e4fSDavid du Colombier }
5379a747e4fSDavid du Colombier
5383be74836SDavid du Colombier /*
5393be74836SDavid du Colombier * Open a path in the vac file system:
5403be74836SDavid du Colombier * just walk each element one at a time.
5413be74836SDavid du Colombier */
5429a747e4fSDavid du Colombier VacFile*
vacfileopen(VacFs * fs,char * path)5433be74836SDavid du Colombier vacfileopen(VacFs *fs, char *path)
5449a747e4fSDavid du Colombier {
5453be74836SDavid du Colombier VacFile *f, *ff;
5463be74836SDavid du Colombier char *p, elem[VtMaxStringSize], *opath;
5479a747e4fSDavid du Colombier int n;
5489a747e4fSDavid du Colombier
5493be74836SDavid du Colombier f = fs->root;
5503be74836SDavid du Colombier vacfileincref(f);
5513be74836SDavid du Colombier opath = path;
5529a747e4fSDavid du Colombier while(*path != 0){
5539a747e4fSDavid du Colombier for(p = path; *p && *p != '/'; p++)
5549a747e4fSDavid du Colombier ;
5559a747e4fSDavid du Colombier n = p - path;
5569a747e4fSDavid du Colombier if(n > 0){
5579a747e4fSDavid du Colombier if(n > VtMaxStringSize){
5583be74836SDavid du Colombier werrstr("%s: element too long", EBadPath);
5599a747e4fSDavid du Colombier goto Err;
5609a747e4fSDavid du Colombier }
5619a747e4fSDavid du Colombier memmove(elem, path, n);
5629a747e4fSDavid du Colombier elem[n] = 0;
5633be74836SDavid du Colombier ff = vacfilewalk(f, elem);
5643be74836SDavid du Colombier if(ff == nil){
5653be74836SDavid du Colombier werrstr("%.*s: %r", utfnlen(opath, p-opath), opath);
5669a747e4fSDavid du Colombier goto Err;
5673be74836SDavid du Colombier }
5683be74836SDavid du Colombier vacfiledecref(f);
5693be74836SDavid du Colombier f = ff;
5709a747e4fSDavid du Colombier }
5719a747e4fSDavid du Colombier if(*p == '/')
5729a747e4fSDavid du Colombier p++;
5739a747e4fSDavid du Colombier path = p;
5749a747e4fSDavid du Colombier }
5753be74836SDavid du Colombier return f;
5769a747e4fSDavid du Colombier Err:
5773be74836SDavid du Colombier vacfiledecref(f);
5789a747e4fSDavid du Colombier return nil;
5799a747e4fSDavid du Colombier }
5809a747e4fSDavid du Colombier
5813be74836SDavid du Colombier /*
5823be74836SDavid du Colombier * Extract the score for the bn'th block in f.
5833be74836SDavid du Colombier */
5843be74836SDavid du Colombier int
vacfileblockscore(VacFile * f,u32int bn,u8int * score)5853be74836SDavid du Colombier vacfileblockscore(VacFile *f, u32int bn, u8int *score)
586e538c934SDavid du Colombier {
5873be74836SDavid du Colombier VtFile *s;
5883be74836SDavid du Colombier uvlong size;
5893be74836SDavid du Colombier int dsize, ret;
5903be74836SDavid du Colombier
5913be74836SDavid du Colombier ret = -1;
5923be74836SDavid du Colombier if(filerlock(f) < 0)
5933be74836SDavid du Colombier return -1;
5943be74836SDavid du Colombier if(vtfilelock(f->source, VtOREAD) < 0)
5953be74836SDavid du Colombier goto out;
5963be74836SDavid du Colombier
5973be74836SDavid du Colombier s = f->source;
5983be74836SDavid du Colombier dsize = s->dsize;
5993be74836SDavid du Colombier size = vtfilegetsize(s);
6003be74836SDavid du Colombier if((uvlong)bn*dsize >= size)
6013be74836SDavid du Colombier goto out1;
6023be74836SDavid du Colombier ret = vtfileblockscore(f->source, bn, score);
6033be74836SDavid du Colombier
6043be74836SDavid du Colombier out1:
6053be74836SDavid du Colombier vtfileunlock(f->source);
6063be74836SDavid du Colombier out:
6073be74836SDavid du Colombier filerunlock(f);
6083be74836SDavid du Colombier return ret;
6093be74836SDavid du Colombier }
6103be74836SDavid du Colombier
6113be74836SDavid du Colombier /*
6123be74836SDavid du Colombier * Read data from f.
6133be74836SDavid du Colombier */
6143be74836SDavid du Colombier int
vacfileread(VacFile * f,void * buf,int cnt,vlong offset)6153be74836SDavid du Colombier vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
6163be74836SDavid du Colombier {
6173be74836SDavid du Colombier int n;
6183be74836SDavid du Colombier
6193be74836SDavid du Colombier if(offset < 0){
6203be74836SDavid du Colombier werrstr(EBadOffset);
6213be74836SDavid du Colombier return -1;
6223be74836SDavid du Colombier }
6233be74836SDavid du Colombier if(filerlock(f) < 0)
6243be74836SDavid du Colombier return -1;
6253be74836SDavid du Colombier if(vtfilelock(f->source, VtOREAD) < 0){
6263be74836SDavid du Colombier filerunlock(f);
6273be74836SDavid du Colombier return -1;
6283be74836SDavid du Colombier }
6293be74836SDavid du Colombier n = vtfileread(f->source, buf, cnt, offset);
6303be74836SDavid du Colombier vtfileunlock(f->source);
6313be74836SDavid du Colombier filerunlock(f);
6323be74836SDavid du Colombier return n;
6333be74836SDavid du Colombier }
6343be74836SDavid du Colombier
6353be74836SDavid du Colombier static int
getentry(VtFile * f,VtEntry * e)6363be74836SDavid du Colombier getentry(VtFile *f, VtEntry *e)
6373be74836SDavid du Colombier {
6383be74836SDavid du Colombier if(vtfilelock(f, VtOREAD) < 0)
6393be74836SDavid du Colombier return -1;
6403be74836SDavid du Colombier if(vtfilegetentry(f, e) < 0){
6413be74836SDavid du Colombier vtfileunlock(f);
6423be74836SDavid du Colombier return -1;
6433be74836SDavid du Colombier }
6443be74836SDavid du Colombier vtfileunlock(f);
6453be74836SDavid du Colombier if(vtglobaltolocal(e->score) != NilBlock){
6463be74836SDavid du Colombier werrstr("internal error - data not on venti");
6473be74836SDavid du Colombier return -1;
6483be74836SDavid du Colombier }
6493be74836SDavid du Colombier return 0;
6503be74836SDavid du Colombier }
6513be74836SDavid du Colombier
6523be74836SDavid du Colombier /*
6533be74836SDavid du Colombier * Get the VtEntries for the data contained in f.
6543be74836SDavid du Colombier */
6553be74836SDavid du Colombier int
vacfilegetentries(VacFile * f,VtEntry * e,VtEntry * me)6563be74836SDavid du Colombier vacfilegetentries(VacFile *f, VtEntry *e, VtEntry *me)
6573be74836SDavid du Colombier {
6583be74836SDavid du Colombier if(filerlock(f) < 0)
6593be74836SDavid du Colombier return -1;
6603be74836SDavid du Colombier if(e && getentry(f->source, e) < 0){
6613be74836SDavid du Colombier filerunlock(f);
6623be74836SDavid du Colombier return -1;
6633be74836SDavid du Colombier }
6643be74836SDavid du Colombier if(me){
6653be74836SDavid du Colombier if(f->msource == nil)
6663be74836SDavid du Colombier memset(me, 0, sizeof *me);
6673be74836SDavid du Colombier else if(getentry(f->msource, me) < 0){
6683be74836SDavid du Colombier filerunlock(f);
6693be74836SDavid du Colombier return -1;
6703be74836SDavid du Colombier }
6713be74836SDavid du Colombier }
6723be74836SDavid du Colombier filerunlock(f);
6733be74836SDavid du Colombier return 0;
6743be74836SDavid du Colombier }
6753be74836SDavid du Colombier
6763be74836SDavid du Colombier /*
6773be74836SDavid du Colombier * Get the file's size.
6783be74836SDavid du Colombier */
6793be74836SDavid du Colombier int
vacfilegetsize(VacFile * f,uvlong * size)6803be74836SDavid du Colombier vacfilegetsize(VacFile *f, uvlong *size)
6813be74836SDavid du Colombier {
6823be74836SDavid du Colombier if(filerlock(f) < 0)
6833be74836SDavid du Colombier return -1;
6843be74836SDavid du Colombier if(vtfilelock(f->source, VtOREAD) < 0){
6853be74836SDavid du Colombier filerunlock(f);
6863be74836SDavid du Colombier return -1;
6873be74836SDavid du Colombier }
6883be74836SDavid du Colombier *size = vtfilegetsize(f->source);
6893be74836SDavid du Colombier vtfileunlock(f->source);
6903be74836SDavid du Colombier filerunlock(f);
6913be74836SDavid du Colombier
6923be74836SDavid du Colombier return 0;
6933be74836SDavid du Colombier }
6943be74836SDavid du Colombier
6953be74836SDavid du Colombier /*
6963be74836SDavid du Colombier * Directory reading.
6973be74836SDavid du Colombier *
6983be74836SDavid du Colombier * A VacDirEnum is a buffer containing directory entries.
6993be74836SDavid du Colombier * Directory entries contain malloced strings and need to
7003be74836SDavid du Colombier * be cleaned up with vdcleanup. The invariant in the
7013be74836SDavid du Colombier * VacDirEnum is that the directory entries between
7023be74836SDavid du Colombier * vde->i and vde->n are owned by the vde and need to
7033be74836SDavid du Colombier * be cleaned up if it is closed. Those from 0 up to vde->i
7043be74836SDavid du Colombier * have been handed to the reader, and the reader must
7053be74836SDavid du Colombier * take care of calling vdcleanup as appropriate.
7063be74836SDavid du Colombier */
7073be74836SDavid du Colombier VacDirEnum*
vdeopen(VacFile * f)7083be74836SDavid du Colombier vdeopen(VacFile *f)
7093be74836SDavid du Colombier {
7103be74836SDavid du Colombier VacDirEnum *vde;
7113be74836SDavid du Colombier VacFile *p;
7123be74836SDavid du Colombier
7133be74836SDavid du Colombier if(!vacfileisdir(f)){
7143be74836SDavid du Colombier werrstr(ENotDir);
7153be74836SDavid du Colombier return nil;
7163be74836SDavid du Colombier }
7173be74836SDavid du Colombier
7183be74836SDavid du Colombier /*
7193be74836SDavid du Colombier * There might be changes to this directory's children
7203be74836SDavid du Colombier * that have not been flushed out into the cache yet.
7213be74836SDavid du Colombier * Those changes are only available if we look at the
7223be74836SDavid du Colombier * VacFile structures directory. But the directory reader
7233be74836SDavid du Colombier * is going to read the cache blocks directly, so update them.
7243be74836SDavid du Colombier */
7253be74836SDavid du Colombier if(filelock(f) < 0)
7263be74836SDavid du Colombier return nil;
7273be74836SDavid du Colombier for(p=f->down; p; p=p->next)
7283be74836SDavid du Colombier filemetaflush(p, nil);
7293be74836SDavid du Colombier fileunlock(f);
7303be74836SDavid du Colombier
7313be74836SDavid du Colombier vde = vtmallocz(sizeof(VacDirEnum));
7323be74836SDavid du Colombier vde->file = vacfileincref(f);
7333be74836SDavid du Colombier
7343be74836SDavid du Colombier return vde;
7353be74836SDavid du Colombier }
7363be74836SDavid du Colombier
7373be74836SDavid du Colombier /*
7383be74836SDavid du Colombier * Figure out the size of the directory entry at offset.
7393be74836SDavid du Colombier * The rest of the metadata is kept in the data half,
7403be74836SDavid du Colombier * but since venti has to track the data size anyway,
7413be74836SDavid du Colombier * we just use that one and avoid updating the directory
7423be74836SDavid du Colombier * each time the file size changes.
7433be74836SDavid du Colombier */
7443be74836SDavid du Colombier static int
direntrysize(VtFile * s,ulong offset,ulong gen,uvlong * size)7453be74836SDavid du Colombier direntrysize(VtFile *s, ulong offset, ulong gen, uvlong *size)
7463be74836SDavid du Colombier {
7473be74836SDavid du Colombier VtBlock *b;
7483be74836SDavid du Colombier ulong bn;
7493be74836SDavid du Colombier VtEntry e;
7503be74836SDavid du Colombier int epb;
7513be74836SDavid du Colombier
7523be74836SDavid du Colombier epb = s->dsize/VtEntrySize;
7533be74836SDavid du Colombier bn = offset/epb;
7543be74836SDavid du Colombier offset -= bn*epb;
7553be74836SDavid du Colombier
7563be74836SDavid du Colombier b = vtfileblock(s, bn, VtOREAD);
7573be74836SDavid du Colombier if(b == nil)
7583be74836SDavid du Colombier goto Err;
7593be74836SDavid du Colombier if(vtentryunpack(&e, b->data, offset) < 0)
7603be74836SDavid du Colombier goto Err;
7613be74836SDavid du Colombier
7623be74836SDavid du Colombier /* dangling entries are returned as zero size */
7633be74836SDavid du Colombier if(!(e.flags & VtEntryActive) || e.gen != gen)
7643be74836SDavid du Colombier *size = 0;
7653be74836SDavid du Colombier else
7663be74836SDavid du Colombier *size = e.size;
7673be74836SDavid du Colombier vtblockput(b);
7683be74836SDavid du Colombier return 0;
7693be74836SDavid du Colombier
7703be74836SDavid du Colombier Err:
7713be74836SDavid du Colombier vtblockput(b);
7723be74836SDavid du Colombier return -1;
7733be74836SDavid du Colombier }
7743be74836SDavid du Colombier
7753be74836SDavid du Colombier /*
7763be74836SDavid du Colombier * Fill in vde with a new batch of directory entries.
7773be74836SDavid du Colombier */
7783be74836SDavid du Colombier static int
vdefill(VacDirEnum * vde)7793be74836SDavid du Colombier vdefill(VacDirEnum *vde)
7803be74836SDavid du Colombier {
7813be74836SDavid du Colombier int i, n;
7823be74836SDavid du Colombier VtFile *meta, *source;
78349223a73SDavid du Colombier MetaBlock mb;
78449223a73SDavid du Colombier MetaEntry me;
7853be74836SDavid du Colombier VacFile *f;
7863be74836SDavid du Colombier VtBlock *b;
7873be74836SDavid du Colombier VacDir *de;
788e538c934SDavid du Colombier
7893be74836SDavid du Colombier /* clean up first */
7903be74836SDavid du Colombier for(i=vde->i; i<vde->n; i++)
7913be74836SDavid du Colombier vdcleanup(vde->buf+i);
7923be74836SDavid du Colombier vtfree(vde->buf);
7933be74836SDavid du Colombier vde->buf = nil;
7943be74836SDavid du Colombier vde->i = 0;
7953be74836SDavid du Colombier vde->n = 0;
7963be74836SDavid du Colombier
7973be74836SDavid du Colombier f = vde->file;
7983be74836SDavid du Colombier
7993be74836SDavid du Colombier source = f->source;
8003be74836SDavid du Colombier meta = f->msource;
8013be74836SDavid du Colombier
8023be74836SDavid du Colombier b = vtfileblock(meta, vde->boff, VtOREAD);
8033be74836SDavid du Colombier if(b == nil)
8043be74836SDavid du Colombier goto Err;
8053be74836SDavid du Colombier if(mbunpack(&mb, b->data, meta->dsize) < 0)
8063be74836SDavid du Colombier goto Err;
8073be74836SDavid du Colombier
8083be74836SDavid du Colombier n = mb.nindex;
8093be74836SDavid du Colombier vde->buf = vtmalloc(n * sizeof(VacDir));
8103be74836SDavid du Colombier
8113be74836SDavid du Colombier for(i=0; i<n; i++){
8123be74836SDavid du Colombier de = vde->buf + i;
8133be74836SDavid du Colombier meunpack(&me, &mb, i);
8143be74836SDavid du Colombier if(vdunpack(de, &me) < 0)
8153be74836SDavid du Colombier goto Err;
8163be74836SDavid du Colombier vde->n++;
8173be74836SDavid du Colombier if(!(de->mode & ModeDir))
8183be74836SDavid du Colombier if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
8193be74836SDavid du Colombier goto Err;
8203be74836SDavid du Colombier }
8213be74836SDavid du Colombier vde->boff++;
8223be74836SDavid du Colombier vtblockput(b);
8233be74836SDavid du Colombier return 0;
8243be74836SDavid du Colombier Err:
8253be74836SDavid du Colombier vtblockput(b);
8263be74836SDavid du Colombier return -1;
8273be74836SDavid du Colombier }
8283be74836SDavid du Colombier
8293be74836SDavid du Colombier /*
8303be74836SDavid du Colombier * Read a single directory entry from vde into de.
8313be74836SDavid du Colombier * Returns -1 on error, 0 on EOF, and 1 on success.
8323be74836SDavid du Colombier * When it returns 1, it becomes the caller's responsibility
8333be74836SDavid du Colombier * to call vdcleanup(de) to free the strings contained
8343be74836SDavid du Colombier * inside, or else to call vdunread to give it back.
8353be74836SDavid du Colombier */
8363be74836SDavid du Colombier int
vderead(VacDirEnum * vde,VacDir * de)8373be74836SDavid du Colombier vderead(VacDirEnum *vde, VacDir *de)
8383be74836SDavid du Colombier {
8393be74836SDavid du Colombier int ret;
8403be74836SDavid du Colombier VacFile *f;
8413be74836SDavid du Colombier u32int nb;
8423be74836SDavid du Colombier
8433be74836SDavid du Colombier f = vde->file;
8443be74836SDavid du Colombier if(filerlock(f) < 0)
8453be74836SDavid du Colombier return -1;
8463be74836SDavid du Colombier
8473be74836SDavid du Colombier if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
8483be74836SDavid du Colombier filerunlock(f);
8493be74836SDavid du Colombier return -1;
8503be74836SDavid du Colombier }
8513be74836SDavid du Colombier
8523be74836SDavid du Colombier nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
8533be74836SDavid du Colombier
8543be74836SDavid du Colombier while(vde->i >= vde->n){
8553be74836SDavid du Colombier if(vde->boff >= nb){
8563be74836SDavid du Colombier ret = 0;
8573be74836SDavid du Colombier goto Return;
8583be74836SDavid du Colombier }
8593be74836SDavid du Colombier if(vdefill(vde) < 0){
8603be74836SDavid du Colombier ret = -1;
8613be74836SDavid du Colombier goto Return;
8623be74836SDavid du Colombier }
8633be74836SDavid du Colombier }
8643be74836SDavid du Colombier
8653be74836SDavid du Colombier memmove(de, vde->buf + vde->i, sizeof(VacDir));
8663be74836SDavid du Colombier vde->i++;
8673be74836SDavid du Colombier ret = 1;
8683be74836SDavid du Colombier
8693be74836SDavid du Colombier Return:
8703be74836SDavid du Colombier vtfileunlock(f->source);
8713be74836SDavid du Colombier vtfileunlock(f->msource);
8723be74836SDavid du Colombier filerunlock(f);
8733be74836SDavid du Colombier
8743be74836SDavid du Colombier return ret;
8753be74836SDavid du Colombier }
8763be74836SDavid du Colombier
8773be74836SDavid du Colombier /*
8783be74836SDavid du Colombier * "Unread" the last directory entry that was read,
8793be74836SDavid du Colombier * so that the next vderead will return the same one.
8803be74836SDavid du Colombier * If the caller calls vdeunread(vde) it should not call
8813be74836SDavid du Colombier * vdcleanup on the entry being "unread".
8823be74836SDavid du Colombier */
8833be74836SDavid du Colombier int
vdeunread(VacDirEnum * vde)8843be74836SDavid du Colombier vdeunread(VacDirEnum *vde)
8853be74836SDavid du Colombier {
8863be74836SDavid du Colombier if(vde->i > 0){
8873be74836SDavid du Colombier vde->i--;
8883be74836SDavid du Colombier return 0;
8893be74836SDavid du Colombier }
8903be74836SDavid du Colombier return -1;
8913be74836SDavid du Colombier }
8923be74836SDavid du Colombier
8933be74836SDavid du Colombier /*
8943be74836SDavid du Colombier * Close the enumerator.
8953be74836SDavid du Colombier */
8963be74836SDavid du Colombier void
vdeclose(VacDirEnum * vde)8973be74836SDavid du Colombier vdeclose(VacDirEnum *vde)
8983be74836SDavid du Colombier {
8993be74836SDavid du Colombier int i;
9003be74836SDavid du Colombier if(vde == nil)
9013be74836SDavid du Colombier return;
9023be74836SDavid du Colombier /* free the strings */
9033be74836SDavid du Colombier for(i=vde->i; i<vde->n; i++)
9043be74836SDavid du Colombier vdcleanup(vde->buf+i);
9053be74836SDavid du Colombier vtfree(vde->buf);
9063be74836SDavid du Colombier vacfiledecref(vde->file);
9073be74836SDavid du Colombier vtfree(vde);
9083be74836SDavid du Colombier }
9093be74836SDavid du Colombier
9103be74836SDavid du Colombier
9113be74836SDavid du Colombier /*
9123be74836SDavid du Colombier * On to mutation. If the vac file system has been opened
9133be74836SDavid du Colombier * read-write, then the files and directories can all be edited.
9143be74836SDavid du Colombier * Changes are kept in the in-memory cache until flushed out
9153be74836SDavid du Colombier * to venti, so we must be careful to explicitly flush data
9163be74836SDavid du Colombier * that we're not likely to modify again.
9173be74836SDavid du Colombier *
9183be74836SDavid du Colombier * Each VacFile has its own copy of its VacDir directory entry
9193be74836SDavid du Colombier * in f->dir, but otherwise the cache is the authoratative source
9203be74836SDavid du Colombier * for data. Thus, for the most part, it suffices if we just
9213be74836SDavid du Colombier * call vtfileflushbefore and vtfileflush when we modify things.
9223be74836SDavid du Colombier * There are a few places where we have to remember to write
9233be74836SDavid du Colombier * changed VacDirs back into the cache. If f->dir *is* out of sync,
9243be74836SDavid du Colombier * then f->dirty should be set.
9253be74836SDavid du Colombier *
9263be74836SDavid du Colombier * The metadata in a directory is, to venti, a plain data file,
9273be74836SDavid du Colombier * but as mentioned above it is actually a sequence of
9283be74836SDavid du Colombier * MetaBlocks that contain sorted lists of VacDir entries.
9293be74836SDavid du Colombier * The filemetaxxx routines manipulate that stream.
9303be74836SDavid du Colombier */
9313be74836SDavid du Colombier
9323be74836SDavid du Colombier /*
9333be74836SDavid du Colombier * Find space in fp for the directory entry dir (not yet written to disk)
9343be74836SDavid du Colombier * and write it to disk, returning NilBlock on failure,
9353be74836SDavid du Colombier * or the block number on success.
9363be74836SDavid du Colombier *
9373be74836SDavid du Colombier * Start is a suggested block number to try.
9383be74836SDavid du Colombier * The caller must have filemetalock'ed f and have
9393be74836SDavid du Colombier * vtfilelock'ed f->up->msource.
9403be74836SDavid du Colombier */
9413be74836SDavid du Colombier static u32int
filemetaalloc(VacFile * fp,VacDir * dir,u32int start)9423be74836SDavid du Colombier filemetaalloc(VacFile *fp, VacDir *dir, u32int start)
9433be74836SDavid du Colombier {
9443be74836SDavid du Colombier u32int nb, bo;
9453be74836SDavid du Colombier VtBlock *b;
9463be74836SDavid du Colombier MetaBlock mb;
9473be74836SDavid du Colombier int nn;
9483be74836SDavid du Colombier uchar *p;
9493be74836SDavid du Colombier int i, n;
9503be74836SDavid du Colombier MetaEntry me;
9513be74836SDavid du Colombier VtFile *ms;
9523be74836SDavid du Colombier
9533be74836SDavid du Colombier ms = fp->msource;
9543be74836SDavid du Colombier n = vdsize(dir, VacDirVersion);
9553be74836SDavid du Colombier
9563be74836SDavid du Colombier /* Look for a block with room for a new entry of size n. */
9573be74836SDavid du Colombier nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
9583be74836SDavid du Colombier if(start == NilBlock){
9593be74836SDavid du Colombier if(nb > 0)
9603be74836SDavid du Colombier start = nb - 1;
9613be74836SDavid du Colombier else
9623be74836SDavid du Colombier start = 0;
9633be74836SDavid du Colombier }
9643be74836SDavid du Colombier
9653be74836SDavid du Colombier if(start > nb)
9663be74836SDavid du Colombier start = nb;
9673be74836SDavid du Colombier for(bo=start; bo<nb; bo++){
9683be74836SDavid du Colombier if((b = vtfileblock(ms, bo, VtOREAD)) == nil)
9693be74836SDavid du Colombier goto Err;
9703be74836SDavid du Colombier if(mbunpack(&mb, b->data, ms->dsize) < 0)
9713be74836SDavid du Colombier goto Err;
9723be74836SDavid du Colombier nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
9733be74836SDavid du Colombier if(n <= nn && mb.nindex < mb.maxindex){
9743be74836SDavid du Colombier /* reopen for writing */
9753be74836SDavid du Colombier vtblockput(b);
9763be74836SDavid du Colombier if((b = vtfileblock(ms, bo, VtORDWR)) == nil)
9773be74836SDavid du Colombier goto Err;
9783be74836SDavid du Colombier mbunpack(&mb, b->data, ms->dsize);
9793be74836SDavid du Colombier goto Found;
9803be74836SDavid du Colombier }
9813be74836SDavid du Colombier vtblockput(b);
9823be74836SDavid du Colombier }
9833be74836SDavid du Colombier
9843be74836SDavid du Colombier /* No block found, extend the file by one metablock. */
9853be74836SDavid du Colombier vtfileflushbefore(ms, nb*(uvlong)ms->dsize);
9863be74836SDavid du Colombier if((b = vtfileblock(ms, nb, VtORDWR)) == nil)
9873be74836SDavid du Colombier goto Err;
9883be74836SDavid du Colombier vtfilesetsize(ms, (nb+1)*ms->dsize);
9893be74836SDavid du Colombier mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
9903be74836SDavid du Colombier
9913be74836SDavid du Colombier Found:
9923be74836SDavid du Colombier /* Now we have a block; allocate space to write the entry. */
9933be74836SDavid du Colombier p = mballoc(&mb, n);
9943be74836SDavid du Colombier if(p == nil){
9953be74836SDavid du Colombier /* mballoc might have changed block */
9963be74836SDavid du Colombier mbpack(&mb);
9973be74836SDavid du Colombier werrstr(EBadMeta);
9983be74836SDavid du Colombier goto Err;
9993be74836SDavid du Colombier }
10003be74836SDavid du Colombier
10013be74836SDavid du Colombier /* Figure out where to put the index entry, and write it. */
10023be74836SDavid du Colombier mbsearch(&mb, dir->elem, &i, &me);
10033be74836SDavid du Colombier assert(me.p == nil); /* not already there */
10043be74836SDavid du Colombier me.p = p;
10053be74836SDavid du Colombier me.size = n;
10063be74836SDavid du Colombier vdpack(dir, &me, VacDirVersion);
10073be74836SDavid du Colombier mbinsert(&mb, i, &me);
10083be74836SDavid du Colombier mbpack(&mb);
10093be74836SDavid du Colombier vtblockput(b);
10103be74836SDavid du Colombier return bo;
10113be74836SDavid du Colombier
10123be74836SDavid du Colombier Err:
10133be74836SDavid du Colombier vtblockput(b);
10143be74836SDavid du Colombier return NilBlock;
10153be74836SDavid du Colombier }
10163be74836SDavid du Colombier
10173be74836SDavid du Colombier /*
10183be74836SDavid du Colombier * Update f's directory entry in the block cache.
10193be74836SDavid du Colombier * We look for the directory entry by name;
10203be74836SDavid du Colombier * if we're trying to rename the file, oelem is the old name.
10213be74836SDavid du Colombier *
10223be74836SDavid du Colombier * Assumes caller has filemetalock'ed f.
10233be74836SDavid du Colombier */
10243be74836SDavid du Colombier static int
filemetaflush(VacFile * f,char * oelem)10253be74836SDavid du Colombier filemetaflush(VacFile *f, char *oelem)
10263be74836SDavid du Colombier {
10273be74836SDavid du Colombier int i, n;
10283be74836SDavid du Colombier MetaBlock mb;
10293be74836SDavid du Colombier MetaEntry me, me2;
10303be74836SDavid du Colombier VacFile *fp;
10313be74836SDavid du Colombier VtBlock *b;
10323be74836SDavid du Colombier u32int bo;
10333be74836SDavid du Colombier
10343be74836SDavid du Colombier if(!f->dirty)
10353be74836SDavid du Colombier return 0;
10363be74836SDavid du Colombier
10373be74836SDavid du Colombier if(oelem == nil)
10383be74836SDavid du Colombier oelem = f->dir.elem;
10393be74836SDavid du Colombier
10403be74836SDavid du Colombier /*
10413be74836SDavid du Colombier * Locate f's old metadata in the parent's metadata file.
10423be74836SDavid du Colombier * We know which block it was in, but not exactly where
10433be74836SDavid du Colombier * in the block.
10443be74836SDavid du Colombier */
10453be74836SDavid du Colombier fp = f->up;
10463be74836SDavid du Colombier if(vtfilelock(fp->msource, -1) < 0)
10473be74836SDavid du Colombier return -1;
10483be74836SDavid du Colombier /* can happen if source is clri'ed out from under us */
10493be74836SDavid du Colombier if(f->boff == NilBlock)
10503be74836SDavid du Colombier goto Err1;
10513be74836SDavid du Colombier b = vtfileblock(fp->msource, f->boff, VtORDWR);
10523be74836SDavid du Colombier if(b == nil)
10533be74836SDavid du Colombier goto Err1;
10543be74836SDavid du Colombier if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
10553be74836SDavid du Colombier goto Err;
10563be74836SDavid du Colombier if(mbsearch(&mb, oelem, &i, &me) < 0)
10573be74836SDavid du Colombier goto Err;
10583be74836SDavid du Colombier
10593be74836SDavid du Colombier /*
10603be74836SDavid du Colombier * Check whether we can resize the entry and keep it
10613be74836SDavid du Colombier * in this block.
10623be74836SDavid du Colombier */
10633be74836SDavid du Colombier n = vdsize(&f->dir, VacDirVersion);
10643be74836SDavid du Colombier if(mbresize(&mb, &me, n) >= 0){
10653be74836SDavid du Colombier /* Okay, can be done without moving to another block. */
10663be74836SDavid du Colombier
10673be74836SDavid du Colombier /* Remove old data */
10683be74836SDavid du Colombier mbdelete(&mb, i, &me);
10693be74836SDavid du Colombier
10703be74836SDavid du Colombier /* Find new location if renaming */
10713be74836SDavid du Colombier if(strcmp(f->dir.elem, oelem) != 0)
10723be74836SDavid du Colombier mbsearch(&mb, f->dir.elem, &i, &me2);
10733be74836SDavid du Colombier
10743be74836SDavid du Colombier /* Pack new data into new location. */
10753be74836SDavid du Colombier vdpack(&f->dir, &me, VacDirVersion);
10763be74836SDavid du Colombier vdunpack(&f->dir, &me);
10773be74836SDavid du Colombier mbinsert(&mb, i, &me);
10783be74836SDavid du Colombier mbpack(&mb);
10793be74836SDavid du Colombier
10803be74836SDavid du Colombier /* Done */
10813be74836SDavid du Colombier vtblockput(b);
10823be74836SDavid du Colombier vtfileunlock(fp->msource);
10833be74836SDavid du Colombier f->dirty = 0;
10843be74836SDavid du Colombier return 0;
10853be74836SDavid du Colombier }
10863be74836SDavid du Colombier
10873be74836SDavid du Colombier /*
10883be74836SDavid du Colombier * The entry must be moved to another block.
10893be74836SDavid du Colombier * This can only really happen on renames that
10903be74836SDavid du Colombier * make the name very long.
10913be74836SDavid du Colombier */
10923be74836SDavid du Colombier
10933be74836SDavid du Colombier /* Allocate a spot in a new block. */
10943be74836SDavid du Colombier if((bo = filemetaalloc(fp, &f->dir, f->boff+1)) == NilBlock){
10953be74836SDavid du Colombier /* mbresize above might have modified block */
10963be74836SDavid du Colombier mbpack(&mb);
10973be74836SDavid du Colombier goto Err;
10983be74836SDavid du Colombier }
10993be74836SDavid du Colombier f->boff = bo;
11003be74836SDavid du Colombier
11013be74836SDavid du Colombier /* Now we're committed. Delete entry in old block. */
11023be74836SDavid du Colombier mbdelete(&mb, i, &me);
11033be74836SDavid du Colombier mbpack(&mb);
11043be74836SDavid du Colombier vtblockput(b);
11053be74836SDavid du Colombier vtfileunlock(fp->msource);
11063be74836SDavid du Colombier
11073be74836SDavid du Colombier f->dirty = 0;
11083be74836SDavid du Colombier return 0;
11093be74836SDavid du Colombier
11103be74836SDavid du Colombier Err:
11113be74836SDavid du Colombier vtblockput(b);
11123be74836SDavid du Colombier Err1:
11133be74836SDavid du Colombier vtfileunlock(fp->msource);
11143be74836SDavid du Colombier return -1;
11153be74836SDavid du Colombier }
11163be74836SDavid du Colombier
11173be74836SDavid du Colombier /*
11183be74836SDavid du Colombier * Remove the directory entry for f.
11193be74836SDavid du Colombier */
11203be74836SDavid du Colombier static int
filemetaremove(VacFile * f)11213be74836SDavid du Colombier filemetaremove(VacFile *f)
11223be74836SDavid du Colombier {
11233be74836SDavid du Colombier VtBlock *b;
11243be74836SDavid du Colombier MetaBlock mb;
11253be74836SDavid du Colombier MetaEntry me;
11263be74836SDavid du Colombier int i;
11273be74836SDavid du Colombier VacFile *fp;
11283be74836SDavid du Colombier
11293be74836SDavid du Colombier b = nil;
11303be74836SDavid du Colombier fp = f->up;
11313be74836SDavid du Colombier filemetalock(f);
11323be74836SDavid du Colombier
11333be74836SDavid du Colombier if(vtfilelock(fp->msource, VtORDWR) < 0)
11343be74836SDavid du Colombier goto Err;
11353be74836SDavid du Colombier b = vtfileblock(fp->msource, f->boff, VtORDWR);
11363be74836SDavid du Colombier if(b == nil)
11373be74836SDavid du Colombier goto Err;
11383be74836SDavid du Colombier
11393be74836SDavid du Colombier if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
11403be74836SDavid du Colombier goto Err;
11413be74836SDavid du Colombier if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
11423be74836SDavid du Colombier goto Err;
11433be74836SDavid du Colombier mbdelete(&mb, i, &me);
11443be74836SDavid du Colombier mbpack(&mb);
11453be74836SDavid du Colombier vtblockput(b);
11463be74836SDavid du Colombier vtfileunlock(fp->msource);
11473be74836SDavid du Colombier
11483be74836SDavid du Colombier f->removed = 1;
11493be74836SDavid du Colombier f->boff = NilBlock;
11503be74836SDavid du Colombier f->dirty = 0;
11513be74836SDavid du Colombier
11523be74836SDavid du Colombier filemetaunlock(f);
11533be74836SDavid du Colombier return 0;
11543be74836SDavid du Colombier
11553be74836SDavid du Colombier Err:
11563be74836SDavid du Colombier vtfileunlock(fp->msource);
11573be74836SDavid du Colombier vtblockput(b);
11583be74836SDavid du Colombier filemetaunlock(f);
11593be74836SDavid du Colombier return -1;
11603be74836SDavid du Colombier }
11613be74836SDavid du Colombier
11623be74836SDavid du Colombier /*
11633be74836SDavid du Colombier * That was far too much effort for directory entries.
11643be74836SDavid du Colombier * Now we can write code that *does* things.
11653be74836SDavid du Colombier */
11663be74836SDavid du Colombier
11673be74836SDavid du Colombier /*
11683be74836SDavid du Colombier * Flush all data associated with f out of the cache and onto venti.
11693be74836SDavid du Colombier * If recursive is set, flush f's children too.
11703be74836SDavid du Colombier * Vacfiledecref knows how to flush source and msource too.
11713be74836SDavid du Colombier */
11723be74836SDavid du Colombier int
vacfileflush(VacFile * f,int recursive)11733be74836SDavid du Colombier vacfileflush(VacFile *f, int recursive)
11743be74836SDavid du Colombier {
11753be74836SDavid du Colombier int ret;
11763be74836SDavid du Colombier VacFile **kids, *p;
11773be74836SDavid du Colombier int i, nkids;
11783be74836SDavid du Colombier
11793be74836SDavid du Colombier if(f->mode == VtOREAD)
11803be74836SDavid du Colombier return 0;
11813be74836SDavid du Colombier
11823be74836SDavid du Colombier ret = 0;
11833be74836SDavid du Colombier filemetalock(f);
11843be74836SDavid du Colombier if(filemetaflush(f, nil) < 0)
11853be74836SDavid du Colombier ret = -1;
11863be74836SDavid du Colombier filemetaunlock(f);
11873be74836SDavid du Colombier
11883be74836SDavid du Colombier if(filelock(f) < 0)
11893be74836SDavid du Colombier return -1;
11903be74836SDavid du Colombier
11913be74836SDavid du Colombier /*
11923be74836SDavid du Colombier * Lock order prevents us from flushing kids while holding
11933be74836SDavid du Colombier * lock, so make a list and then flush without the lock.
11943be74836SDavid du Colombier */
11953be74836SDavid du Colombier nkids = 0;
11963be74836SDavid du Colombier kids = nil;
11973be74836SDavid du Colombier if(recursive){
11983be74836SDavid du Colombier nkids = 0;
11993be74836SDavid du Colombier for(p=f->down; p; p=p->next)
12003be74836SDavid du Colombier nkids++;
12013be74836SDavid du Colombier kids = vtmalloc(nkids*sizeof(VacFile*));
12023be74836SDavid du Colombier i = 0;
12033be74836SDavid du Colombier for(p=f->down; p; p=p->next){
12043be74836SDavid du Colombier kids[i++] = p;
12053be74836SDavid du Colombier p->ref++;
12063be74836SDavid du Colombier }
12073be74836SDavid du Colombier }
12083be74836SDavid du Colombier if(nkids > 0){
12093be74836SDavid du Colombier fileunlock(f);
12103be74836SDavid du Colombier for(i=0; i<nkids; i++){
12113be74836SDavid du Colombier if(vacfileflush(kids[i], 1) < 0)
12123be74836SDavid du Colombier ret = -1;
12133be74836SDavid du Colombier vacfiledecref(kids[i]);
12143be74836SDavid du Colombier }
12153be74836SDavid du Colombier filelock(f);
12163be74836SDavid du Colombier }
12173be74836SDavid du Colombier free(kids);
12183be74836SDavid du Colombier
12193be74836SDavid du Colombier /*
12203be74836SDavid du Colombier * Now we can flush our own data.
12213be74836SDavid du Colombier */
12223be74836SDavid du Colombier vtfilelock(f->source, -1);
12233be74836SDavid du Colombier if(vtfileflush(f->source) < 0)
12243be74836SDavid du Colombier ret = -1;
12253be74836SDavid du Colombier vtfileunlock(f->source);
12263be74836SDavid du Colombier if(f->msource){
12273be74836SDavid du Colombier vtfilelock(f->msource, -1);
12283be74836SDavid du Colombier if(vtfileflush(f->msource) < 0)
12293be74836SDavid du Colombier ret = -1;
12303be74836SDavid du Colombier vtfileunlock(f->msource);
12313be74836SDavid du Colombier }
12323be74836SDavid du Colombier fileunlock(f);
12333be74836SDavid du Colombier
12343be74836SDavid du Colombier return ret;
12353be74836SDavid du Colombier }
12363be74836SDavid du Colombier
12373be74836SDavid du Colombier /*
12383be74836SDavid du Colombier * Create a new file named elem in fp with the given mode.
12393be74836SDavid du Colombier * The mode can be changed later except for the ModeDir bit.
12403be74836SDavid du Colombier */
12413be74836SDavid du Colombier VacFile*
vacfilecreate(VacFile * fp,char * elem,ulong mode)12423be74836SDavid du Colombier vacfilecreate(VacFile *fp, char *elem, ulong mode)
12433be74836SDavid du Colombier {
12443be74836SDavid du Colombier VacFile *ff;
12453be74836SDavid du Colombier VacDir *dir;
12463be74836SDavid du Colombier VtFile *pr, *r, *mr;
12473be74836SDavid du Colombier int type;
12483be74836SDavid du Colombier u32int bo;
12493be74836SDavid du Colombier
12503be74836SDavid du Colombier if(filelock(fp) < 0)
1251d9306527SDavid du Colombier return nil;
1252d9306527SDavid du Colombier
12533be74836SDavid du Colombier /*
12543be74836SDavid du Colombier * First, look to see that there's not a file in memory
12553be74836SDavid du Colombier * with the same name.
12563be74836SDavid du Colombier */
12573be74836SDavid du Colombier for(ff = fp->down; ff; ff=ff->next){
12583be74836SDavid du Colombier if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
12593be74836SDavid du Colombier ff = nil;
12603be74836SDavid du Colombier werrstr(EExists);
12613be74836SDavid du Colombier goto Err1;
12623be74836SDavid du Colombier }
12633be74836SDavid du Colombier }
12643be74836SDavid du Colombier
12653be74836SDavid du Colombier /*
12663be74836SDavid du Colombier * Next check the venti blocks.
12673be74836SDavid du Colombier */
12683be74836SDavid du Colombier ff = dirlookup(fp, elem);
12693be74836SDavid du Colombier if(ff != nil){
12703be74836SDavid du Colombier werrstr(EExists);
12713be74836SDavid du Colombier goto Err1;
12723be74836SDavid du Colombier }
12733be74836SDavid du Colombier
12743be74836SDavid du Colombier /*
12753be74836SDavid du Colombier * By the way, you can't create in a read-only file system.
12763be74836SDavid du Colombier */
12773be74836SDavid du Colombier pr = fp->source;
12783be74836SDavid du Colombier if(pr->mode != VtORDWR){
12793be74836SDavid du Colombier werrstr(EReadOnly);
12803be74836SDavid du Colombier goto Err1;
12813be74836SDavid du Colombier }
12823be74836SDavid du Colombier
12833be74836SDavid du Colombier /*
12843be74836SDavid du Colombier * Okay, time to actually create something. Lock the two
12853be74836SDavid du Colombier * halves of the directory and create a file.
12863be74836SDavid du Colombier */
12873be74836SDavid du Colombier if(vtfilelock2(fp->source, fp->msource, -1) < 0)
12883be74836SDavid du Colombier goto Err1;
12893be74836SDavid du Colombier ff = filealloc(fp->fs);
12903be74836SDavid du Colombier ff->qidoffset = fp->qidoffset; /* hopefully fp->qidoffset == 0 */
12913be74836SDavid du Colombier type = VtDataType;
12923be74836SDavid du Colombier if(mode & ModeDir)
12933be74836SDavid du Colombier type = VtDirType;
1294d9306527SDavid du Colombier mr = nil;
12953be74836SDavid du Colombier if((r = vtfilecreate(pr, pr->psize, pr->dsize, type)) == nil)
129649223a73SDavid du Colombier goto Err;
12973be74836SDavid du Colombier if(mode & ModeDir)
12983be74836SDavid du Colombier if((mr = vtfilecreate(pr, pr->psize, pr->dsize, VtDataType)) == nil)
129949223a73SDavid du Colombier goto Err;
130049223a73SDavid du Colombier
13013be74836SDavid du Colombier /*
13023be74836SDavid du Colombier * Fill in the directory entry and write it to disk.
13033be74836SDavid du Colombier */
13043be74836SDavid du Colombier dir = &ff->dir;
13053be74836SDavid du Colombier dir->elem = vtstrdup(elem);
13063be74836SDavid du Colombier dir->entry = r->offset;
1307d9306527SDavid du Colombier dir->gen = r->gen;
13083be74836SDavid du Colombier if(mode & ModeDir){
13093be74836SDavid du Colombier dir->mentry = mr->offset;
1310d9306527SDavid du Colombier dir->mgen = mr->gen;
1311d9306527SDavid du Colombier }
1312d9306527SDavid du Colombier dir->size = 0;
13133be74836SDavid du Colombier if(_vacfsnextqid(fp->fs, &dir->qid) < 0)
13143be74836SDavid du Colombier goto Err;
13153be74836SDavid du Colombier dir->uid = vtstrdup(fp->dir.uid);
13163be74836SDavid du Colombier dir->gid = vtstrdup(fp->dir.gid);
13173be74836SDavid du Colombier dir->mid = vtstrdup("");
1318d9306527SDavid du Colombier dir->mtime = time(0L);
1319d9306527SDavid du Colombier dir->mcount = 0;
1320d9306527SDavid du Colombier dir->ctime = dir->mtime;
1321d9306527SDavid du Colombier dir->atime = dir->mtime;
1322d9306527SDavid du Colombier dir->mode = mode;
13233be74836SDavid du Colombier if((bo = filemetaalloc(fp, &ff->dir, NilBlock)) == NilBlock)
1324d9306527SDavid du Colombier goto Err;
1325d9306527SDavid du Colombier
13263be74836SDavid du Colombier /*
13273be74836SDavid du Colombier * Now we're committed.
13283be74836SDavid du Colombier */
13293be74836SDavid du Colombier vtfileunlock(fp->source);
13303be74836SDavid du Colombier vtfileunlock(fp->msource);
13313be74836SDavid du Colombier ff->source = r;
13323be74836SDavid du Colombier ff->msource = mr;
13333be74836SDavid du Colombier ff->boff = bo;
1334d9306527SDavid du Colombier
13353be74836SDavid du Colombier /* Link into tree. */
13363be74836SDavid du Colombier ff->next = fp->down;
13373be74836SDavid du Colombier fp->down = ff;
13383be74836SDavid du Colombier ff->up = fp;
13393be74836SDavid du Colombier vacfileincref(fp);
1340d9306527SDavid du Colombier
13413be74836SDavid du Colombier fileunlock(fp);
134249223a73SDavid du Colombier
13433be74836SDavid du Colombier filelock(ff);
13443be74836SDavid du Colombier vtfilelock(ff->source, -1);
13453be74836SDavid du Colombier vtfileunlock(ff->source);
13463be74836SDavid du Colombier fileunlock(ff);
134749223a73SDavid du Colombier
13483be74836SDavid du Colombier return ff;
1349d9306527SDavid du Colombier
1350d9306527SDavid du Colombier Err:
13513be74836SDavid du Colombier vtfileunlock(fp->source);
13523be74836SDavid du Colombier vtfileunlock(fp->msource);
13533be74836SDavid du Colombier if(r){
13543be74836SDavid du Colombier vtfilelock(r, -1);
13553be74836SDavid du Colombier vtfileremove(r);
1356e538c934SDavid du Colombier }
13573be74836SDavid du Colombier if(mr){
13583be74836SDavid du Colombier vtfilelock(mr, -1);
13593be74836SDavid du Colombier vtfileremove(mr);
1360e538c934SDavid du Colombier }
13613be74836SDavid du Colombier Err1:
13623be74836SDavid du Colombier if(ff)
13633be74836SDavid du Colombier vacfiledecref(ff);
13643be74836SDavid du Colombier fileunlock(fp);
136549223a73SDavid du Colombier return nil;
136649223a73SDavid du Colombier }
136749223a73SDavid du Colombier
1368e538c934SDavid du Colombier /*
13693be74836SDavid du Colombier * Change the size of the file f.
1370e538c934SDavid du Colombier */
13713be74836SDavid du Colombier int
vacfilesetsize(VacFile * f,uvlong size)13723be74836SDavid du Colombier vacfilesetsize(VacFile *f, uvlong size)
1373e538c934SDavid du Colombier {
13743be74836SDavid du Colombier if(vacfileisdir(f)){
13753be74836SDavid du Colombier werrstr(ENotFile);
13763be74836SDavid du Colombier return -1;
13773be74836SDavid du Colombier }
1378e538c934SDavid du Colombier
13793be74836SDavid du Colombier if(filelock(f) < 0)
13803be74836SDavid du Colombier return -1;
13813be74836SDavid du Colombier
13823be74836SDavid du Colombier if(f->source->mode != VtORDWR){
13833be74836SDavid du Colombier werrstr(EReadOnly);
13843be74836SDavid du Colombier goto Err;
1385e538c934SDavid du Colombier }
13863be74836SDavid du Colombier if(vtfilelock(f->source, -1) < 0)
13873be74836SDavid du Colombier goto Err;
13883be74836SDavid du Colombier if(vtfilesetsize(f->source, size) < 0){
13893be74836SDavid du Colombier vtfileunlock(f->source);
13903be74836SDavid du Colombier goto Err;
13913be74836SDavid du Colombier }
13923be74836SDavid du Colombier vtfileunlock(f->source);
13933be74836SDavid du Colombier fileunlock(f);
13943be74836SDavid du Colombier return 0;
13953be74836SDavid du Colombier
13963be74836SDavid du Colombier Err:
13973be74836SDavid du Colombier fileunlock(f);
13983be74836SDavid du Colombier return -1;
13993be74836SDavid du Colombier }
14003be74836SDavid du Colombier
14013be74836SDavid du Colombier /*
14023be74836SDavid du Colombier * Write data to f.
14033be74836SDavid du Colombier */
14043be74836SDavid du Colombier int
vacfilewrite(VacFile * f,void * buf,int cnt,vlong offset)14053be74836SDavid du Colombier vacfilewrite(VacFile *f, void *buf, int cnt, vlong offset)
14063be74836SDavid du Colombier {
14073be74836SDavid du Colombier if(vacfileisdir(f)){
14083be74836SDavid du Colombier werrstr(ENotFile);
14093be74836SDavid du Colombier return -1;
14103be74836SDavid du Colombier }
14113be74836SDavid du Colombier if(filelock(f) < 0)
14123be74836SDavid du Colombier return -1;
14133be74836SDavid du Colombier if(f->source->mode != VtORDWR){
14143be74836SDavid du Colombier werrstr(EReadOnly);
14153be74836SDavid du Colombier goto Err;
14163be74836SDavid du Colombier }
14173be74836SDavid du Colombier if(offset < 0){
14183be74836SDavid du Colombier werrstr(EBadOffset);
14193be74836SDavid du Colombier goto Err;
14203be74836SDavid du Colombier }
14213be74836SDavid du Colombier
14223be74836SDavid du Colombier if(vtfilelock(f->source, -1) < 0)
14233be74836SDavid du Colombier goto Err;
14243be74836SDavid du Colombier if(f->dir.mode & ModeAppend)
14253be74836SDavid du Colombier offset = vtfilegetsize(f->source);
14263be74836SDavid du Colombier if(vtfilewrite(f->source, buf, cnt, offset) != cnt
14273be74836SDavid du Colombier || vtfileflushbefore(f->source, offset) < 0){
14283be74836SDavid du Colombier vtfileunlock(f->source);
14293be74836SDavid du Colombier goto Err;
14303be74836SDavid du Colombier }
14313be74836SDavid du Colombier vtfileunlock(f->source);
14323be74836SDavid du Colombier fileunlock(f);
14333be74836SDavid du Colombier return cnt;
14343be74836SDavid du Colombier
14353be74836SDavid du Colombier Err:
14363be74836SDavid du Colombier fileunlock(f);
14373be74836SDavid du Colombier return -1;
14383be74836SDavid du Colombier }
14393be74836SDavid du Colombier
14403be74836SDavid du Colombier /*
14413be74836SDavid du Colombier * Set (!) the VtEntry for the data contained in f.
14423be74836SDavid du Colombier * This let's us efficiently copy data from one file to another.
14433be74836SDavid du Colombier */
14443be74836SDavid du Colombier int
vacfilesetentries(VacFile * f,VtEntry * e,VtEntry * me)14453be74836SDavid du Colombier vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me)
14463be74836SDavid du Colombier {
14473be74836SDavid du Colombier int ret;
14483be74836SDavid du Colombier
14493be74836SDavid du Colombier vacfileflush(f, 0); /* flush blocks to venti, since we won't see them again */
14503be74836SDavid du Colombier
14513be74836SDavid du Colombier if(!(e->flags&VtEntryActive)){
14523be74836SDavid du Colombier werrstr("missing entry for source");
14533be74836SDavid du Colombier return -1;
14543be74836SDavid du Colombier }
14553be74836SDavid du Colombier if(me && !(me->flags&VtEntryActive))
14563be74836SDavid du Colombier me = nil;
14573be74836SDavid du Colombier if(f->msource && !me){
14583be74836SDavid du Colombier werrstr("missing entry for msource");
14593be74836SDavid du Colombier return -1;
14603be74836SDavid du Colombier }
14613be74836SDavid du Colombier if(me && !f->msource){
14623be74836SDavid du Colombier werrstr("no msource to set");
14633be74836SDavid du Colombier return -1;
14643be74836SDavid du Colombier }
14653be74836SDavid du Colombier
14663be74836SDavid du Colombier if(filelock(f) < 0)
14673be74836SDavid du Colombier return -1;
14683be74836SDavid du Colombier if(f->source->mode != VtORDWR
14693be74836SDavid du Colombier || (f->msource && f->msource->mode != VtORDWR)){
14703be74836SDavid du Colombier werrstr(EReadOnly);
14713be74836SDavid du Colombier fileunlock(f);
14723be74836SDavid du Colombier return -1;
14733be74836SDavid du Colombier }
14743be74836SDavid du Colombier if(vtfilelock2(f->source, f->msource, -1) < 0){
14753be74836SDavid du Colombier fileunlock(f);
14763be74836SDavid du Colombier return -1;
14773be74836SDavid du Colombier }
14783be74836SDavid du Colombier ret = 0;
14793be74836SDavid du Colombier if(vtfilesetentry(f->source, e) < 0)
14803be74836SDavid du Colombier ret = -1;
14813be74836SDavid du Colombier else if(me && vtfilesetentry(f->msource, me) < 0)
14823be74836SDavid du Colombier ret = -1;
14833be74836SDavid du Colombier
14843be74836SDavid du Colombier vtfileunlock(f->source);
14853be74836SDavid du Colombier if(f->msource)
14863be74836SDavid du Colombier vtfileunlock(f->msource);
14873be74836SDavid du Colombier fileunlock(f);
14883be74836SDavid du Colombier return ret;
14893be74836SDavid du Colombier }
14903be74836SDavid du Colombier
14913be74836SDavid du Colombier /*
14923be74836SDavid du Colombier * Get the directory entry for f.
14933be74836SDavid du Colombier */
14943be74836SDavid du Colombier int
vacfilegetdir(VacFile * f,VacDir * dir)14953be74836SDavid du Colombier vacfilegetdir(VacFile *f, VacDir *dir)
14963be74836SDavid du Colombier {
14973be74836SDavid du Colombier if(filerlock(f) < 0)
14983be74836SDavid du Colombier return -1;
14993be74836SDavid du Colombier
15003be74836SDavid du Colombier filemetalock(f);
15013be74836SDavid du Colombier vdcopy(dir, &f->dir);
15023be74836SDavid du Colombier filemetaunlock(f);
15033be74836SDavid du Colombier
15043be74836SDavid du Colombier if(!vacfileisdir(f)){
15053be74836SDavid du Colombier if(vtfilelock(f->source, VtOREAD) < 0){
15063be74836SDavid du Colombier filerunlock(f);
15073be74836SDavid du Colombier return -1;
15083be74836SDavid du Colombier }
15093be74836SDavid du Colombier dir->size = vtfilegetsize(f->source);
15103be74836SDavid du Colombier vtfileunlock(f->source);
15113be74836SDavid du Colombier }
15123be74836SDavid du Colombier filerunlock(f);
15133be74836SDavid du Colombier
15143be74836SDavid du Colombier return 0;
15153be74836SDavid du Colombier }
15163be74836SDavid du Colombier
15173be74836SDavid du Colombier /*
15183be74836SDavid du Colombier * Set the directory entry for f.
15193be74836SDavid du Colombier */
15203be74836SDavid du Colombier int
vacfilesetdir(VacFile * f,VacDir * dir)15213be74836SDavid du Colombier vacfilesetdir(VacFile *f, VacDir *dir)
15223be74836SDavid du Colombier {
15233be74836SDavid du Colombier VacFile *ff;
15243be74836SDavid du Colombier char *oelem;
15253be74836SDavid du Colombier u32int mask;
15263be74836SDavid du Colombier u64int size;
15273be74836SDavid du Colombier
15283be74836SDavid du Colombier /* can not set permissions for the root */
15293be74836SDavid du Colombier if(vacfileisroot(f)){
15303be74836SDavid du Colombier werrstr(ERoot);
15313be74836SDavid du Colombier return -1;
15323be74836SDavid du Colombier }
15333be74836SDavid du Colombier
15343be74836SDavid du Colombier if(filelock(f) < 0)
15353be74836SDavid du Colombier return -1;
15363be74836SDavid du Colombier filemetalock(f);
15373be74836SDavid du Colombier
15383be74836SDavid du Colombier if(f->source->mode != VtORDWR){
15393be74836SDavid du Colombier werrstr(EReadOnly);
15403be74836SDavid du Colombier goto Err;
15413be74836SDavid du Colombier }
15423be74836SDavid du Colombier
15433be74836SDavid du Colombier /* On rename, check new name does not already exist */
15443be74836SDavid du Colombier if(strcmp(f->dir.elem, dir->elem) != 0){
15453be74836SDavid du Colombier for(ff = f->up->down; ff; ff=ff->next){
15463be74836SDavid du Colombier if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
15473be74836SDavid du Colombier werrstr(EExists);
15483be74836SDavid du Colombier goto Err;
15493be74836SDavid du Colombier }
15503be74836SDavid du Colombier }
15513be74836SDavid du Colombier ff = dirlookup(f->up, dir->elem);
15523be74836SDavid du Colombier if(ff != nil){
15533be74836SDavid du Colombier vacfiledecref(ff);
15543be74836SDavid du Colombier werrstr(EExists);
15553be74836SDavid du Colombier goto Err;
15563be74836SDavid du Colombier }
15573be74836SDavid du Colombier werrstr(""); /* "failed" dirlookup poisoned it */
15583be74836SDavid du Colombier }
15593be74836SDavid du Colombier
15603be74836SDavid du Colombier /* Get ready... */
15613be74836SDavid du Colombier if(vtfilelock2(f->source, f->msource, -1) < 0)
15623be74836SDavid du Colombier goto Err;
15633be74836SDavid du Colombier if(!vacfileisdir(f)){
15643be74836SDavid du Colombier size = vtfilegetsize(f->source);
15653be74836SDavid du Colombier if(size != dir->size){
15663be74836SDavid du Colombier if(vtfilesetsize(f->source, dir->size) < 0){
15673be74836SDavid du Colombier vtfileunlock(f->source);
15683be74836SDavid du Colombier if(f->msource)
15693be74836SDavid du Colombier vtfileunlock(f->msource);
15703be74836SDavid du Colombier goto Err;
15713be74836SDavid du Colombier }
15723be74836SDavid du Colombier }
15733be74836SDavid du Colombier }
15743be74836SDavid du Colombier /* ... now commited to changing it. */
15753be74836SDavid du Colombier vtfileunlock(f->source);
15763be74836SDavid du Colombier if(f->msource)
15773be74836SDavid du Colombier vtfileunlock(f->msource);
15783be74836SDavid du Colombier
15793be74836SDavid du Colombier oelem = nil;
15803be74836SDavid du Colombier if(strcmp(f->dir.elem, dir->elem) != 0){
15813be74836SDavid du Colombier oelem = f->dir.elem;
15823be74836SDavid du Colombier f->dir.elem = vtstrdup(dir->elem);
15833be74836SDavid du Colombier }
15843be74836SDavid du Colombier
15853be74836SDavid du Colombier if(strcmp(f->dir.uid, dir->uid) != 0){
15863be74836SDavid du Colombier vtfree(f->dir.uid);
15873be74836SDavid du Colombier f->dir.uid = vtstrdup(dir->uid);
15883be74836SDavid du Colombier }
15893be74836SDavid du Colombier
15903be74836SDavid du Colombier if(strcmp(f->dir.gid, dir->gid) != 0){
15913be74836SDavid du Colombier vtfree(f->dir.gid);
15923be74836SDavid du Colombier f->dir.gid = vtstrdup(dir->gid);
15933be74836SDavid du Colombier }
15943be74836SDavid du Colombier
1595*fba43d71SDavid du Colombier if(strcmp(f->dir.mid, dir->mid) != 0){
1596*fba43d71SDavid du Colombier vtfree(f->dir.mid);
1597*fba43d71SDavid du Colombier f->dir.mid = vtstrdup(dir->mid);
1598*fba43d71SDavid du Colombier }
1599*fba43d71SDavid du Colombier
16003be74836SDavid du Colombier f->dir.mtime = dir->mtime;
16013be74836SDavid du Colombier f->dir.atime = dir->atime;
16023be74836SDavid du Colombier
16033be74836SDavid du Colombier mask = ~(ModeDir|ModeSnapshot);
16043be74836SDavid du Colombier f->dir.mode &= ~mask;
16053be74836SDavid du Colombier f->dir.mode |= mask & dir->mode;
16063be74836SDavid du Colombier f->dirty = 1;
16073be74836SDavid du Colombier
16083be74836SDavid du Colombier if(filemetaflush(f, oelem) < 0){
16093be74836SDavid du Colombier vtfree(oelem);
16103be74836SDavid du Colombier goto Err; /* that sucks */
16113be74836SDavid du Colombier }
16123be74836SDavid du Colombier vtfree(oelem);
16133be74836SDavid du Colombier
16143be74836SDavid du Colombier filemetaunlock(f);
16153be74836SDavid du Colombier fileunlock(f);
16163be74836SDavid du Colombier return 0;
16173be74836SDavid du Colombier
16183be74836SDavid du Colombier Err:
16193be74836SDavid du Colombier filemetaunlock(f);
16203be74836SDavid du Colombier fileunlock(f);
16213be74836SDavid du Colombier return -1;
16223be74836SDavid du Colombier }
16233be74836SDavid du Colombier
16243be74836SDavid du Colombier /*
16253be74836SDavid du Colombier * Set the qid space.
16263be74836SDavid du Colombier */
16273be74836SDavid du Colombier int
vacfilesetqidspace(VacFile * f,u64int offset,u64int max)16283be74836SDavid du Colombier vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
16293be74836SDavid du Colombier {
16303be74836SDavid du Colombier int ret;
16313be74836SDavid du Colombier
16323be74836SDavid du Colombier if(filelock(f) < 0)
16333be74836SDavid du Colombier return -1;
16343be74836SDavid du Colombier if(f->source->mode != VtORDWR){
16353be74836SDavid du Colombier fileunlock(f);
16363be74836SDavid du Colombier werrstr(EReadOnly);
16373be74836SDavid du Colombier return -1;
16383be74836SDavid du Colombier }
16393be74836SDavid du Colombier filemetalock(f);
16403be74836SDavid du Colombier f->dir.qidspace = 1;
16413be74836SDavid du Colombier f->dir.qidoffset = offset;
16423be74836SDavid du Colombier f->dir.qidmax = max;
16433be74836SDavid du Colombier f->dirty = 1;
16443be74836SDavid du Colombier ret = filemetaflush(f, nil);
16453be74836SDavid du Colombier filemetaunlock(f);
16463be74836SDavid du Colombier fileunlock(f);
16473be74836SDavid du Colombier return ret;
16483be74836SDavid du Colombier }
16493be74836SDavid du Colombier
16503be74836SDavid du Colombier /*
16513be74836SDavid du Colombier * Check that the file is empty, returning 0 if it is.
16523be74836SDavid du Colombier * Returns -1 on error (and not being empty is an error).
16533be74836SDavid du Colombier */
16543be74836SDavid du Colombier static int
filecheckempty(VacFile * f)16553be74836SDavid du Colombier filecheckempty(VacFile *f)
16563be74836SDavid du Colombier {
16573be74836SDavid du Colombier u32int i, n;
16583be74836SDavid du Colombier VtBlock *b;
16593be74836SDavid du Colombier MetaBlock mb;
16603be74836SDavid du Colombier VtFile *r;
16613be74836SDavid du Colombier
16623be74836SDavid du Colombier r = f->msource;
16633be74836SDavid du Colombier n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
16643be74836SDavid du Colombier for(i=0; i<n; i++){
16653be74836SDavid du Colombier b = vtfileblock(r, i, VtOREAD);
16663be74836SDavid du Colombier if(b == nil)
16673be74836SDavid du Colombier return -1;
16683be74836SDavid du Colombier if(mbunpack(&mb, b->data, r->dsize) < 0)
16693be74836SDavid du Colombier goto Err;
16703be74836SDavid du Colombier if(mb.nindex > 0){
16713be74836SDavid du Colombier werrstr(ENotEmpty);
16723be74836SDavid du Colombier goto Err;
16733be74836SDavid du Colombier }
16743be74836SDavid du Colombier vtblockput(b);
16753be74836SDavid du Colombier }
16763be74836SDavid du Colombier return 0;
16773be74836SDavid du Colombier
16783be74836SDavid du Colombier Err:
16793be74836SDavid du Colombier vtblockput(b);
16803be74836SDavid du Colombier return -1;
16813be74836SDavid du Colombier }
16823be74836SDavid du Colombier
16833be74836SDavid du Colombier /*
16843be74836SDavid du Colombier * Remove the vac file f.
16853be74836SDavid du Colombier */
16863be74836SDavid du Colombier int
vacfileremove(VacFile * f)16873be74836SDavid du Colombier vacfileremove(VacFile *f)
16883be74836SDavid du Colombier {
16893be74836SDavid du Colombier VacFile *ff;
16903be74836SDavid du Colombier
16913be74836SDavid du Colombier /* Cannot remove the root */
16923be74836SDavid du Colombier if(vacfileisroot(f)){
16933be74836SDavid du Colombier werrstr(ERoot);
16943be74836SDavid du Colombier return -1;
16953be74836SDavid du Colombier }
16963be74836SDavid du Colombier
16973be74836SDavid du Colombier if(filelock(f) < 0)
16983be74836SDavid du Colombier return -1;
16993be74836SDavid du Colombier if(f->source->mode != VtORDWR){
17003be74836SDavid du Colombier werrstr(EReadOnly);
17013be74836SDavid du Colombier goto Err1;
17023be74836SDavid du Colombier }
17033be74836SDavid du Colombier if(vtfilelock2(f->source, f->msource, -1) < 0)
17043be74836SDavid du Colombier goto Err1;
17053be74836SDavid du Colombier if(vacfileisdir(f) && filecheckempty(f)<0)
17063be74836SDavid du Colombier goto Err;
17073be74836SDavid du Colombier
17083be74836SDavid du Colombier for(ff=f->down; ff; ff=ff->next)
17093be74836SDavid du Colombier assert(ff->removed);
17103be74836SDavid du Colombier
17113be74836SDavid du Colombier vtfileremove(f->source);
17123be74836SDavid du Colombier f->source = nil;
17133be74836SDavid du Colombier if(f->msource){
17143be74836SDavid du Colombier vtfileremove(f->msource);
17153be74836SDavid du Colombier f->msource = nil;
17163be74836SDavid du Colombier }
17173be74836SDavid du Colombier fileunlock(f);
17183be74836SDavid du Colombier
17193be74836SDavid du Colombier if(filemetaremove(f) < 0)
17203be74836SDavid du Colombier return -1;
17213be74836SDavid du Colombier return 0;
17223be74836SDavid du Colombier
17233be74836SDavid du Colombier Err:
17243be74836SDavid du Colombier vtfileunlock(f->source);
17253be74836SDavid du Colombier if(f->msource)
17263be74836SDavid du Colombier vtfileunlock(f->msource);
17273be74836SDavid du Colombier Err1:
17283be74836SDavid du Colombier fileunlock(f);
17293be74836SDavid du Colombier return -1;
17303be74836SDavid du Colombier }
17313be74836SDavid du Colombier
17323be74836SDavid du Colombier /*
17333be74836SDavid du Colombier * Vac file system format.
17343be74836SDavid du Colombier */
17353be74836SDavid du Colombier static char EBadVacFormat[] = "bad format for vac file";
17363be74836SDavid du Colombier
17373be74836SDavid du Colombier static VacFs *
vacfsalloc(VtConn * z,int bsize,int ncache,int mode)17383be74836SDavid du Colombier vacfsalloc(VtConn *z, int bsize, int ncache, int mode)
17393be74836SDavid du Colombier {
17403be74836SDavid du Colombier VacFs *fs;
17413be74836SDavid du Colombier
17423be74836SDavid du Colombier fs = vtmallocz(sizeof(VacFs));
17433be74836SDavid du Colombier fs->z = z;
17443be74836SDavid du Colombier fs->bsize = bsize;
17453be74836SDavid du Colombier fs->mode = mode;
17463be74836SDavid du Colombier fs->cache = vtcachealloc(z, bsize, ncache);
17473be74836SDavid du Colombier return fs;
17483be74836SDavid du Colombier }
17493be74836SDavid du Colombier
17503be74836SDavid du Colombier static int
readscore(int fd,uchar score[VtScoreSize])17513be74836SDavid du Colombier readscore(int fd, uchar score[VtScoreSize])
17523be74836SDavid du Colombier {
17533be74836SDavid du Colombier char buf[45], *pref;
17543be74836SDavid du Colombier int n;
17553be74836SDavid du Colombier
17563be74836SDavid du Colombier n = readn(fd, buf, sizeof(buf)-1);
17573be74836SDavid du Colombier if(n < sizeof(buf)-1) {
17583be74836SDavid du Colombier werrstr("short read");
17593be74836SDavid du Colombier return -1;
17603be74836SDavid du Colombier }
17613be74836SDavid du Colombier buf[n] = 0;
17623be74836SDavid du Colombier
17633be74836SDavid du Colombier if(vtparsescore(buf, &pref, score) < 0){
17643be74836SDavid du Colombier werrstr(EBadVacFormat);
17653be74836SDavid du Colombier return -1;
17663be74836SDavid du Colombier }
17673be74836SDavid du Colombier if(pref==nil || strcmp(pref, "vac") != 0) {
17683be74836SDavid du Colombier werrstr("not a vac file");
17693be74836SDavid du Colombier return -1;
17703be74836SDavid du Colombier }
17713be74836SDavid du Colombier return 0;
17723be74836SDavid du Colombier }
17733be74836SDavid du Colombier
17743be74836SDavid du Colombier VacFs*
vacfsopen(VtConn * z,char * file,int mode,int ncache)17753be74836SDavid du Colombier vacfsopen(VtConn *z, char *file, int mode, int ncache)
17763be74836SDavid du Colombier {
17773be74836SDavid du Colombier int fd;
17783be74836SDavid du Colombier uchar score[VtScoreSize];
17793be74836SDavid du Colombier char *prefix;
17803be74836SDavid du Colombier
17813be74836SDavid du Colombier if(vtparsescore(file, &prefix, score) >= 0){
178242ae7379SDavid du Colombier if(prefix == nil || strcmp(prefix, "vac") != 0){
17833be74836SDavid du Colombier werrstr("not a vac file");
17843be74836SDavid du Colombier return nil;
17853be74836SDavid du Colombier }
17863be74836SDavid du Colombier }else{
17873be74836SDavid du Colombier fd = open(file, OREAD);
17883be74836SDavid du Colombier if(fd < 0)
17893be74836SDavid du Colombier return nil;
17903be74836SDavid du Colombier if(readscore(fd, score) < 0){
17913be74836SDavid du Colombier close(fd);
17923be74836SDavid du Colombier return nil;
17933be74836SDavid du Colombier }
17943be74836SDavid du Colombier close(fd);
17953be74836SDavid du Colombier }
17963be74836SDavid du Colombier return vacfsopenscore(z, score, mode, ncache);
17973be74836SDavid du Colombier }
17983be74836SDavid du Colombier
17993be74836SDavid du Colombier VacFs*
vacfsopenscore(VtConn * z,u8int * score,int mode,int ncache)18003be74836SDavid du Colombier vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache)
18013be74836SDavid du Colombier {
18023be74836SDavid du Colombier VacFs *fs;
18033be74836SDavid du Colombier int n;
18043be74836SDavid du Colombier VtRoot rt;
18053be74836SDavid du Colombier uchar buf[VtRootSize];
18063be74836SDavid du Colombier VacFile *root;
18073be74836SDavid du Colombier VtFile *r;
18083be74836SDavid du Colombier VtEntry e;
18093be74836SDavid du Colombier
18103be74836SDavid du Colombier n = vtread(z, score, VtRootType, buf, VtRootSize);
18113be74836SDavid du Colombier if(n < 0)
18123be74836SDavid du Colombier return nil;
18133be74836SDavid du Colombier if(n != VtRootSize){
18143be74836SDavid du Colombier werrstr("vtread on root too short");
18153be74836SDavid du Colombier return nil;
18163be74836SDavid du Colombier }
18173be74836SDavid du Colombier
18183be74836SDavid du Colombier if(vtrootunpack(&rt, buf) < 0)
18193be74836SDavid du Colombier return nil;
18203be74836SDavid du Colombier
18213be74836SDavid du Colombier if(strcmp(rt.type, "vac") != 0) {
18223be74836SDavid du Colombier werrstr("not a vac root");
18233be74836SDavid du Colombier return nil;
18243be74836SDavid du Colombier }
18253be74836SDavid du Colombier
18263be74836SDavid du Colombier fs = vacfsalloc(z, rt.blocksize, ncache, mode);
18273be74836SDavid du Colombier memmove(fs->score, score, VtScoreSize);
18283be74836SDavid du Colombier fs->mode = mode;
18293be74836SDavid du Colombier
18303be74836SDavid du Colombier memmove(e.score, rt.score, VtScoreSize);
18313be74836SDavid du Colombier e.gen = 0;
18323be74836SDavid du Colombier e.psize = rt.blocksize;
18333be74836SDavid du Colombier e.dsize = rt.blocksize;
18343be74836SDavid du Colombier e.type = VtDirType;
18353be74836SDavid du Colombier e.flags = VtEntryActive;
18363be74836SDavid du Colombier e.size = 3*VtEntrySize;
18373be74836SDavid du Colombier
18383be74836SDavid du Colombier root = nil;
18393be74836SDavid du Colombier if((r = vtfileopenroot(fs->cache, &e)) == nil)
18403be74836SDavid du Colombier goto Err;
18413be74836SDavid du Colombier if(debug)
18423be74836SDavid du Colombier fprint(2, "r %p\n", r);
18433be74836SDavid du Colombier root = _vacfileroot(fs, r);
18443be74836SDavid du Colombier if(debug)
18453be74836SDavid du Colombier fprint(2, "root %p\n", root);
18463be74836SDavid du Colombier vtfileclose(r);
18473be74836SDavid du Colombier if(root == nil)
18483be74836SDavid du Colombier goto Err;
18493be74836SDavid du Colombier fs->root = root;
18503be74836SDavid du Colombier return fs;
18513be74836SDavid du Colombier Err:
18523be74836SDavid du Colombier if(root)
18533be74836SDavid du Colombier vacfiledecref(root);
18543be74836SDavid du Colombier vacfsclose(fs);
18553be74836SDavid du Colombier return nil;
18563be74836SDavid du Colombier }
18573be74836SDavid du Colombier
18583be74836SDavid du Colombier int
vacfsmode(VacFs * fs)18593be74836SDavid du Colombier vacfsmode(VacFs *fs)
18603be74836SDavid du Colombier {
18613be74836SDavid du Colombier return fs->mode;
18623be74836SDavid du Colombier }
18633be74836SDavid du Colombier
18643be74836SDavid du Colombier VacFile*
vacfsgetroot(VacFs * fs)18653be74836SDavid du Colombier vacfsgetroot(VacFs *fs)
18663be74836SDavid du Colombier {
18673be74836SDavid du Colombier return vacfileincref(fs->root);
18683be74836SDavid du Colombier }
18693be74836SDavid du Colombier
18703be74836SDavid du Colombier int
vacfsgetblocksize(VacFs * fs)18713be74836SDavid du Colombier vacfsgetblocksize(VacFs *fs)
18723be74836SDavid du Colombier {
18733be74836SDavid du Colombier return fs->bsize;
18743be74836SDavid du Colombier }
18753be74836SDavid du Colombier
18763be74836SDavid du Colombier int
vacfsgetscore(VacFs * fs,u8int * score)18773be74836SDavid du Colombier vacfsgetscore(VacFs *fs, u8int *score)
18783be74836SDavid du Colombier {
18793be74836SDavid du Colombier memmove(score, fs->score, VtScoreSize);
18803be74836SDavid du Colombier return 0;
18813be74836SDavid du Colombier }
18823be74836SDavid du Colombier
18833be74836SDavid du Colombier int
_vacfsnextqid(VacFs * fs,uvlong * qid)18843be74836SDavid du Colombier _vacfsnextqid(VacFs *fs, uvlong *qid)
18853be74836SDavid du Colombier {
18863be74836SDavid du Colombier ++fs->qid;
18873be74836SDavid du Colombier *qid = fs->qid;
18883be74836SDavid du Colombier return 0;
18893be74836SDavid du Colombier }
18903be74836SDavid du Colombier
18913be74836SDavid du Colombier void
vacfsjumpqid(VacFs * fs,uvlong step)18923be74836SDavid du Colombier vacfsjumpqid(VacFs *fs, uvlong step)
18933be74836SDavid du Colombier {
18943be74836SDavid du Colombier fs->qid += step;
18953be74836SDavid du Colombier }
18963be74836SDavid du Colombier
18973be74836SDavid du Colombier /*
18983be74836SDavid du Colombier * Set *maxqid to the maximum qid expected in this file system.
18993be74836SDavid du Colombier * In newer vac archives, the maximum qid is stored in the
19003be74836SDavid du Colombier * qidspace VacDir annotation. In older vac archives, the root
19013be74836SDavid du Colombier * got created last, so it had the maximum qid.
19023be74836SDavid du Colombier */
19033be74836SDavid du Colombier int
vacfsgetmaxqid(VacFs * fs,uvlong * maxqid)19043be74836SDavid du Colombier vacfsgetmaxqid(VacFs *fs, uvlong *maxqid)
19053be74836SDavid du Colombier {
19063be74836SDavid du Colombier VacDir vd;
19073be74836SDavid du Colombier
19083be74836SDavid du Colombier if(vacfilegetdir(fs->root, &vd) < 0)
19093be74836SDavid du Colombier return -1;
19103be74836SDavid du Colombier if(vd.qidspace)
19113be74836SDavid du Colombier *maxqid = vd.qidmax;
191249223a73SDavid du Colombier else
19133be74836SDavid du Colombier *maxqid = vd.qid;
19143be74836SDavid du Colombier vdcleanup(&vd);
19153be74836SDavid du Colombier return 0;
1916aedc1c01SDavid du Colombier }
19173be74836SDavid du Colombier
19183be74836SDavid du Colombier
19193be74836SDavid du Colombier void
vacfsclose(VacFs * fs)19203be74836SDavid du Colombier vacfsclose(VacFs *fs)
19213be74836SDavid du Colombier {
19223be74836SDavid du Colombier if(fs->root)
19233be74836SDavid du Colombier vacfiledecref(fs->root);
19243be74836SDavid du Colombier fs->root = nil;
19253be74836SDavid du Colombier vtcachefree(fs->cache);
19263be74836SDavid du Colombier vtfree(fs);
19273be74836SDavid du Colombier }
19283be74836SDavid du Colombier
19293be74836SDavid du Colombier /*
19303be74836SDavid du Colombier * Create a fresh vac fs.
19313be74836SDavid du Colombier */
19323be74836SDavid du Colombier VacFs *
vacfscreate(VtConn * z,int bsize,int ncache)19333be74836SDavid du Colombier vacfscreate(VtConn *z, int bsize, int ncache)
19343be74836SDavid du Colombier {
19353be74836SDavid du Colombier VacFs *fs;
19363be74836SDavid du Colombier VtFile *f;
19373be74836SDavid du Colombier uchar buf[VtEntrySize], metascore[VtScoreSize];
19383be74836SDavid du Colombier VtEntry e;
19393be74836SDavid du Colombier VtBlock *b;
19403be74836SDavid du Colombier MetaBlock mb;
19413be74836SDavid du Colombier VacDir vd;
19423be74836SDavid du Colombier MetaEntry me;
19433be74836SDavid du Colombier int psize;
19443be74836SDavid du Colombier int mbsize;
19453be74836SDavid du Colombier
19463be74836SDavid du Colombier if((fs = vacfsalloc(z, bsize, ncache, VtORDWR)) == nil)
19473be74836SDavid du Colombier return nil;
19483be74836SDavid du Colombier
19493be74836SDavid du Colombier /*
19503be74836SDavid du Colombier * Fake up an empty vac fs.
19513be74836SDavid du Colombier */
19523be74836SDavid du Colombier psize = bsize;
19533be74836SDavid du Colombier f = vtfilecreateroot(fs->cache, psize, bsize, VtDirType);
19543be74836SDavid du Colombier vtfilelock(f, VtORDWR);
19553be74836SDavid du Colombier
19563be74836SDavid du Colombier /* Metablocks can't be too big -- they have 16-bit offsets in them. */
19573be74836SDavid du Colombier mbsize = bsize;
19583be74836SDavid du Colombier if(mbsize >= 56*1024)
19593be74836SDavid du Colombier mbsize = 56*1024;
19603be74836SDavid du Colombier
19613be74836SDavid du Colombier /* Write metablock containing root directory VacDir. */
19623be74836SDavid du Colombier b = vtcacheallocblock(fs->cache, VtDataType);
19633be74836SDavid du Colombier mbinit(&mb, b->data, mbsize, mbsize/BytesPerEntry);
19643be74836SDavid du Colombier memset(&vd, 0, sizeof vd);
19653be74836SDavid du Colombier vd.elem = "/";
19663be74836SDavid du Colombier vd.mode = 0777|ModeDir;
19673be74836SDavid du Colombier vd.uid = "vac";
19683be74836SDavid du Colombier vd.gid = "vac";
19693be74836SDavid du Colombier vd.mid = "";
19703be74836SDavid du Colombier me.size = vdsize(&vd, VacDirVersion);
19713be74836SDavid du Colombier me.p = mballoc(&mb, me.size);
19723be74836SDavid du Colombier vdpack(&vd, &me, VacDirVersion);
19733be74836SDavid du Colombier mbinsert(&mb, 0, &me);
19743be74836SDavid du Colombier mbpack(&mb);
19753be74836SDavid du Colombier vtblockwrite(b);
19763be74836SDavid du Colombier memmove(metascore, b->score, VtScoreSize);
19773be74836SDavid du Colombier vtblockput(b);
19783be74836SDavid du Colombier
19793be74836SDavid du Colombier /* First entry: empty venti directory stream. */
19803be74836SDavid du Colombier memset(&e, 0, sizeof e);
19813be74836SDavid du Colombier e.flags = VtEntryActive;
19823be74836SDavid du Colombier e.psize = psize;
19833be74836SDavid du Colombier e.dsize = bsize;
19843be74836SDavid du Colombier e.type = VtDirType;
19853be74836SDavid du Colombier memmove(e.score, vtzeroscore, VtScoreSize);
19863be74836SDavid du Colombier vtentrypack(&e, buf, 0);
19873be74836SDavid du Colombier vtfilewrite(f, buf, VtEntrySize, 0);
19883be74836SDavid du Colombier
19893be74836SDavid du Colombier /* Second entry: empty metadata stream. */
19903be74836SDavid du Colombier e.type = VtDataType;
19913be74836SDavid du Colombier e.dsize = mbsize;
19923be74836SDavid du Colombier vtentrypack(&e, buf, 0);
19933be74836SDavid du Colombier vtfilewrite(f, buf, VtEntrySize, VtEntrySize);
19943be74836SDavid du Colombier
19953be74836SDavid du Colombier /* Third entry: metadata stream with root directory. */
19963be74836SDavid du Colombier memmove(e.score, metascore, VtScoreSize);
19973be74836SDavid du Colombier e.size = mbsize;
19983be74836SDavid du Colombier vtentrypack(&e, buf, 0);
19993be74836SDavid du Colombier vtfilewrite(f, buf, VtEntrySize, VtEntrySize*2);
20003be74836SDavid du Colombier
20013be74836SDavid du Colombier vtfileflush(f);
20023be74836SDavid du Colombier vtfileunlock(f);
20033be74836SDavid du Colombier
20043be74836SDavid du Colombier /* Now open it as a vac fs. */
20053be74836SDavid du Colombier fs->root = _vacfileroot(fs, f);
20063be74836SDavid du Colombier if(fs->root == nil){
20073be74836SDavid du Colombier werrstr("vacfileroot: %r");
20083be74836SDavid du Colombier vacfsclose(fs);
20093be74836SDavid du Colombier return nil;
20103be74836SDavid du Colombier }
20113be74836SDavid du Colombier
20123be74836SDavid du Colombier return fs;
20133be74836SDavid du Colombier }
20143be74836SDavid du Colombier
20153be74836SDavid du Colombier int
vacfssync(VacFs * fs)20163be74836SDavid du Colombier vacfssync(VacFs *fs)
20173be74836SDavid du Colombier {
20183be74836SDavid du Colombier uchar buf[1024];
20193be74836SDavid du Colombier VtEntry e;
20203be74836SDavid du Colombier VtFile *f;
20213be74836SDavid du Colombier VtRoot root;
20223be74836SDavid du Colombier
20233be74836SDavid du Colombier /* Sync the entire vacfs to disk. */
20243be74836SDavid du Colombier if(vacfileflush(fs->root, 1) < 0)
20253be74836SDavid du Colombier return -1;
20263be74836SDavid du Colombier if(vtfilelock(fs->root->up->msource, -1) < 0)
20273be74836SDavid du Colombier return -1;
20283be74836SDavid du Colombier if(vtfileflush(fs->root->up->msource) < 0){
20293be74836SDavid du Colombier vtfileunlock(fs->root->up->msource);
20303be74836SDavid du Colombier return -1;
20313be74836SDavid du Colombier }
20323be74836SDavid du Colombier vtfileunlock(fs->root->up->msource);
20333be74836SDavid du Colombier
20343be74836SDavid du Colombier /* Prepare the dir stream for the root block. */
20353be74836SDavid du Colombier if(getentry(fs->root->source, &e) < 0)
20363be74836SDavid du Colombier return -1;
20373be74836SDavid du Colombier vtentrypack(&e, buf, 0);
20383be74836SDavid du Colombier if(getentry(fs->root->msource, &e) < 0)
20393be74836SDavid du Colombier return -1;
20403be74836SDavid du Colombier vtentrypack(&e, buf, 1);
20413be74836SDavid du Colombier if(getentry(fs->root->up->msource, &e) < 0)
20423be74836SDavid du Colombier return -1;
20433be74836SDavid du Colombier vtentrypack(&e, buf, 2);
20443be74836SDavid du Colombier
20453be74836SDavid du Colombier f = vtfilecreateroot(fs->cache, fs->bsize, fs->bsize, VtDirType);
20463be74836SDavid du Colombier vtfilelock(f, VtORDWR);
20473be74836SDavid du Colombier if(vtfilewrite(f, buf, 3*VtEntrySize, 0) < 0
20483be74836SDavid du Colombier || vtfileflush(f) < 0){
20493be74836SDavid du Colombier vtfileunlock(f);
20503be74836SDavid du Colombier vtfileclose(f);
20513be74836SDavid du Colombier return -1;
20523be74836SDavid du Colombier }
20533be74836SDavid du Colombier vtfileunlock(f);
20543be74836SDavid du Colombier if(getentry(f, &e) < 0){
20553be74836SDavid du Colombier vtfileclose(f);
20563be74836SDavid du Colombier return -1;
20573be74836SDavid du Colombier }
20583be74836SDavid du Colombier vtfileclose(f);
20593be74836SDavid du Colombier
20603be74836SDavid du Colombier /* Build a root block. */
20613be74836SDavid du Colombier memset(&root, 0, sizeof root);
20623be74836SDavid du Colombier strcpy(root.type, "vac");
20633be74836SDavid du Colombier strcpy(root.name, fs->name);
20643be74836SDavid du Colombier memmove(root.score, e.score, VtScoreSize);
20653be74836SDavid du Colombier root.blocksize = fs->bsize;
20663be74836SDavid du Colombier memmove(root.prev, fs->score, VtScoreSize);
20673be74836SDavid du Colombier vtrootpack(&root, buf);
20683be74836SDavid du Colombier if(vtwrite(fs->z, fs->score, VtRootType, buf, VtRootSize) < 0){
20693be74836SDavid du Colombier werrstr("writing root: %r");
20703be74836SDavid du Colombier return -1;
20713be74836SDavid du Colombier }
20723be74836SDavid du Colombier if(vtsync(fs->z) < 0)
20733be74836SDavid du Colombier return -1;
20743be74836SDavid du Colombier return 0;
20753be74836SDavid du Colombier }
20763be74836SDavid du Colombier
20773be74836SDavid du Colombier int
vacfiledsize(VacFile * f)20783be74836SDavid du Colombier vacfiledsize(VacFile *f)
20793be74836SDavid du Colombier {
20803be74836SDavid du Colombier VtEntry e;
20813be74836SDavid du Colombier
20823be74836SDavid du Colombier if(vacfilegetentries(f,&e,nil) < 0)
20833be74836SDavid du Colombier return -1;
20843be74836SDavid du Colombier return e.dsize;
20853be74836SDavid du Colombier }
20863be74836SDavid du Colombier
20873be74836SDavid du Colombier /*
20883be74836SDavid du Colombier * Does block b of f have the same SHA1 hash as the n bytes at buf?
20893be74836SDavid du Colombier */
20903be74836SDavid du Colombier int
sha1matches(VacFile * f,ulong b,uchar * buf,int n)20913be74836SDavid du Colombier sha1matches(VacFile *f, ulong b, uchar *buf, int n)
20923be74836SDavid du Colombier {
20933be74836SDavid du Colombier uchar fscore[VtScoreSize];
20943be74836SDavid du Colombier uchar bufscore[VtScoreSize];
20953be74836SDavid du Colombier
20963be74836SDavid du Colombier if(vacfileblockscore(f, b, fscore) < 0)
20973be74836SDavid du Colombier return 0;
20983be74836SDavid du Colombier n = vtzerotruncate(VtDataType, buf, n);
20993be74836SDavid du Colombier sha1(buf, n, bufscore, nil);
21003be74836SDavid du Colombier if(memcmp(bufscore, fscore, VtScoreSize) == 0)
21013be74836SDavid du Colombier return 1;
21023be74836SDavid du Colombier return 0;
21033be74836SDavid du Colombier }
21043be74836SDavid du Colombier
2105