1 7763a61a 2003-11-23 devnull #include "stdinc.h"
2 7763a61a 2003-11-23 devnull #include "vac.h"
3 7763a61a 2003-11-23 devnull #include "dat.h"
4 7763a61a 2003-11-23 devnull #include "fns.h"
5 7763a61a 2003-11-23 devnull #include "error.h"
7 23fb2edb 2005-07-24 devnull #define debug 0
10 ecc0a1b0 2008-06-15 rsc * Vac file system. This is a simplified version of the same code in Fossil.
12 ecc0a1b0 2008-06-15 rsc * The locking order in the tree is upward: a thread can hold the lock
13 ecc0a1b0 2008-06-15 rsc * for a VacFile and then acquire the lock of f->up (the parent),
14 ecc0a1b0 2008-06-15 rsc * but not vice-versa.
16 ecc0a1b0 2008-06-15 rsc * A vac file is one or two venti files. Plain data files are one venti file,
17 ecc0a1b0 2008-06-15 rsc * while directores are two: a venti data file containing traditional
18 ecc0a1b0 2008-06-15 rsc * directory entries, and a venti directory file containing venti
19 ecc0a1b0 2008-06-15 rsc * directory entries. The traditional directory entries in the data file
20 ecc0a1b0 2008-06-15 rsc * contain integers indexing into the venti directory entry file.
21 ecc0a1b0 2008-06-15 rsc * It's a little complicated, but it makes the data usable by standard
22 ecc0a1b0 2008-06-15 rsc * tools like venti/copy.
26 ecc0a1b0 2008-06-15 rsc static int filemetaflush(VacFile*, char*);
28 3d77c87e 2004-03-15 devnull struct VacFile
30 3d77c87e 2004-03-15 devnull VacFs *fs; /* immutable */
32 7763a61a 2003-11-23 devnull /* meta data for file: protected by the lk in the parent */
33 3d77c87e 2004-03-15 devnull int ref; /* holds this data structure up */
35 3d77c87e 2004-03-15 devnull int partial; /* file was never really open */
36 3d77c87e 2004-03-15 devnull int removed; /* file has been removed */
37 3d77c87e 2004-03-15 devnull int dirty; /* dir is dirty with respect to meta data in block */
38 3d77c87e 2004-03-15 devnull u32int boff; /* block offset within msource for this file's metadata */
39 3d77c87e 2004-03-15 devnull VacDir dir; /* metadata for this file */
40 3d77c87e 2004-03-15 devnull VacFile *up; /* parent file */
41 3d77c87e 2004-03-15 devnull VacFile *next; /* sibling */
43 3d77c87e 2004-03-15 devnull RWLock lk; /* lock for the following */
44 3d77c87e 2004-03-15 devnull VtFile *source; /* actual data */
45 3d77c87e 2004-03-15 devnull VtFile *msource; /* metadata for children in a directory */
46 3d77c87e 2004-03-15 devnull VacFile *down; /* children */
47 3d77c87e 2004-03-15 devnull int mode;
49 003c13aa 2008-06-15 rsc uvlong qidoffset; /* qid offset */
52 3d77c87e 2004-03-15 devnull static VacFile*
53 3d77c87e 2004-03-15 devnull filealloc(VacFs *fs)
55 3d77c87e 2004-03-15 devnull VacFile *f;
57 3d77c87e 2004-03-15 devnull f = vtmallocz(sizeof(VacFile));
58 3d77c87e 2004-03-15 devnull f->ref = 1;
59 3d77c87e 2004-03-15 devnull f->fs = fs;
60 3d77c87e 2004-03-15 devnull f->boff = NilBlock;
61 3d77c87e 2004-03-15 devnull f->mode = fs->mode;
62 3d77c87e 2004-03-15 devnull return f;
65 7763a61a 2003-11-23 devnull static void
66 3d77c87e 2004-03-15 devnull filefree(VacFile *f)
68 3d77c87e 2004-03-15 devnull vtfileclose(f->source);
69 3d77c87e 2004-03-15 devnull vtfileclose(f->msource);
70 3d77c87e 2004-03-15 devnull vdcleanup(&f->dir);
71 3d77c87e 2004-03-15 devnull memset(f, ~0, sizeof *f); /* paranoia */
72 3d77c87e 2004-03-15 devnull vtfree(f);
76 ecc0a1b0 2008-06-15 rsc chksource(VacFile *f)
78 ecc0a1b0 2008-06-15 rsc if(f->partial)
81 ecc0a1b0 2008-06-15 rsc if(f->source == nil
82 ecc0a1b0 2008-06-15 rsc || ((f->dir.mode & ModeDir) && f->msource == nil)){
83 ecc0a1b0 2008-06-15 rsc werrstr(ERemoved);
90 ecc0a1b0 2008-06-15 rsc filelock(VacFile *f)
92 ecc0a1b0 2008-06-15 rsc wlock(&f->lk);
93 ecc0a1b0 2008-06-15 rsc if(chksource(f) < 0){
94 ecc0a1b0 2008-06-15 rsc wunlock(&f->lk);
101 ecc0a1b0 2008-06-15 rsc fileunlock(VacFile *f)
103 ecc0a1b0 2008-06-15 rsc wunlock(&f->lk);
107 ecc0a1b0 2008-06-15 rsc filerlock(VacFile *f)
109 ecc0a1b0 2008-06-15 rsc rlock(&f->lk);
110 ecc0a1b0 2008-06-15 rsc if(chksource(f) < 0){
111 ecc0a1b0 2008-06-15 rsc runlock(&f->lk);
118 ecc0a1b0 2008-06-15 rsc filerunlock(VacFile *f)
120 ecc0a1b0 2008-06-15 rsc runlock(&f->lk);
124 ecc0a1b0 2008-06-15 rsc * The file metadata, like f->dir and f->ref,
125 ecc0a1b0 2008-06-15 rsc * are synchronized via the parent's lock.
126 ecc0a1b0 2008-06-15 rsc * This is why locking order goes up.
129 ecc0a1b0 2008-06-15 rsc filemetalock(VacFile *f)
131 ecc0a1b0 2008-06-15 rsc assert(f->up != nil);
132 ecc0a1b0 2008-06-15 rsc wlock(&f->up->lk);
136 ecc0a1b0 2008-06-15 rsc filemetaunlock(VacFile *f)
138 ecc0a1b0 2008-06-15 rsc wunlock(&f->up->lk);
142 ecc0a1b0 2008-06-15 rsc vacfilegetid(VacFile *f)
144 ecc0a1b0 2008-06-15 rsc /* immutable */
145 003c13aa 2008-06-15 rsc return f->qidoffset + f->dir.qid;
149 fa3c8da1 2008-06-15 rsc vacfilegetqidoffset(VacFile *f)
151 fa3c8da1 2008-06-15 rsc return f->qidoffset;
155 ecc0a1b0 2008-06-15 rsc vacfilegetmcount(VacFile *f)
157 ecc0a1b0 2008-06-15 rsc ulong mcount;
159 ecc0a1b0 2008-06-15 rsc filemetalock(f);
160 ecc0a1b0 2008-06-15 rsc mcount = f->dir.mcount;
161 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
162 ecc0a1b0 2008-06-15 rsc return mcount;
166 ecc0a1b0 2008-06-15 rsc vacfilegetmode(VacFile *f)
170 ecc0a1b0 2008-06-15 rsc filemetalock(f);
171 ecc0a1b0 2008-06-15 rsc mode = f->dir.mode;
172 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
173 ecc0a1b0 2008-06-15 rsc return mode;
177 ecc0a1b0 2008-06-15 rsc vacfileisdir(VacFile *f)
179 ecc0a1b0 2008-06-15 rsc /* immutable */
180 ecc0a1b0 2008-06-15 rsc return (f->dir.mode & ModeDir) != 0;
184 ecc0a1b0 2008-06-15 rsc vacfileisroot(VacFile *f)
186 ecc0a1b0 2008-06-15 rsc return f == f->fs->root;
190 ecc0a1b0 2008-06-15 rsc * The files are reference counted, and while the reference
191 ecc0a1b0 2008-06-15 rsc * is bigger than zero, each file can be found in its parent's
192 ecc0a1b0 2008-06-15 rsc * f->down list (chains via f->next), so that multiple threads
193 ecc0a1b0 2008-06-15 rsc * end up sharing a VacFile* when referring to the same file.
195 ecc0a1b0 2008-06-15 rsc * Each VacFile holds a reference to its parent.
198 ecc0a1b0 2008-06-15 rsc vacfileincref(VacFile *vf)
200 ecc0a1b0 2008-06-15 rsc filemetalock(vf);
201 ecc0a1b0 2008-06-15 rsc assert(vf->ref > 0);
203 ecc0a1b0 2008-06-15 rsc filemetaunlock(vf);
208 ecc0a1b0 2008-06-15 rsc vacfiledecref(VacFile *f)
210 ecc0a1b0 2008-06-15 rsc VacFile *p, *q, **qq;
212 ecc0a1b0 2008-06-15 rsc if(f->up == nil){
213 ecc0a1b0 2008-06-15 rsc /* never linked in */
214 ecc0a1b0 2008-06-15 rsc assert(f->ref == 1);
215 ecc0a1b0 2008-06-15 rsc filefree(f);
219 ecc0a1b0 2008-06-15 rsc filemetalock(f);
221 ecc0a1b0 2008-06-15 rsc if(f->ref > 0){
222 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
225 ecc0a1b0 2008-06-15 rsc assert(f->ref == 0);
226 ecc0a1b0 2008-06-15 rsc assert(f->down == nil);
228 ecc0a1b0 2008-06-15 rsc if(f->source && vtfilelock(f->source, -1) >= 0){
229 ecc0a1b0 2008-06-15 rsc vtfileflush(f->source);
230 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
232 ecc0a1b0 2008-06-15 rsc if(f->msource && vtfilelock(f->msource, -1) >= 0){
233 ecc0a1b0 2008-06-15 rsc vtfileflush(f->msource);
234 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->msource);
238 ecc0a1b0 2008-06-15 rsc * Flush f's directory information to the cache.
240 ecc0a1b0 2008-06-15 rsc filemetaflush(f, nil);
243 ecc0a1b0 2008-06-15 rsc qq = &p->down;
244 ecc0a1b0 2008-06-15 rsc for(q = *qq; q; q = *qq){
247 ecc0a1b0 2008-06-15 rsc qq = &q->next;
249 ecc0a1b0 2008-06-15 rsc assert(q != nil);
250 ecc0a1b0 2008-06-15 rsc *qq = f->next;
252 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
253 ecc0a1b0 2008-06-15 rsc filefree(f);
254 ecc0a1b0 2008-06-15 rsc vacfiledecref(p);
260 ecc0a1b0 2008-06-15 rsc * Construct a vacfile for the root of a vac tree, given the
261 ecc0a1b0 2008-06-15 rsc * venti file for the root information. That venti file is a
262 ecc0a1b0 2008-06-15 rsc * directory file containing VtEntries for three more venti files:
263 ecc0a1b0 2008-06-15 rsc * the two venti files making up the root directory, and a
264 ecc0a1b0 2008-06-15 rsc * third venti file that would be the metadata half of the
265 ecc0a1b0 2008-06-15 rsc * "root's parent".
267 ecc0a1b0 2008-06-15 rsc * Fossil generates slightly different vac files, due to a now
268 ecc0a1b0 2008-06-15 rsc * impossible-to-change bug, which contain a VtEntry
269 ecc0a1b0 2008-06-15 rsc * for just one venti file, that itself contains the expected
270 ecc0a1b0 2008-06-15 rsc * three directory entries. Sigh.
272 3d77c87e 2004-03-15 devnull VacFile*
273 3d77c87e 2004-03-15 devnull _vacfileroot(VacFs *fs, VtFile *r)
275 23fb2edb 2005-07-24 devnull int redirected;
276 23fb2edb 2005-07-24 devnull char err[ERRMAX];
277 3d77c87e 2004-03-15 devnull VtBlock *b;
278 3d77c87e 2004-03-15 devnull VtFile *r0, *r1, *r2;
279 7763a61a 2003-11-23 devnull MetaBlock mb;
280 7763a61a 2003-11-23 devnull MetaEntry me;
281 7763a61a 2003-11-23 devnull VacFile *root, *mr;
283 23fb2edb 2005-07-24 devnull redirected = 0;
285 3d77c87e 2004-03-15 devnull b = nil;
286 7763a61a 2003-11-23 devnull root = nil;
287 7763a61a 2003-11-23 devnull mr = nil;
288 7763a61a 2003-11-23 devnull r1 = nil;
289 7763a61a 2003-11-23 devnull r2 = nil;
291 3d77c87e 2004-03-15 devnull if(vtfilelock(r, -1) < 0)
292 3d77c87e 2004-03-15 devnull return nil;
293 3d77c87e 2004-03-15 devnull r0 = vtfileopen(r, 0, fs->mode);
294 23fb2edb 2005-07-24 devnull if(debug)
295 23fb2edb 2005-07-24 devnull fprint(2, "r0 %p\n", r0);
296 3d77c87e 2004-03-15 devnull if(r0 == nil)
297 7763a61a 2003-11-23 devnull goto Err;
298 23fb2edb 2005-07-24 devnull r2 = vtfileopen(r, 2, fs->mode);
299 23fb2edb 2005-07-24 devnull if(debug)
300 23fb2edb 2005-07-24 devnull fprint(2, "r2 %p\n", r2);
301 23fb2edb 2005-07-24 devnull if(r2 == nil){
303 23fb2edb 2005-07-24 devnull * some vac files (e.g., from fossil)
304 23fb2edb 2005-07-24 devnull * have an extra layer of indirection.
306 23fb2edb 2005-07-24 devnull rerrstr(err, sizeof err);
307 23fb2edb 2005-07-24 devnull if(!redirected && strstr(err, "not active")){
308 caf12d8c 2005-07-25 devnull redirected = 1;
309 23fb2edb 2005-07-24 devnull vtfileunlock(r);
311 23fb2edb 2005-07-24 devnull goto Top;
313 23fb2edb 2005-07-24 devnull goto Err;
315 3d77c87e 2004-03-15 devnull r1 = vtfileopen(r, 1, fs->mode);
316 23fb2edb 2005-07-24 devnull if(debug)
317 23fb2edb 2005-07-24 devnull fprint(2, "r1 %p\n", r1);
318 3d77c87e 2004-03-15 devnull if(r1 == nil)
319 7763a61a 2003-11-23 devnull goto Err;
321 3d77c87e 2004-03-15 devnull mr = filealloc(fs);
322 7763a61a 2003-11-23 devnull mr->msource = r2;
323 7763a61a 2003-11-23 devnull r2 = nil;
325 3d77c87e 2004-03-15 devnull root = filealloc(fs);
326 3d77c87e 2004-03-15 devnull root->boff = 0;
327 7763a61a 2003-11-23 devnull root->up = mr;
328 7763a61a 2003-11-23 devnull root->source = r0;
329 7763a61a 2003-11-23 devnull r0 = nil;
330 7763a61a 2003-11-23 devnull root->msource = r1;
331 7763a61a 2003-11-23 devnull r1 = nil;
333 7763a61a 2003-11-23 devnull mr->down = root;
334 ecc0a1b0 2008-06-15 rsc vtfileunlock(r);
336 ecc0a1b0 2008-06-15 rsc if(vtfilelock(mr->msource, VtOREAD) < 0)
338 3d77c87e 2004-03-15 devnull b = vtfileblock(mr->msource, 0, VtOREAD);
339 3d77c87e 2004-03-15 devnull vtfileunlock(mr->msource);
340 3d77c87e 2004-03-15 devnull if(b == nil)
343 3d77c87e 2004-03-15 devnull if(mbunpack(&mb, b->data, mr->msource->dsize) < 0)
346 3d77c87e 2004-03-15 devnull meunpack(&me, &mb, 0);
347 3d77c87e 2004-03-15 devnull if(vdunpack(&root->dir, &me) < 0)
349 3d77c87e 2004-03-15 devnull vtblockput(b);
351 7763a61a 2003-11-23 devnull return root;
353 ecc0a1b0 2008-06-15 rsc vtfileunlock(r);
355 3d77c87e 2004-03-15 devnull vtblockput(b);
357 3d77c87e 2004-03-15 devnull vtfileclose(r0);
359 3d77c87e 2004-03-15 devnull vtfileclose(r1);
361 3d77c87e 2004-03-15 devnull vtfileclose(r2);
363 3d77c87e 2004-03-15 devnull filefree(mr);
364 7763a61a 2003-11-23 devnull if(root)
365 3d77c87e 2004-03-15 devnull filefree(root);
371 ecc0a1b0 2008-06-15 rsc * Vac directories are a sequence of metablocks, each of which
372 ecc0a1b0 2008-06-15 rsc * contains a bunch of metaentries sorted by file name.
373 ecc0a1b0 2008-06-15 rsc * The whole sequence isn't sorted, though, so you still have
374 ecc0a1b0 2008-06-15 rsc * to look at every block to find a given name.
375 ecc0a1b0 2008-06-15 rsc * Dirlookup looks in f for an element name elem.
376 ecc0a1b0 2008-06-15 rsc * It returns a new VacFile with the dir, boff, and mode
377 ecc0a1b0 2008-06-15 rsc * filled in, but the sources (venti files) are not, and f is
378 ecc0a1b0 2008-06-15 rsc * not yet linked into the tree. These details must be taken
379 ecc0a1b0 2008-06-15 rsc * care of by the caller.
381 ecc0a1b0 2008-06-15 rsc * f must be locked, f->msource must not.
383 ecc0a1b0 2008-06-15 rsc static VacFile*
384 ecc0a1b0 2008-06-15 rsc dirlookup(VacFile *f, char *elem)
387 ecc0a1b0 2008-06-15 rsc MetaBlock mb;
388 ecc0a1b0 2008-06-15 rsc MetaEntry me;
390 ecc0a1b0 2008-06-15 rsc VtFile *meta;
391 ecc0a1b0 2008-06-15 rsc VacFile *ff;
392 ecc0a1b0 2008-06-15 rsc u32int bo, nb;
394 ecc0a1b0 2008-06-15 rsc meta = f->msource;
396 ecc0a1b0 2008-06-15 rsc if(vtfilelock(meta, -1) < 0)
398 ecc0a1b0 2008-06-15 rsc nb = (vtfilegetsize(meta)+meta->dsize-1)/meta->dsize;
399 ecc0a1b0 2008-06-15 rsc for(bo=0; bo<nb; bo++){
400 ecc0a1b0 2008-06-15 rsc b = vtfileblock(meta, bo, VtOREAD);
401 ecc0a1b0 2008-06-15 rsc if(b == nil)
403 ecc0a1b0 2008-06-15 rsc if(mbunpack(&mb, b->data, meta->dsize) < 0)
405 ecc0a1b0 2008-06-15 rsc if(mbsearch(&mb, elem, &i, &me) >= 0){
406 ecc0a1b0 2008-06-15 rsc ff = filealloc(f->fs);
407 ecc0a1b0 2008-06-15 rsc if(vdunpack(&ff->dir, &me) < 0){
408 ecc0a1b0 2008-06-15 rsc filefree(ff);
411 003c13aa 2008-06-15 rsc ff->qidoffset = f->qidoffset + ff->dir.qidoffset;
412 ecc0a1b0 2008-06-15 rsc vtfileunlock(meta);
413 ecc0a1b0 2008-06-15 rsc vtblockput(b);
414 ecc0a1b0 2008-06-15 rsc ff->boff = bo;
415 ecc0a1b0 2008-06-15 rsc ff->mode = f->mode;
418 ecc0a1b0 2008-06-15 rsc vtblockput(b);
421 ecc0a1b0 2008-06-15 rsc werrstr(ENoFile);
422 ecc0a1b0 2008-06-15 rsc /* fall through */
424 ecc0a1b0 2008-06-15 rsc vtfileunlock(meta);
425 ecc0a1b0 2008-06-15 rsc vtblockput(b);
426 7763a61a 2003-11-23 devnull return nil;
430 ecc0a1b0 2008-06-15 rsc * Open the venti file at offset in the directory f->source.
431 ecc0a1b0 2008-06-15 rsc * f is locked.
433 3d77c87e 2004-03-15 devnull static VtFile *
434 3d77c87e 2004-03-15 devnull fileopensource(VacFile *f, u32int offset, u32int gen, int dir, uint mode)
436 3d77c87e 2004-03-15 devnull VtFile *r;
438 ecc0a1b0 2008-06-15 rsc if((r = vtfileopen(f->source, offset, mode)) == nil)
439 3d77c87e 2004-03-15 devnull return nil;
440 3d77c87e 2004-03-15 devnull if(r == nil)
441 3d77c87e 2004-03-15 devnull return nil;
442 3d77c87e 2004-03-15 devnull if(r->gen != gen){
443 3d77c87e 2004-03-15 devnull werrstr(ERemoved);
444 ecc0a1b0 2008-06-15 rsc vtfileclose(r);
447 3d77c87e 2004-03-15 devnull if(r->dir != dir && r->mode != -1){
448 3d77c87e 2004-03-15 devnull werrstr(EBadMeta);
449 ecc0a1b0 2008-06-15 rsc vtfileclose(r);
452 3d77c87e 2004-03-15 devnull return r;
455 3d77c87e 2004-03-15 devnull VacFile*
456 ecc0a1b0 2008-06-15 rsc vacfilegetparent(VacFile *f)
458 ecc0a1b0 2008-06-15 rsc if(vacfileisroot(f))
459 ecc0a1b0 2008-06-15 rsc return vacfileincref(f);
460 ecc0a1b0 2008-06-15 rsc return vacfileincref(f->up);
464 ecc0a1b0 2008-06-15 rsc * Given an unlocked vacfile (directory) f,
465 ecc0a1b0 2008-06-15 rsc * return the vacfile named elem in f.
466 ecc0a1b0 2008-06-15 rsc * Interprets . and .. as a convenience to callers.
469 ecc0a1b0 2008-06-15 rsc vacfilewalk(VacFile *f, char *elem)
471 3d77c87e 2004-03-15 devnull VacFile *ff;
473 3d77c87e 2004-03-15 devnull if(elem[0] == 0){
474 3d77c87e 2004-03-15 devnull werrstr(EBadPath);
475 7763a61a 2003-11-23 devnull return nil;
478 3d77c87e 2004-03-15 devnull if(!vacfileisdir(f)){
479 3d77c87e 2004-03-15 devnull werrstr(ENotDir);
480 7763a61a 2003-11-23 devnull return nil;
483 ecc0a1b0 2008-06-15 rsc if(strcmp(elem, ".") == 0)
484 3d77c87e 2004-03-15 devnull return vacfileincref(f);
486 ecc0a1b0 2008-06-15 rsc if(strcmp(elem, "..") == 0)
487 ecc0a1b0 2008-06-15 rsc return vacfilegetparent(f);
489 3d77c87e 2004-03-15 devnull if(filelock(f) < 0)
490 7763a61a 2003-11-23 devnull return nil;
492 3d77c87e 2004-03-15 devnull for(ff = f->down; ff; ff=ff->next){
493 3d77c87e 2004-03-15 devnull if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
494 3d77c87e 2004-03-15 devnull ff->ref++;
495 7763a61a 2003-11-23 devnull goto Exit;
499 3d77c87e 2004-03-15 devnull ff = dirlookup(f, elem);
500 3d77c87e 2004-03-15 devnull if(ff == nil)
501 7763a61a 2003-11-23 devnull goto Err;
503 3d77c87e 2004-03-15 devnull if(ff->dir.mode & ModeSnapshot)
504 3d77c87e 2004-03-15 devnull ff->mode = VtOREAD;
506 ecc0a1b0 2008-06-15 rsc if(vtfilelock(f->source, f->mode) < 0)
508 ecc0a1b0 2008-06-15 rsc if(ff->dir.mode & ModeDir){
509 3d77c87e 2004-03-15 devnull ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
510 3d77c87e 2004-03-15 devnull ff->msource = fileopensource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
511 3d77c87e 2004-03-15 devnull if(ff->source == nil || ff->msource == nil)
514 3d77c87e 2004-03-15 devnull ff->source = fileopensource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
515 3d77c87e 2004-03-15 devnull if(ff->source == nil)
518 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
520 7763a61a 2003-11-23 devnull /* link in and up parent ref count */
521 3d77c87e 2004-03-15 devnull ff->next = f->down;
522 3d77c87e 2004-03-15 devnull f->down = ff;
523 3d77c87e 2004-03-15 devnull ff->up = f;
524 3d77c87e 2004-03-15 devnull vacfileincref(f);
526 3d77c87e 2004-03-15 devnull fileunlock(f);
527 3d77c87e 2004-03-15 devnull return ff;
530 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
532 3d77c87e 2004-03-15 devnull fileunlock(f);
533 3d77c87e 2004-03-15 devnull if(ff != nil)
534 3d77c87e 2004-03-15 devnull vacfiledecref(ff);
535 7763a61a 2003-11-23 devnull return nil;
539 ecc0a1b0 2008-06-15 rsc * Open a path in the vac file system:
540 ecc0a1b0 2008-06-15 rsc * just walk each element one at a time.
542 3d77c87e 2004-03-15 devnull VacFile*
543 ecc0a1b0 2008-06-15 rsc vacfileopen(VacFs *fs, char *path)
545 3d77c87e 2004-03-15 devnull VacFile *f, *ff;
546 3d77c87e 2004-03-15 devnull char *p, elem[VtMaxStringSize], *opath;
549 3d77c87e 2004-03-15 devnull f = fs->root;
550 3d77c87e 2004-03-15 devnull vacfileincref(f);
551 3d77c87e 2004-03-15 devnull opath = path;
552 3d77c87e 2004-03-15 devnull while(*path != 0){
553 7763a61a 2003-11-23 devnull for(p = path; *p && *p != '/'; p++)
555 7763a61a 2003-11-23 devnull n = p - path;
556 3d77c87e 2004-03-15 devnull if(n > 0){
557 3d77c87e 2004-03-15 devnull if(n > VtMaxStringSize){
558 3d77c87e 2004-03-15 devnull werrstr("%s: element too long", EBadPath);
559 7763a61a 2003-11-23 devnull goto Err;
561 7763a61a 2003-11-23 devnull memmove(elem, path, n);
562 7763a61a 2003-11-23 devnull elem[n] = 0;
563 ecc0a1b0 2008-06-15 rsc ff = vacfilewalk(f, elem);
564 3d77c87e 2004-03-15 devnull if(ff == nil){
565 c52cda30 2008-06-14 rsc werrstr("%.*s: %r", utfnlen(opath, p-opath), opath);
566 7763a61a 2003-11-23 devnull goto Err;
568 3d77c87e 2004-03-15 devnull vacfiledecref(f);
571 7763a61a 2003-11-23 devnull if(*p == '/')
573 7763a61a 2003-11-23 devnull path = p;
575 3d77c87e 2004-03-15 devnull return f;
577 3d77c87e 2004-03-15 devnull vacfiledecref(f);
578 7763a61a 2003-11-23 devnull return nil;
582 ecc0a1b0 2008-06-15 rsc * Extract the score for the bn'th block in f.
585 3d77c87e 2004-03-15 devnull vacfileblockscore(VacFile *f, u32int bn, u8int *score)
587 3d77c87e 2004-03-15 devnull VtFile *s;
588 7763a61a 2003-11-23 devnull uvlong size;
589 3d77c87e 2004-03-15 devnull int dsize, ret;
591 3d77c87e 2004-03-15 devnull ret = -1;
592 3d77c87e 2004-03-15 devnull if(filerlock(f) < 0)
593 3d77c87e 2004-03-15 devnull return -1;
594 3d77c87e 2004-03-15 devnull if(vtfilelock(f->source, VtOREAD) < 0)
595 3d77c87e 2004-03-15 devnull goto out;
597 3d77c87e 2004-03-15 devnull s = f->source;
598 3d77c87e 2004-03-15 devnull dsize = s->dsize;
599 3d77c87e 2004-03-15 devnull size = vtfilegetsize(s);
600 3d77c87e 2004-03-15 devnull if((uvlong)bn*dsize >= size)
602 3d77c87e 2004-03-15 devnull ret = vtfileblockscore(f->source, bn, score);
605 3d77c87e 2004-03-15 devnull vtfileunlock(f->source);
607 3d77c87e 2004-03-15 devnull filerunlock(f);
608 3d77c87e 2004-03-15 devnull return ret;
612 ecc0a1b0 2008-06-15 rsc * Read data from f.
615 3d77c87e 2004-03-15 devnull vacfileread(VacFile *f, void *buf, int cnt, vlong offset)
619 3d77c87e 2004-03-15 devnull if(offset < 0){
620 3d77c87e 2004-03-15 devnull werrstr(EBadOffset);
623 ecc0a1b0 2008-06-15 rsc if(filerlock(f) < 0)
625 ecc0a1b0 2008-06-15 rsc if(vtfilelock(f->source, VtOREAD) < 0){
626 ecc0a1b0 2008-06-15 rsc filerunlock(f);
629 ecc0a1b0 2008-06-15 rsc n = vtfileread(f->source, buf, cnt, offset);
630 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
631 3d77c87e 2004-03-15 devnull filerunlock(f);
636 ecc0a1b0 2008-06-15 rsc getentry(VtFile *f, VtEntry *e)
638 ecc0a1b0 2008-06-15 rsc if(vtfilelock(f, VtOREAD) < 0)
639 3d77c87e 2004-03-15 devnull return -1;
640 ecc0a1b0 2008-06-15 rsc if(vtfilegetentry(f, e) < 0){
641 ecc0a1b0 2008-06-15 rsc vtfileunlock(f);
644 ecc0a1b0 2008-06-15 rsc vtfileunlock(f);
645 ecc0a1b0 2008-06-15 rsc if(vtglobaltolocal(e->score) != NilBlock){
646 ecc0a1b0 2008-06-15 rsc werrstr("internal error - data not on venti");
647 3d77c87e 2004-03-15 devnull return -1;
653 ecc0a1b0 2008-06-15 rsc * Get the VtEntries for the data contained in f.
656 ecc0a1b0 2008-06-15 rsc vacfilegetentries(VacFile *f, VtEntry *e, VtEntry *me)
658 3d77c87e 2004-03-15 devnull if(filerlock(f) < 0)
659 3d77c87e 2004-03-15 devnull return -1;
660 ecc0a1b0 2008-06-15 rsc if(e && getentry(f->source, e) < 0){
661 ecc0a1b0 2008-06-15 rsc filerunlock(f);
665 ecc0a1b0 2008-06-15 rsc if(f->msource == nil)
666 ecc0a1b0 2008-06-15 rsc memset(me, 0, sizeof *me);
667 9b3ac170 2008-07-02 rsc else if(getentry(f->msource, me) < 0){
668 3d77c87e 2004-03-15 devnull filerunlock(f);
669 3d77c87e 2004-03-15 devnull return -1;
672 3d77c87e 2004-03-15 devnull filerunlock(f);
673 3d77c87e 2004-03-15 devnull return 0;
677 ecc0a1b0 2008-06-15 rsc * Get the file's size.
680 ecc0a1b0 2008-06-15 rsc vacfilegetsize(VacFile *f, uvlong *size)
682 ecc0a1b0 2008-06-15 rsc if(filerlock(f) < 0)
683 3d77c87e 2004-03-15 devnull return -1;
684 ecc0a1b0 2008-06-15 rsc if(vtfilelock(f->source, VtOREAD) < 0){
685 ecc0a1b0 2008-06-15 rsc filerunlock(f);
686 3d77c87e 2004-03-15 devnull return -1;
688 ecc0a1b0 2008-06-15 rsc *size = vtfilegetsize(f->source);
689 3d77c87e 2004-03-15 devnull vtfileunlock(f->source);
690 ecc0a1b0 2008-06-15 rsc filerunlock(f);
692 3d77c87e 2004-03-15 devnull return 0;
696 ecc0a1b0 2008-06-15 rsc * Directory reading.
698 ecc0a1b0 2008-06-15 rsc * A VacDirEnum is a buffer containing directory entries.
699 ecc0a1b0 2008-06-15 rsc * Directory entries contain malloced strings and need to
700 ecc0a1b0 2008-06-15 rsc * be cleaned up with vdcleanup. The invariant in the
701 ecc0a1b0 2008-06-15 rsc * VacDirEnum is that the directory entries between
702 ecc0a1b0 2008-06-15 rsc * vde->i and vde->n are owned by the vde and need to
703 ecc0a1b0 2008-06-15 rsc * be cleaned up if it is closed. Those from 0 up to vde->i
704 ecc0a1b0 2008-06-15 rsc * have been handed to the reader, and the reader must
705 ecc0a1b0 2008-06-15 rsc * take care of calling vdcleanup as appropriate.
708 ecc0a1b0 2008-06-15 rsc vdeopen(VacFile *f)
710 ecc0a1b0 2008-06-15 rsc VacDirEnum *vde;
713 ecc0a1b0 2008-06-15 rsc if(!vacfileisdir(f)){
714 ecc0a1b0 2008-06-15 rsc werrstr(ENotDir);
719 ecc0a1b0 2008-06-15 rsc * There might be changes to this directory's children
720 ecc0a1b0 2008-06-15 rsc * that have not been flushed out into the cache yet.
721 ecc0a1b0 2008-06-15 rsc * Those changes are only available if we look at the
722 ecc0a1b0 2008-06-15 rsc * VacFile structures directory. But the directory reader
723 ecc0a1b0 2008-06-15 rsc * is going to read the cache blocks directly, so update them.
725 3d77c87e 2004-03-15 devnull if(filelock(f) < 0)
727 ecc0a1b0 2008-06-15 rsc for(p=f->down; p; p=p->next)
728 ecc0a1b0 2008-06-15 rsc filemetaflush(p, nil);
729 ecc0a1b0 2008-06-15 rsc fileunlock(f);
731 ecc0a1b0 2008-06-15 rsc vde = vtmallocz(sizeof(VacDirEnum));
732 ecc0a1b0 2008-06-15 rsc vde->file = vacfileincref(f);
738 ecc0a1b0 2008-06-15 rsc * Figure out the size of the directory entry at offset.
739 ecc0a1b0 2008-06-15 rsc * The rest of the metadata is kept in the data half,
740 ecc0a1b0 2008-06-15 rsc * but since venti has to track the data size anyway,
741 ecc0a1b0 2008-06-15 rsc * we just use that one and avoid updating the directory
742 ecc0a1b0 2008-06-15 rsc * each time the file size changes.
745 ecc0a1b0 2008-06-15 rsc direntrysize(VtFile *s, ulong offset, ulong gen, uvlong *size)
752 ecc0a1b0 2008-06-15 rsc epb = s->dsize/VtEntrySize;
753 ecc0a1b0 2008-06-15 rsc bn = offset/epb;
754 ecc0a1b0 2008-06-15 rsc offset -= bn*epb;
756 ecc0a1b0 2008-06-15 rsc b = vtfileblock(s, bn, VtOREAD);
757 ecc0a1b0 2008-06-15 rsc if(b == nil)
758 7763a61a 2003-11-23 devnull goto Err;
759 ecc0a1b0 2008-06-15 rsc if(vtentryunpack(&e, b->data, offset) < 0)
762 ecc0a1b0 2008-06-15 rsc /* dangling entries are returned as zero size */
763 ecc0a1b0 2008-06-15 rsc if(!(e.flags & VtEntryActive) || e.gen != gen)
766 ecc0a1b0 2008-06-15 rsc *size = e.size;
767 ecc0a1b0 2008-06-15 rsc vtblockput(b);
771 ecc0a1b0 2008-06-15 rsc vtblockput(b);
776 ecc0a1b0 2008-06-15 rsc * Fill in vde with a new batch of directory entries.
779 ecc0a1b0 2008-06-15 rsc vdefill(VacDirEnum *vde)
782 ecc0a1b0 2008-06-15 rsc VtFile *meta, *source;
783 ecc0a1b0 2008-06-15 rsc MetaBlock mb;
784 ecc0a1b0 2008-06-15 rsc MetaEntry me;
789 ecc0a1b0 2008-06-15 rsc /* clean up first */
790 ecc0a1b0 2008-06-15 rsc for(i=vde->i; i<vde->n; i++)
791 ecc0a1b0 2008-06-15 rsc vdcleanup(vde->buf+i);
792 ecc0a1b0 2008-06-15 rsc vtfree(vde->buf);
793 ecc0a1b0 2008-06-15 rsc vde->buf = nil;
797 ecc0a1b0 2008-06-15 rsc f = vde->file;
799 ecc0a1b0 2008-06-15 rsc source = f->source;
800 ecc0a1b0 2008-06-15 rsc meta = f->msource;
802 ecc0a1b0 2008-06-15 rsc b = vtfileblock(meta, vde->boff, VtOREAD);
803 ecc0a1b0 2008-06-15 rsc if(b == nil)
805 ecc0a1b0 2008-06-15 rsc if(mbunpack(&mb, b->data, meta->dsize) < 0)
808 ecc0a1b0 2008-06-15 rsc n = mb.nindex;
809 ecc0a1b0 2008-06-15 rsc vde->buf = vtmalloc(n * sizeof(VacDir));
811 ecc0a1b0 2008-06-15 rsc for(i=0; i<n; i++){
812 ecc0a1b0 2008-06-15 rsc de = vde->buf + i;
813 ecc0a1b0 2008-06-15 rsc meunpack(&me, &mb, i);
814 ecc0a1b0 2008-06-15 rsc if(vdunpack(de, &me) < 0)
817 ecc0a1b0 2008-06-15 rsc if(!(de->mode & ModeDir))
818 ecc0a1b0 2008-06-15 rsc if(direntrysize(source, de->entry, de->gen, &de->size) < 0)
821 ecc0a1b0 2008-06-15 rsc vde->boff++;
822 ecc0a1b0 2008-06-15 rsc vtblockput(b);
823 7763a61a 2003-11-23 devnull return 0;
825 ecc0a1b0 2008-06-15 rsc vtblockput(b);
826 3d77c87e 2004-03-15 devnull return -1;
830 ecc0a1b0 2008-06-15 rsc * Read a single directory entry from vde into de.
831 ecc0a1b0 2008-06-15 rsc * Returns -1 on error, 0 on EOF, and 1 on success.
832 ecc0a1b0 2008-06-15 rsc * When it returns 1, it becomes the caller's responsibility
833 ecc0a1b0 2008-06-15 rsc * to call vdcleanup(de) to free the strings contained
834 ecc0a1b0 2008-06-15 rsc * inside, or else to call vdunread to give it back.
837 ecc0a1b0 2008-06-15 rsc vderead(VacDirEnum *vde, VacDir *de)
839 3d77c87e 2004-03-15 devnull int ret;
843 ecc0a1b0 2008-06-15 rsc f = vde->file;
844 ecc0a1b0 2008-06-15 rsc if(filerlock(f) < 0)
845 3d77c87e 2004-03-15 devnull return -1;
847 ecc0a1b0 2008-06-15 rsc if(vtfilelock2(f->source, f->msource, VtOREAD) < 0){
848 ecc0a1b0 2008-06-15 rsc filerunlock(f);
852 ecc0a1b0 2008-06-15 rsc nb = (vtfilegetsize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
854 ecc0a1b0 2008-06-15 rsc while(vde->i >= vde->n){
855 ecc0a1b0 2008-06-15 rsc if(vde->boff >= nb){
857 ecc0a1b0 2008-06-15 rsc goto Return;
859 ecc0a1b0 2008-06-15 rsc if(vdefill(vde) < 0){
861 ecc0a1b0 2008-06-15 rsc goto Return;
865 ecc0a1b0 2008-06-15 rsc memmove(de, vde->buf + vde->i, sizeof(VacDir));
870 3d77c87e 2004-03-15 devnull vtfileunlock(f->source);
871 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->msource);
872 3d77c87e 2004-03-15 devnull filerunlock(f);
878 ecc0a1b0 2008-06-15 rsc * "Unread" the last directory entry that was read,
879 ecc0a1b0 2008-06-15 rsc * so that the next vderead will return the same one.
880 ecc0a1b0 2008-06-15 rsc * If the caller calls vdeunread(vde) it should not call
881 ecc0a1b0 2008-06-15 rsc * vdcleanup on the entry being "unread".
884 ecc0a1b0 2008-06-15 rsc vdeunread(VacDirEnum *vde)
886 ecc0a1b0 2008-06-15 rsc if(vde->i > 0){
888 7763a61a 2003-11-23 devnull return 0;
894 ecc0a1b0 2008-06-15 rsc * Close the enumerator.
897 ecc0a1b0 2008-06-15 rsc vdeclose(VacDirEnum *vde)
900 ecc0a1b0 2008-06-15 rsc if(vde == nil)
902 ecc0a1b0 2008-06-15 rsc /* free the strings */
903 ecc0a1b0 2008-06-15 rsc for(i=vde->i; i<vde->n; i++)
904 ecc0a1b0 2008-06-15 rsc vdcleanup(vde->buf+i);
905 ecc0a1b0 2008-06-15 rsc vtfree(vde->buf);
906 ecc0a1b0 2008-06-15 rsc vacfiledecref(vde->file);
907 ecc0a1b0 2008-06-15 rsc vtfree(vde);
912 ecc0a1b0 2008-06-15 rsc * On to mutation. If the vac file system has been opened
913 ecc0a1b0 2008-06-15 rsc * read-write, then the files and directories can all be edited.
914 ecc0a1b0 2008-06-15 rsc * Changes are kept in the in-memory cache until flushed out
915 ecc0a1b0 2008-06-15 rsc * to venti, so we must be careful to explicitly flush data
916 ecc0a1b0 2008-06-15 rsc * that we're not likely to modify again.
918 ecc0a1b0 2008-06-15 rsc * Each VacFile has its own copy of its VacDir directory entry
919 ecc0a1b0 2008-06-15 rsc * in f->dir, but otherwise the cache is the authoratative source
920 ecc0a1b0 2008-06-15 rsc * for data. Thus, for the most part, it suffices if we just
921 ecc0a1b0 2008-06-15 rsc * call vtfileflushbefore and vtfileflush when we modify things.
922 ecc0a1b0 2008-06-15 rsc * There are a few places where we have to remember to write
923 ecc0a1b0 2008-06-15 rsc * changed VacDirs back into the cache. If f->dir *is* out of sync,
924 ecc0a1b0 2008-06-15 rsc * then f->dirty should be set.
926 ecc0a1b0 2008-06-15 rsc * The metadata in a directory is, to venti, a plain data file,
927 ecc0a1b0 2008-06-15 rsc * but as mentioned above it is actually a sequence of
928 ecc0a1b0 2008-06-15 rsc * MetaBlocks that contain sorted lists of VacDir entries.
929 ecc0a1b0 2008-06-15 rsc * The filemetaxxx routines manipulate that stream.
933 ecc0a1b0 2008-06-15 rsc * Find space in fp for the directory entry dir (not yet written to disk)
934 ecc0a1b0 2008-06-15 rsc * and write it to disk, returning NilBlock on failure,
935 ecc0a1b0 2008-06-15 rsc * or the block number on success.
937 ecc0a1b0 2008-06-15 rsc * Start is a suggested block number to try.
938 ecc0a1b0 2008-06-15 rsc * The caller must have filemetalock'ed f and have
939 ecc0a1b0 2008-06-15 rsc * vtfilelock'ed f->up->msource.
941 ecc0a1b0 2008-06-15 rsc static u32int
942 ecc0a1b0 2008-06-15 rsc filemetaalloc(VacFile *fp, VacDir *dir, u32int start)
944 ecc0a1b0 2008-06-15 rsc u32int nb, bo;
946 ecc0a1b0 2008-06-15 rsc MetaBlock mb;
950 ecc0a1b0 2008-06-15 rsc MetaEntry me;
953 ecc0a1b0 2008-06-15 rsc ms = fp->msource;
954 ecc0a1b0 2008-06-15 rsc n = vdsize(dir, VacDirVersion);
956 ecc0a1b0 2008-06-15 rsc /* Look for a block with room for a new entry of size n. */
957 ecc0a1b0 2008-06-15 rsc nb = (vtfilegetsize(ms)+ms->dsize-1)/ms->dsize;
958 ecc0a1b0 2008-06-15 rsc if(start == NilBlock){
960 ecc0a1b0 2008-06-15 rsc start = nb - 1;
965 ecc0a1b0 2008-06-15 rsc if(start > nb)
967 ecc0a1b0 2008-06-15 rsc for(bo=start; bo<nb; bo++){
968 ecc0a1b0 2008-06-15 rsc if((b = vtfileblock(ms, bo, VtOREAD)) == nil)
970 ecc0a1b0 2008-06-15 rsc if(mbunpack(&mb, b->data, ms->dsize) < 0)
972 ecc0a1b0 2008-06-15 rsc nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
973 ecc0a1b0 2008-06-15 rsc if(n <= nn && mb.nindex < mb.maxindex){
974 ecc0a1b0 2008-06-15 rsc /* reopen for writing */
975 ecc0a1b0 2008-06-15 rsc vtblockput(b);
976 ecc0a1b0 2008-06-15 rsc if((b = vtfileblock(ms, bo, VtORDWR)) == nil)
978 e05b0ff3 2008-07-03 rsc mbunpack(&mb, b->data, ms->dsize);
981 ecc0a1b0 2008-06-15 rsc vtblockput(b);
984 ecc0a1b0 2008-06-15 rsc /* No block found, extend the file by one metablock. */
985 ecc0a1b0 2008-06-15 rsc vtfileflushbefore(ms, nb*(uvlong)ms->dsize);
986 ecc0a1b0 2008-06-15 rsc if((b = vtfileblock(ms, nb, VtORDWR)) == nil)
988 ecc0a1b0 2008-06-15 rsc vtfilesetsize(ms, (nb+1)*ms->dsize);
989 ecc0a1b0 2008-06-15 rsc mbinit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
992 ecc0a1b0 2008-06-15 rsc /* Now we have a block; allocate space to write the entry. */
993 ecc0a1b0 2008-06-15 rsc p = mballoc(&mb, n);
994 ecc0a1b0 2008-06-15 rsc if(p == nil){
995 ecc0a1b0 2008-06-15 rsc /* mballoc might have changed block */
996 ecc0a1b0 2008-06-15 rsc mbpack(&mb);
997 ecc0a1b0 2008-06-15 rsc werrstr(EBadMeta);
1001 ecc0a1b0 2008-06-15 rsc /* Figure out where to put the index entry, and write it. */
1002 ecc0a1b0 2008-06-15 rsc mbsearch(&mb, dir->elem, &i, &me);
1003 ecc0a1b0 2008-06-15 rsc assert(me.p == nil); /* not already there */
1005 ecc0a1b0 2008-06-15 rsc me.size = n;
1006 ecc0a1b0 2008-06-15 rsc vdpack(dir, &me, VacDirVersion);
1007 ecc0a1b0 2008-06-15 rsc mbinsert(&mb, i, &me);
1008 ecc0a1b0 2008-06-15 rsc mbpack(&mb);
1009 ecc0a1b0 2008-06-15 rsc vtblockput(b);
1013 ecc0a1b0 2008-06-15 rsc vtblockput(b);
1014 ecc0a1b0 2008-06-15 rsc return NilBlock;
1018 ecc0a1b0 2008-06-15 rsc * Update f's directory entry in the block cache.
1019 ecc0a1b0 2008-06-15 rsc * We look for the directory entry by name;
1020 ecc0a1b0 2008-06-15 rsc * if we're trying to rename the file, oelem is the old name.
1022 ecc0a1b0 2008-06-15 rsc * Assumes caller has filemetalock'ed f.
1024 3d77c87e 2004-03-15 devnull static int
1025 ecc0a1b0 2008-06-15 rsc filemetaflush(VacFile *f, char *oelem)
1028 3d77c87e 2004-03-15 devnull MetaBlock mb;
1029 3d77c87e 2004-03-15 devnull MetaEntry me, me2;
1030 ecc0a1b0 2008-06-15 rsc VacFile *fp;
1031 ecc0a1b0 2008-06-15 rsc VtBlock *b;
1034 3d77c87e 2004-03-15 devnull if(!f->dirty)
1035 7763a61a 2003-11-23 devnull return 0;
1037 3d77c87e 2004-03-15 devnull if(oelem == nil)
1038 3d77c87e 2004-03-15 devnull oelem = f->dir.elem;
1041 ecc0a1b0 2008-06-15 rsc * Locate f's old metadata in the parent's metadata file.
1042 ecc0a1b0 2008-06-15 rsc * We know which block it was in, but not exactly where
1043 ecc0a1b0 2008-06-15 rsc * in the block.
1045 3d77c87e 2004-03-15 devnull fp = f->up;
1046 3d77c87e 2004-03-15 devnull if(vtfilelock(fp->msource, -1) < 0)
1048 3d77c87e 2004-03-15 devnull /* can happen if source is clri'ed out from under us */
1049 3d77c87e 2004-03-15 devnull if(f->boff == NilBlock)
1050 3d77c87e 2004-03-15 devnull goto Err1;
1051 3d77c87e 2004-03-15 devnull b = vtfileblock(fp->msource, f->boff, VtORDWR);
1052 3d77c87e 2004-03-15 devnull if(b == nil)
1053 3d77c87e 2004-03-15 devnull goto Err1;
1054 3d77c87e 2004-03-15 devnull if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1055 7763a61a 2003-11-23 devnull goto Err;
1056 3d77c87e 2004-03-15 devnull if(mbsearch(&mb, oelem, &i, &me) < 0)
1057 3d77c87e 2004-03-15 devnull goto Err;
1060 ecc0a1b0 2008-06-15 rsc * Check whether we can resize the entry and keep it
1061 ecc0a1b0 2008-06-15 rsc * in this block.
1063 64f9764e 2008-06-14 rsc n = vdsize(&f->dir, VacDirVersion);
1064 3d77c87e 2004-03-15 devnull if(mbresize(&mb, &me, n) >= 0){
1065 ecc0a1b0 2008-06-15 rsc /* Okay, can be done without moving to another block. */
1067 ecc0a1b0 2008-06-15 rsc /* Remove old data */
1068 3d77c87e 2004-03-15 devnull mbdelete(&mb, i, &me);
1070 ecc0a1b0 2008-06-15 rsc /* Find new location if renaming */
1071 3d77c87e 2004-03-15 devnull if(strcmp(f->dir.elem, oelem) != 0)
1072 3d77c87e 2004-03-15 devnull mbsearch(&mb, f->dir.elem, &i, &me2);
1074 ecc0a1b0 2008-06-15 rsc /* Pack new data into new location. */
1075 64f9764e 2008-06-14 rsc vdpack(&f->dir, &me, VacDirVersion);
1076 003c13aa 2008-06-15 rsc vdunpack(&f->dir, &me);
1077 3d77c87e 2004-03-15 devnull mbinsert(&mb, i, &me);
1078 3d77c87e 2004-03-15 devnull mbpack(&mb);
1081 3d77c87e 2004-03-15 devnull vtblockput(b);
1082 3d77c87e 2004-03-15 devnull vtfileunlock(fp->msource);
1083 3d77c87e 2004-03-15 devnull f->dirty = 0;
1088 ecc0a1b0 2008-06-15 rsc * The entry must be moved to another block.
1089 ecc0a1b0 2008-06-15 rsc * This can only really happen on renames that
1090 ecc0a1b0 2008-06-15 rsc * make the name very long.
1093 ecc0a1b0 2008-06-15 rsc /* Allocate a spot in a new block. */
1094 ecc0a1b0 2008-06-15 rsc if((bo = filemetaalloc(fp, &f->dir, f->boff+1)) == NilBlock){
1095 ecc0a1b0 2008-06-15 rsc /* mbresize above might have modified block */
1096 3d77c87e 2004-03-15 devnull mbpack(&mb);
1097 3d77c87e 2004-03-15 devnull goto Err;
1099 ecc0a1b0 2008-06-15 rsc f->boff = bo;
1101 ecc0a1b0 2008-06-15 rsc /* Now we're committed. Delete entry in old block. */
1102 3d77c87e 2004-03-15 devnull mbdelete(&mb, i, &me);
1103 3d77c87e 2004-03-15 devnull mbpack(&mb);
1104 3d77c87e 2004-03-15 devnull vtblockput(b);
1105 3d77c87e 2004-03-15 devnull vtfileunlock(fp->msource);
1107 3d77c87e 2004-03-15 devnull f->dirty = 0;
1108 3d77c87e 2004-03-15 devnull return 0;
1111 3d77c87e 2004-03-15 devnull vtblockput(b);
1113 3d77c87e 2004-03-15 devnull vtfileunlock(fp->msource);
1114 3d77c87e 2004-03-15 devnull return -1;
1118 ecc0a1b0 2008-06-15 rsc * Remove the directory entry for f.
1120 3d77c87e 2004-03-15 devnull static int
1121 ecc0a1b0 2008-06-15 rsc filemetaremove(VacFile *f)
1123 3d77c87e 2004-03-15 devnull VtBlock *b;
1124 3d77c87e 2004-03-15 devnull MetaBlock mb;
1125 3d77c87e 2004-03-15 devnull MetaEntry me;
1127 ecc0a1b0 2008-06-15 rsc VacFile *fp;
1129 3d77c87e 2004-03-15 devnull b = nil;
1130 ecc0a1b0 2008-06-15 rsc fp = f->up;
1131 3d77c87e 2004-03-15 devnull filemetalock(f);
1133 ecc0a1b0 2008-06-15 rsc if(vtfilelock(fp->msource, VtORDWR) < 0)
1134 3d77c87e 2004-03-15 devnull goto Err;
1135 ecc0a1b0 2008-06-15 rsc b = vtfileblock(fp->msource, f->boff, VtORDWR);
1136 3d77c87e 2004-03-15 devnull if(b == nil)
1137 3d77c87e 2004-03-15 devnull goto Err;
1139 ecc0a1b0 2008-06-15 rsc if(mbunpack(&mb, b->data, fp->msource->dsize) < 0)
1140 3d77c87e 2004-03-15 devnull goto Err;
1141 3d77c87e 2004-03-15 devnull if(mbsearch(&mb, f->dir.elem, &i, &me) < 0)
1142 3d77c87e 2004-03-15 devnull goto Err;
1143 3d77c87e 2004-03-15 devnull mbdelete(&mb, i, &me);
1144 3d77c87e 2004-03-15 devnull mbpack(&mb);
1145 3d77c87e 2004-03-15 devnull vtblockput(b);
1146 ecc0a1b0 2008-06-15 rsc vtfileunlock(fp->msource);
1148 3d77c87e 2004-03-15 devnull f->removed = 1;
1149 3d77c87e 2004-03-15 devnull f->boff = NilBlock;
1150 3d77c87e 2004-03-15 devnull f->dirty = 0;
1152 3d77c87e 2004-03-15 devnull filemetaunlock(f);
1153 7763a61a 2003-11-23 devnull return 0;
1156 ecc0a1b0 2008-06-15 rsc vtfileunlock(fp->msource);
1157 3d77c87e 2004-03-15 devnull vtblockput(b);
1158 3d77c87e 2004-03-15 devnull filemetaunlock(f);
1159 3d77c87e 2004-03-15 devnull return -1;
1163 ecc0a1b0 2008-06-15 rsc * That was far too much effort for directory entries.
1164 ecc0a1b0 2008-06-15 rsc * Now we can write code that *does* things.
1168 ecc0a1b0 2008-06-15 rsc * Flush all data associated with f out of the cache and onto venti.
1169 ecc0a1b0 2008-06-15 rsc * If recursive is set, flush f's children too.
1170 e05b0ff3 2008-07-03 rsc * Vacfiledecref knows how to flush source and msource too.
1173 ecc0a1b0 2008-06-15 rsc vacfileflush(VacFile *f, int recursive)
1176 ecc0a1b0 2008-06-15 rsc VacFile **kids, *p;
1177 ecc0a1b0 2008-06-15 rsc int i, nkids;
1179 ecc0a1b0 2008-06-15 rsc if(f->mode == VtOREAD)
1183 ecc0a1b0 2008-06-15 rsc filemetalock(f);
1184 ecc0a1b0 2008-06-15 rsc if(filemetaflush(f, nil) < 0)
1186 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
1188 ecc0a1b0 2008-06-15 rsc if(filelock(f) < 0)
1192 ecc0a1b0 2008-06-15 rsc * Lock order prevents us from flushing kids while holding
1193 e05b0ff3 2008-07-03 rsc * lock, so make a list and then flush without the lock.
1196 ecc0a1b0 2008-06-15 rsc kids = nil;
1197 ecc0a1b0 2008-06-15 rsc if(recursive){
1199 ecc0a1b0 2008-06-15 rsc for(p=f->down; p; p=p->next)
1201 ecc0a1b0 2008-06-15 rsc kids = vtmalloc(nkids*sizeof(VacFile*));
1203 ecc0a1b0 2008-06-15 rsc for(p=f->down; p; p=p->next){
1204 ecc0a1b0 2008-06-15 rsc kids[i++] = p;
1208 e05b0ff3 2008-07-03 rsc if(nkids > 0){
1209 e05b0ff3 2008-07-03 rsc fileunlock(f);
1210 e05b0ff3 2008-07-03 rsc for(i=0; i<nkids; i++){
1211 e05b0ff3 2008-07-03 rsc if(vacfileflush(kids[i], 1) < 0)
1213 e05b0ff3 2008-07-03 rsc vacfiledecref(kids[i]);
1215 e05b0ff3 2008-07-03 rsc filelock(f);
1217 ecc0a1b0 2008-06-15 rsc free(kids);
1220 e05b0ff3 2008-07-03 rsc * Now we can flush our own data.
1222 e05b0ff3 2008-07-03 rsc vtfilelock(f->source, -1);
1223 e05b0ff3 2008-07-03 rsc if(vtfileflush(f->source) < 0)
1225 e05b0ff3 2008-07-03 rsc vtfileunlock(f->source);
1226 e05b0ff3 2008-07-03 rsc if(f->msource){
1227 e05b0ff3 2008-07-03 rsc vtfilelock(f->msource, -1);
1228 e05b0ff3 2008-07-03 rsc if(vtfileflush(f->msource) < 0)
1230 e05b0ff3 2008-07-03 rsc vtfileunlock(f->msource);
1232 e05b0ff3 2008-07-03 rsc fileunlock(f);
1234 ecc0a1b0 2008-06-15 rsc return ret;
1238 ecc0a1b0 2008-06-15 rsc * Create a new file named elem in fp with the given mode.
1239 ecc0a1b0 2008-06-15 rsc * The mode can be changed later except for the ModeDir bit.
1242 ecc0a1b0 2008-06-15 rsc vacfilecreate(VacFile *fp, char *elem, ulong mode)
1244 3d77c87e 2004-03-15 devnull VacFile *ff;
1245 ecc0a1b0 2008-06-15 rsc VacDir *dir;
1246 ecc0a1b0 2008-06-15 rsc VtFile *pr, *r, *mr;
1250 ecc0a1b0 2008-06-15 rsc if(filelock(fp) < 0)
1251 ecc0a1b0 2008-06-15 rsc return nil;
1254 ecc0a1b0 2008-06-15 rsc * First, look to see that there's not a file in memory
1255 ecc0a1b0 2008-06-15 rsc * with the same name.
1257 ecc0a1b0 2008-06-15 rsc for(ff = fp->down; ff; ff=ff->next){
1258 ecc0a1b0 2008-06-15 rsc if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
1260 ecc0a1b0 2008-06-15 rsc werrstr(EExists);
1266 ecc0a1b0 2008-06-15 rsc * Next check the venti blocks.
1268 ecc0a1b0 2008-06-15 rsc ff = dirlookup(fp, elem);
1269 ecc0a1b0 2008-06-15 rsc if(ff != nil){
1270 ecc0a1b0 2008-06-15 rsc werrstr(EExists);
1275 ecc0a1b0 2008-06-15 rsc * By the way, you can't create in a read-only file system.
1277 ecc0a1b0 2008-06-15 rsc pr = fp->source;
1278 ecc0a1b0 2008-06-15 rsc if(pr->mode != VtORDWR){
1279 3d77c87e 2004-03-15 devnull werrstr(EReadOnly);
1280 3d77c87e 2004-03-15 devnull goto Err1;
1284 ecc0a1b0 2008-06-15 rsc * Okay, time to actually create something. Lock the two
1285 ecc0a1b0 2008-06-15 rsc * halves of the directory and create a file.
1287 ecc0a1b0 2008-06-15 rsc if(vtfilelock2(fp->source, fp->msource, -1) < 0)
1288 3d77c87e 2004-03-15 devnull goto Err1;
1289 ecc0a1b0 2008-06-15 rsc ff = filealloc(fp->fs);
1290 003c13aa 2008-06-15 rsc ff->qidoffset = fp->qidoffset; /* hopefully fp->qidoffset == 0 */
1291 ecc0a1b0 2008-06-15 rsc type = VtDataType;
1292 ecc0a1b0 2008-06-15 rsc if(mode & ModeDir)
1293 ecc0a1b0 2008-06-15 rsc type = VtDirType;
1295 ecc0a1b0 2008-06-15 rsc if((r = vtfilecreate(pr, pr->psize, pr->dsize, type)) == nil)
1296 3d77c87e 2004-03-15 devnull goto Err;
1297 ecc0a1b0 2008-06-15 rsc if(mode & ModeDir)
1298 ecc0a1b0 2008-06-15 rsc if((mr = vtfilecreate(pr, pr->psize, pr->dsize, VtDataType)) == nil)
1302 ecc0a1b0 2008-06-15 rsc * Fill in the directory entry and write it to disk.
1304 ecc0a1b0 2008-06-15 rsc dir = &ff->dir;
1305 ecc0a1b0 2008-06-15 rsc dir->elem = vtstrdup(elem);
1306 ecc0a1b0 2008-06-15 rsc dir->entry = r->offset;
1307 ecc0a1b0 2008-06-15 rsc dir->gen = r->gen;
1308 ecc0a1b0 2008-06-15 rsc if(mode & ModeDir){
1309 ecc0a1b0 2008-06-15 rsc dir->mentry = mr->offset;
1310 ecc0a1b0 2008-06-15 rsc dir->mgen = mr->gen;
1312 ecc0a1b0 2008-06-15 rsc dir->size = 0;
1313 ecc0a1b0 2008-06-15 rsc if(_vacfsnextqid(fp->fs, &dir->qid) < 0)
1315 ecc0a1b0 2008-06-15 rsc dir->uid = vtstrdup(fp->dir.uid);
1316 ecc0a1b0 2008-06-15 rsc dir->gid = vtstrdup(fp->dir.gid);
1317 ecc0a1b0 2008-06-15 rsc dir->mid = vtstrdup("");
1318 ecc0a1b0 2008-06-15 rsc dir->mtime = time(0L);
1319 ecc0a1b0 2008-06-15 rsc dir->mcount = 0;
1320 ecc0a1b0 2008-06-15 rsc dir->ctime = dir->mtime;
1321 ecc0a1b0 2008-06-15 rsc dir->atime = dir->mtime;
1322 ecc0a1b0 2008-06-15 rsc dir->mode = mode;
1323 948cc14e 2008-06-15 rsc if((bo = filemetaalloc(fp, &ff->dir, NilBlock)) == NilBlock)
1327 ecc0a1b0 2008-06-15 rsc * Now we're committed.
1329 ecc0a1b0 2008-06-15 rsc vtfileunlock(fp->source);
1330 ecc0a1b0 2008-06-15 rsc vtfileunlock(fp->msource);
1331 ecc0a1b0 2008-06-15 rsc ff->source = r;
1332 ecc0a1b0 2008-06-15 rsc ff->msource = mr;
1333 ecc0a1b0 2008-06-15 rsc ff->boff = bo;
1335 ecc0a1b0 2008-06-15 rsc /* Link into tree. */
1336 ecc0a1b0 2008-06-15 rsc ff->next = fp->down;
1337 ecc0a1b0 2008-06-15 rsc fp->down = ff;
1338 ecc0a1b0 2008-06-15 rsc ff->up = fp;
1339 ecc0a1b0 2008-06-15 rsc vacfileincref(fp);
1341 ecc0a1b0 2008-06-15 rsc fileunlock(fp);
1343 e05b0ff3 2008-07-03 rsc filelock(ff);
1344 e05b0ff3 2008-07-03 rsc vtfilelock(ff->source, -1);
1345 e05b0ff3 2008-07-03 rsc vtfileunlock(ff->source);
1346 e05b0ff3 2008-07-03 rsc fileunlock(ff);
1351 ecc0a1b0 2008-06-15 rsc vtfileunlock(fp->source);
1352 ecc0a1b0 2008-06-15 rsc vtfileunlock(fp->msource);
1354 ecc0a1b0 2008-06-15 rsc vtfilelock(r, -1);
1355 ecc0a1b0 2008-06-15 rsc vtfileremove(r);
1358 ecc0a1b0 2008-06-15 rsc vtfilelock(mr, -1);
1359 ecc0a1b0 2008-06-15 rsc vtfileremove(mr);
1363 ecc0a1b0 2008-06-15 rsc vacfiledecref(ff);
1364 ecc0a1b0 2008-06-15 rsc fileunlock(fp);
1365 ecc0a1b0 2008-06-15 rsc return nil;
1369 ecc0a1b0 2008-06-15 rsc * Change the size of the file f.
1372 ecc0a1b0 2008-06-15 rsc vacfilesetsize(VacFile *f, uvlong size)
1374 ecc0a1b0 2008-06-15 rsc if(vacfileisdir(f)){
1375 ecc0a1b0 2008-06-15 rsc werrstr(ENotFile);
1376 3d77c87e 2004-03-15 devnull return -1;
1379 ecc0a1b0 2008-06-15 rsc if(filelock(f) < 0)
1380 3d77c87e 2004-03-15 devnull return -1;
1382 ecc0a1b0 2008-06-15 rsc if(f->source->mode != VtORDWR){
1383 ecc0a1b0 2008-06-15 rsc werrstr(EReadOnly);
1386 ecc0a1b0 2008-06-15 rsc if(vtfilelock(f->source, -1) < 0)
1388 ecc0a1b0 2008-06-15 rsc if(vtfilesetsize(f->source, size) < 0){
1389 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1392 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1393 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1397 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1402 ecc0a1b0 2008-06-15 rsc * Write data to f.
1405 ecc0a1b0 2008-06-15 rsc vacfilewrite(VacFile *f, void *buf, int cnt, vlong offset)
1407 ecc0a1b0 2008-06-15 rsc if(vacfileisdir(f)){
1408 ecc0a1b0 2008-06-15 rsc werrstr(ENotFile);
1411 ecc0a1b0 2008-06-15 rsc if(filelock(f) < 0)
1413 ecc0a1b0 2008-06-15 rsc if(f->source->mode != VtORDWR){
1414 ecc0a1b0 2008-06-15 rsc werrstr(EReadOnly);
1417 ecc0a1b0 2008-06-15 rsc if(offset < 0){
1418 ecc0a1b0 2008-06-15 rsc werrstr(EBadOffset);
1422 ecc0a1b0 2008-06-15 rsc if(vtfilelock(f->source, -1) < 0)
1424 ecc0a1b0 2008-06-15 rsc if(f->dir.mode & ModeAppend)
1425 ecc0a1b0 2008-06-15 rsc offset = vtfilegetsize(f->source);
1426 ecc0a1b0 2008-06-15 rsc if(vtfilewrite(f->source, buf, cnt, offset) != cnt
1427 ecc0a1b0 2008-06-15 rsc || vtfileflushbefore(f->source, offset) < 0){
1428 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1431 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1432 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1433 ecc0a1b0 2008-06-15 rsc return cnt;
1436 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1441 ecc0a1b0 2008-06-15 rsc * Set (!) the VtEntry for the data contained in f.
1442 ecc0a1b0 2008-06-15 rsc * This let's us efficiently copy data from one file to another.
1445 ecc0a1b0 2008-06-15 rsc vacfilesetentries(VacFile *f, VtEntry *e, VtEntry *me)
1449 ecc0a1b0 2008-06-15 rsc vacfileflush(f, 0); /* flush blocks to venti, since we won't see them again */
1451 ecc0a1b0 2008-06-15 rsc if(!(e->flags&VtEntryActive)){
1452 ecc0a1b0 2008-06-15 rsc werrstr("missing entry for source");
1455 ecc0a1b0 2008-06-15 rsc if(me && !(me->flags&VtEntryActive))
1457 ecc0a1b0 2008-06-15 rsc if(f->msource && !me){
1458 ecc0a1b0 2008-06-15 rsc werrstr("missing entry for msource");
1461 ecc0a1b0 2008-06-15 rsc if(me && !f->msource){
1462 ecc0a1b0 2008-06-15 rsc werrstr("no msource to set");
1466 ecc0a1b0 2008-06-15 rsc if(filelock(f) < 0)
1467 3d77c87e 2004-03-15 devnull return -1;
1468 ecc0a1b0 2008-06-15 rsc if(f->source->mode != VtORDWR
1469 ecc0a1b0 2008-06-15 rsc || (f->msource && f->msource->mode != VtORDWR)){
1470 ecc0a1b0 2008-06-15 rsc werrstr(EReadOnly);
1471 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1474 ecc0a1b0 2008-06-15 rsc if(vtfilelock2(f->source, f->msource, -1) < 0){
1475 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1479 ecc0a1b0 2008-06-15 rsc if(vtfilesetentry(f->source, e) < 0)
1481 ecc0a1b0 2008-06-15 rsc else if(me && vtfilesetentry(f->msource, me) < 0)
1484 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1485 ecc0a1b0 2008-06-15 rsc if(f->msource)
1486 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->msource);
1487 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1488 ecc0a1b0 2008-06-15 rsc return ret;
1492 ecc0a1b0 2008-06-15 rsc * Get the directory entry for f.
1495 ecc0a1b0 2008-06-15 rsc vacfilegetdir(VacFile *f, VacDir *dir)
1497 ecc0a1b0 2008-06-15 rsc if(filerlock(f) < 0)
1500 ecc0a1b0 2008-06-15 rsc filemetalock(f);
1501 ecc0a1b0 2008-06-15 rsc vdcopy(dir, &f->dir);
1502 3d77c87e 2004-03-15 devnull filemetaunlock(f);
1504 ecc0a1b0 2008-06-15 rsc if(!vacfileisdir(f)){
1505 ecc0a1b0 2008-06-15 rsc if(vtfilelock(f->source, VtOREAD) < 0){
1506 ecc0a1b0 2008-06-15 rsc filerunlock(f);
1509 ecc0a1b0 2008-06-15 rsc dir->size = vtfilegetsize(f->source);
1510 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1512 ecc0a1b0 2008-06-15 rsc filerunlock(f);
1514 3d77c87e 2004-03-15 devnull return 0;
1518 ecc0a1b0 2008-06-15 rsc * Set the directory entry for f.
1521 ecc0a1b0 2008-06-15 rsc vacfilesetdir(VacFile *f, VacDir *dir)
1523 ecc0a1b0 2008-06-15 rsc VacFile *ff;
1524 ecc0a1b0 2008-06-15 rsc char *oelem;
1525 ecc0a1b0 2008-06-15 rsc u32int mask;
1526 ecc0a1b0 2008-06-15 rsc u64int size;
1528 ecc0a1b0 2008-06-15 rsc /* can not set permissions for the root */
1529 ecc0a1b0 2008-06-15 rsc if(vacfileisroot(f)){
1530 ecc0a1b0 2008-06-15 rsc werrstr(ERoot);
1534 3d77c87e 2004-03-15 devnull if(filelock(f) < 0)
1536 ecc0a1b0 2008-06-15 rsc filemetalock(f);
1538 ecc0a1b0 2008-06-15 rsc if(f->source->mode != VtORDWR){
1539 ecc0a1b0 2008-06-15 rsc werrstr(EReadOnly);
1543 ecc0a1b0 2008-06-15 rsc /* On rename, check new name does not already exist */
1544 ecc0a1b0 2008-06-15 rsc if(strcmp(f->dir.elem, dir->elem) != 0){
1545 ecc0a1b0 2008-06-15 rsc for(ff = f->up->down; ff; ff=ff->next){
1546 ecc0a1b0 2008-06-15 rsc if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
1547 ecc0a1b0 2008-06-15 rsc werrstr(EExists);
1551 ecc0a1b0 2008-06-15 rsc ff = dirlookup(f->up, dir->elem);
1552 ecc0a1b0 2008-06-15 rsc if(ff != nil){
1553 ecc0a1b0 2008-06-15 rsc vacfiledecref(ff);
1554 ecc0a1b0 2008-06-15 rsc werrstr(EExists);
1557 ecc0a1b0 2008-06-15 rsc werrstr(""); /* "failed" dirlookup poisoned it */
1560 ecc0a1b0 2008-06-15 rsc /* Get ready... */
1561 ecc0a1b0 2008-06-15 rsc if(vtfilelock2(f->source, f->msource, -1) < 0)
1563 ecc0a1b0 2008-06-15 rsc if(!vacfileisdir(f)){
1564 ecc0a1b0 2008-06-15 rsc size = vtfilegetsize(f->source);
1565 ecc0a1b0 2008-06-15 rsc if(size != dir->size){
1566 ecc0a1b0 2008-06-15 rsc if(vtfilesetsize(f->source, dir->size) < 0){
1567 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1568 ecc0a1b0 2008-06-15 rsc if(f->msource)
1569 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->msource);
1574 ecc0a1b0 2008-06-15 rsc /* ... now commited to changing it. */
1575 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->source);
1576 ecc0a1b0 2008-06-15 rsc if(f->msource)
1577 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->msource);
1579 ecc0a1b0 2008-06-15 rsc oelem = nil;
1580 ecc0a1b0 2008-06-15 rsc if(strcmp(f->dir.elem, dir->elem) != 0){
1581 ecc0a1b0 2008-06-15 rsc oelem = f->dir.elem;
1582 ecc0a1b0 2008-06-15 rsc f->dir.elem = vtstrdup(dir->elem);
1585 ecc0a1b0 2008-06-15 rsc if(strcmp(f->dir.uid, dir->uid) != 0){
1586 ecc0a1b0 2008-06-15 rsc vtfree(f->dir.uid);
1587 ecc0a1b0 2008-06-15 rsc f->dir.uid = vtstrdup(dir->uid);
1590 ecc0a1b0 2008-06-15 rsc if(strcmp(f->dir.gid, dir->gid) != 0){
1591 ecc0a1b0 2008-06-15 rsc vtfree(f->dir.gid);
1592 ecc0a1b0 2008-06-15 rsc f->dir.gid = vtstrdup(dir->gid);
1595 ecc0a1b0 2008-06-15 rsc f->dir.mtime = dir->mtime;
1596 ecc0a1b0 2008-06-15 rsc f->dir.atime = dir->atime;
1598 ecc0a1b0 2008-06-15 rsc mask = ~(ModeDir|ModeSnapshot);
1599 ecc0a1b0 2008-06-15 rsc f->dir.mode &= ~mask;
1600 ecc0a1b0 2008-06-15 rsc f->dir.mode |= mask & dir->mode;
1601 ecc0a1b0 2008-06-15 rsc f->dirty = 1;
1603 ecc0a1b0 2008-06-15 rsc if(filemetaflush(f, oelem) < 0){
1604 ecc0a1b0 2008-06-15 rsc vtfree(oelem);
1605 ecc0a1b0 2008-06-15 rsc goto Err; /* that sucks */
1607 ecc0a1b0 2008-06-15 rsc vtfree(oelem);
1609 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
1610 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1611 3d77c87e 2004-03-15 devnull return 0;
1614 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
1615 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1616 3d77c87e 2004-03-15 devnull return -1;
1620 ecc0a1b0 2008-06-15 rsc * Set the qid space.
1623 ecc0a1b0 2008-06-15 rsc vacfilesetqidspace(VacFile *f, u64int offset, u64int max)
1627 ecc0a1b0 2008-06-15 rsc if(filelock(f) < 0)
1629 003c13aa 2008-06-15 rsc if(f->source->mode != VtORDWR){
1630 003c13aa 2008-06-15 rsc fileunlock(f);
1631 003c13aa 2008-06-15 rsc werrstr(EReadOnly);
1634 ecc0a1b0 2008-06-15 rsc filemetalock(f);
1635 ecc0a1b0 2008-06-15 rsc f->dir.qidspace = 1;
1636 ecc0a1b0 2008-06-15 rsc f->dir.qidoffset = offset;
1637 ecc0a1b0 2008-06-15 rsc f->dir.qidmax = max;
1638 003c13aa 2008-06-15 rsc f->dirty = 1;
1639 ecc0a1b0 2008-06-15 rsc ret = filemetaflush(f, nil);
1640 ecc0a1b0 2008-06-15 rsc filemetaunlock(f);
1641 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1642 ecc0a1b0 2008-06-15 rsc return ret;
1646 ecc0a1b0 2008-06-15 rsc * Check that the file is empty, returning 0 if it is.
1647 ecc0a1b0 2008-06-15 rsc * Returns -1 on error (and not being empty is an error).
1649 3d77c87e 2004-03-15 devnull static int
1650 ecc0a1b0 2008-06-15 rsc filecheckempty(VacFile *f)
1652 ecc0a1b0 2008-06-15 rsc u32int i, n;
1653 3d77c87e 2004-03-15 devnull VtBlock *b;
1654 ecc0a1b0 2008-06-15 rsc MetaBlock mb;
1657 ecc0a1b0 2008-06-15 rsc r = f->msource;
1658 ecc0a1b0 2008-06-15 rsc n = (vtfilegetsize(r)+r->dsize-1)/r->dsize;
1659 3d77c87e 2004-03-15 devnull for(i=0; i<n; i++){
1660 ecc0a1b0 2008-06-15 rsc b = vtfileblock(r, i, VtOREAD);
1661 ecc0a1b0 2008-06-15 rsc if(b == nil)
1663 ecc0a1b0 2008-06-15 rsc if(mbunpack(&mb, b->data, r->dsize) < 0)
1664 7763a61a 2003-11-23 devnull goto Err;
1665 ecc0a1b0 2008-06-15 rsc if(mb.nindex > 0){
1666 ecc0a1b0 2008-06-15 rsc werrstr(ENotEmpty);
1667 3d77c87e 2004-03-15 devnull goto Err;
1669 ecc0a1b0 2008-06-15 rsc vtblockput(b);
1671 3d77c87e 2004-03-15 devnull return 0;
1674 3d77c87e 2004-03-15 devnull vtblockput(b);
1675 7763a61a 2003-11-23 devnull return -1;
1679 ecc0a1b0 2008-06-15 rsc * Remove the vac file f.
1682 ecc0a1b0 2008-06-15 rsc vacfileremove(VacFile *f)
1684 ecc0a1b0 2008-06-15 rsc VacFile *ff;
1686 ecc0a1b0 2008-06-15 rsc /* Cannot remove the root */
1687 ecc0a1b0 2008-06-15 rsc if(vacfileisroot(f)){
1688 ecc0a1b0 2008-06-15 rsc werrstr(ERoot);
1689 3d77c87e 2004-03-15 devnull return -1;
1692 ecc0a1b0 2008-06-15 rsc if(filelock(f) < 0)
1693 3d77c87e 2004-03-15 devnull return -1;
1694 ecc0a1b0 2008-06-15 rsc if(f->source->mode != VtORDWR){
1695 ecc0a1b0 2008-06-15 rsc werrstr(EReadOnly);
1698 ecc0a1b0 2008-06-15 rsc if(vtfilelock2(f->source, f->msource, -1) < 0)
1700 ecc0a1b0 2008-06-15 rsc if(vacfileisdir(f) && filecheckempty(f)<0)
1703 ecc0a1b0 2008-06-15 rsc for(ff=f->down; ff; ff=ff->next)
1704 ecc0a1b0 2008-06-15 rsc assert(ff->removed);
1706 ecc0a1b0 2008-06-15 rsc vtfileremove(f->source);
1707 ecc0a1b0 2008-06-15 rsc f->source = nil;
1708 ecc0a1b0 2008-06-15 rsc if(f->msource){
1709 ecc0a1b0 2008-06-15 rsc vtfileremove(f->msource);
1710 ecc0a1b0 2008-06-15 rsc f->msource = nil;
1712 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1714 ecc0a1b0 2008-06-15 rsc if(filemetaremove(f) < 0)
1719 3d77c87e 2004-03-15 devnull vtfileunlock(f->source);
1720 ecc0a1b0 2008-06-15 rsc if(f->msource)
1721 ecc0a1b0 2008-06-15 rsc vtfileunlock(f->msource);
1723 ecc0a1b0 2008-06-15 rsc fileunlock(f);
1728 ecc0a1b0 2008-06-15 rsc * Vac file system format.
1730 ecc0a1b0 2008-06-15 rsc static char EBadVacFormat[] = "bad format for vac file";
1732 ecc0a1b0 2008-06-15 rsc static VacFs *
1733 75d04888 2009-05-25 rsc vacfsalloc(VtConn *z, int bsize, ulong cachemem, int mode)
1737 ecc0a1b0 2008-06-15 rsc fs = vtmallocz(sizeof(VacFs));
1739 ecc0a1b0 2008-06-15 rsc fs->bsize = bsize;
1740 ecc0a1b0 2008-06-15 rsc fs->mode = mode;
1741 75d04888 2009-05-25 rsc fs->cache = vtcachealloc(z, cachemem);
1746 ecc0a1b0 2008-06-15 rsc readscore(int fd, uchar score[VtScoreSize])
1748 ecc0a1b0 2008-06-15 rsc char buf[45], *pref;
1751 ecc0a1b0 2008-06-15 rsc n = readn(fd, buf, sizeof(buf)-1);
1752 ecc0a1b0 2008-06-15 rsc if(n < sizeof(buf)-1) {
1753 ecc0a1b0 2008-06-15 rsc werrstr("short read");
1756 ecc0a1b0 2008-06-15 rsc buf[n] = 0;
1758 ecc0a1b0 2008-06-15 rsc if(vtparsescore(buf, &pref, score) < 0){
1759 ecc0a1b0 2008-06-15 rsc werrstr(EBadVacFormat);
1762 ecc0a1b0 2008-06-15 rsc if(pref==nil || strcmp(pref, "vac") != 0) {
1763 ecc0a1b0 2008-06-15 rsc werrstr("not a vac file");
1770 75d04888 2009-05-25 rsc vacfsopen(VtConn *z, char *file, int mode, ulong cachemem)
1773 ecc0a1b0 2008-06-15 rsc uchar score[VtScoreSize];
1774 ecc0a1b0 2008-06-15 rsc char *prefix;
1776 ecc0a1b0 2008-06-15 rsc if(vtparsescore(file, &prefix, score) >= 0){
1777 ecc0a1b0 2008-06-15 rsc if(strcmp(prefix, "vac") != 0){
1778 ecc0a1b0 2008-06-15 rsc werrstr("not a vac file");
1779 ecc0a1b0 2008-06-15 rsc return nil;
1782 ecc0a1b0 2008-06-15 rsc fd = open(file, OREAD);
1784 ecc0a1b0 2008-06-15 rsc return nil;
1785 ecc0a1b0 2008-06-15 rsc if(readscore(fd, score) < 0){
1787 ecc0a1b0 2008-06-15 rsc return nil;
1791 4a18fa68 2009-07-08 mt fprint(2, "vacfsopen %V\n", score);
1792 75d04888 2009-05-25 rsc return vacfsopenscore(z, score, mode, cachemem);
1796 75d04888 2009-05-25 rsc vacfsopenscore(VtConn *z, u8int *score, int mode, ulong cachemem)
1801 ecc0a1b0 2008-06-15 rsc uchar buf[VtRootSize];
1802 ecc0a1b0 2008-06-15 rsc VacFile *root;
1806 ecc0a1b0 2008-06-15 rsc n = vtread(z, score, VtRootType, buf, VtRootSize);
1808 4a18fa68 2009-07-08 mt fprint(2, "read %r\n");
1809 ecc0a1b0 2008-06-15 rsc return nil;
1811 ecc0a1b0 2008-06-15 rsc if(n != VtRootSize){
1812 ecc0a1b0 2008-06-15 rsc werrstr("vtread on root too short");
1813 4a18fa68 2009-07-08 mt fprint(2, "size %d\n", n);
1814 ecc0a1b0 2008-06-15 rsc return nil;
1817 4a18fa68 2009-07-08 mt if(vtrootunpack(&rt, buf) < 0) {
1818 4a18fa68 2009-07-08 mt fprint(2, "unpack: %r\n");
1819 ecc0a1b0 2008-06-15 rsc return nil;
1822 ecc0a1b0 2008-06-15 rsc if(strcmp(rt.type, "vac") != 0) {
1823 4a18fa68 2009-07-08 mt fprint(2, "bad type %s\n", rt.type);
1824 ecc0a1b0 2008-06-15 rsc werrstr("not a vac root");
1825 ecc0a1b0 2008-06-15 rsc return nil;
1828 75d04888 2009-05-25 rsc fs = vacfsalloc(z, rt.blocksize, cachemem, mode);
1829 ecc0a1b0 2008-06-15 rsc memmove(fs->score, score, VtScoreSize);
1830 ecc0a1b0 2008-06-15 rsc fs->mode = mode;
1832 ecc0a1b0 2008-06-15 rsc memmove(e.score, rt.score, VtScoreSize);
1835 4a18fa68 2009-07-08 mt // Don't waste cache memory on pointer blocks
1836 75d04888 2009-05-25 rsc // when rt.blocksize is large.
1837 ecc0a1b0 2008-06-15 rsc e.psize = (rt.blocksize/VtEntrySize)*VtEntrySize;
1838 75d04888 2009-05-25 rsc if(e.psize > 60000)
1839 75d04888 2009-05-25 rsc e.psize = (60000/VtEntrySize)*VtEntrySize;
1841 ecc0a1b0 2008-06-15 rsc e.dsize = rt.blocksize;
1842 4a18fa68 2009-07-08 mt fprint(2, "openscore %d psize %d dsize %d\n", (int)rt.blocksize, (int)e.psize, (int)e.dsize);
1843 ecc0a1b0 2008-06-15 rsc e.type = VtDirType;
1844 ecc0a1b0 2008-06-15 rsc e.flags = VtEntryActive;
1845 ecc0a1b0 2008-06-15 rsc e.size = 3*VtEntrySize;
1847 ecc0a1b0 2008-06-15 rsc root = nil;
1848 ecc0a1b0 2008-06-15 rsc if((r = vtfileopenroot(fs->cache, &e)) == nil)
1851 ecc0a1b0 2008-06-15 rsc fprint(2, "r %p\n", r);
1852 ecc0a1b0 2008-06-15 rsc root = _vacfileroot(fs, r);
1854 ecc0a1b0 2008-06-15 rsc fprint(2, "root %p\n", root);
1855 ecc0a1b0 2008-06-15 rsc vtfileclose(r);
1856 ecc0a1b0 2008-06-15 rsc if(root == nil)
1858 ecc0a1b0 2008-06-15 rsc fs->root = root;
1862 ecc0a1b0 2008-06-15 rsc vacfiledecref(root);
1863 ecc0a1b0 2008-06-15 rsc vacfsclose(fs);
1864 ecc0a1b0 2008-06-15 rsc return nil;
1868 ecc0a1b0 2008-06-15 rsc vacfsmode(VacFs *fs)
1870 ecc0a1b0 2008-06-15 rsc return fs->mode;
1874 ecc0a1b0 2008-06-15 rsc vacfsgetroot(VacFs *fs)
1876 ecc0a1b0 2008-06-15 rsc return vacfileincref(fs->root);
1880 ecc0a1b0 2008-06-15 rsc vacfsgetblocksize(VacFs *fs)
1882 ecc0a1b0 2008-06-15 rsc return fs->bsize;
1886 ecc0a1b0 2008-06-15 rsc vacfsgetscore(VacFs *fs, u8int *score)
1888 ecc0a1b0 2008-06-15 rsc memmove(score, fs->score, VtScoreSize);
1889 3d77c87e 2004-03-15 devnull return 0;
1893 ecc0a1b0 2008-06-15 rsc _vacfsnextqid(VacFs *fs, uvlong *qid)
1896 ecc0a1b0 2008-06-15 rsc *qid = fs->qid;
1901 003c13aa 2008-06-15 rsc vacfsjumpqid(VacFs *fs, uvlong step)
1903 003c13aa 2008-06-15 rsc fs->qid += step;
1907 003c13aa 2008-06-15 rsc * Set *maxqid to the maximum qid expected in this file system.
1908 003c13aa 2008-06-15 rsc * In newer vac archives, the maximum qid is stored in the
1909 003c13aa 2008-06-15 rsc * qidspace VacDir annotation. In older vac archives, the root
1910 003c13aa 2008-06-15 rsc * got created last, so it had the maximum qid.
1913 003c13aa 2008-06-15 rsc vacfsgetmaxqid(VacFs *fs, uvlong *maxqid)
1917 003c13aa 2008-06-15 rsc if(vacfilegetdir(fs->root, &vd) < 0)
1919 003c13aa 2008-06-15 rsc if(vd.qidspace)
1920 003c13aa 2008-06-15 rsc *maxqid = vd.qidmax;
1922 003c13aa 2008-06-15 rsc *maxqid = vd.qid;
1923 003c13aa 2008-06-15 rsc vdcleanup(&vd);
1929 ecc0a1b0 2008-06-15 rsc vacfsclose(VacFs *fs)
1931 ecc0a1b0 2008-06-15 rsc if(fs->root)
1932 ecc0a1b0 2008-06-15 rsc vacfiledecref(fs->root);
1933 ecc0a1b0 2008-06-15 rsc fs->root = nil;
1934 ecc0a1b0 2008-06-15 rsc vtcachefree(fs->cache);
1935 ecc0a1b0 2008-06-15 rsc vtfree(fs);
1939 ecc0a1b0 2008-06-15 rsc * Create a fresh vac fs.
1942 75d04888 2009-05-25 rsc vacfscreate(VtConn *z, int bsize, ulong cachemem)
1946 ecc0a1b0 2008-06-15 rsc uchar buf[VtEntrySize], metascore[VtScoreSize];
1948 ecc0a1b0 2008-06-15 rsc VtBlock *b;
1949 ecc0a1b0 2008-06-15 rsc MetaBlock mb;
1951 ecc0a1b0 2008-06-15 rsc MetaEntry me;
1954 75d04888 2009-05-25 rsc if((fs = vacfsalloc(z, bsize, cachemem, VtORDWR)) == nil)
1955 ecc0a1b0 2008-06-15 rsc return nil;
1958 ecc0a1b0 2008-06-15 rsc * Fake up an empty vac fs.
1960 4a18fa68 2009-07-08 mt psize = bsize/VtScoreSize*VtScoreSize;
1961 75d04888 2009-05-25 rsc if(psize > 60000)
1962 4a18fa68 2009-07-08 mt psize = 60000/VtScoreSize*VtScoreSize;
1963 75d04888 2009-05-25 rsc fprint(2, "create bsize %d psize %d\n", bsize, psize);
1965 ecc0a1b0 2008-06-15 rsc f = vtfilecreateroot(fs->cache, psize, bsize, VtDirType);
1966 75d04888 2009-05-25 rsc if(f == nil)
1967 75d04888 2009-05-25 rsc sysfatal("vtfilecreateroot: %r");
1968 ecc0a1b0 2008-06-15 rsc vtfilelock(f, VtORDWR);
1970 ecc0a1b0 2008-06-15 rsc /* Write metablock containing root directory VacDir. */
1971 75d04888 2009-05-25 rsc b = vtcacheallocblock(fs->cache, VtDataType, bsize);
1972 ecc0a1b0 2008-06-15 rsc mbinit(&mb, b->data, bsize, bsize/BytesPerEntry);
1973 ecc0a1b0 2008-06-15 rsc memset(&vd, 0, sizeof vd);
1974 ecc0a1b0 2008-06-15 rsc vd.elem = "/";
1975 ecc0a1b0 2008-06-15 rsc vd.mode = 0777|ModeDir;
1976 ecc0a1b0 2008-06-15 rsc vd.uid = "vac";
1977 ecc0a1b0 2008-06-15 rsc vd.gid = "vac";
1978 ecc0a1b0 2008-06-15 rsc vd.mid = "";
1979 ecc0a1b0 2008-06-15 rsc me.size = vdsize(&vd, VacDirVersion);
1980 ecc0a1b0 2008-06-15 rsc me.p = mballoc(&mb, me.size);
1981 ecc0a1b0 2008-06-15 rsc vdpack(&vd, &me, VacDirVersion);
1982 ecc0a1b0 2008-06-15 rsc mbinsert(&mb, 0, &me);
1983 ecc0a1b0 2008-06-15 rsc mbpack(&mb);
1984 ecc0a1b0 2008-06-15 rsc vtblockwrite(b);
1985 ecc0a1b0 2008-06-15 rsc memmove(metascore, b->score, VtScoreSize);
1986 ecc0a1b0 2008-06-15 rsc vtblockput(b);
1988 ecc0a1b0 2008-06-15 rsc /* First entry: empty venti directory stream. */
1989 ecc0a1b0 2008-06-15 rsc memset(&e, 0, sizeof e);
1990 ecc0a1b0 2008-06-15 rsc e.flags = VtEntryActive;
1991 ecc0a1b0 2008-06-15 rsc e.psize = psize;
1992 ecc0a1b0 2008-06-15 rsc e.dsize = bsize;
1993 ecc0a1b0 2008-06-15 rsc e.type = VtDirType;
1994 ecc0a1b0 2008-06-15 rsc memmove(e.score, vtzeroscore, VtScoreSize);
1995 ecc0a1b0 2008-06-15 rsc vtentrypack(&e, buf, 0);
1996 ecc0a1b0 2008-06-15 rsc vtfilewrite(f, buf, VtEntrySize, 0);
1998 ecc0a1b0 2008-06-15 rsc /* Second entry: empty metadata stream. */
1999 ecc0a1b0 2008-06-15 rsc e.type = VtDataType;
2000 ecc0a1b0 2008-06-15 rsc vtentrypack(&e, buf, 0);
2001 ecc0a1b0 2008-06-15 rsc vtfilewrite(f, buf, VtEntrySize, VtEntrySize);
2003 ecc0a1b0 2008-06-15 rsc /* Third entry: metadata stream with root directory. */
2004 ecc0a1b0 2008-06-15 rsc memmove(e.score, metascore, VtScoreSize);
2005 ecc0a1b0 2008-06-15 rsc e.size = bsize;
2006 ecc0a1b0 2008-06-15 rsc vtentrypack(&e, buf, 0);
2007 ecc0a1b0 2008-06-15 rsc vtfilewrite(f, buf, VtEntrySize, VtEntrySize*2);
2009 ecc0a1b0 2008-06-15 rsc vtfileflush(f);
2010 ecc0a1b0 2008-06-15 rsc vtfileunlock(f);
2012 ecc0a1b0 2008-06-15 rsc /* Now open it as a vac fs. */
2013 ecc0a1b0 2008-06-15 rsc fs->root = _vacfileroot(fs, f);
2014 ecc0a1b0 2008-06-15 rsc if(fs->root == nil){
2015 ecc0a1b0 2008-06-15 rsc werrstr("vacfileroot: %r");
2016 ecc0a1b0 2008-06-15 rsc vacfsclose(fs);
2017 ecc0a1b0 2008-06-15 rsc return nil;
2024 ecc0a1b0 2008-06-15 rsc vacfssync(VacFs *fs)
2026 ecc0a1b0 2008-06-15 rsc uchar buf[1024];
2029 ecc0a1b0 2008-06-15 rsc VtRoot root;
2031 ecc0a1b0 2008-06-15 rsc /* Sync the entire vacfs to disk. */
2032 ecc0a1b0 2008-06-15 rsc if(vacfileflush(fs->root, 1) < 0)
2034 003c13aa 2008-06-15 rsc if(vtfilelock(fs->root->up->msource, -1) < 0)
2036 003c13aa 2008-06-15 rsc if(vtfileflush(fs->root->up->msource) < 0){
2037 003c13aa 2008-06-15 rsc vtfileunlock(fs->root->up->msource);
2040 003c13aa 2008-06-15 rsc vtfileunlock(fs->root->up->msource);
2042 ecc0a1b0 2008-06-15 rsc /* Prepare the dir stream for the root block. */
2043 ecc0a1b0 2008-06-15 rsc if(getentry(fs->root->source, &e) < 0)
2045 ecc0a1b0 2008-06-15 rsc vtentrypack(&e, buf, 0);
2046 ecc0a1b0 2008-06-15 rsc if(getentry(fs->root->msource, &e) < 0)
2048 ecc0a1b0 2008-06-15 rsc vtentrypack(&e, buf, 1);
2049 ecc0a1b0 2008-06-15 rsc if(getentry(fs->root->up->msource, &e) < 0)
2051 ecc0a1b0 2008-06-15 rsc vtentrypack(&e, buf, 2);
2053 ecc0a1b0 2008-06-15 rsc f = vtfilecreateroot(fs->cache, fs->bsize, fs->bsize, VtDirType);
2054 ecc0a1b0 2008-06-15 rsc vtfilelock(f, VtORDWR);
2055 ecc0a1b0 2008-06-15 rsc if(vtfilewrite(f, buf, 3*VtEntrySize, 0) < 0
2056 ecc0a1b0 2008-06-15 rsc || vtfileflush(f) < 0){
2057 ecc0a1b0 2008-06-15 rsc vtfileunlock(f);
2058 ecc0a1b0 2008-06-15 rsc vtfileclose(f);
2061 ecc0a1b0 2008-06-15 rsc vtfileunlock(f);
2062 ecc0a1b0 2008-06-15 rsc if(getentry(f, &e) < 0){
2063 ecc0a1b0 2008-06-15 rsc vtfileclose(f);
2066 ecc0a1b0 2008-06-15 rsc vtfileclose(f);
2068 ecc0a1b0 2008-06-15 rsc /* Build a root block. */
2069 ecc0a1b0 2008-06-15 rsc memset(&root, 0, sizeof root);
2070 ecc0a1b0 2008-06-15 rsc strcpy(root.type, "vac");
2071 ecc0a1b0 2008-06-15 rsc strcpy(root.name, fs->name);
2072 ecc0a1b0 2008-06-15 rsc memmove(root.score, e.score, VtScoreSize);
2073 ecc0a1b0 2008-06-15 rsc root.blocksize = fs->bsize;
2074 ecc0a1b0 2008-06-15 rsc memmove(root.prev, fs->score, VtScoreSize);
2075 ecc0a1b0 2008-06-15 rsc vtrootpack(&root, buf);
2076 ecc0a1b0 2008-06-15 rsc if(vtwrite(fs->z, fs->score, VtRootType, buf, VtRootSize) < 0){
2077 ecc0a1b0 2008-06-15 rsc werrstr("writing root: %r");
2080 ecc0a1b0 2008-06-15 rsc if(vtsync(fs->z) < 0)
2086 286bb40b 2008-12-07 rsc vacfiledsize(VacFile *f)
2090 286bb40b 2008-12-07 rsc if(vacfilegetentries(f,&e,nil) < 0)
2092 286bb40b 2008-12-07 rsc return e.dsize;
2096 286bb40b 2008-12-07 rsc * Does block b of f have the same SHA1 hash as the n bytes at buf?
2099 286bb40b 2008-12-07 rsc sha1matches(VacFile *f, ulong b, uchar *buf, int n)
2101 286bb40b 2008-12-07 rsc uchar fscore[VtScoreSize];
2102 286bb40b 2008-12-07 rsc uchar bufscore[VtScoreSize];
2104 286bb40b 2008-12-07 rsc if(vacfileblockscore(f, b, fscore) < 0)
2106 286bb40b 2008-12-07 rsc n = vtzerotruncate(VtDataType, buf, n);
2107 286bb40b 2008-12-07 rsc sha1(buf, n, bufscore, nil);
2108 286bb40b 2008-12-07 rsc if(memcmp(bufscore, fscore, VtScoreSize) == 0)