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

📄 file.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	f->dir.qidMax = max;	ret = fileMetaFlush2(f, nil)>=0;	fileMetaUnlock(f);	fileUnlock(f);	return ret;}uvlongfileGetId(File *f){	/* immutable */	return f->dir.qid;}ulongfileGetMcount(File *f){	ulong mcount;	fileMetaLock(f);	mcount = f->dir.mcount;	fileMetaUnlock(f);	return mcount;}ulongfileGetMode(File *f){	ulong mode;	fileMetaLock(f);	mode = f->dir.mode;	fileMetaUnlock(f);	return mode;}intfileIsDir(File *f){	/* immutable */	return (f->dir.mode & ModeDir) != 0;}intfileIsRoot(File *f){	return f == f->fs->file;}intfileIsRoFs(File *f){	return f->fs->mode == OReadOnly;}intfileGetSize(File *f, uvlong *size){	if(!fileRLock(f))		return 0;	if(!sourceLock(f->source, OReadOnly)){		fileRUnlock(f);		return 0;	}	*size = sourceGetSize(f->source);	sourceUnlock(f->source);	fileRUnlock(f);	return 1;}intfileMetaFlush(File *f, int rec){	File **kids, *p;	int nkids;	int i, rv;	fileMetaLock(f);	rv = fileMetaFlush2(f, nil);	fileMetaUnlock(f);	if(!rec || !fileIsDir(f))		return rv;	if(!fileLock(f))		return rv;	nkids = 0;	for(p=f->down; p; p=p->next)		nkids++;	kids = vtMemAlloc(nkids*sizeof(File*));	i = 0;	for(p=f->down; p; p=p->next){		kids[i++] = p;		p->ref++;	}	fileUnlock(f);	for(i=0; i<nkids; i++){		rv |= fileMetaFlush(kids[i], 1);		fileDecRef(kids[i]);	}	vtMemFree(kids);	return rv;}/* assumes metaLock is held */static intfileMetaFlush2(File *f, char *oelem){	File *fp;	Block *b, *bb;	MetaBlock mb;	MetaEntry me, me2;	int i, n;	u32int boff;	if(!f->dirty)		return 0;	if(oelem == nil)		oelem = f->dir.elem;//print("fileMetaFlush %s->%s\n", oelem, f->dir.elem);	fp = f->up;	if(!sourceLock(fp->msource, -1))		return -1;	/* can happen if source is clri'ed out from under us */	if(f->boff == NilBlock)		goto Err1;	b = sourceBlock(fp->msource, f->boff, OReadWrite);	if(b == nil)		goto Err1;	if(!mbUnpack(&mb, b->data, fp->msource->dsize))		goto Err;	if(!mbSearch(&mb, oelem, &i, &me))		goto Err;	n = deSize(&f->dir);if(0)fprint(2, "old size %d new size %d\n", me.size, n);	if(mbResize(&mb, &me, n)){		/* fits in the block */		mbDelete(&mb, i);		if(strcmp(f->dir.elem, oelem) != 0)			mbSearch(&mb, f->dir.elem, &i, &me2);		dePack(&f->dir, &me);		mbInsert(&mb, i, &me);		mbPack(&mb);		blockDirty(b);		blockPut(b);		sourceUnlock(fp->msource);		f->dirty = 0;		return 1;	}	/*	 * moving entry to another block	 * it is feasible for the fs to crash leaving two copies	 * of the directory entry.  This is just too much work to	 * fix.  Given that entries are only allocated in a block that	 * is less than PercentageFull, most modifications of meta data	 * will fit within the block.  i.e. this code should almost	 * never be executed.	 */	boff = fileMetaAlloc(fp, &f->dir, f->boff+1);	if(boff == NilBlock){		/* mbResize might have modified block */		mbPack(&mb);		blockDirty(b);		goto Err;	}fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);	f->boff = boff;	/* make sure deletion goes to disk after new entry */	bb = sourceBlock(fp->msource, f->boff, OReadWrite);	mbDelete(&mb, i);	mbPack(&mb);	blockDependency(b, bb, -1, nil, nil);	blockPut(bb);	blockDirty(b);	blockPut(b);	sourceUnlock(fp->msource);	f->dirty = 0;	return 1;Err:	blockPut(b);Err1:	sourceUnlock(fp->msource);	return -1;}static intfileMetaRemove(File *f, char *uid){	Block *b;	MetaBlock mb;	MetaEntry me;	int i;	File *up;	up = f->up;	fileWAccess(up, uid);	fileMetaLock(f);	sourceLock(up->msource, OReadWrite);	b = sourceBlock(up->msource, f->boff, OReadWrite);	if(b == nil)		goto Err;	if(!mbUnpack(&mb, b->data, up->msource->dsize)){fprint(2, "U\n");		goto Err;}	if(!mbSearch(&mb, f->dir.elem, &i, &me)){fprint(2, "S\n");		goto Err;}	mbDelete(&mb, i);	mbPack(&mb);	sourceUnlock(up->msource);	blockDirty(b);	blockPut(b);	f->removed = 1;	f->boff = NilBlock;	f->dirty = 0;	fileMetaUnlock(f);	return 1;Err:	sourceUnlock(up->msource);	blockPut(b);	fileMetaUnlock(f);	return 0;}/* assume file is locked, assume f->msource is locked */static intfileCheckEmpty(File *f){	u32int i, n;	Block *b;	MetaBlock mb;	Source *r;	r = f->msource;	n = (sourceGetSize(r)+r->dsize-1)/r->dsize;	for(i=0; i<n; i++){		b = sourceBlock(r, i, OReadOnly);		if(b == nil)			goto Err;		if(!mbUnpack(&mb, b->data, r->dsize))			goto Err;		if(mb.nindex > 0){			vtSetError(ENotEmpty);			goto Err;		}		blockPut(b);	}	return 1;Err:	blockPut(b);	return 0;}intfileRemove(File *f, char *uid){	File *ff;	/* can not remove the root */	if(fileIsRoot(f)){		vtSetError(ERoot);		return 0;	}	if(!fileLock(f))		return 0;	if(f->source->mode != OReadWrite){		vtSetError(EReadOnly);		goto Err1;	}	if(!sourceLock2(f->source, f->msource, -1))		goto Err1;	if(fileIsDir(f) && !fileCheckEmpty(f))		goto Err;	for(ff=f->down; ff; ff=ff->next)		assert(ff->removed);	sourceRemove(f->source);	f->source = nil;	if(f->msource){		sourceRemove(f->msource);		f->msource = nil;	}	fileUnlock(f);	if(!fileMetaRemove(f, uid))		return 0;	return 1;Err:	sourceUnlock(f->source);	if(f->msource)		sourceUnlock(f->msource);Err1:	fileUnlock(f);	return 0;}static intclri(File *f, char *uid){	int r;	if(f == nil)		return 0;	if(f->up->source->mode != OReadWrite){		vtSetError(EReadOnly);		fileDecRef(f);		return 0;	}	r = fileMetaRemove(f, uid);	fileDecRef(f);	return r;}intfileClriPath(Fs *fs, char *path, char *uid){	return clri(_fileOpen(fs, path, 1), uid);}intfileClri(File *dir, char *elem, char *uid){	return clri(_fileWalk(dir, elem, 1), uid);}File *fileIncRef(File *vf){	fileMetaLock(vf);	assert(vf->ref > 0);	vf->ref++;	fileMetaUnlock(vf);	return vf;}intfileDecRef(File *f){	File *p, *q, **qq;	if(f->up == nil){		/* never linked in */		assert(f->ref == 1);		fileFree(f);		return 1;	}	fileMetaLock(f);	f->ref--;	if(f->ref > 0){		fileMetaUnlock(f);		return 0;	}	assert(f->ref == 0);	assert(f->down == nil);	fileMetaFlush2(f, nil);	p = f->up;	qq = &p->down;	for(q = *qq; q; q = *qq){		if(q == f)			break;		qq = &q->next;	}	assert(q != nil);	*qq = f->next;	fileMetaUnlock(f);	fileFree(f);	fileDecRef(p);	return 1;}File *fileGetParent(File *f){	if(fileIsRoot(f))		return fileIncRef(f);	return fileIncRef(f->up);}DirEntryEnum *deeOpen(File *f){	DirEntryEnum *dee;	File *p;	if(!fileIsDir(f)){		vtSetError(ENotDir);		fileDecRef(f);		return nil;	}	/* flush out meta data */	if(!fileLock(f))		return nil;	for(p=f->down; p; p=p->next)		fileMetaFlush2(p, nil);	fileUnlock(f);	dee = vtMemAllocZ(sizeof(DirEntryEnum));	dee->file = fileIncRef(f);	return dee;}static intdirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size){	Block *b;	ulong bn;	Entry e;	int epb;	epb = s->dsize/VtEntrySize;	bn = elem/epb;	elem -= bn*epb;	b = sourceBlock(s, bn, OReadOnly);	if(b == nil)		goto Err;	if(!entryUnpack(&e, b->data, elem))		goto Err;	/* hanging entries are returned as zero size */	if(!(e.flags & VtEntryActive) || e.gen != gen)		*size = 0;	else		*size = e.size;	blockPut(b);	return 1;Err:	blockPut(b);	return 0;}static intdeeFill(DirEntryEnum *dee){	int i, n;	Source *meta, *source;	MetaBlock mb;	MetaEntry me;	File *f;	Block *b;	DirEntry *de;	/* clean up first */	for(i=dee->i; i<dee->n; i++)		deCleanup(dee->buf+i);	vtMemFree(dee->buf);	dee->buf = nil;	dee->i = 0;	dee->n = 0;	f = dee->file;	source = f->source;	meta = f->msource;	b = sourceBlock(meta, dee->boff, OReadOnly);	if(b == nil)		goto Err;	if(!mbUnpack(&mb, b->data, meta->dsize))		goto Err;	n = mb.nindex;	dee->buf = vtMemAlloc(n * sizeof(DirEntry));	for(i=0; i<n; i++){		de = dee->buf + i;		meUnpack(&me, &mb, i);		if(!deUnpack(de, &me))			goto Err;		dee->n++;		if(!(de->mode & ModeDir))		if(!dirEntrySize(source, de->entry, de->gen, &de->size))			goto Err;	}	dee->boff++;	blockPut(b);	return 1;Err:	blockPut(b);	return 0;}intdeeRead(DirEntryEnum *dee, DirEntry *de){	int ret, didread;	File *f;	u32int nb;	if(dee == nil){		vtSetError("cannot happen in deeRead");		return -1;	}	f = dee->file;	if(!fileRLock(f))		return -1;	if(!sourceLock2(f->source, f->msource, OReadOnly)){		fileRUnlock(f);		return -1;	}	nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize;	didread = 0;	while(dee->i >= dee->n){		if(dee->boff >= nb){			ret = 0;			goto Return;		}		didread = 1;		if(!deeFill(dee)){			ret = -1;			goto Return;		}	}	memmove(de, dee->buf + dee->i, sizeof(DirEntry));	dee->i++;	ret = 1;Return:	sourceUnlock(f->source);	sourceUnlock(f->msource);	fileRUnlock(f);	if(didread)		fileRAccess(f);	return ret;}voiddeeClose(DirEntryEnum *dee){	int i;	if(dee == nil)		return;	for(i=dee->i; i<dee->n; i++)		deCleanup(dee->buf+i);	vtMemFree(dee->buf);	fileDecRef(dee->file);	vtMemFree(dee);}/* * caller must lock f->source and f->msource * caller must NOT lock the source and msource * referenced by dir. */static u32intfileMetaAlloc(File *f, DirEntry *dir, u32int start){	u32int nb, bo;	Block *b, *bb;	MetaBlock mb;	int nn;	uchar *p;	int i, n, epb;	MetaEntry me;	Source *s, *ms;	s = f->source;	ms = f->msource;	n = deSize(dir);	nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize;	b = nil;	if(start > nb)		start = nb;	for(bo=start; bo<nb; bo++){		b = sourceBlock(ms, bo, OReadWrite);		if(b == nil)			goto Err;		if(!mbUnpack(&mb, b->data, ms->dsize))			goto Err;		nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;		if(n <= nn && mb.nindex < mb.maxindex)			break;		blockPut(b);		b = nil;	}	/* add block to meta file */	if(b == nil){		b = sourceBlock(ms, bo, OReadWrite);		if(b == nil)			goto Err;		sourceSetSize(ms, (nb+1)*ms->dsize);		mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);	}	p = mbAlloc(&mb, n);	if(p == nil){		/* mbAlloc might have changed block */		mbPack(&mb);		blockDirty(b);		vtSetError(EBadMeta);		goto Err;	}	mbSearch(&mb, dir->elem, &i, &me);	assert(me.p == nil);	me.p = p;	me.size = n;	dePack(dir, &me);	mbInsert(&mb, i, &me);	mbPack(&mb);	/* meta block depends on super block for qid ... */	bb = cacheLocal(b->c, PartSuper, 0, OReadOnly);	blockDependency(b, bb, -1, nil, nil);	blockPut(bb);	/* ... and one or two dir entries */	epb = s->dsize/VtEntrySize;	bb = sourceBlock(s, dir->entry/epb, OReadOnly);	blockDependency(b, bb, -1, nil, nil);	blockPut(bb);	if(dir->mode & ModeDir){		bb = sourceBlock(s, dir->mentry/epb, OReadOnly);		blockDependency(b, bb, -1, nil, nil);		blockPut(bb);	}	blockDirty(b);	blockPut(b);	return bo;Err:	blockPut(b);	return NilBlock;}static intchkSource(File *f){	if(f->partial)		return 1;	if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){		vtSetError(ERemoved);		return 0;	}	return 1;}static intfileRLock(File *f){	assert(!vtCanLock(f->fs->elk));	vtRLock(f->lk);	if(!chkSource(f)){		fileRUnlock(f);		return 0;	}	return 1;}static voidfileRUnlock(File *f){	vtRUnlock(f->lk);}static intfileLock(File *f){	assert(!vtCanLock(f->fs->elk));	vtLock(f->lk);	if(!chkSource(f)){		fileUnlock(f);		return 0;	}	return 1;}static voidfileUnlock(File *f){	vtUnlock(f->lk);}/* * f->source and f->msource must NOT be locked. * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). * We have to respect that ordering. */static voidfileMetaLock(File *f){if(f->up == nil)fprint(2, "f->elem = %s\n", f->dir.elem);	assert(f->up != nil);	assert(!vtCanLock(f->fs->elk));	vtLock(f->up->lk);}static voidfileMetaUnlock(File *f){	vtUnlock(f->up->lk);}/* * f->source and f->msource must NOT be locked. * see fileMetaLock. */static voidfileRAccess(File* f){	if(f->mode == OReadOnly)		return;	fileMetaLock(f);	f->dir.atime = time(0L);	f->dirty = 1;	fileMetaUnlock(f);}/* * f->source and f->msource must NOT be locked. * see fileMetaLock. */static voidfileWAccess(File* f, char *mid){	if(f->mode == OReadOnly)		return;	fileMetaLock(f);	f->dir.atime = f->dir.mtime = time(0L);	if(strcmp(f->dir.mid, mid) != 0){		vtMemFree(f->dir.mid);		f->dir.mid = vtStrDup(mid);	}	f->dir.mcount++;	f->dirty = 1;	fileMetaUnlock(f);/*RSC: let's try this *//*presotto - lets not	if(f->up)		fileWAccess(f->up, mid);*/}static intgetEntry(Source *r, Entry *e, int checkepoch){	u32int epoch;	Block *b;	if(r == nil){		memset(&e, 0, sizeof e);		return 1;	}	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly);	if(b == nil)		return 0;	if(!entryUnpack(e, b->data, r->offset % r->epb)){		blockPut(b);		return 0;	}	epoch = b->l.epoch;	blockPut(b);	if(checkepoch){		b = cacheGlobal(r->fs->cache, e->score, entryType(e), e->tag, OReadOnly);		if(b){			if(b->l.epoch >= epoch)				fprint(2, "warning: entry %p epoch not older %#.8ux/%d %V/%d in getEntry\n",					r, b->addr, b->l.epoch, r->score, epoch);			blockPut(b);		}	}	return 1;}static intsetEntry(Source *r, Entry *e){	Block *b;	Entry oe;	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite);	if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);	if(b == nil)		return 0;	if(!entryUnpack(&oe, b->data, r->offset % r->epb)){		blockPut(b);		return 0;	}	e->gen = oe.gen;	entryPack(e, b->data, r->offset % r->epb);	/* BUG b should depend on the entry pointer */	blockDirty(b);	blockPut(b);	return 1;}/* assumes hold elk */intfileSnapshot(File *dst, File *src, u32int epoch, int doarchive){	Entry e, ee;	/* add link to snapshot */	if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))		return 0;	e.snap = epoch;	e.archive = doarchive;	ee.snap = epoch;	ee.archive = doarchive;	if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))		return 0;	return 1;}intfileGetSources(File *f, Entry *e, Entry *ee){	if(!getEntry(f->source, e, 0)	|| !getEntry(f->msource, ee, 0))		return 0;	return 1;}	/* * Walk down to the block(s) containing the Entries * for f->source and f->msource, copying as we go. */intfileWalkSources(File *f){	if(f->mode == OReadOnly){		fprint(2, "readonly in fileWalkSources\n");		return 1;	}	if(!sourceLock2(f->source, f->msource, OReadWrite)){		fprint(2, "sourceLock2 failed in fileWalkSources\n");		return 0;	}	sourceUnlock(f->source);	sourceUnlock(f->msource);	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -