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 VacFile9 * and then acquire the lock of its parent10 */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 void37 vfRUnlock(VacFile *vf)38 {39 vtRUnlock(vf->lk);40 }43 static int44 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 void56 vfUnlock(VacFile *vf)57 {58 vtUnlock(vf->lk);59 }61 static int62 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 void74 vfMetaLock(VacFile *vf)75 {76 assert(vf->up->msource != nil);77 vtLock(vf->up->lk);78 }80 static void81 vfMetaUnlock(VacFile *vf)82 {83 vtUnlock(vf->up->lk);84 }87 static void88 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 void98 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);105 }106 vf->dir.mcount++;107 vf->dirty = 1;108 vfMetaUnlock(vf);109 vfMetaFlush(vf);110 }112 void113 vdCleanup(VacDir *dir)114 {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;123 }125 void126 vdCopy(VacDir *dst, VacDir *src)127 {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);133 }135 static int136 mbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me)137 {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 else151 x = meCmp(me, elem);153 if(x == 0) {154 *ri = i;155 return 1;156 }158 if(x < 0)159 b = i+1;160 else /* x > 0 */161 t = i;162 }164 assert(b == t);166 *ri = b; /* b is the index to insert this entry */167 memset(me, 0, sizeof(*me));169 return 1;170 }172 static void173 mbInit(MetaBlock *mb, uchar *p, int n)174 {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;180 }182 static int183 vfMetaFlush(VacFile *vf)184 {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 */222 }223 nme.p = p;224 nme.size = n;225 }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);232 }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;246 }248 static VacFile *249 vfAlloc(VacFS *fs)250 {251 VacFile *vf;253 vf = vtMemAllocZ(sizeof(VacFile));254 vf->lk = vtLockAlloc();255 vf->ref = 1;256 vf->fs = fs;257 return vf;258 }260 static void261 vfFree(VacFile *vf)262 {263 sourceFree(vf->source);264 vtLockFree(vf->lk);265 sourceFree(vf->msource);266 vdCleanup(&vf->dir);268 vtMemFree(vf);269 }271 /* the file is locked already */272 static VacFile *273 dirLookup(VacFile *vf, char *elem)274 {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;298 }299 lumpDecRef(u, 1);300 nvf->block = i;301 return nvf;302 }304 lumpDecRef(u, 1);305 u = nil;306 }307 vtSetError("file does not exist");308 /* fall through */309 Err:310 lumpDecRef(u, 1);311 return nil;312 }314 VacFile *315 vfRoot(VacFS *fs, uchar *score)316 {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;340 }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;348 }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;376 }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;425 }427 VacFile *428 vfWalk(VacFile *vf, char *elem)429 {430 VacFile *nvf;432 vfRAccess(vf);434 if(elem[0] == 0) {435 vtSetError("illegal path element");436 return nil;437 }438 if(!vfIsDir(vf)) {439 vtSetError("not a directory");440 return nil;441 }443 if(strcmp(elem, ".") == 0) {444 return vfIncRef(vf);445 }447 if(strcmp(elem, "..") == 0) {448 if(vfIsRoot(vf))449 return vfIncRef(vf);450 return vfIncRef(vf->up);451 }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;460 }461 }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;473 }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;488 }490 VacFile *491 vfOpen(VacFS *fs, char *path)492 {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++)501 ;502 n = p - path;503 if(n > 0) {504 if(n > VtMaxStringSize) {505 vtSetError("path element too long");506 goto Err;507 }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;515 }516 if(*p == '/')517 p++;518 path = p;519 }520 return vf;521 Err:522 vfDecRef(vf);523 return nil;524 }526 VacFile *527 vfCreate(VacFile *vf, char *elem, ulong mode, char *user)528 {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;551 }552 }554 nvf = dirLookup(vf, elem);555 if(nvf != nil) {556 vtSetError(EExists);557 goto Err;558 }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;571 }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;580 }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;640 }643 int644 vfRead(VacFile *vf, void *buf, int cnt, vlong offset)645 {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;666 }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;685 }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);699 }700 vfRUnlock(vf);701 return b-(uchar*)buf;702 Err:703 vfRUnlock(vf);704 return -1;705 }707 int708 vfWrite(VacFile *vf, void *buf, int cnt, vlong offset, char *user)709 {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;724 }726 if(vf->dir.mode & ModeDir) {727 vtSetError(ENotFile);728 goto Err;729 }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;738 }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;758 }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;768 }769 vfLock(vf);770 return b-(uchar*)buf;771 Err:772 vfLock(vf);773 return -1;774 }776 int777 vfGetDir(VacFile *vf, VacDir *dir)778 {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;791 }793 uvlong794 vfGetId(VacFile *vf)795 {796 /* immutable */797 return vf->dir.qid;798 }800 ulong801 vfGetMcount(VacFile *vf)802 {803 ulong mcount;805 vfMetaLock(vf);806 mcount = vf->dir.mcount;807 vfMetaUnlock(vf);808 return mcount;809 }812 int813 vfIsDir(VacFile *vf)814 {815 /* immutable */816 return (vf->dir.mode & ModeDir) != 0;817 }819 int820 vfIsRoot(VacFile *vf)821 {822 return vf == vf->fs->root;823 }825 int826 vfGetSize(VacFile *vf, uvlong *size)827 {828 if(!vfRLock(vf))829 return 0;830 *size = sourceGetSize(vf->source);831 vfRUnlock(vf);833 return 1;834 }836 static int837 vfMetaRemove(VacFile *vf, char *user)838 {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;876 }879 static int880 vfCheckEmpty(VacFile *vf)881 {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;898 }899 lumpDecRef(u, 1);900 }901 return 1;902 Err:903 lumpDecRef(u, 1);904 return 0;905 }907 int908 vfRemove(VacFile *vf, char *user)909 {910 /* can not remove the root */911 if(vfIsRoot(vf)) {912 vtSetError(ERoot);913 return 0;914 }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;929 }931 vfUnlock(vf);933 if(!vfMetaRemove(vf, user))934 return 0;936 return 1;938 Err:939 vfUnlock(vf);940 return 0;941 }943 VacFile *944 vfIncRef(VacFile *vf)945 {946 vfMetaLock(vf);947 assert(vf->ref > 0);948 vf->ref++;949 vfMetaUnlock(vf);950 return vf;951 }953 void954 vfDecRef(VacFile *vf)955 {956 VacFile *p, *q, **qq;958 if(vf->up == nil) {959 vfFree(vf);960 return;961 }963 vfMetaLock(vf);964 vf->ref--;965 if(vf->ref > 0) {966 vfMetaUnlock(vf);967 return;968 }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);984 }986 int987 vfGetVtEntry(VacFile *vf, VtEntry *e)988 {989 int res;991 if(!vfRLock(vf))992 return 0;993 res = sourceGetVtEntry(vf->source, e);994 vfRUnlock(vf);995 return res;996 }998 int999 vfGetBlockScore(VacFile *vf, ulong bn, uchar score[VtScoreSize])1000 {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;1014 }1016 ret = lumpGetScore(u, off, score);1017 lumpDecRef(u, 0);1018 vfRUnlock(vf);1020 return ret;1021 }1023 VacFile *1024 vfGetParent(VacFile *vf)1025 {1026 if(vfIsRoot(vf))1027 return vfIncRef(vf);1028 return vfIncRef(vf->up);1029 }1031 static VacDirEnum *1032 vdeAlloc(VacFile *vf)1033 {1034 VacDirEnum *ds;1036 if(!(vf->dir.mode & ModeDir)) {1037 vtSetError(ENotDir);1038 vfDecRef(vf);1039 return nil;1040 }1042 ds = vtMemAllocZ(sizeof(VacDirEnum));1043 ds->file = vf;1045 return ds;1046 }1048 VacDirEnum *1049 vdeOpen(VacFS *fs, char *path)1050 {1051 VacFile *vf;1053 vf = vfOpen(fs, path);1054 if(vf == nil)1055 return nil;1057 return vdeAlloc(vf);1058 }1060 VacDirEnum *1061 vfDirEnum(VacFile *vf)1062 {1063 return vdeAlloc(vfIncRef(vf));1064 }1066 static int1067 dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size)1068 {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;1082 }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;1088 }1090 *size = e.size;1091 lumpDecRef(u, 1);1092 return 1;1094 Err:1095 lumpDecRef(u, 1);1096 return 0;1097 }1099 int1100 vdeRead(VacDirEnum *ds, VacDir *dir, int n)1101 {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;1141 }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;1150 }1151 ds->index++;1152 }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;1164 }1166 void1167 vdeFree(VacDirEnum *ds)1168 {1169 if(ds == nil)1170 return;1171 vfDecRef(ds->file);1172 vtMemFree(ds);1173 }1175 static ulong1176 msAlloc(Source *ms, ulong start, int n)1177 {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;1196 }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);1207 }1208 lumpDecRef(u, 1);1209 return i;1210 Err:1211 lumpDecRef(u, 1);1212 return NilBlock;1213 }