1869 lines · 31.1 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "stdinc.h"#include "9.h"			/* for consPrint */#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, including component name */ 	File	*up;		/* parent file (directory) */	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;	int	issnapshot;}; 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;			ff->issnapshot = f->issnapshot;			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, 0);	if(r0 == nil)		goto Err;	r1 = sourceOpen(r, 1, fs->mode, 0);	if(r1 == nil)		goto Err;	r2 = sourceOpen(r, 2, fs->mode, 0);	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->file = root;			/* point back to source */	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,	int issnapshot){	char *rname, *fname;	Source *r; 	if(!sourceLock(f->source, mode))		return nil;	r = sourceOpen(f->source, offset, mode, issnapshot);	sourceUnlock(f->source);	if(r == nil)		return nil;	if(r->gen != gen){		vtSetError(ERemoved);		goto Err;	}	if(r->dir != dir && r->mode != -1){		/* this hasn't been as useful as we hoped it would be. */		rname = sourceName(r);		fname = fileName(f);		consPrint("%s: source %s for file %s: fileOpenSource: "			"dir mismatch %d %d\n",			f->source->fs->name, rname, fname, r->dir, dir);		free(rname);		free(fname); 		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;		ff->issnapshot = 1;	} 	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->issnapshot);		ff->msource = fileOpenSource(f, ff->dir.mentry, ff->dir.mgen,			0, ff->mode, ff->issnapshot);		if(ff->source == nil || ff->msource == nil)			goto Err;	}else{		ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen,			0, ff->mode, ff->issnapshot);		if(ff->source == nil)			goto Err;	} 	/* link in and up parent ref count */	if (ff->source)		ff->source->file = ff;		/* point back */	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;	r->file = ff;			/* point back */	ff->msource = mr; 	if(mode&ModeTemporary){		if(!sourceLock2(r, mr, -1))			goto Err1;		fileSetTmp(ff, 1);

Lines 1–500 of 1869.