]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/vac/file.c
exec(2): fix prototypes
[plan9front.git] / sys / src / cmd / vac / file.c
1 #include "stdinc.h"
2 #include "vac.h"
3 #include "dat.h"
4 #include "fns.h"
5 #include "error.h"
6
7 #define debug 0
8
9 /*
10  * Vac file system.  This is a simplified version of the same code in Fossil.
11  * 
12  * The locking order in the tree is upward: a thread can hold the lock
13  * for a VacFile and then acquire the lock of f->up (the parent),
14  * but not vice-versa.
15  * 
16  * A vac file is one or two venti files.  Plain data files are one venti file,
17  * while directores are two: a venti data file containing traditional
18  * directory entries, and a venti directory file containing venti 
19  * directory entries.  The traditional directory entries in the data file
20  * contain integers indexing into the venti directory entry file.
21  * It's a little complicated, but it makes the data usable by standard
22  * tools like venti/copy.
23  *
24  */
25  
26 static int filemetaflush(VacFile*, char*);
27
28 struct VacFile
29 {
30         VacFs   *fs;    /* immutable */
31
32         /* meta data for file: protected by the lk in the parent */
33         int             ref;    /* holds this data structure up */
34
35         int             partial;        /* file was never really open */
36         int             removed;        /* file has been removed */
37         int             dirty;  /* dir is dirty with respect to meta data in block */
38         u32int  boff;           /* block offset within msource for this file's metadata */
39         VacDir  dir;            /* metadata for this file */
40         VacFile *up;            /* parent file */
41         VacFile *next;  /* sibling */
42
43         RWLock  lk;             /* lock for the following */
44         VtFile  *source;        /* actual data */
45         VtFile  *msource;       /* metadata for children in a directory */
46         VacFile *down;  /* children */
47         int             mode;
48         
49         uvlong  qidoffset;      /* qid offset */
50 };
51
52 static VacFile*
53 filealloc(VacFs *fs)
54 {
55         VacFile *f;
56
57         f = vtmallocz(sizeof(VacFile));
58         f->ref = 1;
59         f->fs = fs;
60         f->boff = NilBlock;
61         f->mode = fs->mode;
62         return f;
63 }
64
65 static void
66 filefree(VacFile *f)
67 {
68         vtfileclose(f->source);
69         vtfileclose(f->msource);
70         vdcleanup(&f->dir);
71         memset(f, ~0, sizeof *f);       /* paranoia */
72         vtfree(f);
73 }
74
75 static int
76 chksource(VacFile *f)
77 {
78         if(f->partial)
79                 return 0;
80
81         if(f->source == nil
82         || ((f->dir.mode & ModeDir) && f->msource == nil)){
83                 werrstr(ERemoved);
84                 return -1;
85         }
86         return 0;
87 }
88
89 static int
90 filelock(VacFile *f)
91 {
92         wlock(&f->lk);
93         if(chksource(f) < 0){
94                 wunlock(&f->lk);
95                 return -1;
96         }
97         return 0;
98 }
99
100 static void
101 fileunlock(VacFile *f)
102 {
103         wunlock(&f->lk);
104 }
105
106 static int
107 filerlock(VacFile *f)
108 {
109         rlock(&f->lk);
110         if(chksource(f) < 0){
111                 runlock(&f->lk);
112                 return -1;
113         }
114         return 0;
115 }
116
117 static void
118 filerunlock(VacFile *f)
119 {
120         runlock(&f->lk);
121 }
122
123 /*
124  * The file metadata, like f->dir and f->ref,
125  * are synchronized via the parent's lock.
126  * This is why locking order goes up.
127  */
128 static void
129 filemetalock(VacFile *f)
130 {
131         assert(f->up != nil);
132         wlock(&f->up->lk);
133 }
134
135 static void
136 filemetaunlock(VacFile *f)
137 {
138         wunlock(&f->up->lk);
139 }
140
141 uvlong
142 vacfilegetid(VacFile *f)
143 {
144         /* immutable */
145         return f->qidoffset + f->dir.qid;
146 }
147
148 uvlong
149 vacfilegetqidoffset(VacFile *f)
150 {
151         return f->qidoffset;
152 }
153
154 ulong
155 vacfilegetmcount(VacFile *f)
156 {
157         ulong mcount;
158
159         filemetalock(f);
160         mcount = f->dir.mcount;
161         filemetaunlock(f);
162         return mcount;
163 }
164
165 ulong
166 vacfilegetmode(VacFile *f)
167 {
168         ulong mode;
169
170         filemetalock(f);
171         mode = f->dir.mode;
172         filemetaunlock(f);
173         return mode;
174 }
175
176 int
177 vacfileisdir(VacFile *f)
178 {
179         /* immutable */
180         return (f->dir.mode & ModeDir) != 0;
181 }
182
183 int
184 vacfileisroot(VacFile *f)
185 {
186         return f == f->fs->root;
187 }
188
189 /*
190  * The files are reference counted, and while the reference
191  * is bigger than zero, each file can be found in its parent's
192  * f->down list (chains via f->next), so that multiple threads
193  * end up sharing a VacFile* when referring to the same file.
194  *
195  * Each VacFile holds a reference to its parent.
196  */
197 VacFile*
198 vacfileincref(VacFile *vf)
199 {
200         filemetalock(vf);
201         assert(vf->ref > 0);
202         vf->ref++;
203         filemetaunlock(vf);
204         return vf;
205 }
206
207 int
208 vacfiledecref(VacFile *f)
209 {
210         VacFile *p, *q, **qq;
211
212         if(f->up == nil){
213                 /* never linked in */
214                 assert(f->ref == 1);
215                 filefree(f);
216                 return 0;
217         }
218         
219         filemetalock(f);
220         f->ref--;
221         if(f->ref > 0){
222                 filemetaunlock(f);
223                 return -1;
224         }
225         assert(f->ref == 0);
226         assert(f->down == nil);
227
228         if(f->source && vtfilelock(f->source, -1) >= 0){
229                 vtfileflush(f->source);
230                 vtfileunlock(f->source);
231         }
232         if(f->msource && vtfilelock(f->msource, -1) >= 0){
233                 vtfileflush(f->msource);
234                 vtfileunlock(f->msource);
235         }
236
237         /*
238          * Flush f's directory information to the cache.
239          */
240         filemetaflush(f, nil);
241
242         p = f->up;
243         qq = &p->down;
244         for(q = *qq; q; q = *qq){
245                 if(q == f)
246                         break;
247                 qq = &q->next;
248         }
249         assert(q != nil);
250         *qq = f->next;
251
252         filemetaunlock(f);
253         filefree(f);
254         vacfiledecref(p);
255         return 0;
256 }
257
258
259 /* 
260  * Construct a vacfile for the root of a vac tree, given the 
261  * venti file for the root information.  That venti file is a 
262  * directory file containing VtEntries for three more venti files:
263  * the two venti files making up the root directory, and a 
264  * third venti file that would be the metadata half of the 
265  * "root's parent".
266  *
267  * Fossil generates slightly different vac files, due to a now
268  * impossible-to-change bug, which contain a VtEntry
269  * for just one venti file, that itself contains the expected
270  * three directory entries.  Sigh.
271  */
272 VacFile*
273 _vacfileroot(VacFs *fs, VtFile *r)
274 {
275         int redirected;
276         char err[ERRMAX];       
277         VtBlock *b;
278         VtFile *r0, *r1, *r2;
279         MetaBlock mb;
280         MetaEntry me;
281         VacFile *root, *mr;
282
283         redirected = 0;
284 Top:
285         b = nil;
286         root = nil;
287         mr = nil;
288         r1 = nil;
289         r2 = nil;
290
291         if(vtfilelock(r, -1) < 0)
292                 return nil;
293         r0 = vtfileopen(r, 0, fs->mode);
294         if(debug)
295                 fprint(2, "r0 %p\n", r0);
296         if(r0 == nil)
297                 goto Err;
298         r2 = vtfileopen(r, 2, fs->mode);
299         if(debug)
300                 fprint(2, "r2 %p\n", r2);
301         if(r2 == nil){
302                 /*
303                  * some vac files (e.g., from fossil)
304                  * have an extra layer of indirection.
305                  */
306                 rerrstr(err, sizeof err);
307                 if(!redirected && strstr(err, "not active")){
308                         redirected = 1;
309                         vtfileunlock(r);
310                         r = r0;
311                         goto Top;
312                 }
313                 goto Err;
314         }
315         r1 = vtfileopen(r, 1, fs->mode);
316         if(debug)
317                 fprint(2, "r1 %p\n", r1);
318         if(r1 == nil)
319                 goto Err;
320
321         mr = filealloc(fs);
322         mr->msource = r2;
323         r2 = nil;
324
325         root = filealloc(fs);
326         root->boff = 0;
327         root->up = mr;
328         root->source = r0;
329         r0 = nil;
330         root->msource = r1;
331         r1 = nil;
332
333         mr->down = root;
334         vtfileunlock(r);
335
336         if(vtfilelock(mr->msource, VtOREAD) < 0)
337                 goto Err1;
338         b = vtfileblock(mr->msource, 0, VtOREAD);
339         vtfileunlock(mr->msource);
340         if(b == nil)
341                 goto Err1;
342
343         if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
344                 goto Err1;
345
346         meunpack(&me, &mb, 0);
347         if(vdunpack(&root->dir, &me) < 0)
348                 goto Err1;
349         vtblockput(b);
350
351         return root;
352 Err:
353         vtfileunlock(r);
354 Err1:
355         vtblockput(b);
356         if(r0)
357                 vtfileclose(r0);
358         if(r1)
359                 vtfileclose(r1);
360         if(r2)
361                 vtfileclose(r2);
362         if(mr)
363                 filefree(mr);
364         if(root)
365                 filefree(root);
366
367         return nil;
368 }
369
370 /*
371  * Vac directories are a sequence of metablocks, each of which
372  * contains a bunch of metaentries sorted by file name.
373  * The whole sequence isn't sorted, though, so you still have
374  * to look at every block to find a given name.
375  * Dirlookup looks in f for an element name elem.
376  * It returns a new VacFile with the dir, boff, and mode
377  * filled in, but the sources (venti files) are not, and f is 
378  * not yet linked into the tree.  These details must be taken
379  * care of by the caller.
380  *
381  * f must be locked, f->msource must not.
382  */
383 static VacFile*
384 dirlookup(VacFile *f, char *elem)
385 {
386         int i;
387         MetaBlock mb;
388         MetaEntry me;
389         VtBlock *b;
390         VtFile *meta;
391         VacFile *ff;
392         u32int bo, nb;
393
394         meta = f->msource;
395         b = nil;
396         if(vtfilelock(meta, -1) < 0)
397                 return nil;
398         nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
399         for(bo=0; bo<nb; bo++){
400                 b = vtfileblock(meta, bo, VtOREAD);
401                 if(b == nil)
402                         goto Err;
403                 if(mbunpack(&mb, b->data, meta->dsize) < 0)
404                         goto Err;
405                 if(mbsearch(&mb, elem, &i, &me) >= 0){
406                         ff = filealloc(f->fs);
407                         if(vdunpack(&ff->dir, &me) < 0){
408                                 filefree(ff);
409                                 goto Err;
410                         }
411                         ff->qidoffset = f->qidoffset + ff->dir.qidoffset;
412                         vtfileunlock(meta);
413                         vtblockput(b);
414                         ff->boff = bo;
415                         ff->mode = f->mode;
416                         return ff;
417                 }
418                 vtblockput(b);
419                 b = nil;
420         }
421         werrstr(ENoFile);
422         /* fall through */
423 Err:
424         vtfileunlock(meta);
425         vtblockput(b);
426         return nil;
427 }
428
429 /*
430  * Open the venti file at offset in the directory f->source.
431  * f is locked.
432  */
433 static VtFile *
434 fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
435 {
436         VtFile *r;
437
438         if((r = vtfileopen(f->source, offset, mode)) == nil)
439                 return nil;
440         if(r == nil)
441                 return nil;
442         if(r->gen != gen){
443                 werrstr(ERemoved);
444                 vtfileclose(r);
445                 return nil;
446         }
447         if(r->dir != dir && r->mode != -1){
448                 werrstr(EBadMeta);
449                 vtfileclose(r);
450                 return nil;
451         }
452         return r;
453 }
454
455 VacFile*
456 vacfilegetparent(VacFile *f)
457 {
458         if(vacfileisroot(f))
459                 return vacfileincref(f);
460         return vacfileincref(f->up);
461 }
462
463 /*
464  * Given an unlocked vacfile (directory) f,
465  * return the vacfile named elem in f.
466  * Interprets . and .. as a convenience to callers.
467  */
468 VacFile*
469 vacfilewalk(VacFile *f, char *elem)
470 {
471         VacFile *ff;
472
473         if(elem[0] == 0){
474                 werrstr(EBadPath);
475                 return nil;
476         }
477
478         if(!vacfileisdir(f)){
479                 werrstr(ENotDir);
480                 return nil;
481         }
482
483         if(strcmp(elem, ".") == 0)
484                 return vacfileincref(f);
485
486         if(strcmp(elem, "..") == 0)
487                 return vacfilegetparent(f);
488
489         if(filelock(f) < 0)
490                 return nil;
491
492         for(ff = f->down; ff; ff=ff->next){
493                 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
494                         ff->ref++;
495                         goto Exit;
496                 }
497         }
498
499         ff = dirlookup(f, elem);
500         if(ff == nil)
501                 goto Err;
502
503         if(ff->dir.mode & ModeSnapshot)
504                 ff->mode = VtOREAD;
505
506         if(vtfilelock(f->source, f->mode) < 0)
507                 goto Err;
508         if(ff->dir.mode & ModeDir){
509                 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
510                 ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
511                 if(ff->source == nil || ff->msource == nil)
512                         goto Err1;
513         }else{
514                 ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
515                 if(ff->source == nil)
516                         goto Err1;
517         }
518         vtfileunlock(f->source);
519
520         /* link in and up parent ref count */
521         ff->next = f->down;
522         f->down = ff;
523         ff->up = f;
524         vacfileincref(f);
525 Exit:
526         fileunlock(f);
527         return ff;
528
529 Err1:
530         vtfileunlock(f->source);
531 Err:
532         fileunlock(f);
533         if(ff != nil)
534                 vacfiledecref(ff);
535         return nil;
536 }
537
538 /* 
539  * Open a path in the vac file system: 
540  * just walk each element one at a time.
541  */
542 VacFile*
543 vacfileopen(VacFs *fs, char *path)
544 {
545         VacFile *f, *ff;
546         char *p, elem[VtMaxStringSize], *opath;
547         int n;
548
549         f = fs->root;
550         vacfileincref(f);
551         opath = path;
552         while(*path != 0){
553                 for(p = path; *p && *p != '/'; p++)
554                         ;
555                 n = p - path;
556                 if(n > 0){
557                         if(n > VtMaxStringSize){
558                                 werrstr("%s: element too long", EBadPath);
559                                 goto Err;
560                         }
561                         memmove(elem, path, n);
562                         elem[n] = 0;
563                         ff = vacfilewalk(f, elem);
564                         if(ff == nil){
565                                 werrstr("%.*s: %r", utfnlen(opath, p-opath), opath);
566                                 goto Err;
567                         }
568                         vacfiledecref(f);
569                         f = ff;
570                 }
571                 if(*p == '/')
572                         p++;
573                 path = p;
574         }
575         return f;
576 Err:
577         vacfiledecref(f);
578         return nil;
579 }
580
581 /*
582  * Extract the score for the bn'th block in f.
583  */
584 int
585 vacfileblockscore(VacFile *f, u32int bn, u8int *score)
586 {
587         VtFile *s;
588         uvlong size;
589         int dsize, ret;
590
591         ret = -1;
592         if(filerlock(f) < 0)
593                 return -1;
594         if(vtfilelock(f->source, VtOREAD) < 0)
595                 goto out;
596
597         s = f->source;
598         dsize = s->dsize;
599         size = vtfilegetsize(s);
600         if((uvlong)bn*dsize >= size)
601                 goto out1;
602         ret = vtfileblockscore(f->source, bn, score);
603
604 out1:
605         vtfileunlock(f->source);
606 out:
607         filerunlock(f);
608         return ret;
609 }
610
611 /*
612  * Read data from f.
613  */
614 int
615 vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
616 {
617         int n;
618
619         if(offset < 0){
620                 werrstr(EBadOffset);
621                 return -1;
622         }
623         if(filerlock(f) < 0)
624                 return -1;
625         if(vtfilelock(f->source, VtOREAD) < 0){
626                 filerunlock(f);
627                 return -1;
628         }
629         n = vtfileread(f->source, buf, cnt, offset);
630         vtfileunlock(f->source);
631         filerunlock(f);
632         return n;
633 }
634
635 static int
636 getentry(VtFile *f, VtEntry *e)
637 {
638         if(vtfilelock(f, VtOREAD) < 0)
639                 return -1;
640         if(vtfilegetentry(f, e) < 0){
641                 vtfileunlock(f);
642                 return -1;
643         }
644         vtfileunlock(f);
645         if(vtglobaltolocal(e->score) != NilBlock){
646                 werrstr("internal error - data not on venti");
647                 return -1;
648         }
649         return 0;
650 }
651
652 /*
653  * Get the VtEntries for the data contained in f.
654  */
655 int
656 vacfilegetentries(VacFile *f, VtEntry *e, VtEntry *me)
657 {
658         if(filerlock(f) < 0)
659                 return -1;
660         if(e && getentry(f->source, e) < 0){
661                 filerunlock(f);
662                 return -1;
663         }
664         if(me){
665                 if(f->msource == nil)
666                         memset(me, 0, sizeof *me);
667                 else if(getentry(f->msource, me) < 0){
668                         filerunlock(f);
669                         return -1;
670                 }
671         }
672         filerunlock(f);
673         return 0;
674 }
675
676 /*
677  * Get the file's size.
678  */
679 int
680 vacfilegetsize(VacFile *f, uvlong *size)
681 {
682         if(filerlock(f) < 0)
683                 return -1;
684         if(vtfilelock(f->source, VtOREAD) < 0){
685                 filerunlock(f);
686                 return -1;
687         }
688         *size = vtfilegetsize(f->source);
689         vtfileunlock(f->source);
690         filerunlock(f);
691
692         return 0;
693 }
694
695 /*
696  * Directory reading.
697  *
698  * A VacDirEnum is a buffer containing directory entries.
699  * Directory entries contain malloced strings and need to 
700  * be cleaned up with vdcleanup.  The invariant in the 
701  * VacDirEnum is that the directory entries between
702  * vde->i and vde->n are owned by the vde and need to
703  * be cleaned up if it is closed.  Those from 0 up to vde->i
704  * have been handed to the reader, and the reader must 
705  * take care of calling vdcleanup as appropriate.
706  */
707 VacDirEnum*
708 vdeopen(VacFile *f)
709 {
710         VacDirEnum *vde;
711         VacFile *p;
712
713         if(!vacfileisdir(f)){
714                 werrstr(ENotDir);
715                 return nil;
716         }
717
718         /*
719          * There might be changes to this directory's children
720          * that have not been flushed out into the cache yet.
721          * Those changes are only available if we look at the 
722          * VacFile structures directory.  But the directory reader
723          * is going to read the cache blocks directly, so update them.
724          */
725         if(filelock(f) < 0)
726                 return nil;
727         for(p=f->down; p; p=p->next)
728                 filemetaflush(p, nil);
729         fileunlock(f);
730
731         vde = vtmallocz(sizeof(VacDirEnum));
732         vde->file = vacfileincref(f);
733
734         return vde;
735 }
736
737 /*
738  * Figure out the size of the directory entry at offset.
739  * The rest of the metadata is kept in the data half,
740  * but since venti has to track the data size anyway,
741  * we just use that one and avoid updating the directory
742  * each time the file size changes.
743  */
744 static int
745 direntrysize(VtFile *s, ulong offset, ulong gen, uvlong *size)
746 {
747         VtBlock *b;
748         ulong bn;
749         VtEntry e;
750         int epb;
751
752         epb = s->dsize/VtEntrySize;
753         bn = offset/epb;
754         offset -= bn*epb;
755
756         b = vtfileblock(s, bn, VtOREAD);
757         if(b == nil)
758                 goto Err;
759         if(vtentryunpack(&e, b->data, offset) < 0)
760                 goto Err;
761
762         /* dangling entries are returned as zero size */
763         if(!(e.flags & VtEntryActive) || e.gen != gen)
764                 *size = 0;
765         else
766                 *size = e.size;
767         vtblockput(b);
768         return 0;
769
770 Err:
771         vtblockput(b);
772         return -1;
773 }
774
775 /*
776  * Fill in vde with a new batch of directory entries.
777  */
778 static int
779 vdefill(VacDirEnum *vde)
780 {
781         int i, n;
782         VtFile *meta, *source;
783         MetaBlock mb;
784         MetaEntry me;
785         VacFile *f;
786         VtBlock *b;
787         VacDir *de;
788
789         /* clean up first */
790         for(i=vde->i; i<vde->n; i++)
791                 vdcleanup(vde->buf+i);
792         vtfree(vde->buf);
793         vde->buf = nil;
794         vde->i = 0;
795         vde->n = 0;
796
797         f = vde->file;
798
799         source = f->source;
800         meta = f->msource;
801
802         b = vtfileblock(meta, vde->boff, VtOREAD);
803         if(b == nil)
804                 goto Err;
805         if(mbunpack(&mb, b->data, meta->dsize) < 0)
806                 goto Err;
807
808         n = mb.nindex;
809         vde->buf = vtmalloc(n * sizeof(VacDir));
810
811         for(i=0; i<n; i++){
812                 de = vde->buf + i;
813                 meunpack(&me, &mb, i);
814                 if(vdunpack(de, &me) < 0)
815                         goto Err;
816                 vde->n++;
817                 if(!(de->mode & ModeDir))
818                 if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
819                         goto Err;
820         }
821         vde->boff++;
822         vtblockput(b);
823         return 0;
824 Err:
825         vtblockput(b);
826         return -1;
827 }
828
829 /*
830  * Read a single directory entry from vde into de.
831  * Returns -1 on error, 0 on EOF, and 1 on success.
832  * When it returns 1, it becomes the caller's responsibility
833  * to call vdcleanup(de) to free the strings contained
834  * inside, or else to call vdunread to give it back.
835  */
836 int
837 vderead(VacDirEnum *vde, VacDir *de)
838 {
839         int ret;
840         VacFile *f;
841         u32int nb;
842
843         f = vde->file;
844         if(filerlock(f) < 0)
845                 return -1;
846
847         if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
848                 filerunlock(f);
849                 return -1;
850         }
851
852         nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
853
854         while(vde->i >= vde->n){
855                 if(vde->boff >= nb){
856                         ret = 0;
857                         goto Return;
858                 }
859                 if(vdefill(vde) < 0){
860                         ret = -1;
861                         goto Return;
862                 }
863         }
864
865         memmove(de, vde->buf + vde->i, sizeof(VacDir));
866         vde->i++;
867         ret = 1;
868
869 Return:
870         vtfileunlock(f->source);
871         vtfileunlock(f->msource);
872         filerunlock(f);
873
874         return ret;
875 }
876
877 /*
878  * "Unread" the last directory entry that was read,
879  * so that the next vderead will return the same one.
880  * If the caller calls vdeunread(vde) it should not call
881  * vdcleanup on the entry being "unread".
882  */
883 int
884 vdeunread(VacDirEnum *vde)
885 {
886         if(vde->i > 0){
887                 vde->i--;
888                 return 0;
889         }
890         return -1;
891 }
892
893 /*
894  * Close the enumerator.
895  */
896 void
897 vdeclose(VacDirEnum *vde)
898 {
899         int i;
900         if(vde == nil)
901                 return;
902         /* free the strings */
903         for(i=vde->i; i<vde->n; i++)
904                 vdcleanup(vde->buf+i);
905         vtfree(vde->buf);
906         vacfiledecref(vde->file);
907         vtfree(vde);
908 }
909
910
911 /*
912  * On to mutation.  If the vac file system has been opened
913  * read-write, then the files and directories can all be edited.
914  * Changes are kept in the in-memory cache until flushed out
915  * to venti, so we must be careful to explicitly flush data 
916  * that we're not likely to modify again.
917  *
918  * Each VacFile has its own copy of its VacDir directory entry
919  * in f->dir, but otherwise the cache is the authoratative source
920  * for data.  Thus, for the most part, it suffices if we just 
921  * call vtfileflushbefore and vtfileflush when we modify things.
922  * There are a few places where we have to remember to write
923  * changed VacDirs back into the cache.  If f->dir *is* out of sync,
924  * then f->dirty should be set.
925  *
926  * The metadata in a directory is, to venti, a plain data file,
927  * but as mentioned above it is actually a sequence of 
928  * MetaBlocks that contain sorted lists of VacDir entries.
929  * The filemetaxxx routines manipulate that stream.
930  */
931
932 /*
933  * Find space in fp for the directory entry dir (not yet written to disk)
934  * and write it to disk, returning NilBlock on failure,
935  * or the block number on success.
936  *
937  * Start is a suggested block number to try.
938  * The caller must have filemetalock'ed f and have
939  * vtfilelock'ed f->up->msource.
940  */
941 static u32int
942 filemetaalloc(VacFile *fp, VacDir *dir, u32int start)
943 {
944         u32int nb, bo;
945         VtBlock *b;
946         MetaBlock mb;
947         int nn;
948         uchar *p;
949         int i, n;
950         MetaEntry me;
951         VtFile *ms;
952         
953         ms = fp->msource;
954         n = vdsize(dir, VacDirVersion);
955         
956         /* Look for a block with room for a new entry of size n. */
957         nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
958         if(start == NilBlock){
959                 if(nb > 0)
960                         start = nb - 1;
961                 else
962                         start = 0;
963         }
964         
965         if(start > nb)
966                 start = nb;
967         for(bo=start; bo<nb; bo++){
968                 if((b = vtfileblock(ms, bo, VtOREAD)) == nil)
969                         goto Err;
970                 if(mbunpack(&mb, b->data, ms->dsize) < 0)
971                         goto Err;
972                 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
973                 if(n <= nn && mb.nindex < mb.maxindex){
974                         /* reopen for writing */
975                         vtblockput(b);
976                         if((b = vtfileblock(ms, bo, VtORDWR)) == nil)
977                                 goto Err;
978                         mbunpack(&mb, b->data, ms->dsize);
979                         goto Found;
980                 }
981                 vtblockput(b);
982         }
983
984         /* No block found, extend the file by one metablock. */
985         vtfileflushbefore(ms, nb*(uvlong)ms->dsize);
986         if((b = vtfileblock(ms, nb, VtORDWR)) == nil)
987                 goto Err;
988         vtfilesetsize(ms, (nb+1)*ms->dsize);
989         mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
990
991 Found:
992         /* Now we have a block; allocate space to write the entry. */
993         p = mballoc(&mb, n);
994         if(p == nil){
995                 /* mballoc might have changed block */
996                 mbpack(&mb);
997                 werrstr(EBadMeta);
998                 goto Err;
999         }
1000
1001         /* Figure out where to put the index entry, and write it. */
1002         mbsearch(&mb, dir->elem, &i, &me);
1003         assert(me.p == nil);    /* not already there */
1004         me.p = p;
1005         me.size = n;
1006         vdpack(dir, &me, VacDirVersion);
1007         mbinsert(&mb, i, &me);
1008         mbpack(&mb);
1009         vtblockput(b);
1010         return bo;
1011
1012 Err:
1013         vtblockput(b);
1014         return NilBlock;
1015 }
1016
1017 /*
1018  * Update f's directory entry in the block cache. 
1019  * We look for the directory entry by name;
1020  * if we're trying to rename the file, oelem is the old name.
1021  *
1022  * Assumes caller has filemetalock'ed f.
1023  */
1024 static int
1025 filemetaflush(VacFile *f, char *oelem)
1026 {
1027         int i, n;
1028         MetaBlock mb;
1029         MetaEntry me, me2;
1030         VacFile *fp;
1031         VtBlock *b;
1032         u32int bo;
1033
1034         if(!f->dirty)
1035                 return 0;
1036
1037         if(oelem == nil)
1038                 oelem = f->dir.elem;
1039
1040         /*
1041          * Locate f's old metadata in the parent's metadata file.
1042          * We know which block it was in, but not exactly where
1043          * in the block.
1044          */
1045         fp = f->up;
1046         if(vtfilelock(fp->msource, -1) < 0)
1047                 return -1;
1048         /* can happen if source is clri'ed out from under us */
1049         if(f->boff == NilBlock)
1050                 goto Err1;
1051         b = vtfileblock(fp->msource, f->boff, VtORDWR);
1052         if(b == nil)
1053                 goto Err1;
1054         if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1055                 goto Err;
1056         if(mbsearch(&mb, oelem, &i, &me) < 0)
1057                 goto Err;
1058
1059         /*
1060          * Check whether we can resize the entry and keep it 
1061          * in this block.
1062          */
1063         n = vdsize(&f->dir, VacDirVersion);
1064         if(mbresize(&mb, &me, n) >= 0){
1065                 /* Okay, can be done without moving to another block. */
1066
1067                 /* Remove old data */
1068                 mbdelete(&mb, i, &me);
1069
1070                 /* Find new location if renaming */
1071                 if(strcmp(f->dir.elem, oelem) != 0)
1072                         mbsearch(&mb, f->dir.elem, &i, &me2);
1073
1074                 /* Pack new data into new location. */
1075                 vdpack(&f->dir, &me, VacDirVersion);
1076 vdunpack(&f->dir, &me);
1077                 mbinsert(&mb, i, &me);
1078                 mbpack(&mb);
1079                 
1080                 /* Done */
1081                 vtblockput(b);
1082                 vtfileunlock(fp->msource);
1083                 f->dirty = 0;
1084                 return 0;
1085         }
1086         
1087         /*
1088          * The entry must be moved to another block.
1089          * This can only really happen on renames that
1090          * make the name very long.
1091          */
1092         
1093         /* Allocate a spot in a new block. */
1094         if((bo = filemetaalloc(fp, &f->dir, f->boff+1)) == NilBlock){
1095                 /* mbresize above might have modified block */
1096                 mbpack(&mb);
1097                 goto Err;
1098         }
1099         f->boff = bo;
1100
1101         /* Now we're committed.  Delete entry in old block. */
1102         mbdelete(&mb, i, &me);
1103         mbpack(&mb);
1104         vtblockput(b);
1105         vtfileunlock(fp->msource);
1106
1107         f->dirty = 0;
1108         return 0;
1109
1110 Err:
1111         vtblockput(b);
1112 Err1:
1113         vtfileunlock(fp->msource);
1114         return -1;
1115 }
1116
1117 /*
1118  * Remove the directory entry for f.
1119  */
1120 static int
1121 filemetaremove(VacFile *f)
1122 {
1123         VtBlock *b;
1124         MetaBlock mb;
1125         MetaEntry me;
1126         int i;
1127         VacFile *fp;
1128
1129         b = nil;
1130         fp = f->up;
1131         filemetalock(f);
1132
1133         if(vtfilelock(fp->msource, VtORDWR) < 0)
1134                 goto Err;
1135         b = vtfileblock(fp->msource, f->boff, VtORDWR);
1136         if(b == nil)
1137                 goto Err;
1138
1139         if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1140                 goto Err;
1141         if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
1142                 goto Err;
1143         mbdelete(&mb, i, &me);
1144         mbpack(&mb);
1145         vtblockput(b);
1146         vtfileunlock(fp->msource);
1147
1148         f->removed = 1;
1149         f->boff = NilBlock;
1150         f->dirty = 0;
1151
1152         filemetaunlock(f);
1153         return 0;
1154
1155 Err:
1156         vtfileunlock(fp->msource);
1157         vtblockput(b);
1158         filemetaunlock(f);
1159         return -1;
1160 }
1161
1162 /*
1163  * That was far too much effort for directory entries.
1164  * Now we can write code that *does* things.
1165  */
1166
1167 /*
1168  * Flush all data associated with f out of the cache and onto venti.
1169  * If recursive is set, flush f's children too.
1170  * Vacfiledecref knows how to flush source and msource too.
1171  */
1172 int
1173 vacfileflush(VacFile *f, int recursive)
1174 {
1175         int ret;
1176         VacFile **kids, *p;
1177         int i, nkids;
1178         
1179         if(f->mode == VtOREAD)
1180                 return 0;
1181
1182         ret = 0;
1183         filemetalock(f);
1184         if(filemetaflush(f, nil) < 0)
1185                 ret = -1;
1186         filemetaunlock(f);
1187
1188         if(filelock(f) < 0)
1189                 return -1;
1190
1191         /*
1192          * Lock order prevents us from flushing kids while holding
1193          * lock, so make a list and then flush without the lock.
1194          */
1195         nkids = 0;
1196         kids = nil;
1197         if(recursive){
1198                 nkids = 0;
1199                 for(p=f->down; p; p=p->next)
1200                         nkids++;
1201                 kids = vtmalloc(nkids*sizeof(VacFile*));
1202                 i = 0;
1203                 for(p=f->down; p; p=p->next){
1204                         kids[i++] = p;
1205                         p->ref++;
1206                 }
1207         }
1208         if(nkids > 0){
1209                 fileunlock(f);
1210                 for(i=0; i<nkids; i++){
1211                         if(vacfileflush(kids[i], 1) < 0)
1212                                 ret = -1;
1213                         vacfiledecref(kids[i]);
1214                 }
1215                 filelock(f);
1216         }
1217         free(kids);
1218
1219         /*
1220          * Now we can flush our own data.
1221          */     
1222         vtfilelock(f->source, -1);
1223         if(vtfileflush(f->source) < 0)
1224                 ret = -1;
1225         vtfileunlock(f->source);
1226         if(f->msource){
1227                 vtfilelock(f->msource, -1);
1228                 if(vtfileflush(f->msource) < 0)
1229                         ret = -1;
1230                 vtfileunlock(f->msource);
1231         }
1232         fileunlock(f);
1233
1234         return ret;
1235 }
1236                 
1237 /*
1238  * Create a new file named elem in fp with the given mode.
1239  * The mode can be changed later except for the ModeDir bit.
1240  */
1241 VacFile*
1242 vacfilecreate(VacFile *fp, char *elem, ulong mode)
1243 {
1244         VacFile *ff;
1245         VacDir *dir;
1246         VtFile *pr, *r, *mr;
1247         int type;
1248         u32int bo;
1249
1250         if(filelock(fp) < 0)
1251                 return nil;
1252
1253         /*
1254          * First, look to see that there's not a file in memory
1255          * with the same name.
1256          */
1257         for(ff = fp->down; ff; ff=ff->next){
1258                 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
1259                         ff = nil;
1260                         werrstr(EExists);
1261                         goto Err1;
1262                 }
1263         }
1264
1265         /*
1266          * Next check the venti blocks.
1267          */
1268         ff = dirlookup(fp, elem);
1269         if(ff != nil){
1270                 werrstr(EExists);
1271                 goto Err1;
1272         }
1273
1274         /*
1275          * By the way, you can't create in a read-only file system.
1276          */
1277         pr = fp->source;
1278         if(pr->mode != VtORDWR){
1279                 werrstr(EReadOnly);
1280                 goto Err1;
1281         }
1282
1283         /*
1284          * Okay, time to actually create something.  Lock the two
1285          * halves of the directory and create a file.
1286          */
1287         if(vtfilelock2(fp->source, fp->msource, -1) < 0)
1288                 goto Err1;
1289         ff = filealloc(fp->fs);
1290         ff->qidoffset = fp->qidoffset;  /* hopefully fp->qidoffset == 0 */
1291         type = VtDataType;
1292         if(mode & ModeDir)
1293                 type = VtDirType;
1294         mr = nil;
1295         if((r = vtfilecreate(pr, pr->psize, pr->dsize, type)) == nil)
1296                 goto Err;
1297         if(mode & ModeDir)
1298         if((mr = vtfilecreate(pr, pr->psize, pr->dsize, VtDataType)) == nil)
1299                 goto Err;
1300
1301         /*
1302          * Fill in the directory entry and write it to disk.
1303          */
1304         dir = &ff->dir;
1305         dir->elem = vtstrdup(elem);
1306         dir->entry = r->offset;
1307         dir->gen = r->gen;
1308         if(mode & ModeDir){
1309                 dir->mentry = mr->offset;
1310                 dir->mgen = mr->gen;
1311         }
1312         dir->size = 0;
1313         if(_vacfsnextqid(fp->fs, &dir->qid) < 0)
1314                 goto Err;
1315         dir->uid = vtstrdup(fp->dir.uid);
1316         dir->gid = vtstrdup(fp->dir.gid);
1317         dir->mid = vtstrdup("");
1318         dir->mtime = time(0L);
1319         dir->mcount = 0;
1320         dir->ctime = dir->mtime;
1321         dir->atime = dir->mtime;
1322         dir->mode = mode;
1323         if((bo = filemetaalloc(fp, &ff->dir, NilBlock)) == NilBlock)
1324                 goto Err;
1325
1326         /*
1327          * Now we're committed.
1328          */
1329         vtfileunlock(fp->source);
1330         vtfileunlock(fp->msource);
1331         ff->source = r;
1332         ff->msource = mr;
1333         ff->boff = bo;
1334
1335         /* Link into tree. */
1336         ff->next = fp->down;
1337         fp->down = ff;
1338         ff->up = fp;
1339         vacfileincref(fp);
1340
1341         fileunlock(fp);
1342         
1343         filelock(ff);
1344         vtfilelock(ff->source, -1);
1345         vtfileunlock(ff->source);
1346         fileunlock(ff);
1347
1348         return ff;
1349
1350 Err:
1351         vtfileunlock(fp->source);
1352         vtfileunlock(fp->msource);
1353         if(r){
1354                 vtfilelock(r, -1);
1355                 vtfileremove(r);
1356         }
1357         if(mr){
1358                 vtfilelock(mr, -1);
1359                 vtfileremove(mr);
1360         }
1361 Err1:
1362         if(ff)
1363                 vacfiledecref(ff);
1364         fileunlock(fp);
1365         return nil;
1366 }
1367
1368 /*
1369  * Change the size of the file f.
1370  */
1371 int
1372 vacfilesetsize(VacFile *f, uvlong size)
1373 {
1374         if(vacfileisdir(f)){
1375                 werrstr(ENotFile);
1376                 return -1;
1377         }
1378         
1379         if(filelock(f) < 0)
1380                 return -1;
1381
1382         if(f->source->mode != VtORDWR){
1383                 werrstr(EReadOnly);
1384                 goto Err;
1385         }
1386         if(vtfilelock(f->source, -1) < 0)
1387                 goto Err;
1388         if(vtfilesetsize(f->source, size) < 0){
1389                 vtfileunlock(f->source);
1390                 goto Err;
1391         }
1392         vtfileunlock(f->source);
1393         fileunlock(f);
1394         return 0;
1395
1396 Err:
1397         fileunlock(f);
1398         return -1;
1399 }
1400
1401 /*
1402  * Write data to f.
1403  */
1404 int
1405 vacfilewrite(VacFile *f, void *buf, int cnt, vlong offset)
1406 {
1407         if(vacfileisdir(f)){
1408                 werrstr(ENotFile);
1409                 return -1;
1410         }
1411         if(filelock(f) < 0)
1412                 return -1;
1413         if(f->source->mode != VtORDWR){
1414                 werrstr(EReadOnly);
1415                 goto Err;
1416         }
1417         if(offset < 0){
1418                 werrstr(EBadOffset);
1419                 goto Err;
1420         }
1421
1422         if(vtfilelock(f->source, -1) < 0)
1423                 goto Err;
1424         if(f->dir.mode & ModeAppend)
1425                 offset = vtfilegetsize(f->source);
1426         if(vtfilewrite(f->source, buf, cnt, offset) != cnt
1427         || vtfileflushbefore(f->source, offset) < 0){
1428                 vtfileunlock(f->source);
1429                 goto Err;
1430         }
1431         vtfileunlock(f->source);
1432         fileunlock(f);
1433         return cnt;
1434
1435 Err:
1436         fileunlock(f);
1437         return -1;
1438 }
1439
1440 /*
1441  * Set (!) the VtEntry for the data contained in f.
1442  * This let's us efficiently copy data from one file to another.
1443  */
1444 int
1445 vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me)
1446 {
1447         int ret;
1448
1449         vacfileflush(f, 0);     /* flush blocks to venti, since we won't see them again */
1450
1451         if(!(e->flags&VtEntryActive)){
1452                 werrstr("missing entry for source");
1453                 return -1;
1454         }
1455         if(me && !(me->flags&VtEntryActive))
1456                 me = nil;
1457         if(f->msource && !me){
1458                 werrstr("missing entry for msource");
1459                 return -1;
1460         }
1461         if(me && !f->msource){
1462                 werrstr("no msource to set");
1463                 return -1;
1464         }
1465
1466         if(filelock(f) < 0)
1467                 return -1;
1468         if(f->source->mode != VtORDWR
1469         || (f->msource && f->msource->mode != VtORDWR)){
1470                 werrstr(EReadOnly);
1471                 fileunlock(f);
1472                 return -1;
1473         }
1474         if(vtfilelock2(f->source, f->msource, -1) < 0){
1475                 fileunlock(f);
1476                 return -1;
1477         }
1478         ret = 0;
1479         if(vtfilesetentry(f->source, e) < 0)
1480                 ret = -1;
1481         else if(me && vtfilesetentry(f->msource, me) < 0)
1482                 ret = -1;
1483
1484         vtfileunlock(f->source);
1485         if(f->msource)
1486                 vtfileunlock(f->msource);
1487         fileunlock(f);
1488         return ret;
1489 }
1490
1491 /*
1492  * Get the directory entry for f.
1493  */
1494 int
1495 vacfilegetdir(VacFile *f, VacDir *dir)
1496 {
1497         if(filerlock(f) < 0)
1498                 return -1;
1499
1500         filemetalock(f);
1501         vdcopy(dir, &f->dir);
1502         filemetaunlock(f);
1503
1504         if(!vacfileisdir(f)){
1505                 if(vtfilelock(f->source, VtOREAD) < 0){
1506                         filerunlock(f);
1507                         return -1;
1508                 }
1509                 dir->size = vtfilegetsize(f->source);
1510                 vtfileunlock(f->source);
1511         }
1512         filerunlock(f);
1513
1514         return 0;
1515 }
1516
1517 /*
1518  * Set the directory entry for f.
1519  */
1520 int
1521 vacfilesetdir(VacFile *f, VacDir *dir)
1522 {
1523         VacFile *ff;
1524         char *oelem;
1525         u32int mask;
1526         u64int size;
1527
1528         /* can not set permissions for the root */
1529         if(vacfileisroot(f)){
1530                 werrstr(ERoot);
1531                 return -1;
1532         }
1533
1534         if(filelock(f) < 0)
1535                 return -1;
1536         filemetalock(f);
1537         
1538         if(f->source->mode != VtORDWR){
1539                 werrstr(EReadOnly);
1540                 goto Err;
1541         }
1542
1543         /* On rename, check new name does not already exist */
1544         if(strcmp(f->dir.elem, dir->elem) != 0){
1545                 for(ff = f->up->down; ff; ff=ff->next){
1546                         if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
1547                                 werrstr(EExists);
1548                                 goto Err;
1549                         }
1550                 }
1551                 ff = dirlookup(f->up, dir->elem);
1552                 if(ff != nil){
1553                         vacfiledecref(ff);
1554                         werrstr(EExists);
1555                         goto Err;
1556                 }
1557                 werrstr("");    /* "failed" dirlookup poisoned it */
1558         }
1559
1560         /* Get ready... */
1561         if(vtfilelock2(f->source, f->msource, -1) < 0)
1562                 goto Err;
1563         if(!vacfileisdir(f)){
1564                 size = vtfilegetsize(f->source);
1565                 if(size != dir->size){
1566                         if(vtfilesetsize(f->source, dir->size) < 0){
1567                                 vtfileunlock(f->source);
1568                                 if(f->msource)
1569                                         vtfileunlock(f->msource);
1570                                 goto Err;
1571                         }
1572                 }
1573         }
1574         /* ... now commited to changing it. */
1575         vtfileunlock(f->source);
1576         if(f->msource)
1577                 vtfileunlock(f->msource);
1578
1579         oelem = nil;
1580         if(strcmp(f->dir.elem, dir->elem) != 0){
1581                 oelem = f->dir.elem;
1582                 f->dir.elem = vtstrdup(dir->elem);
1583         }
1584
1585         if(strcmp(f->dir.uid, dir->uid) != 0){
1586                 vtfree(f->dir.uid);
1587                 f->dir.uid = vtstrdup(dir->uid);
1588         }
1589
1590         if(strcmp(f->dir.gid, dir->gid) != 0){
1591                 vtfree(f->dir.gid);
1592                 f->dir.gid = vtstrdup(dir->gid);
1593         }
1594
1595         if(strcmp(f->dir.mid, dir->mid) != 0){
1596                 vtfree(f->dir.mid);
1597                 f->dir.mid = vtstrdup(dir->mid);
1598         }
1599
1600         f->dir.mtime = dir->mtime;
1601         f->dir.atime = dir->atime;
1602
1603         mask = ~(ModeDir|ModeSnapshot);
1604         f->dir.mode &= ~mask;
1605         f->dir.mode |= mask & dir->mode;
1606         f->dirty = 1;
1607
1608         if(filemetaflush(f, oelem) < 0){
1609                 vtfree(oelem);
1610                 goto Err;       /* that sucks */
1611         }
1612         vtfree(oelem);
1613
1614         filemetaunlock(f);
1615         fileunlock(f);
1616         return 0;
1617
1618 Err:
1619         filemetaunlock(f);
1620         fileunlock(f);
1621         return -1;
1622 }
1623
1624 /*
1625  * Set the qid space.
1626  */
1627 int
1628 vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
1629 {
1630         int ret;
1631
1632         if(filelock(f) < 0)
1633                 return -1;
1634         if(f->source->mode != VtORDWR){
1635                 fileunlock(f);
1636                 werrstr(EReadOnly);
1637                 return -1;
1638         }
1639         filemetalock(f);
1640         f->dir.qidspace = 1;
1641         f->dir.qidoffset = offset;
1642         f->dir.qidmax = max;
1643         f->dirty = 1;
1644         ret = filemetaflush(f, nil);
1645         filemetaunlock(f);
1646         fileunlock(f);
1647         return ret;
1648 }
1649
1650 /*
1651  * Check that the file is empty, returning 0 if it is.
1652  * Returns -1 on error (and not being empty is an error).
1653  */
1654 static int
1655 filecheckempty(VacFile *f)
1656 {
1657         u32int i, n;
1658         VtBlock *b;
1659         MetaBlock mb;
1660         VtFile *r;
1661
1662         r = f->msource;
1663         n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
1664         for(i=0; i<n; i++){
1665                 b = vtfileblock(r, i, VtOREAD);
1666                 if(b == nil)
1667                         return -1;
1668                 if(mbunpack(&mb, b->data, r->dsize) < 0)
1669                         goto Err;
1670                 if(mb.nindex > 0){
1671                         werrstr(ENotEmpty);
1672                         goto Err;
1673                 }
1674                 vtblockput(b);
1675         }
1676         return 0;
1677
1678 Err:
1679         vtblockput(b);
1680         return -1;
1681 }
1682
1683 /*
1684  * Remove the vac file f.
1685  */
1686 int
1687 vacfileremove(VacFile *f)
1688 {
1689         VacFile *ff;
1690
1691         /* Cannot remove the root */
1692         if(vacfileisroot(f)){
1693                 werrstr(ERoot);
1694                 return -1;
1695         }
1696
1697         if(filelock(f) < 0)
1698                 return -1;
1699         if(f->source->mode != VtORDWR){
1700                 werrstr(EReadOnly);
1701                 goto Err1;
1702         }
1703         if(vtfilelock2(f->source, f->msource, -1) < 0)
1704                 goto Err1;
1705         if(vacfileisdir(f) && filecheckempty(f)<0)
1706                 goto Err;
1707
1708         for(ff=f->down; ff; ff=ff->next)
1709                 assert(ff->removed);
1710
1711         vtfileremove(f->source);
1712         f->source = nil;
1713         if(f->msource){
1714                 vtfileremove(f->msource);
1715                 f->msource = nil;
1716         }
1717         fileunlock(f);
1718
1719         if(filemetaremove(f) < 0)
1720                 return -1;
1721         return 0;
1722
1723 Err:
1724         vtfileunlock(f->source);
1725         if(f->msource)
1726                 vtfileunlock(f->msource);
1727 Err1:
1728         fileunlock(f);
1729         return -1;
1730 }
1731
1732 /*
1733  * Vac file system format.
1734  */
1735 static char EBadVacFormat[] = "bad format for vac file";
1736
1737 static VacFs *
1738 vacfsalloc(VtConn *z, int bsize, int ncache, int mode)
1739 {
1740         VacFs *fs;
1741
1742         fs = vtmallocz(sizeof(VacFs));
1743         fs->z = z;
1744         fs->bsize = bsize;
1745         fs->mode = mode;
1746         fs->cache = vtcachealloc(z, bsize, ncache);
1747         return fs;
1748 }
1749
1750 static int
1751 readscore(int fd, uchar score[VtScoreSize])
1752 {
1753         char buf[45], *pref;
1754         int n;
1755
1756         n = readn(fd, buf, sizeof(buf)-1);
1757         if(n < sizeof(buf)-1) {
1758                 werrstr("short read");
1759                 return -1;
1760         }
1761         buf[n] = 0;
1762
1763         if(vtparsescore(buf, &pref, score) < 0){
1764                 werrstr(EBadVacFormat);
1765                 return -1;
1766         }
1767         if(pref==nil || strcmp(pref, "vac") != 0) {
1768                 werrstr("not a vac file");
1769                 return -1;
1770         }
1771         return 0;
1772 }
1773
1774 VacFs*
1775 vacfsopen(VtConn *z, char *file, int mode, int ncache)
1776 {
1777         int fd;
1778         uchar score[VtScoreSize];
1779         char *prefix;
1780         
1781         if(vtparsescore(file, &prefix, score) >= 0){
1782                 if(prefix == nil || strcmp(prefix, "vac") != 0){
1783                         werrstr("not a vac file");
1784                         return nil;
1785                 }
1786         }else{
1787                 fd = open(file, OREAD);
1788                 if(fd < 0)
1789                         return nil;
1790                 if(readscore(fd, score) < 0){
1791                         close(fd);
1792                         return nil;
1793                 }
1794                 close(fd);
1795         }
1796         return vacfsopenscore(z, score, mode, ncache);
1797 }
1798
1799 VacFs*
1800 vacfsopenscore(VtConn *z, u8int *score, int mode, int ncache)
1801 {
1802         VacFs *fs;
1803         int n;
1804         VtRoot rt;
1805         uchar buf[VtRootSize];
1806         VacFile *root;
1807         VtFile *r;
1808         VtEntry e;
1809
1810         n = vtread(z, score, VtRootType, buf, VtRootSize);
1811         if(n < 0)
1812                 return nil;
1813         if(n != VtRootSize){
1814                 werrstr("vtread on root too short");
1815                 return nil;
1816         }
1817
1818         if(vtrootunpack(&rt, buf) < 0)
1819                 return nil;
1820
1821         if(strcmp(rt.type, "vac") != 0) {
1822                 werrstr("not a vac root");
1823                 return nil;
1824         }
1825
1826         fs = vacfsalloc(z, rt.blocksize, ncache, mode);
1827         memmove(fs->score, score, VtScoreSize);
1828         fs->mode = mode;
1829
1830         memmove(e.score, rt.score, VtScoreSize);
1831         e.gen = 0;
1832         e.psize = rt.blocksize;
1833         e.dsize = rt.blocksize;
1834         e.type = VtDirType;
1835         e.flags = VtEntryActive;
1836         e.size = 3*VtEntrySize;
1837
1838         root = nil;
1839         if((r = vtfileopenroot(fs->cache, &e)) == nil)
1840                 goto Err;
1841         if(debug)
1842                 fprint(2, "r %p\n", r);
1843         root = _vacfileroot(fs, r);
1844         if(debug)
1845                 fprint(2, "root %p\n", root);
1846         vtfileclose(r);
1847         if(root == nil)
1848                 goto Err;
1849         fs->root = root;
1850         return fs;
1851 Err:
1852         if(root)
1853                 vacfiledecref(root);
1854         vacfsclose(fs);
1855         return nil;
1856 }
1857
1858 int
1859 vacfsmode(VacFs *fs)
1860 {
1861         return fs->mode;
1862 }
1863
1864 VacFile*
1865 vacfsgetroot(VacFs *fs)
1866 {
1867         return vacfileincref(fs->root);
1868 }
1869
1870 int
1871 vacfsgetblocksize(VacFs *fs)
1872 {
1873         return fs->bsize;
1874 }
1875
1876 int
1877 vacfsgetscore(VacFs *fs, u8int *score)
1878 {
1879         memmove(score, fs->score, VtScoreSize);
1880         return 0;
1881 }
1882
1883 int
1884 _vacfsnextqid(VacFs *fs, uvlong *qid)
1885 {
1886         ++fs->qid;
1887         *qid = fs->qid;
1888         return 0;
1889 }
1890
1891 void
1892 vacfsjumpqid(VacFs *fs, uvlong step)
1893 {
1894         fs->qid += step;
1895 }
1896
1897 /*
1898  * Set *maxqid to the maximum qid expected in this file system.
1899  * In newer vac archives, the maximum qid is stored in the
1900  * qidspace VacDir annotation.  In older vac archives, the root
1901  * got created last, so it had the maximum qid.
1902  */
1903 int
1904 vacfsgetmaxqid(VacFs *fs, uvlong *maxqid)
1905 {
1906         VacDir vd;
1907         
1908         if(vacfilegetdir(fs->root, &vd) < 0)
1909                 return -1;
1910         if(vd.qidspace)
1911                 *maxqid = vd.qidmax;
1912         else
1913                 *maxqid = vd.qid;
1914         vdcleanup(&vd);
1915         return 0;
1916 }
1917
1918
1919 void
1920 vacfsclose(VacFs *fs)
1921 {
1922         if(fs->root)
1923                 vacfiledecref(fs->root);
1924         fs->root = nil;
1925         vtcachefree(fs->cache);
1926         vtfree(fs);
1927 }
1928
1929 /*
1930  * Create a fresh vac fs.
1931  */
1932 VacFs *
1933 vacfscreate(VtConn *z, int bsize, int ncache)
1934 {
1935         VacFs *fs;
1936         VtFile *f;
1937         uchar buf[VtEntrySize], metascore[VtScoreSize];
1938         VtEntry e;
1939         VtBlock *b;
1940         MetaBlock mb;
1941         VacDir vd;
1942         MetaEntry me;
1943         int psize;
1944         int mbsize;
1945         
1946         if((fs = vacfsalloc(z, bsize, ncache, VtORDWR)) == nil)
1947                 return nil;
1948         
1949         /*
1950          * Fake up an empty vac fs.
1951          */
1952         psize = bsize;
1953         f = vtfilecreateroot(fs->cache, psize, bsize, VtDirType);
1954         vtfilelock(f, VtORDWR);
1955         
1956         /* Metablocks can't be too big -- they have 16-bit offsets in them. */
1957         mbsize = bsize;
1958         if(mbsize >= 56*1024)
1959                 mbsize = 56*1024;
1960
1961         /* Write metablock containing root directory VacDir. */
1962         b = vtcacheallocblock(fs->cache, VtDataType);
1963         mbinit(&mb, b->data, mbsize, mbsize/BytesPerEntry);
1964         memset(&vd, 0, sizeof vd);
1965         vd.elem = "/";
1966         vd.mode = 0777|ModeDir;
1967         vd.uid = "vac";
1968         vd.gid = "vac";
1969         vd.mid = "";
1970         me.size = vdsize(&vd, VacDirVersion);
1971         me.p = mballoc(&mb, me.size);
1972         vdpack(&vd, &me, VacDirVersion);
1973         mbinsert(&mb, 0, &me);
1974         mbpack(&mb);
1975         vtblockwrite(b);
1976         memmove(metascore, b->score, VtScoreSize);
1977         vtblockput(b);
1978         
1979         /* First entry: empty venti directory stream. */
1980         memset(&e, 0, sizeof e);
1981         e.flags = VtEntryActive;
1982         e.psize = psize;
1983         e.dsize = bsize;
1984         e.type = VtDirType;
1985         memmove(e.score, vtzeroscore, VtScoreSize);
1986         vtentrypack(&e, buf, 0);
1987         vtfilewrite(f, buf, VtEntrySize, 0);
1988         
1989         /* Second entry: empty metadata stream. */
1990         e.type = VtDataType;
1991         e.dsize = mbsize;
1992         vtentrypack(&e, buf, 0);
1993         vtfilewrite(f, buf, VtEntrySize, VtEntrySize);
1994
1995         /* Third entry: metadata stream with root directory. */
1996         memmove(e.score, metascore, VtScoreSize);
1997         e.size = mbsize;
1998         vtentrypack(&e, buf, 0);
1999         vtfilewrite(f, buf, VtEntrySize, VtEntrySize*2);
2000
2001         vtfileflush(f);
2002         vtfileunlock(f);
2003         
2004         /* Now open it as a vac fs. */
2005         fs->root = _vacfileroot(fs, f);
2006         if(fs->root == nil){
2007                 werrstr("vacfileroot: %r");
2008                 vacfsclose(fs);
2009                 return nil;
2010         }
2011
2012         return fs;
2013 }
2014
2015 int
2016 vacfssync(VacFs *fs)
2017 {
2018         uchar buf[1024];
2019         VtEntry e;
2020         VtFile *f;
2021         VtRoot root;
2022
2023         /* Sync the entire vacfs to disk. */
2024         if(vacfileflush(fs->root, 1) < 0)
2025                 return -1;
2026         if(vtfilelock(fs->root->up->msource, -1) < 0)
2027                 return -1;
2028         if(vtfileflush(fs->root->up->msource) < 0){
2029                 vtfileunlock(fs->root->up->msource);
2030                 return -1;
2031         }
2032         vtfileunlock(fs->root->up->msource);
2033
2034         /* Prepare the dir stream for the root block. */
2035         if(getentry(fs->root->source, &e) < 0)
2036                 return -1;
2037         vtentrypack(&e, buf, 0);
2038         if(getentry(fs->root->msource, &e) < 0)
2039                 return -1;
2040         vtentrypack(&e, buf, 1);
2041         if(getentry(fs->root->up->msource, &e) < 0)
2042                 return -1;
2043         vtentrypack(&e, buf, 2);
2044
2045         f = vtfilecreateroot(fs->cache, fs->bsize, fs->bsize, VtDirType);
2046         vtfilelock(f, VtORDWR);
2047         if(vtfilewrite(f, buf, 3*VtEntrySize, 0) < 0
2048         || vtfileflush(f) < 0){
2049                 vtfileunlock(f);
2050                 vtfileclose(f);
2051                 return -1;
2052         }
2053         vtfileunlock(f);
2054         if(getentry(f, &e) < 0){
2055                 vtfileclose(f);
2056                 return -1;
2057         }
2058         vtfileclose(f);
2059
2060         /* Build a root block. */
2061         memset(&root, 0, sizeof root);
2062         strcpy(root.type, "vac");
2063         strcpy(root.name, fs->name);
2064         memmove(root.score, e.score, VtScoreSize);
2065         root.blocksize = fs->bsize;
2066         memmove(root.prev, fs->score, VtScoreSize);
2067         vtrootpack(&root, buf);
2068         if(vtwrite(fs->z, fs->score, VtRootType, buf, VtRootSize) < 0){
2069                 werrstr("writing root: %r");
2070                 return -1;
2071         }
2072         if(vtsync(fs->z) < 0)
2073                 return -1;
2074         return 0;
2075 }
2076
2077 int
2078 vacfiledsize(VacFile *f)
2079 {
2080         VtEntry e;
2081
2082         if(vacfilegetentries(f,&e,nil) < 0)
2083                 return -1;
2084         return e.dsize;
2085 }
2086
2087 /*
2088  * Does block b of f have the same SHA1 hash as the n bytes at buf?
2089  */
2090 int
2091 sha1matches(VacFile *f, ulong b, uchar *buf, int n)
2092 {
2093         uchar fscore[VtScoreSize];
2094         uchar bufscore[VtScoreSize];
2095         
2096         if(vacfileblockscore(f, b, fscore) < 0)
2097                 return 0;
2098         n = vtzerotruncate(VtDataType, buf, n);
2099         sha1(buf, n, bufscore, nil);
2100         if(memcmp(bufscore, fscore, VtScoreSize) == 0)
2101                 return 1;
2102         return 0;
2103 }
2104