📄 file.c
字号:
#include "stdinc.h"#include "vac.h"#include "dat.h"#include "fns.h"#include "error.h"/* * locking order is upwards. A thread can hold the lock for a VacFile * and then acquire the lock of its parent */struct VacFile { /* meta data for file: protected by the lk in the parent */ int ref; /* holds this data structure up */ VacFS *fs; /* immutable */ int removed; /* file has been removed */ int dirty; /* dir is dirty with respect to meta data in block */ ulong block; /* block offset withing msource for this file's meta data */ VacDir dir; /* meta data for this file */ VacFile *up; /* parent file */ VacFile *next; /* sibling */ /* data for file */ VtLock *lk; /* lock for source and msource */ Source *source; Source *msource; /* for directories: meta data for children */ VacFile *down; /* children */};char *vfName(VacFile *, char *);static int vfMetaFlush(VacFile*);static ulong msAlloc(Source *ms, ulong, int n);static voidvfRUnlock(VacFile *vf){ vtRUnlock(vf->lk);}static intvfRLock(VacFile *vf){ vtRLock(vf->lk); if(vf->source == nil) { vfRUnlock(vf); vtSetError(ERemoved); return 0; } return 1;}static voidvfUnlock(VacFile *vf){ vtUnlock(vf->lk);}static intvfLock(VacFile *vf){ vtLock(vf->lk); if(vf->source == nil) { vfUnlock(vf); vtSetError(ERemoved); return 0; } return 1;}static voidvfMetaLock(VacFile *vf){ assert(vf->up->msource != nil); vtLock(vf->up->lk);}static voidvfMetaUnlock(VacFile *vf){ vtUnlock(vf->up->lk);}static voidvfRAccess(VacFile* vf){ vfMetaLock(vf); vf->dir.atime = time(0L); vf->dirty = 1; vfMetaUnlock(vf); vfMetaFlush(vf);}static voidvfWAccess(VacFile* vf, char *mid){ vfMetaLock(vf); vf->dir.atime = vf->dir.mtime = time(0L); if(strcmp(vf->dir.mid, mid) != 0) { vtMemFree(vf->dir.mid); vf->dir.mid = vtStrDup(mid); } vf->dir.mcount++; vf->dirty = 1; vfMetaUnlock(vf); vfMetaFlush(vf);}voidvdCleanup(VacDir *dir){ vtMemFree(dir->elem); dir->elem = nil; vtMemFree(dir->uid); dir->uid = nil; vtMemFree(dir->gid); dir->gid = nil; vtMemFree(dir->mid); dir->mid = nil;}voidvdCopy(VacDir *dst, VacDir *src){ *dst = *src; dst->elem = vtStrDup(src->elem); dst->uid = vtStrDup(src->uid); dst->gid = vtStrDup(src->gid); dst->mid = vtStrDup(src->mid);}static intmbSearch(MetaBlock *mb, char *elem, int *ri, MetaEntry *me){ int i; int b, t, x; /* binary search within block */ b = 0; t = mb->nindex; while(b < t) { i = (b+t)>>1; if(!meUnpack(me, mb, i)) return 0; if(mb->unbotch) x = meCmpNew(me, elem); else x = meCmp(me, elem); if(x == 0) { *ri = i; return 1; } if(x < 0) b = i+1; else /* x > 0 */ t = i; } assert(b == t); *ri = b; /* b is the index to insert this entry */ memset(me, 0, sizeof(*me)); return 1;}static voidmbInit(MetaBlock *mb, uchar *p, int n){ memset(mb, 0, sizeof(MetaBlock)); mb->maxsize = n; mb->buf = p; mb->maxindex = n/100; mb->size = MetaHeaderSize + mb->maxindex*MetaIndexSize;}static intvfMetaFlush(VacFile *vf){ VacFile *vfp; Lump *u; MetaBlock mb; MetaEntry me, nme; uchar *p; int i, n, moved;//print("vfMetaFlush %s\n", vf->dir.elem); /* assume name has not changed for the moment */ vfMetaLock(vf); vfp = vf->up; moved = 0; u = sourceGetLump(vfp->msource, vf->block, 0, 1); if(u == nil) goto Err; if(!mbUnpack(&mb, u->data, u->asize)) goto Err; if(!mbSearch(&mb, vf->dir.elem, &i, &me) || me.p == nil) goto Err; nme = me; n = vdSize(&vf->dir);//print("old size %d new size %d\n", me.size, n); if(n <= nme.size) { nme.size = n; } else { /* try expand entry? */ p = mbAlloc(&mb, n);//print("alloced %ld\n", p - mb.buf); if(p == nil) {assert(0); /* much more work */ } nme.p = p; nme.size = n; } mbDelete(&mb, i, &me); memset(me.p, 0, me.size); if(!moved) { vdPack(&vf->dir, &nme); mbInsert(&mb, i, &nme); } mbPack(&mb); lumpDecRef(u, 1); vf->dirty = 0; vfMetaUnlock(vf); return 1;Err: lumpDecRef(u, 1); vfMetaUnlock(vf); return 0;}static VacFile *vfAlloc(VacFS *fs){ VacFile *vf; vf = vtMemAllocZ(sizeof(VacFile)); vf->lk = vtLockAlloc(); vf->ref = 1; vf->fs = fs; return vf;}static voidvfFree(VacFile *vf){ sourceFree(vf->source); vtLockFree(vf->lk); sourceFree(vf->msource); vdCleanup(&vf->dir); vtMemFree(vf);}/* the file is locked already */static VacFile *dirLookup(VacFile *vf, char *elem){ int i, j, nb; MetaBlock mb; MetaEntry me; Lump *u; Source *meta; VacFile *nvf; meta = vf->msource; u = nil; nb = sourceGetNumBlocks(meta); for(i=0; i<nb; i++) { u = sourceGetLump(meta, i, 1, 1); if(u == nil) goto Err; if(!mbUnpack(&mb, u->data, u->asize)) goto Err; if(!mbSearch(&mb, elem, &j, &me)) goto Err; if(me.p != nil) { nvf = vfAlloc(vf->fs); if(!vdUnpack(&nvf->dir, &me)) { vfFree(nvf); goto Err; } lumpDecRef(u, 1); nvf->block = i; return nvf; } lumpDecRef(u, 1); u = nil; } vtSetError("file does not exist"); /* fall through */Err: lumpDecRef(u, 1); return nil;}/* point r back at vf */static voidpointback(Source *r, VacFile *vf){ assert(r->vf == nil); r->vf = vf;}VacFile *vfRoot(VacFS *fs, uchar *score){ VtEntry e; Lump *u, *v; Source *r, *r0, *r1, *r2; MetaBlock mb; MetaEntry me; VacFile *root, *mr; root = nil; mr = nil; r0 = nil; r1 = nil; r2 = nil; v = nil; r = nil; u = cacheGetLump(fs->cache, score, VtDirType, fs->bsize); if(u == nil) goto Err; if(!fs->readOnly) { v = cacheAllocLump(fs->cache, VtDirType, fs->bsize, 1); if(v == nil) { vtUnlock(u->lk); goto Err; } v->gen = u->gen; v->asize = u->asize; v->state = LumpActive; memmove(v->data, u->data, v->asize); lumpDecRef(u, 1); u = v; v = nil; } vtUnlock(u->lk); vtEntryUnpack(&e, u->data, 2); if(e.flags == 0){ /* just one entry */ r = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly); if(r == nil) goto Err; r0 = sourceOpen(r, 0, fs->readOnly); if(r0 == nil) goto Err; r1 = sourceOpen(r, 1, fs->readOnly); if(r1 == nil) goto Err; r2 = sourceOpen(r, 2, fs->readOnly); if(r2 == nil) goto Err; sourceFree(r); r = nil; }else{ r0 = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly); if(r0 == nil) goto Err; r1 = sourceAlloc(fs->cache, u, 0, 1, fs->readOnly); if(r1 == nil) goto Err; r2 = sourceAlloc(fs->cache, u, 0, 2, fs->readOnly); if(r2 == nil) goto Err; } lumpDecRef(u, 0); u = sourceGetLump(r2, 0, 1, 0); if(u == nil) goto Err; mr = vfAlloc(fs); mr->msource = r2; pointback(r2, mr); r2 = nil; root = vfAlloc(fs); root->up = mr; root->source = r0; pointback(r0, root); r0 = nil; root->msource = r1; pointback(r1, root); r1 = nil; mr->down = root; if(!mbUnpack(&mb, u->data, u->asize)) goto Err; if(!meUnpack(&me, &mb, 0)) goto Err; if(!vdUnpack(&root->dir, &me)) goto Err; vfRAccess(root); lumpDecRef(u, 0); sourceFree(r2); return root;Err: lumpDecRef(u, 0); lumpDecRef(v, 0); if(r0) sourceFree(r0); if(r1) sourceFree(r1); if(r2) sourceFree(r2); if(r) sourceFree(r); if(mr) vfFree(mr); if(root) vfFree(root); return nil;}VacFile *vfWalk(VacFile *vf, char *elem){ VacFile *nvf; vfRAccess(vf); if(elem[0] == 0) { vtSetError("illegal path element"); return nil; } if(!vfIsDir(vf)) { vtSetError("not a directory"); return nil; } if(strcmp(elem, ".") == 0) { return vfIncRef(vf); } if(strcmp(elem, "..") == 0) { if(vfIsRoot(vf)) return vfIncRef(vf); return vfIncRef(vf->up); } if(!vfLock(vf)) return nil; for(nvf = vf->down; nvf; nvf=nvf->next) { if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) { nvf->ref++; goto Exit; } } nvf = dirLookup(vf, elem); if(nvf == nil) goto Err; nvf->source = sourceOpen(vf->source, nvf->dir.entry, vf->fs->readOnly); if(nvf->source == nil) goto Err; pointback(nvf->source, nvf); if(nvf->dir.mode & ModeDir) { nvf->msource = sourceOpen(vf->source, nvf->dir.mentry, vf->fs->readOnly); if(nvf->msource == nil) goto Err; pointback(nvf->msource, nvf); } /* link in and up parent ref count */ nvf->next = vf->down; vf->down = nvf; nvf->up = vf; vfIncRef(vf);Exit: vfUnlock(vf); return nvf;Err: vfUnlock(vf); if(nvf != nil) vfFree(nvf); return nil;}VacFile *vfOpen(VacFS *fs, char *path){ VacFile *vf, *nvf; char *p, elem[VtMaxStringSize]; int n; vf = fs->root; vfIncRef(vf); while(*path != 0) { for(p = path; *p && *p != '/'; p++) ; n = p - path; if(n > 0) { if(n > VtMaxStringSize) { vtSetError("path element too long"); goto Err; } memmove(elem, path, n); elem[n] = 0; nvf = vfWalk(vf, elem); if(nvf == nil) goto Err; vfDecRef(vf); vf = nvf; } if(*p == '/') p++; path = p; } return vf;Err: vfDecRef(vf); return nil;}VacFile *vfCreate(VacFile *vf, char *elem, ulong mode, char *user){ VacFile *nvf; VacDir *dir; int n, i; uchar *p; Source *pr, *r, *mr; int isdir; MetaBlock mb; MetaEntry me; Lump *u; if(!vfLock(vf)) return nil; r = nil; mr = nil; u = nil; for(nvf = vf->down; nvf; nvf=nvf->next) { if(strcmp(elem, nvf->dir.elem) == 0 && !nvf->removed) { nvf = nil; vtSetError(EExists); goto Err; } } nvf = dirLookup(vf, elem); if(nvf != nil) { vtSetError(EExists); goto Err; } nvf = vfAlloc(vf->fs); isdir = mode & ModeDir; pr = vf->source; r = sourceCreate(pr, pr->psize, pr->dsize, isdir, 0); if(r == nil) goto Err; if(isdir) { mr = sourceCreate(pr, pr->psize, pr->dsize, 0, r->block*pr->epb + r->entry); if(mr == nil) goto Err; } dir = &nvf->dir; dir->elem = vtStrDup(elem); dir->entry = r->block*pr->epb + r->entry; dir->gen = r->gen; if(isdir) { dir->mentry = mr->block*pr->epb + mr->entry; dir->mgen = mr->gen; } dir->size = 0; dir->qid = vf->fs->qid++; dir->uid = vtStrDup(user); dir->gid = vtStrDup(vf->dir.gid); dir->mid = vtStrDup(user); dir->mtime = time(0L); dir->mcount = 0; dir->ctime = dir->mtime; dir->atime = dir->mtime; dir->mode = mode; n = vdSize(dir); nvf->block = msAlloc(vf->msource, 0, n); if(nvf->block == NilBlock) goto Err; u = sourceGetLump(vf->msource, nvf->block, 0, 1); if(u == nil) goto Err; if(!mbUnpack(&mb, u->data, u->asize)) goto Err; p = mbAlloc(&mb, n); if(p == nil) goto Err; if(!mbSearch(&mb, elem, &i, &me)) goto Err; assert(me.p == nil); me.p = p; me.size = n; vdPack(dir, &me); mbInsert(&mb, i, &me); mbPack(&mb); lumpDecRef(u, 1); nvf->source = r; pointback(r, nvf); nvf->msource = mr; pointback(mr, vf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -