Blob


1 #include "stdinc.h"
2 #include "vac.h"
3 #include "dat.h"
4 #include "fns.h"
5 #include "error.h"
7 /*
8 * locking order is upwards. A thread can hold the lock for a VacFile
9 * and then acquire the lock of its parent
10 */
12 struct VacFile {
13 /* meta data for file: protected by the lk in the parent */
14 int ref; /* holds this data structure up */
15 VacFS *fs; /* immutable */
17 int removed; /* file has been removed */
18 int dirty; /* dir is dirty with respect to meta data in block */
19 ulong block; /* block offset withing msource for this file's meta data */
21 VacDir dir; /* meta data for this file */
23 VacFile *up; /* parent file */
24 VacFile *next; /* sibling */
26 /* data for file */
27 VtLock *lk; /* lock for source and msource */
28 Source *source;
29 Source *msource; /* for directories: meta data for children */
30 VacFile *down; /* children */
31 };
33 static int vfMetaFlush(VacFile*);
34 static ulong msAlloc(Source *ms, ulong, int n);
36 static void
37 vfRUnlock(VacFile *vf)
38 {
39 vtRUnlock(vf->lk);
40 }
43 static int
44 vfRLock(VacFile *vf)
45 {
46 vtRLock(vf->lk);
47 if(vf->source == nil) {
48 vfRUnlock(vf);
49 vtSetError(ERemoved);
50 return 0;
51 }
52 return 1;
53 }
55 static void
56 vfUnlock(VacFile *vf)
57 {
58 vtUnlock(vf->lk);
59 }
61 static int
62 vfLock(VacFile *vf)
63 {
64 vtLock(vf->lk);
65 if(vf->source == nil) {
66 vfUnlock(vf);
67 vtSetError(ERemoved);
68 return 0;
69 }
70 return 1;
71 }
73 static void
74 vfMetaLock(VacFile *vf)
75 {
76 assert(vf->up->msource != nil);
77 vtLock(vf->up->lk);
78 }
80 static void
81 vfMetaUnlock(VacFile *vf)
82 {
83 vtUnlock(vf->up->lk);
84 }
87 static void
88 vfRAccess(VacFile* vf)
89 {
90 vfMetaLock(vf);
91 vf->dir.atime = time(0L);
92 vf->dirty = 1;
93 vfMetaUnlock(vf);
94 vfMetaFlush(vf);
95 }
97 static void
98 vfWAccess(VacFile* vf, char *mid)
99 {
100 vfMetaLock(vf);
101 vf->dir.atime = vf->dir.mtime = time(0L);
102 if(strcmp(vf->dir.mid, mid) != 0) {
103 vtMemFree(vf->dir.mid);
104 vf->dir.mid = vtStrDup(mid);
106 vf->dir.mcount++;
107 vf->dirty = 1;
108 vfMetaUnlock(vf);
109 vfMetaFlush(vf);
112 void
113 vdCleanup(VacDir *dir)
115 vtMemFree(dir->elem);
116 dir->elem = nil;
117 vtMemFree(dir->uid);
118 dir->uid = nil;
119 vtMemFree(dir->gid);
120 dir->gid = nil;
121 vtMemFree(dir->mid);
122 dir->mid = nil;
125 void
126 vdCopy(VacDir *dst, VacDir *src)
128 *dst = *src;
129 dst->elem = vtStrDup(src->elem);
130 dst->uid = vtStrDup(src->uid);
131 dst->gid = vtStrDup(src->gid);
132 dst->mid = vtStrDup(src->mid);
135 static int
136 mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)
138 int i;
139 int b, t, x;
141 /* binary search within block */
142 b = 0;
143 t = mb->nindex;
144 while(b < t) {
145 i = (b+t)>>1;
146 if(!meUnpack(me, mb, i))
147 return 0;
148 if(mb->unbotch)
149 x = meCmpNew(me, elem);
150 else
151 x = meCmp(me, elem);
153 if(x == 0) {
154 *ri = i;
155 return 1;
158 if(x < 0)
159 b = i+1;
160 else /* x > 0 */
161 t = i;
164 assert(b == t);
166 *ri = b; /* b is the index to insert this entry */
167 memset(me, 0, sizeof(*me));
169 return 1;
172 static void
173 mbInit(MetaBlock *mb, uchar *p, int n)
175 memset(mb, 0, sizeof(MetaBlock));
176 mb->maxsize = n;
177 mb->buf = p;
178 mb->maxindex = n/100;
179 mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;
182 static int
183 vfMetaFlush(VacFile *vf)
185 VacFile *vfp;
186 Lump *u;
187 MetaBlock mb;
188 MetaEntry me, nme;
189 uchar *p;
190 int i, n, moved;
192 //print("vfMetaFlush %s\n", vf->dir.elem);
194 /* assume name has not changed for the moment */
196 vfMetaLock(vf);
198 vfp = vf->up;
199 moved = 0;
201 u = sourceGetLump(vfp->msource, vf->block, 0, 1);
202 if(u == nil)
203 goto Err;
205 if(!mbUnpack(&mb, u->data, u->asize))
206 goto Err;
207 if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil)
208 goto Err;
210 nme = me;
211 n = vdSize(&vf->dir);
212 //print("old size %d new size %d\n", me.size, n);
213 if(n <= nme.size) {
214 nme.size = n;
215 } else {
216 /* try expand entry? */
217 p = mbAlloc(&mb, n);
218 //print("alloced %ld\n", p - mb.buf);
219 if(p == nil) {
220 assert(0);
221 /* much more work */
223 nme.p = p;
224 nme.size = n;
227 mbDelete(&mb, i, &me);
228 memset(me.p, 0, me.size);
229 if(!moved) {
230 vdPack(&vf->dir, &nme);
231 mbInsert(&mb, i, &nme);
234 mbPack(&mb);
235 lumpDecRef(u, 1);
237 vf->dirty = 0;
239 vfMetaUnlock(vf);
240 return 1;
242 Err:
243 lumpDecRef(u, 1);
244 vfMetaUnlock(vf);
245 return 0;
248 static VacFile *
249 vfAlloc(VacFS *fs)
251 VacFile *vf;
253 vf = vtMemAllocZ(sizeof(VacFile));
254 vf->lk = vtLockAlloc();
255 vf->ref = 1;
256 vf->fs = fs;
257 return vf;
260 static void
261 vfFree(VacFile *vf)
263 sourceFree(vf->source);
264 vtLockFree(vf->lk);
265 sourceFree(vf->msource);
266 vdCleanup(&vf->dir);
268 vtMemFree(vf);
271 /* the file is locked already */
272 static VacFile *
273 dirLookup(VacFile *vf, char *elem)
275 int i, j, nb;
276 MetaBlock mb;
277 MetaEntry me;
278 Lump *u;
279 Source *meta;
280 VacFile *nvf;
282 meta = vf->msource;
283 u = nil;
284 nb = sourceGetNumBlocks(meta);
285 for(i=0; i<nb; i++) {
286 u = sourceGetLump(meta, i, 1, 1);
287 if(u == nil)
288 goto Err;
289 if(!mbUnpack(&mb, u->data, u->asize))
290 goto Err;
291 if(!mbSearch(&mb, elem, &j, &me))
292 goto Err;
293 if(me.p != nil) {
294 nvf = vfAlloc(vf->fs);
295 if(!vdUnpack(&nvf->dir, &me)) {
296 vfFree(nvf);
297 goto Err;
299 lumpDecRef(u, 1);
300 nvf->block = i;
301 return nvf;
304 lumpDecRef(u, 1);
305 u = nil;
307 vtSetError("file does not exist");
308 /* fall through */
309 Err:
310 lumpDecRef(u, 1);
311 return nil;
314 VacFile *
315 vfRoot(VacFS *fs, uchar *score)
317 VtEntry e;
318 Lump *u, *v;
319 Source *r, *r0, *r1, *r2;
320 MetaBlock mb;
321 MetaEntry me;
322 VacFile *root, *mr;
324 root = nil;
325 mr = nil;
326 r0 = nil;
327 r1 = nil;
328 r2 = nil;
329 v = nil;
330 r = nil;
332 u = cacheGetLump(fs->cache, score, VtDirType, fs->bsize);
333 if(u == nil)
334 goto Err;
335 if(!fs->readOnly) {
336 v = cacheAllocLump(fs->cache, VtDirType, fs->bsize, 1);
337 if(v == nil) {
338 vtUnlock(u->lk);
339 goto Err;
341 v->gen = u->gen;
342 v->asize = u->asize;
343 v->state = LumpActive;
344 memmove(v->data, u->data, v->asize);
345 lumpDecRef(u, 1);
346 u = v;
347 v = nil;
349 vtUnlock(u->lk);
350 vtEntryUnpack(&e, u->data, 2);
351 if(e.flags == 0){ /* just one entry */
352 r = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly);
353 if(r == nil)
354 goto Err;
355 r0 = sourceOpen(r, 0, fs->readOnly);
356 if(r0 == nil)
357 goto Err;
358 r1 = sourceOpen(r, 1, fs->readOnly);
359 if(r1 == nil)
360 goto Err;
361 r2 = sourceOpen(r, 2, fs->readOnly);
362 if(r2 == nil)
363 goto Err;
364 sourceFree(r);
365 r = nil;
366 }else{
367 r0 = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly);
368 if(r0 == nil)
369 goto Err;
370 r1 = sourceAlloc(fs->cache, u, 0, 1, fs->readOnly);
371 if(r1 == nil)
372 goto Err;
373 r2 = sourceAlloc(fs->cache, u, 0, 2, fs->readOnly);
374 if(r2 == nil)
375 goto Err;
377 lumpDecRef(u, 0);
378 u = sourceGetLump(r2, 0, 1, 0);
379 if(u == nil)
380 goto Err;
382 mr = vfAlloc(fs);
383 mr->msource = r2;
384 r2 = nil;
386 root = vfAlloc(fs);
387 root->up = mr;
388 root->source = r0;
389 r0 = nil;
390 root->msource = r1;
391 r1 = nil;
393 mr->down = root;
395 if(!mbUnpack(&mb, u->data, u->asize))
396 goto Err;
398 if(!meUnpack(&me, &mb, 0))
399 goto Err;
400 if(!vdUnpack(&root->dir, &me))
401 goto Err;
403 vfRAccess(root);
404 lumpDecRef(u, 0);
405 sourceFree(r2);
407 return root;
408 Err:
409 lumpDecRef(u, 0);
410 lumpDecRef(v, 0);
411 if(r0)
412 sourceFree(r0);
413 if(r1)
414 sourceFree(r1);
415 if(r2)
416 sourceFree(r2);
417 if(r)
418 sourceFree(r);
419 if(mr)
420 vfFree(mr);
421 if(root)
422 vfFree(root);
424 return nil;
427 VacFile *
428 vfWalk(VacFile *vf, char *elem)
430 VacFile *nvf;
432 vfRAccess(vf);
434 if(elem[0] == 0) {
435 vtSetError("illegal path element");
436 return nil;
438 if(!vfIsDir(vf)) {
439 vtSetError("not a directory");
440 return nil;
443 if(strcmp(elem, ".") == 0) {
444 return vfIncRef(vf);
447 if(strcmp(elem, "..") == 0) {
448 if(vfIsRoot(vf))
449 return vfIncRef(vf);
450 return vfIncRef(vf->up);
453 if(!vfLock(vf))
454 return nil;
456 for(nvf = vf->down; nvf; nvf=nvf->next) {
457 if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) {
458 nvf->ref++;
459 goto Exit;
463 nvf = dirLookup(vf, elem);
464 if(nvf == nil)
465 goto Err;
466 nvf->source = sourceOpen(vf->source, nvf->dir.entry, vf->fs->readOnly);
467 if(nvf->source == nil)
468 goto Err;
469 if(nvf->dir.mode & ModeDir) {
470 nvf->msource = sourceOpen(vf->source, nvf->dir.mentry, vf->fs->readOnly);
471 if(nvf->msource == nil)
472 goto Err;
475 /* link in and up parent ref count */
476 nvf->next = vf->down;
477 vf->down = nvf;
478 nvf->up = vf;
479 vfIncRef(vf);
480 Exit:
481 vfUnlock(vf);
482 return nvf;
483 Err:
484 vfUnlock(vf);
485 if(nvf != nil)
486 vfFree(nvf);
487 return nil;
490 VacFile *
491 vfOpen(VacFS *fs, char *path)
493 VacFile *vf, *nvf;
494 char *p, elem[VtMaxStringSize];
495 int n;
497 vf = fs->root;
498 vfIncRef(vf);
499 while(*path != 0) {
500 for(p = path; *p && *p != '/'; p++)
502 n = p - path;
503 if(n > 0) {
504 if(n > VtMaxStringSize) {
505 vtSetError("path element too long");
506 goto Err;
508 memmove(elem, path, n);
509 elem[n] = 0;
510 nvf = vfWalk(vf, elem);
511 if(nvf == nil)
512 goto Err;
513 vfDecRef(vf);
514 vf = nvf;
516 if(*p == '/')
517 p++;
518 path = p;
520 return vf;
521 Err:
522 vfDecRef(vf);
523 return nil;
526 VacFile *
527 vfCreate(VacFile *vf, char *elem, ulong mode, char *user)
529 VacFile *nvf;
530 VacDir *dir;
531 int n, i;
532 uchar *p;
533 Source *pr, *r, *mr;
534 int isdir;
535 MetaBlock mb;
536 MetaEntry me;
537 Lump *u;
539 if(!vfLock(vf))
540 return nil;
542 r = nil;
543 mr = nil;
544 u = nil;
546 for(nvf = vf->down; nvf; nvf=nvf->next) {
547 if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) {
548 nvf = nil;
549 vtSetError(EExists);
550 goto Err;
554 nvf = dirLookup(vf, elem);
555 if(nvf != nil) {
556 vtSetError(EExists);
557 goto Err;
560 nvf = vfAlloc(vf->fs);
561 isdir = mode & ModeDir;
563 pr = vf->source;
564 r = sourceCreate(pr, pr->psize, pr->dsize, isdir, 0);
565 if(r == nil)
566 goto Err;
567 if(isdir) {
568 mr = sourceCreate(pr, pr->psize, pr->dsize, 0, r->block*pr->epb + r->entry);
569 if(mr == nil)
570 goto Err;
573 dir = &nvf->dir;
574 dir->elem = vtStrDup(elem);
575 dir->entry = r->block*pr->epb + r->entry;
576 dir->gen = r->gen;
577 if(isdir) {
578 dir->mentry = mr->block*pr->epb + mr->entry;
579 dir->mgen = mr->gen;
581 dir->size = 0;
582 dir->qid = vf->fs->qid++;
583 dir->uid = vtStrDup(user);
584 dir->gid = vtStrDup(vf->dir.gid);
585 dir->mid = vtStrDup(user);
586 dir->mtime = time(0L);
587 dir->mcount = 0;
588 dir->ctime = dir->mtime;
589 dir->atime = dir->mtime;
590 dir->mode = mode;
592 n = vdSize(dir);
593 nvf->block = msAlloc(vf->msource, 0, n);
594 if(nvf->block == NilBlock)
595 goto Err;
596 u = sourceGetLump(vf->msource, nvf->block, 0, 1);
597 if(u == nil)
598 goto Err;
599 if(!mbUnpack(&mb, u->data, u->asize))
600 goto Err;
601 p = mbAlloc(&mb, n);
602 if(p == nil)
603 goto Err;
605 if(!mbSearch(&mb, elem, &i, &me))
606 goto Err;
607 assert(me.p == nil);
608 me.p = p;
609 me.size = n;
611 vdPack(dir, &me);
612 mbInsert(&mb, i, &me);
613 mbPack(&mb);
614 lumpDecRef(u, 1);
616 nvf->source = r;
617 nvf->msource = mr;
619 /* link in and up parent ref count */
620 nvf->next = vf->down;
621 vf->down = nvf;
622 nvf->up = vf;
623 vfIncRef(vf);
625 vfWAccess(vf, user);
627 vfUnlock(vf);
628 return nvf;
630 Err:
631 lumpDecRef(u, 1);
632 if(r)
633 sourceRemove(r);
634 if(mr)
635 sourceRemove(mr);
636 if(nvf)
637 vfFree(nvf);
638 vfUnlock(vf);
639 return 0;
643 int
644 vfRead(VacFile *vf, void *buf, int cnt, vlong offset)
646 Source *s;
647 uvlong size;
648 ulong bn;
649 int off, dsize, n, nn;
650 Lump *u;
651 uchar *b;
653 if(0)fprint(2, "vfRead: %s %d, %lld\n", vf->dir.elem, cnt, offset);
655 if(!vfRLock(vf))
656 return -1;
658 s = vf->source;
660 dsize = s->dsize;
661 size = sourceGetSize(s);
663 if(offset < 0) {
664 vtSetError(EBadOffset);
665 goto Err;
668 vfRAccess(vf);
670 if(offset >= size)
671 offset = size;
673 if(cnt > size-offset)
674 cnt = size-offset;
675 bn = offset/dsize;
676 off = offset%dsize;
677 b = buf;
678 while(cnt > 0) {
679 u = sourceGetLump(s, bn, 1, 0);
680 if(u == nil)
681 goto Err;
682 if(u->asize <= off) {
683 lumpDecRef(u, 0);
684 goto Err;
686 n = cnt;
687 if(n > dsize-off)
688 n = dsize-off;
689 nn = u->asize-off;
690 if(nn > n)
691 nn = n;
692 memmove(b, u->data+off, nn);
693 memset(b+nn, 0, n-nn);
694 off = 0;
695 bn++;
696 cnt -= n;
697 b += n;
698 lumpDecRef(u, 0);
700 vfRUnlock(vf);
701 return b-(uchar*)buf;
702 Err:
703 vfRUnlock(vf);
704 return -1;
707 int
708 vfWrite(VacFile *vf, void *buf, int cnt, vlong offset, char *user)
710 Source *s;
711 ulong bn;
712 int off, dsize, n;
713 Lump *u;
714 uchar *b;
716 USED(user);
718 if(!vfLock(vf))
719 return -1;
721 if(vf->fs->readOnly) {
722 vtSetError(EReadOnly);
723 goto Err;
726 if(vf->dir.mode & ModeDir) {
727 vtSetError(ENotFile);
728 goto Err;
730 if(0)fprint(2, "vfWrite: %s %d, %lld\n", vf->dir.elem, cnt, offset);
732 s = vf->source;
733 dsize = s->dsize;
735 if(offset < 0) {
736 vtSetError(EBadOffset);
737 goto Err;
740 vfWAccess(vf, user);
742 bn = offset/dsize;
743 off = offset%dsize;
744 b = buf;
745 while(cnt > 0) {
746 n = cnt;
747 if(n > dsize-off)
748 n = dsize-off;
749 if(!sourceSetDepth(s, offset+n))
750 goto Err;
751 u = sourceGetLump(s, bn, 0, 0);
752 if(u == nil)
753 goto Err;
754 if(u->asize < dsize) {
755 vtSetError("runt block");
756 lumpDecRef(u, 0);
757 goto Err;
759 memmove(u->data+off, b, n);
760 off = 0;
761 cnt -= n;
762 b += n;
763 offset += n;
764 bn++;
765 lumpDecRef(u, 0);
766 if(!sourceSetSize(s, offset))
767 goto Err;
769 vfLock(vf);
770 return b-(uchar*)buf;
771 Err:
772 vfLock(vf);
773 return -1;
776 int
777 vfGetDir(VacFile *vf, VacDir *dir)
779 if(!vfRLock(vf))
780 return 0;
782 vfMetaLock(vf);
783 vdCopy(dir, &vf->dir);
784 vfMetaUnlock(vf);
786 if(!vfIsDir(vf))
787 dir->size = sourceGetSize(vf->source);
788 vfRUnlock(vf);
790 return 1;
793 uvlong
794 vfGetId(VacFile *vf)
796 /* immutable */
797 return vf->dir.qid;
800 ulong
801 vfGetMcount(VacFile *vf)
803 ulong mcount;
805 vfMetaLock(vf);
806 mcount = vf->dir.mcount;
807 vfMetaUnlock(vf);
808 return mcount;
812 int
813 vfIsDir(VacFile *vf)
815 /* immutable */
816 return (vf->dir.mode & ModeDir) != 0;
819 int
820 vfIsRoot(VacFile *vf)
822 return vf == vf->fs->root;
825 int
826 vfGetSize(VacFile *vf, uvlong *size)
828 if(!vfRLock(vf))
829 return 0;
830 *size = sourceGetSize(vf->source);
831 vfRUnlock(vf);
833 return 1;
836 static int
837 vfMetaRemove(VacFile *vf, char *user)
839 Lump *u;
840 MetaBlock mb;
841 MetaEntry me;
842 int i;
843 VacFile *vfp;
845 vfp = vf->up;
847 vfWAccess(vfp, user);
849 vfMetaLock(vf);
851 u = sourceGetLump(vfp->msource, vf->block, 0, 1);
852 if(u == nil)
853 goto Err;
855 if(!mbUnpack(&mb, u->data, u->asize))
856 goto Err;
857 if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil)
858 goto Err;
859 print("deleting %d entry\n", i);
860 mbDelete(&mb, i, &me);
861 memset(me.p, 0, me.size);
862 mbPack(&mb);
864 lumpDecRef(u, 1);
866 vf->removed = 1;
867 vf->block = NilBlock;
869 vfMetaUnlock(vf);
870 return 1;
872 Err:
873 lumpDecRef(u, 1);
874 vfMetaUnlock(vf);
875 return 0;
879 static int
880 vfCheckEmpty(VacFile *vf)
882 int i, n;
883 Lump *u;
884 MetaBlock mb;
885 Source *r;
887 r = vf->msource;
888 n = sourceGetNumBlocks(r);
889 for(i=0; i<n; i++) {
890 u = sourceGetLump(r, i, 1, 1);
891 if(u == nil)
892 goto Err;
893 if(!mbUnpack(&mb, u->data, u->asize))
894 goto Err;
895 if(mb.nindex > 0) {
896 vtSetError(ENotEmpty);
897 goto Err;
899 lumpDecRef(u, 1);
901 return 1;
902 Err:
903 lumpDecRef(u, 1);
904 return 0;
907 int
908 vfRemove(VacFile *vf, char *user)
910 /* can not remove the root */
911 if(vfIsRoot(vf)) {
912 vtSetError(ERoot);
913 return 0;
916 if(!vfLock(vf))
917 return 0;
919 if(vfIsDir(vf) && !vfCheckEmpty(vf))
920 goto Err;
922 assert(vf->down == nil);
924 sourceRemove(vf->source);
925 vf->source = nil;
926 if(vf->msource) {
927 sourceRemove(vf->msource);
928 vf->msource = nil;
931 vfUnlock(vf);
933 if(!vfMetaRemove(vf, user))
934 return 0;
936 return 1;
938 Err:
939 vfUnlock(vf);
940 return 0;
943 VacFile *
944 vfIncRef(VacFile *vf)
946 vfMetaLock(vf);
947 assert(vf->ref > 0);
948 vf->ref++;
949 vfMetaUnlock(vf);
950 return vf;
953 void
954 vfDecRef(VacFile *vf)
956 VacFile *p, *q, **qq;
958 if(vf->up == nil) {
959 vfFree(vf);
960 return;
963 vfMetaLock(vf);
964 vf->ref--;
965 if(vf->ref > 0) {
966 vfMetaUnlock(vf);
967 return;
969 assert(vf->ref == 0);
970 assert(vf->down == nil);
972 p = vf->up;
973 qq = &p->down;
974 for(q = *qq; q; qq=&q->next,q=*qq)
975 if(q == vf)
976 break;
977 assert(q != nil);
978 *qq = vf->next;
980 vfMetaUnlock(vf);
981 vfFree(vf);
983 vfDecRef(p);
986 int
987 vfGetVtEntry(VacFile *vf, VtEntry *e)
989 int res;
991 if(!vfRLock(vf))
992 return 0;
993 res = sourceGetVtEntry(vf->source, e);
994 vfRUnlock(vf);
995 return res;
998 int
999 vfGetBlockScore(VacFile *vf, ulong bn, uchar score[VtScoreSize])
1001 Lump *u;
1002 int ret, off;
1003 Source *r;
1005 if(!vfRLock(vf))
1006 return 0;
1008 r = vf->source;
1010 u = sourceWalk(r, bn, 1, &off);
1011 if(u == nil){
1012 vfRUnlock(vf);
1013 return 0;
1016 ret = lumpGetScore(u, off, score);
1017 lumpDecRef(u, 0);
1018 vfRUnlock(vf);
1020 return ret;
1023 VacFile *
1024 vfGetParent(VacFile *vf)
1026 if(vfIsRoot(vf))
1027 return vfIncRef(vf);
1028 return vfIncRef(vf->up);
1031 static VacDirEnum *
1032 vdeAlloc(VacFile *vf)
1034 VacDirEnum *ds;
1036 if(!(vf->dir.mode & ModeDir)) {
1037 vtSetError(ENotDir);
1038 vfDecRef(vf);
1039 return nil;
1042 ds = vtMemAllocZ(sizeof(VacDirEnum));
1043 ds->file = vf;
1045 return ds;
1048 VacDirEnum *
1049 vdeOpen(VacFS *fs, char *path)
1051 VacFile *vf;
1053 vf = vfOpen(fs, path);
1054 if(vf == nil)
1055 return nil;
1057 return vdeAlloc(vf);
1060 VacDirEnum *
1061 vfDirEnum(VacFile *vf)
1063 return vdeAlloc(vfIncRef(vf));
1066 static int
1067 dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size)
1069 Lump *u;
1070 ulong bn;
1071 VtEntry e;
1073 bn = elem/s->epb;
1074 elem -= bn*s->epb;
1076 u = sourceGetLump(s, bn, 1, 1);
1077 if(u == nil)
1078 goto Err;
1079 if(u->asize < (elem+1)*VtEntrySize) {
1080 vtSetError(ENoDir);
1081 goto Err;
1083 vtEntryUnpack(&e, u->data, elem);
1084 if(!(e.flags & VtEntryActive) || e.gen != gen) {
1085 fprint(2, "gen mismatch\n");
1086 vtSetError(ENoDir);
1087 goto Err;
1090 *size = e.size;
1091 lumpDecRef(u, 1);
1092 return 1;
1094 Err:
1095 lumpDecRef(u, 1);
1096 return 0;
1099 int
1100 vdeRead(VacDirEnum *ds, VacDir *dir, int n)
1102 ulong nb;
1103 int i;
1104 Source *meta, *source;
1105 MetaBlock mb;
1106 MetaEntry me;
1107 Lump *u;
1109 vfRAccess(ds->file);
1111 if(!vfRLock(ds->file))
1112 return -1;
1114 i = 0;
1115 u = nil;
1116 source = ds->file->source;
1117 meta = ds->file->msource;
1118 nb = (sourceGetSize(meta) + meta->dsize - 1)/meta->dsize;
1120 if(ds->block >= nb)
1121 goto Exit;
1122 u = sourceGetLump(meta, ds->block, 1, 1);
1123 if(u == nil)
1124 goto Err;
1125 if(!mbUnpack(&mb, u->data, u->asize))
1126 goto Err;
1128 for(i=0; i<n; i++) {
1129 while(ds->index >= mb.nindex) {
1130 lumpDecRef(u, 1);
1131 u = nil;
1132 ds->index = 0;
1133 ds->block++;
1134 if(ds->block >= nb)
1135 goto Exit;
1136 u = sourceGetLump(meta, ds->block, 1, 1);
1137 if(u == nil)
1138 goto Err;
1139 if(!mbUnpack(&mb, u->data, u->asize))
1140 goto Err;
1142 if(!meUnpack(&me, &mb, ds->index))
1143 goto Err;
1144 if(dir != nil) {
1145 if(!vdUnpack(&dir[i], &me))
1146 goto Err;
1147 if(!(dir[i].mode & ModeDir))
1148 if(!dirEntrySize(source, dir[i].entry, dir[i].gen, &dir[i].size))
1149 goto Err;
1151 ds->index++;
1153 Exit:
1154 lumpDecRef(u, 1);
1155 vfRUnlock(ds->file);
1156 return i;
1157 Err:
1158 lumpDecRef(u, 1);
1159 vfRUnlock(ds->file);
1160 n = i;
1161 for(i=0; i<n ; i++)
1162 vdCleanup(&dir[i]);
1163 return -1;
1166 void
1167 vdeFree(VacDirEnum *ds)
1169 if(ds == nil)
1170 return;
1171 vfDecRef(ds->file);
1172 vtMemFree(ds);
1175 static ulong
1176 msAlloc(Source *ms, ulong start, int n)
1178 ulong nb, i;
1179 Lump *u;
1180 MetaBlock mb;
1182 nb = sourceGetNumBlocks(ms);
1183 u = nil;
1184 if(start > nb)
1185 start = nb;
1186 for(i=start; i<nb; i++) {
1187 u = sourceGetLump(ms, i, 1, 1);
1188 if(u == nil)
1189 goto Err;
1190 if(!mbUnpack(&mb, u->data, ms->dsize))
1191 goto Err;
1192 if(mb.maxsize - mb.size + mb.free >= n && mb.nindex < mb.maxindex)
1193 break;
1194 lumpDecRef(u, 1);
1195 u = nil;
1197 /* add block to meta file */
1198 if(i == nb) {
1199 if(!sourceSetDepth(ms, (i+1)*ms->dsize))
1200 goto Err;
1201 u = sourceGetLump(ms, i, 0, 1);
1202 if(u == nil)
1203 goto Err;
1204 sourceSetSize(ms, (nb+1)*ms->dsize);
1205 mbInit(&mb, u->data, u->asize);
1206 mbPack(&mb);
1208 lumpDecRef(u, 1);
1209 return i;
1210 Err:
1211 lumpDecRef(u, 1);
1212 return NilBlock;