⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 file.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -