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

📄 file.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "stdinc.h"#include "dat.h"#include "fns.h"#include "error.h"/* * locking order is upwards.  A thread can hold the lock for a File * and then acquire the lock of its parent */struct File {	Fs	*fs;		/* immutable */	/* meta data for file: protected by the lk in the parent */	int	ref;		/* holds this data structure up */	int	partial;	/* file was never really open */	int	removed;	/* file has been removed */	int	dirty;		/* dir is dirty with respect to meta data in block */	u32int	boff;		/* block offset within msource for this file's meta data */	DirEntry dir;		/* meta data for this file */	File	*up;		/* parent file */	File	*next;		/* sibling */	/* data for file */	VtLock	*lk;		/* lock for the following */	Source	*source;	Source	*msource;	/* for directories: meta data for children */	File	*down;		/* children */	int	mode;};static int fileMetaFlush2(File*, char*);static u32int fileMetaAlloc(File*, DirEntry*, u32int);static int fileRLock(File*);static void fileRUnlock(File*);static int fileLock(File*);static void fileUnlock(File*);static void fileMetaLock(File*);static void fileMetaUnlock(File*);static void fileRAccess(File*);static void fileWAccess(File*, char*);static File *fileAlloc(Fs *fs){	File *f;	f = vtMemAllocZ(sizeof(File));	f->lk = vtLockAlloc();	f->ref = 1;	f->fs = fs;	f->boff = NilBlock;	f->mode = fs->mode;	return f;}static voidfileFree(File *f){	sourceClose(f->source);	vtLockFree(f->lk);	sourceClose(f->msource);	deCleanup(&f->dir);	memset(f, ~0, sizeof(File));	vtMemFree(f);}/* * the file is locked already * f->msource is unlocked */static File *dirLookup(File *f, char *elem){	int i;	MetaBlock mb;	MetaEntry me;	Block *b;	Source *meta;	File *ff;	u32int bo, nb;	meta = f->msource;	b = nil;	if(!sourceLock(meta, -1))		return nil;	nb = (sourceGetSize(meta)+meta->dsize-1)/meta->dsize;	for(bo=0; bo<nb; bo++){		b = sourceBlock(meta, bo, OReadOnly);		if(b == nil)			goto Err;		if(!mbUnpack(&mb, b->data, meta->dsize))			goto Err;		if(mbSearch(&mb, elem, &i, &me)){			ff = fileAlloc(f->fs);			if(!deUnpack(&ff->dir, &me)){				fileFree(ff);				goto Err;			}			sourceUnlock(meta);			blockPut(b);			ff->boff = bo;			ff->mode = f->mode;			return ff;		}		blockPut(b);		b = nil;	}	vtSetError(ENoFile);	/* fall through */Err:	sourceUnlock(meta);	blockPut(b);	return nil;}File *fileRoot(Source *r){	Block *b;	Source *r0, *r1, *r2;	MetaBlock mb;	MetaEntry me;	File *root, *mr;	Fs *fs;	b = nil;	root = nil;	mr = nil;	r1 = nil;	r2 = nil;	fs = r->fs;	if(!sourceLock(r, -1))		return nil;	r0 = sourceOpen(r, 0, fs->mode);	if(r0 == nil)		goto Err;	r1 = sourceOpen(r, 1, fs->mode);	if(r1 == nil)		goto Err;	r2 = sourceOpen(r, 2, fs->mode);	if(r2 == nil)		goto Err;	mr = fileAlloc(fs);	mr->msource = r2;	r2 = nil;	root = fileAlloc(fs);	root->boff = 0;	root->up = mr;	root->source = r0;	r0 = nil;	root->msource = r1;	r1 = nil;	mr->down = root;	if(!sourceLock(mr->msource, -1))		goto Err;	b = sourceBlock(mr->msource, 0, OReadOnly);	sourceUnlock(mr->msource);	if(b == nil)		goto Err;	if(!mbUnpack(&mb, b->data, mr->msource->dsize))		goto Err;	meUnpack(&me, &mb, 0);	if(!deUnpack(&root->dir, &me))		goto Err;	blockPut(b);	sourceUnlock(r);	fileRAccess(root);	return root;Err:	blockPut(b);	if(r0)		sourceClose(r0);	if(r1)		sourceClose(r1);	if(r2)		sourceClose(r2);	if(mr)		fileFree(mr);	if(root)		fileFree(root);	sourceUnlock(r);	return nil;}static Source *fileOpenSource(File *f, u32int offset, u32int gen, int dir, uint mode){	Source *r;	if(!sourceLock(f->source, mode))		return nil;	r = sourceOpen(f->source, offset, mode);	sourceUnlock(f->source);	if(r == nil)		return nil;	if(r->gen != gen){		vtSetError(ERemoved);		goto Err;	}	if(r->dir != dir && r->mode != -1){fprint(2, "fileOpenSource: dir mismatch %d %d\n", r->dir, dir);		vtSetError(EBadMeta);		goto Err;	}	return r;Err:	sourceClose(r);	return nil;}File *_fileWalk(File *f, char *elem, int partial){	File *ff;	fileRAccess(f);	if(elem[0] == 0){		vtSetError(EBadPath);		return nil;	}	if(!fileIsDir(f)){		vtSetError(ENotDir);		return nil;	}	if(strcmp(elem, ".") == 0){		return fileIncRef(f);	}	if(strcmp(elem, "..") == 0){		if(fileIsRoot(f))			return fileIncRef(f);		return fileIncRef(f->up);	}	if(!fileLock(f))		return nil;	for(ff = f->down; ff; ff=ff->next){		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){			ff->ref++;			goto Exit;		}	}	ff = dirLookup(f, elem);	if(ff == nil)		goto Err;	if(ff->dir.mode & ModeSnapshot)		ff->mode = OReadOnly;	if(partial){		/*		 * Do nothing.  We're opening this file only so we can clri it.		 * Usually the sources can't be opened, hence we won't even bother.		 * Be VERY careful with the returned file.  If you hand it to a routine		 * expecting ff->source and/or ff->msource to be non-nil, we're		 * likely to dereference nil.  FileClri should be the only routine		 * setting partial.		 */		ff->partial = 1;	}else if(ff->dir.mode & ModeDir){		ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);		ff->msource = fileOpenSource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);		if(ff->source == nil || ff->msource == nil)			goto Err;	}else{		ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);		if(ff->source == nil)			goto Err;	}	/* link in and up parent ref count */	ff->next = f->down;	f->down = ff;	ff->up = f;	fileIncRef(f);Exit:	fileUnlock(f);	return ff;Err:	fileUnlock(f);	if(ff != nil)		fileDecRef(ff);	return nil;}File *fileWalk(File *f, char *elem){	return _fileWalk(f, elem, 0);}File *_fileOpen(Fs *fs, char *path, int partial){	File *f, *ff;	char *p, elem[VtMaxStringSize], *opath;	int n;	f = fs->file;	fileIncRef(f);	opath = path;	while(*path != 0){		for(p = path; *p && *p != '/'; p++)			;		n = p - path;		if(n > 0){			if(n > VtMaxStringSize){				vtSetError("%s: element too long", EBadPath);				goto Err;			}			memmove(elem, path, n);			elem[n] = 0;			ff = _fileWalk(f, elem, partial && *p=='\0');			if(ff == nil){				vtSetError("%.*s: %R", utfnlen(opath, p-opath), opath);				goto Err;			}			fileDecRef(f);			f = ff;		}		if(*p == '/')			p++;		path = p;	}	return f;Err:	fileDecRef(f);	return nil;}File*fileOpen(Fs *fs, char *path){	return _fileOpen(fs, path, 0);}static voidfileSetTmp(File *f, int istmp){	int i;	Entry e;	Source *r;	for(i=0; i<2; i++){		if(i==0)			r = f->source;		else			r = f->msource;		if(r == nil)			continue;		if(!sourceGetEntry(r, &e)){			fprint(2, "sourceGetEntry failed (cannot happen): %r\n");			continue;		}		if(istmp)			e.flags |= VtEntryNoArchive;		else			e.flags &= ~VtEntryNoArchive;		if(!sourceSetEntry(r, &e)){			fprint(2, "sourceSetEntry failed (cannot happen): %r\n");			continue;		}	}}File *fileCreate(File *f, char *elem, ulong mode, char *uid){	File *ff;	DirEntry *dir;	Source *pr, *r, *mr;	int isdir;	if(!fileLock(f))		return nil;	r = nil;	mr = nil;	for(ff = f->down; ff; ff=ff->next){		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){			ff = nil;			vtSetError(EExists);			goto Err1;		}	}	ff = dirLookup(f, elem);	if(ff != nil){		vtSetError(EExists);		goto Err1;	}	pr = f->source;	if(pr->mode != OReadWrite){		vtSetError(EReadOnly);		goto Err1;	}	if(!sourceLock2(f->source, f->msource, -1))		goto Err1;	ff = fileAlloc(f->fs);	isdir = mode & ModeDir;	r = sourceCreate(pr, pr->dsize, isdir, 0);	if(r == nil)		goto Err;	if(isdir){		mr = sourceCreate(pr, pr->dsize, 0, r->offset);		if(mr == nil)			goto Err;	}	dir = &ff->dir;	dir->elem = vtStrDup(elem);	dir->entry = r->offset;	dir->gen = r->gen;	if(isdir){		dir->mentry = mr->offset;		dir->mgen = mr->gen;	}	dir->size = 0;	if(!fsNextQid(f->fs, &dir->qid))		goto Err;	dir->uid = vtStrDup(uid);	dir->gid = vtStrDup(f->dir.gid);	dir->mid = vtStrDup(uid);	dir->mtime = time(0L);	dir->mcount = 0;	dir->ctime = dir->mtime;	dir->atime = dir->mtime;	dir->mode = mode;	ff->boff = fileMetaAlloc(f, dir, 0);	if(ff->boff == NilBlock)		goto Err;	sourceUnlock(f->source);	sourceUnlock(f->msource);	ff->source = r;	ff->msource = mr;	if(mode&ModeTemporary){		if(!sourceLock2(r, mr, -1))			goto Err1;		fileSetTmp(ff, 1);		sourceUnlock(r);		if(mr)			sourceUnlock(mr);	}	/* committed */	/* link in and up parent ref count */	ff->next = f->down;	f->down = ff;	ff->up = f;	fileIncRef(f);	fileWAccess(f, uid);	fileUnlock(f);	return ff;Err:	sourceUnlock(f->source);	sourceUnlock(f->msource);Err1:	if(r){		sourceLock(r, -1);		sourceRemove(r);	}	if(mr){		sourceLock(mr, -1);		sourceRemove(mr);	}	if(ff)		fileDecRef(ff);	fileUnlock(f);	return 0;}intfileRead(File *f, void *buf, int cnt, vlong offset){	Source *s;	uvlong size;	u32int bn;	int off, dsize, n, nn;	Block *b;	uchar *p;if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset);	if(!fileRLock(f))		return -1;	if(offset < 0){		vtSetError(EBadOffset);		goto Err1;	}	fileRAccess(f);	if(!sourceLock(f->source, OReadOnly))		goto Err1;	s = f->source;	dsize = s->dsize;	size = sourceGetSize(s);	if(offset >= size)		offset = size;	if(cnt > size-offset)		cnt = size-offset;	bn = offset/dsize;	off = offset%dsize;	p = buf;	while(cnt > 0){		b = sourceBlock(s, bn, OReadOnly);		if(b == nil)			goto Err;		n = cnt;		if(n > dsize-off)			n = dsize-off;		nn = dsize-off;		if(nn > n)			nn = n;		memmove(p, b->data+off, nn);		memset(p+nn, 0, nn-n);		off = 0;		bn++;		cnt -= n;		p += n;		blockPut(b);	}	sourceUnlock(s);	fileRUnlock(f);	return p-(uchar*)buf;Err:	sourceUnlock(s);Err1:	fileRUnlock(f);	return -1;}/*  * Changes the file block bn to be the given block score. * Very sneaky.  Only used by flfmt. */intfileMapBlock(File *f, ulong bn, uchar score[VtScoreSize], ulong tag){	Block *b;	Entry e;	Source *s;	if(!fileLock(f))		return 0;	s = nil;	if(f->dir.mode & ModeDir){		vtSetError(ENotFile);		goto Err;	}	if(f->source->mode != OReadWrite){		vtSetError(EReadOnly);		goto Err;	}	if(!sourceLock(f->source, -1))		goto Err;	s = f->source;	b = _sourceBlock(s, bn, OReadWrite, 1, tag);	if(b == nil)		goto Err;	if(!sourceGetEntry(s, &e))		goto Err;	if(b->l.type == BtDir){		memmove(e.score, score, VtScoreSize);		assert(e.tag == tag || e.tag == 0);		e.tag = tag;		e.flags |= VtEntryLocal;		entryPack(&e, b->data, f->source->offset % f->source->epb);	}else		memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize);	blockDirty(b);	blockPut(b);	sourceUnlock(s);	fileUnlock(f);	return 1;Err:	if(s)		sourceUnlock(s);	fileUnlock(f);	return 0;}intfileSetSize(File *f, uvlong size){	int r;	if(!fileLock(f))		return 0;	r = 0;	if(f->dir.mode & ModeDir){		vtSetError(ENotFile);		goto Err;	}	if(f->source->mode != OReadWrite){		vtSetError(EReadOnly);		goto Err;	}	if(!sourceLock(f->source, -1))		goto Err;	r = sourceSetSize(f->source, size);	sourceUnlock(f->source);Err:	fileUnlock(f);	return r;}intfileWrite(File *f, void *buf, int cnt, vlong offset, char *uid){	Source *s;	ulong bn;	int off, dsize, n;	Block *b;	uchar *p;	vlong eof;if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset);	if(!fileLock(f))		return -1;	s = nil;	if(f->dir.mode & ModeDir){		vtSetError(ENotFile);		goto Err;	}	if(f->source->mode != OReadWrite){		vtSetError(EReadOnly);		goto Err;	}	if(offset < 0){		vtSetError(EBadOffset);		goto Err;	}	fileWAccess(f, uid);	if(!sourceLock(f->source, -1))		goto Err;	s = f->source;	dsize = s->dsize;	eof = sourceGetSize(s);	if(f->dir.mode & ModeAppend)		offset = eof;	bn = offset/dsize;	off = offset%dsize;	p = buf;	while(cnt > 0){		n = cnt;		if(n > dsize-off)			n = dsize-off;		b = sourceBlock(s, bn, n<dsize?OReadWrite:OOverWrite);		if(b == nil){			if(offset > eof)				sourceSetSize(s, offset);			goto Err;		}		memmove(b->data+off, p, n);		off = 0;		cnt -= n;		p += n;		offset += n;		bn++;		blockDirty(b);		blockPut(b);	}	if(offset > eof && !sourceSetSize(s, offset))		goto Err;	sourceUnlock(s);	fileUnlock(f);	return p-(uchar*)buf;Err:	if(s)		sourceUnlock(s);	fileUnlock(f);	return -1;}intfileGetDir(File *f, DirEntry *dir){	if(!fileRLock(f))		return 0;	fileMetaLock(f);	deCopy(dir, &f->dir);	fileMetaUnlock(f);	if(!fileIsDir(f)){		if(!sourceLock(f->source, OReadOnly)){			fileRUnlock(f);			return 0;		}		dir->size = sourceGetSize(f->source);		sourceUnlock(f->source);	}	fileRUnlock(f);	return 1;}intfileTruncate(File *f, char *uid){	if(fileIsDir(f)){		vtSetError(ENotFile);		return 0;	}	if(!fileLock(f))		return 0;	if(f->source->mode != OReadWrite){		vtSetError(EReadOnly);		fileUnlock(f);		return 0;	}	if(!sourceLock(f->source, -1)){		fileUnlock(f);		return 0;	}	if(!sourceTruncate(f->source)){		sourceUnlock(f->source);		fileUnlock(f);		return 0;	}	sourceUnlock(f->source);	fileUnlock(f);	fileWAccess(f, uid);	return 1;}intfileSetDir(File *f, DirEntry *dir, char *uid){	File *ff;	char *oelem;	u32int mask;	u64int size;	/* can not set permissions for the root */	if(fileIsRoot(f)){		vtSetError(ERoot);		return 0;	}	if(!fileLock(f))		return 0;	if(f->source->mode != OReadWrite){		vtSetError(EReadOnly);		fileUnlock(f);		return 0;	}	fileMetaLock(f);	/* check new name does not already exist */	if(strcmp(f->dir.elem, dir->elem) != 0){		for(ff = f->up->down; ff; ff=ff->next){			if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){				vtSetError(EExists);				goto Err;			}		}		ff = dirLookup(f->up, dir->elem);		if(ff != nil){			fileDecRef(ff);			vtSetError(EExists);			goto Err;		}	}	if(!sourceLock2(f->source, f->msource, -1))		goto Err;	if(!fileIsDir(f)){		size = sourceGetSize(f->source);		if(size != dir->size){			if(!sourceSetSize(f->source, dir->size)){				sourceUnlock(f->source);				if(f->msource)					sourceUnlock(f->msource);				goto Err;			}			/* commited to changing it now */		}	}	/* commited to changing it now */	if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary))		fileSetTmp(f, dir->mode&ModeTemporary);	sourceUnlock(f->source);	if(f->msource)		sourceUnlock(f->msource);	oelem = nil;	if(strcmp(f->dir.elem, dir->elem) != 0){		oelem = f->dir.elem;		f->dir.elem = vtStrDup(dir->elem);	}	if(strcmp(f->dir.uid, dir->uid) != 0){		vtMemFree(f->dir.uid);		f->dir.uid = vtStrDup(dir->uid);	}	if(strcmp(f->dir.gid, dir->gid) != 0){		vtMemFree(f->dir.gid);		f->dir.gid = vtStrDup(dir->gid);	}	f->dir.mtime = dir->mtime;	f->dir.atime = dir->atime;//fprint(2, "mode %x %x ", f->dir.mode, dir->mode);	mask = ~(ModeDir|ModeSnapshot);	f->dir.mode &= ~mask;	f->dir.mode |= mask & dir->mode;	f->dirty = 1;//fprint(2, "->%x\n", f->dir.mode);	fileMetaFlush2(f, oelem);	vtMemFree(oelem);	fileMetaUnlock(f);	fileUnlock(f);	fileWAccess(f->up, uid);	return 1;Err:	fileMetaUnlock(f);	fileUnlock(f);	return 0;}intfileSetQidSpace(File *f, u64int offset, u64int max){	int ret;	if(!fileLock(f))		return 0;	fileMetaLock(f);	f->dir.qidSpace = 1;	f->dir.qidOffset = offset;

⌨️ 快捷键说明

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