xref: /plan9-contrib/sys/src/cmd/fossil/file.c (revision 4671045461313a8e462aa8a4c2e3770940197e26)
15e96a66cSDavid du Colombier #include "stdinc.h"
23b86f2f8SDavid du Colombier #include "9.h"			/* for consPrint */
35e96a66cSDavid du Colombier #include "dat.h"
45e96a66cSDavid du Colombier #include "fns.h"
55e96a66cSDavid du Colombier #include "error.h"
65e96a66cSDavid du Colombier 
75e96a66cSDavid du Colombier /*
85e96a66cSDavid du Colombier  * locking order is upwards.  A thread can hold the lock for a File
95e96a66cSDavid du Colombier  * and then acquire the lock of its parent
105e96a66cSDavid du Colombier  */
115e96a66cSDavid du Colombier 
125e96a66cSDavid du Colombier struct File {
135e96a66cSDavid du Colombier 	Fs	*fs;		/* immutable */
145e96a66cSDavid du Colombier 
155e96a66cSDavid du Colombier 	/* meta data for file: protected by the lk in the parent */
165e96a66cSDavid du Colombier 	int	ref;		/* holds this data structure up */
175e96a66cSDavid du Colombier 
185e96a66cSDavid du Colombier 	int	partial;	/* file was never really open */
195e96a66cSDavid du Colombier 	int	removed;	/* file has been removed */
205e96a66cSDavid du Colombier 	int	dirty;	/* dir is dirty with respect to meta data in block */
215e96a66cSDavid du Colombier 	u32int	boff;	/* block offset within msource for this file's meta data */
225e96a66cSDavid du Colombier 
233b86f2f8SDavid du Colombier 	DirEntry dir;	/* meta data for this file, including component name */
245e96a66cSDavid du Colombier 
253b86f2f8SDavid du Colombier 	File	*up;		/* parent file (directory) */
265e96a66cSDavid du Colombier 	File	*next;		/* sibling */
275e96a66cSDavid du Colombier 
285e96a66cSDavid du Colombier 	/* data for file */
29d7aba6c3SDavid du Colombier 	RWLock	lk;		/* lock for the following */
305e96a66cSDavid du Colombier 	Source	*source;
315e96a66cSDavid du Colombier 	Source	*msource;	/* for directories: meta data for children */
325e96a66cSDavid du Colombier 	File	*down;		/* children */
335e96a66cSDavid du Colombier 
345e96a66cSDavid du Colombier 	int	mode;
3557195852SDavid du Colombier 	int	issnapshot;
365e96a66cSDavid du Colombier };
375e96a66cSDavid du Colombier 
385e96a66cSDavid du Colombier static int fileMetaFlush2(File*, char*);
395e96a66cSDavid du Colombier static u32int fileMetaAlloc(File*, DirEntry*, u32int);
405e96a66cSDavid du Colombier static int fileRLock(File*);
415e96a66cSDavid du Colombier static void fileRUnlock(File*);
425e96a66cSDavid du Colombier static int fileLock(File*);
435e96a66cSDavid du Colombier static void fileUnlock(File*);
445e96a66cSDavid du Colombier static void fileMetaLock(File*);
455e96a66cSDavid du Colombier static void fileMetaUnlock(File*);
465e96a66cSDavid du Colombier static void fileRAccess(File*);
475e96a66cSDavid du Colombier static void fileWAccess(File*, char*);
485e96a66cSDavid du Colombier 
495e96a66cSDavid du Colombier static File *
fileAlloc(Fs * fs)505e96a66cSDavid du Colombier fileAlloc(Fs *fs)
515e96a66cSDavid du Colombier {
525e96a66cSDavid du Colombier 	File *f;
535e96a66cSDavid du Colombier 
54d7aba6c3SDavid du Colombier 	f = vtmallocz(sizeof(File));
555e96a66cSDavid du Colombier 	f->ref = 1;
565e96a66cSDavid du Colombier 	f->fs = fs;
575e96a66cSDavid du Colombier 	f->boff = NilBlock;
585e96a66cSDavid du Colombier 	f->mode = fs->mode;
595e96a66cSDavid du Colombier 	return f;
605e96a66cSDavid du Colombier }
615e96a66cSDavid du Colombier 
625e96a66cSDavid du Colombier static void
fileFree(File * f)635e96a66cSDavid du Colombier fileFree(File *f)
645e96a66cSDavid du Colombier {
655e96a66cSDavid du Colombier 	sourceClose(f->source);
665e96a66cSDavid du Colombier 	sourceClose(f->msource);
675e96a66cSDavid du Colombier 	deCleanup(&f->dir);
685e96a66cSDavid du Colombier 
695e96a66cSDavid du Colombier 	memset(f, ~0, sizeof(File));
70d7aba6c3SDavid du Colombier 	vtfree(f);
715e96a66cSDavid du Colombier }
725e96a66cSDavid du Colombier 
735e96a66cSDavid du Colombier /*
745e96a66cSDavid du Colombier  * the file is locked already
755e96a66cSDavid du Colombier  * f->msource is unlocked
765e96a66cSDavid du Colombier  */
775e96a66cSDavid du Colombier static File *
dirLookup(File * f,char * elem)785e96a66cSDavid du Colombier dirLookup(File *f, char *elem)
795e96a66cSDavid du Colombier {
805e96a66cSDavid du Colombier 	int i;
815e96a66cSDavid du Colombier 	MetaBlock mb;
825e96a66cSDavid du Colombier 	MetaEntry me;
835e96a66cSDavid du Colombier 	Block *b;
845e96a66cSDavid du Colombier 	Source *meta;
855e96a66cSDavid du Colombier 	File *ff;
865e96a66cSDavid du Colombier 	u32int bo, nb;
875e96a66cSDavid du Colombier 
885e96a66cSDavid du Colombier 	meta = f->msource;
895e96a66cSDavid du Colombier 	b = nil;
905e96a66cSDavid du Colombier 	if(!sourceLock(meta, -1))
915e96a66cSDavid du Colombier 		return nil;
925e96a66cSDavid du Colombier 	nb = (sourceGetSize(meta)+meta->dsize-1)/meta->dsize;
935e96a66cSDavid du Colombier 	for(bo=0; bo<nb; bo++){
945e96a66cSDavid du Colombier 		b = sourceBlock(meta, bo, OReadOnly);
955e96a66cSDavid du Colombier 		if(b == nil)
965e96a66cSDavid du Colombier 			goto Err;
975e96a66cSDavid du Colombier 		if(!mbUnpack(&mb, b->data, meta->dsize))
985e96a66cSDavid du Colombier 			goto Err;
995e96a66cSDavid du Colombier 		if(mbSearch(&mb, elem, &i, &me)){
1005e96a66cSDavid du Colombier 			ff = fileAlloc(f->fs);
1015e96a66cSDavid du Colombier 			if(!deUnpack(&ff->dir, &me)){
1025e96a66cSDavid du Colombier 				fileFree(ff);
1035e96a66cSDavid du Colombier 				goto Err;
1045e96a66cSDavid du Colombier 			}
1055e96a66cSDavid du Colombier 			sourceUnlock(meta);
1065e96a66cSDavid du Colombier 			blockPut(b);
1075e96a66cSDavid du Colombier 			ff->boff = bo;
1085e96a66cSDavid du Colombier 			ff->mode = f->mode;
10957195852SDavid du Colombier 			ff->issnapshot = f->issnapshot;
1105e96a66cSDavid du Colombier 			return ff;
1115e96a66cSDavid du Colombier 		}
1125e96a66cSDavid du Colombier 
1135e96a66cSDavid du Colombier 		blockPut(b);
1145e96a66cSDavid du Colombier 		b = nil;
1155e96a66cSDavid du Colombier 	}
116d7aba6c3SDavid du Colombier 	werrstr(ENoFile);
1175e96a66cSDavid du Colombier 	/* fall through */
1185e96a66cSDavid du Colombier Err:
1195e96a66cSDavid du Colombier 	sourceUnlock(meta);
1205e96a66cSDavid du Colombier 	blockPut(b);
1215e96a66cSDavid du Colombier 	return nil;
1225e96a66cSDavid du Colombier }
1235e96a66cSDavid du Colombier 
1245e96a66cSDavid du Colombier File *
fileRoot(Source * r)1255e96a66cSDavid du Colombier fileRoot(Source *r)
1265e96a66cSDavid du Colombier {
1275e96a66cSDavid du Colombier 	Block *b;
1285e96a66cSDavid du Colombier 	Source *r0, *r1, *r2;
1295e96a66cSDavid du Colombier 	MetaBlock mb;
1305e96a66cSDavid du Colombier 	MetaEntry me;
1315e96a66cSDavid du Colombier 	File *root, *mr;
1325e96a66cSDavid du Colombier 	Fs *fs;
1335e96a66cSDavid du Colombier 
1345e96a66cSDavid du Colombier 	b = nil;
1355e96a66cSDavid du Colombier 	root = nil;
1365e96a66cSDavid du Colombier 	mr = nil;
1375e96a66cSDavid du Colombier 	r1 = nil;
1385e96a66cSDavid du Colombier 	r2 = nil;
1395e96a66cSDavid du Colombier 
1405e96a66cSDavid du Colombier 	fs = r->fs;
1415e96a66cSDavid du Colombier 	if(!sourceLock(r, -1))
1425e96a66cSDavid du Colombier 		return nil;
14357195852SDavid du Colombier 	r0 = sourceOpen(r, 0, fs->mode, 0);
1445e96a66cSDavid du Colombier 	if(r0 == nil)
1455e96a66cSDavid du Colombier 		goto Err;
14657195852SDavid du Colombier 	r1 = sourceOpen(r, 1, fs->mode, 0);
1475e96a66cSDavid du Colombier 	if(r1 == nil)
1485e96a66cSDavid du Colombier 		goto Err;
14957195852SDavid du Colombier 	r2 = sourceOpen(r, 2, fs->mode, 0);
1505e96a66cSDavid du Colombier 	if(r2 == nil)
1515e96a66cSDavid du Colombier 		goto Err;
1525e96a66cSDavid du Colombier 
1535e96a66cSDavid du Colombier 	mr = fileAlloc(fs);
1545e96a66cSDavid du Colombier 	mr->msource = r2;
1555e96a66cSDavid du Colombier 	r2 = nil;
1565e96a66cSDavid du Colombier 
1575e96a66cSDavid du Colombier 	root = fileAlloc(fs);
1585e96a66cSDavid du Colombier 	root->boff = 0;
1595e96a66cSDavid du Colombier 	root->up = mr;
1605e96a66cSDavid du Colombier 	root->source = r0;
1613b86f2f8SDavid du Colombier 	r0->file = root;			/* point back to source */
1625e96a66cSDavid du Colombier 	r0 = nil;
1635e96a66cSDavid du Colombier 	root->msource = r1;
1645e96a66cSDavid du Colombier 	r1 = nil;
1655e96a66cSDavid du Colombier 
1665e96a66cSDavid du Colombier 	mr->down = root;
1675e96a66cSDavid du Colombier 
1685e96a66cSDavid du Colombier 	if(!sourceLock(mr->msource, -1))
1695e96a66cSDavid du Colombier 		goto Err;
1705e96a66cSDavid du Colombier 	b = sourceBlock(mr->msource, 0, OReadOnly);
1715e96a66cSDavid du Colombier 	sourceUnlock(mr->msource);
1725e96a66cSDavid du Colombier 	if(b == nil)
1735e96a66cSDavid du Colombier 		goto Err;
1745e96a66cSDavid du Colombier 
1755e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, mr->msource->dsize))
1765e96a66cSDavid du Colombier 		goto Err;
1775e96a66cSDavid du Colombier 
1785e96a66cSDavid du Colombier 	meUnpack(&me, &mb, 0);
1795e96a66cSDavid du Colombier 	if(!deUnpack(&root->dir, &me))
1805e96a66cSDavid du Colombier 		goto Err;
1815e96a66cSDavid du Colombier 	blockPut(b);
1825e96a66cSDavid du Colombier 	sourceUnlock(r);
1835e96a66cSDavid du Colombier 	fileRAccess(root);
1845e96a66cSDavid du Colombier 
1855e96a66cSDavid du Colombier 	return root;
1865e96a66cSDavid du Colombier Err:
1875e96a66cSDavid du Colombier 	blockPut(b);
1885e96a66cSDavid du Colombier 	if(r0)
1895e96a66cSDavid du Colombier 		sourceClose(r0);
1905e96a66cSDavid du Colombier 	if(r1)
1915e96a66cSDavid du Colombier 		sourceClose(r1);
1925e96a66cSDavid du Colombier 	if(r2)
1935e96a66cSDavid du Colombier 		sourceClose(r2);
1945e96a66cSDavid du Colombier 	if(mr)
1955e96a66cSDavid du Colombier 		fileFree(mr);
1965e96a66cSDavid du Colombier 	if(root)
1975e96a66cSDavid du Colombier 		fileFree(root);
1985e96a66cSDavid du Colombier 	sourceUnlock(r);
1995e96a66cSDavid du Colombier 
2005e96a66cSDavid du Colombier 	return nil;
2015e96a66cSDavid du Colombier }
2025e96a66cSDavid du Colombier 
2035e96a66cSDavid du Colombier static Source *
fileOpenSource(File * f,u32int offset,u32int gen,int dir,uint mode,int issnapshot)2043b86f2f8SDavid du Colombier fileOpenSource(File *f, u32int offset, u32int gen, int dir, uint mode,
2053b86f2f8SDavid du Colombier 	int issnapshot)
2065e96a66cSDavid du Colombier {
2073b86f2f8SDavid du Colombier 	char *rname, *fname;
2085e96a66cSDavid du Colombier 	Source *r;
2095e96a66cSDavid du Colombier 
2105e96a66cSDavid du Colombier 	if(!sourceLock(f->source, mode))
2115e96a66cSDavid du Colombier 		return nil;
21257195852SDavid du Colombier 	r = sourceOpen(f->source, offset, mode, issnapshot);
2135e96a66cSDavid du Colombier 	sourceUnlock(f->source);
2145e96a66cSDavid du Colombier 	if(r == nil)
2155e96a66cSDavid du Colombier 		return nil;
2165e96a66cSDavid du Colombier 	if(r->gen != gen){
217d7aba6c3SDavid du Colombier 		werrstr(ERemoved);
2185e96a66cSDavid du Colombier 		goto Err;
2195e96a66cSDavid du Colombier 	}
2205e96a66cSDavid du Colombier 	if(r->dir != dir && r->mode != -1){
2213b86f2f8SDavid du Colombier 		/* this hasn't been as useful as we hoped it would be. */
2223b86f2f8SDavid du Colombier 		rname = sourceName(r);
2233b86f2f8SDavid du Colombier 		fname = fileName(f);
2243b86f2f8SDavid du Colombier 		consPrint("%s: source %s for file %s: fileOpenSource: "
2253b86f2f8SDavid du Colombier 			"dir mismatch %d %d\n",
2263b86f2f8SDavid du Colombier 			f->source->fs->name, rname, fname, r->dir, dir);
2273b86f2f8SDavid du Colombier 		free(rname);
2283b86f2f8SDavid du Colombier 		free(fname);
2293b86f2f8SDavid du Colombier 
230d7aba6c3SDavid du Colombier 		werrstr(EBadMeta);
2315e96a66cSDavid du Colombier 		goto Err;
2325e96a66cSDavid du Colombier 	}
2335e96a66cSDavid du Colombier 	return r;
2345e96a66cSDavid du Colombier Err:
2355e96a66cSDavid du Colombier 	sourceClose(r);
2365e96a66cSDavid du Colombier 	return nil;
2375e96a66cSDavid du Colombier }
2385e96a66cSDavid du Colombier 
2395e96a66cSDavid du Colombier File *
_fileWalk(File * f,char * elem,int partial)2405e96a66cSDavid du Colombier _fileWalk(File *f, char *elem, int partial)
2415e96a66cSDavid du Colombier {
2425e96a66cSDavid du Colombier 	File *ff;
2435e96a66cSDavid du Colombier 
2445e96a66cSDavid du Colombier 	fileRAccess(f);
2455e96a66cSDavid du Colombier 
2465e96a66cSDavid du Colombier 	if(elem[0] == 0){
247d7aba6c3SDavid du Colombier 		werrstr(EBadPath);
2485e96a66cSDavid du Colombier 		return nil;
2495e96a66cSDavid du Colombier 	}
2505e96a66cSDavid du Colombier 
2515e96a66cSDavid du Colombier 	if(!fileIsDir(f)){
252d7aba6c3SDavid du Colombier 		werrstr(ENotDir);
2535e96a66cSDavid du Colombier 		return nil;
2545e96a66cSDavid du Colombier 	}
2555e96a66cSDavid du Colombier 
2565e96a66cSDavid du Colombier 	if(strcmp(elem, ".") == 0){
2575e96a66cSDavid du Colombier 		return fileIncRef(f);
2585e96a66cSDavid du Colombier 	}
2595e96a66cSDavid du Colombier 
2605e96a66cSDavid du Colombier 	if(strcmp(elem, "..") == 0){
2615e96a66cSDavid du Colombier 		if(fileIsRoot(f))
2625e96a66cSDavid du Colombier 			return fileIncRef(f);
2635e96a66cSDavid du Colombier 		return fileIncRef(f->up);
2645e96a66cSDavid du Colombier 	}
2655e96a66cSDavid du Colombier 
2665e96a66cSDavid du Colombier 	if(!fileLock(f))
2675e96a66cSDavid du Colombier 		return nil;
2685e96a66cSDavid du Colombier 
2695e96a66cSDavid du Colombier 	for(ff = f->down; ff; ff=ff->next){
2705e96a66cSDavid du Colombier 		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
2715e96a66cSDavid du Colombier 			ff->ref++;
2725e96a66cSDavid du Colombier 			goto Exit;
2735e96a66cSDavid du Colombier 		}
2745e96a66cSDavid du Colombier 	}
2755e96a66cSDavid du Colombier 
2765e96a66cSDavid du Colombier 	ff = dirLookup(f, elem);
2775e96a66cSDavid du Colombier 	if(ff == nil)
2785e96a66cSDavid du Colombier 		goto Err;
2795e96a66cSDavid du Colombier 
28057195852SDavid du Colombier 	if(ff->dir.mode & ModeSnapshot){
2815e96a66cSDavid du Colombier 		ff->mode = OReadOnly;
28257195852SDavid du Colombier 		ff->issnapshot = 1;
28357195852SDavid du Colombier 	}
2845e96a66cSDavid du Colombier 
2855e96a66cSDavid du Colombier 	if(partial){
2865e96a66cSDavid du Colombier 		/*
2875e96a66cSDavid du Colombier 		 * Do nothing.  We're opening this file only so we can clri it.
2885e96a66cSDavid du Colombier 		 * Usually the sources can't be opened, hence we won't even bother.
2895e96a66cSDavid du Colombier 		 * Be VERY careful with the returned file.  If you hand it to a routine
2905e96a66cSDavid du Colombier 		 * expecting ff->source and/or ff->msource to be non-nil, we're
2915e96a66cSDavid du Colombier 		 * likely to dereference nil.  FileClri should be the only routine
2925e96a66cSDavid du Colombier 		 * setting partial.
2935e96a66cSDavid du Colombier 		 */
2945e96a66cSDavid du Colombier 		ff->partial = 1;
2955e96a66cSDavid du Colombier 	}else if(ff->dir.mode & ModeDir){
2963b86f2f8SDavid du Colombier 		ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen,
2973b86f2f8SDavid du Colombier 			1, ff->mode, ff->issnapshot);
2983b86f2f8SDavid du Colombier 		ff->msource = fileOpenSource(f, ff->dir.mentry, ff->dir.mgen,
2993b86f2f8SDavid du Colombier 			0, ff->mode, ff->issnapshot);
3005e96a66cSDavid du Colombier 		if(ff->source == nil || ff->msource == nil)
3015e96a66cSDavid du Colombier 			goto Err;
3025e96a66cSDavid du Colombier 	}else{
3033b86f2f8SDavid du Colombier 		ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen,
3043b86f2f8SDavid du Colombier 			0, ff->mode, ff->issnapshot);
3055e96a66cSDavid du Colombier 		if(ff->source == nil)
3065e96a66cSDavid du Colombier 			goto Err;
3075e96a66cSDavid du Colombier 	}
3085e96a66cSDavid du Colombier 
3095e96a66cSDavid du Colombier 	/* link in and up parent ref count */
3103b86f2f8SDavid du Colombier 	if (ff->source)
3113b86f2f8SDavid du Colombier 		ff->source->file = ff;		/* point back */
3125e96a66cSDavid du Colombier 	ff->next = f->down;
3135e96a66cSDavid du Colombier 	f->down = ff;
3145e96a66cSDavid du Colombier 	ff->up = f;
3155e96a66cSDavid du Colombier 	fileIncRef(f);
3165e96a66cSDavid du Colombier Exit:
3175e96a66cSDavid du Colombier 	fileUnlock(f);
3185e96a66cSDavid du Colombier 	return ff;
3195e96a66cSDavid du Colombier Err:
3205e96a66cSDavid du Colombier 	fileUnlock(f);
3215e96a66cSDavid du Colombier 	if(ff != nil)
3225e96a66cSDavid du Colombier 		fileDecRef(ff);
3235e96a66cSDavid du Colombier 	return nil;
3245e96a66cSDavid du Colombier }
3255e96a66cSDavid du Colombier 
3265e96a66cSDavid du Colombier File *
fileWalk(File * f,char * elem)3275e96a66cSDavid du Colombier fileWalk(File *f, char *elem)
3285e96a66cSDavid du Colombier {
3295e96a66cSDavid du Colombier 	return _fileWalk(f, elem, 0);
3305e96a66cSDavid du Colombier }
3315e96a66cSDavid du Colombier 
3325e96a66cSDavid du Colombier File *
_fileOpen(Fs * fs,char * path,int partial)3335e96a66cSDavid du Colombier _fileOpen(Fs *fs, char *path, int partial)
3345e96a66cSDavid du Colombier {
3355e96a66cSDavid du Colombier 	File *f, *ff;
336f8e525acSDavid du Colombier 	char *p, elem[VtMaxStringSize], *opath;
3375e96a66cSDavid du Colombier 	int n;
3385e96a66cSDavid du Colombier 
3395e96a66cSDavid du Colombier 	f = fs->file;
3405e96a66cSDavid du Colombier 	fileIncRef(f);
341f8e525acSDavid du Colombier 	opath = path;
3425e96a66cSDavid du Colombier 	while(*path != 0){
3435e96a66cSDavid du Colombier 		for(p = path; *p && *p != '/'; p++)
3445e96a66cSDavid du Colombier 			;
3455e96a66cSDavid du Colombier 		n = p - path;
3465e96a66cSDavid du Colombier 		if(n > 0){
3475e96a66cSDavid du Colombier 			if(n > VtMaxStringSize){
348d7aba6c3SDavid du Colombier 				werrstr("%s: element too long", EBadPath);
3495e96a66cSDavid du Colombier 				goto Err;
3505e96a66cSDavid du Colombier 			}
3515e96a66cSDavid du Colombier 			memmove(elem, path, n);
3525e96a66cSDavid du Colombier 			elem[n] = 0;
3535e96a66cSDavid du Colombier 			ff = _fileWalk(f, elem, partial && *p=='\0');
354f8e525acSDavid du Colombier 			if(ff == nil){
355d7aba6c3SDavid du Colombier 				werrstr("%.*s: %r", utfnlen(opath, p-opath),
3563b86f2f8SDavid du Colombier 					opath);
3575e96a66cSDavid du Colombier 				goto Err;
358f8e525acSDavid du Colombier 			}
3595e96a66cSDavid du Colombier 			fileDecRef(f);
3605e96a66cSDavid du Colombier 			f = ff;
3615e96a66cSDavid du Colombier 		}
3625e96a66cSDavid du Colombier 		if(*p == '/')
3635e96a66cSDavid du Colombier 			p++;
3645e96a66cSDavid du Colombier 		path = p;
3655e96a66cSDavid du Colombier 	}
3665e96a66cSDavid du Colombier 	return f;
3675e96a66cSDavid du Colombier Err:
3685e96a66cSDavid du Colombier 	fileDecRef(f);
3695e96a66cSDavid du Colombier 	return nil;
3705e96a66cSDavid du Colombier }
3715e96a66cSDavid du Colombier 
3725e96a66cSDavid du Colombier File*
fileOpen(Fs * fs,char * path)3735e96a66cSDavid du Colombier fileOpen(Fs *fs, char *path)
3745e96a66cSDavid du Colombier {
3755e96a66cSDavid du Colombier 	return _fileOpen(fs, path, 0);
3765e96a66cSDavid du Colombier }
3775e96a66cSDavid du Colombier 
378fe853e23SDavid du Colombier static void
fileSetTmp(File * f,int istmp)379fe853e23SDavid du Colombier fileSetTmp(File *f, int istmp)
380fe853e23SDavid du Colombier {
381fe853e23SDavid du Colombier 	int i;
382fe853e23SDavid du Colombier 	Entry e;
383fe853e23SDavid du Colombier 	Source *r;
384fe853e23SDavid du Colombier 
385fe853e23SDavid du Colombier 	for(i=0; i<2; i++){
386fe853e23SDavid du Colombier 		if(i==0)
387fe853e23SDavid du Colombier 			r = f->source;
388fe853e23SDavid du Colombier 		else
389fe853e23SDavid du Colombier 			r = f->msource;
390fe853e23SDavid du Colombier 		if(r == nil)
391fe853e23SDavid du Colombier 			continue;
392f352e144SDavid du Colombier 		if(!sourceGetEntry(r, &e)){
393fe853e23SDavid du Colombier 			fprint(2, "sourceGetEntry failed (cannot happen): %r\n");
394fe853e23SDavid du Colombier 			continue;
395fe853e23SDavid du Colombier 		}
396fe853e23SDavid du Colombier 		if(istmp)
397fe853e23SDavid du Colombier 			e.flags |= VtEntryNoArchive;
398fe853e23SDavid du Colombier 		else
399fe853e23SDavid du Colombier 			e.flags &= ~VtEntryNoArchive;
400f352e144SDavid du Colombier 		if(!sourceSetEntry(r, &e)){
401fe853e23SDavid du Colombier 			fprint(2, "sourceSetEntry failed (cannot happen): %r\n");
402fe853e23SDavid du Colombier 			continue;
403fe853e23SDavid du Colombier 		}
404fe853e23SDavid du Colombier 	}
405fe853e23SDavid du Colombier }
406fe853e23SDavid du Colombier 
4075e96a66cSDavid du Colombier File *
fileCreate(File * f,char * elem,ulong mode,char * uid)4085e96a66cSDavid du Colombier fileCreate(File *f, char *elem, ulong mode, char *uid)
4095e96a66cSDavid du Colombier {
4105e96a66cSDavid du Colombier 	File *ff;
4115e96a66cSDavid du Colombier 	DirEntry *dir;
4125e96a66cSDavid du Colombier 	Source *pr, *r, *mr;
4135e96a66cSDavid du Colombier 	int isdir;
4145e96a66cSDavid du Colombier 
4155e96a66cSDavid du Colombier 	if(!fileLock(f))
4165e96a66cSDavid du Colombier 		return nil;
4175e96a66cSDavid du Colombier 
4185e96a66cSDavid du Colombier 	r = nil;
4195e96a66cSDavid du Colombier 	mr = nil;
4205e96a66cSDavid du Colombier 	for(ff = f->down; ff; ff=ff->next){
4215e96a66cSDavid du Colombier 		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
4225e96a66cSDavid du Colombier 			ff = nil;
423d7aba6c3SDavid du Colombier 			werrstr(EExists);
4245e96a66cSDavid du Colombier 			goto Err1;
4255e96a66cSDavid du Colombier 		}
4265e96a66cSDavid du Colombier 	}
4275e96a66cSDavid du Colombier 
4285e96a66cSDavid du Colombier 	ff = dirLookup(f, elem);
4295e96a66cSDavid du Colombier 	if(ff != nil){
430d7aba6c3SDavid du Colombier 		werrstr(EExists);
4315e96a66cSDavid du Colombier 		goto Err1;
4325e96a66cSDavid du Colombier 	}
4335e96a66cSDavid du Colombier 
4345e96a66cSDavid du Colombier 	pr = f->source;
4355e96a66cSDavid du Colombier 	if(pr->mode != OReadWrite){
436d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
4375e96a66cSDavid du Colombier 		goto Err1;
4385e96a66cSDavid du Colombier 	}
4395e96a66cSDavid du Colombier 
4405e96a66cSDavid du Colombier 	if(!sourceLock2(f->source, f->msource, -1))
4415e96a66cSDavid du Colombier 		goto Err1;
4425e96a66cSDavid du Colombier 
4435e96a66cSDavid du Colombier 	ff = fileAlloc(f->fs);
4445e96a66cSDavid du Colombier 	isdir = mode & ModeDir;
4455e96a66cSDavid du Colombier 
4465e96a66cSDavid du Colombier 	r = sourceCreate(pr, pr->dsize, isdir, 0);
4475e96a66cSDavid du Colombier 	if(r == nil)
4485e96a66cSDavid du Colombier 		goto Err;
4495e96a66cSDavid du Colombier 	if(isdir){
4505e96a66cSDavid du Colombier 		mr = sourceCreate(pr, pr->dsize, 0, r->offset);
4515e96a66cSDavid du Colombier 		if(mr == nil)
4525e96a66cSDavid du Colombier 			goto Err;
4535e96a66cSDavid du Colombier 	}
4545e96a66cSDavid du Colombier 
4555e96a66cSDavid du Colombier 	dir = &ff->dir;
456d7aba6c3SDavid du Colombier 	dir->elem = vtstrdup(elem);
4575e96a66cSDavid du Colombier 	dir->entry = r->offset;
4585e96a66cSDavid du Colombier 	dir->gen = r->gen;
4595e96a66cSDavid du Colombier 	if(isdir){
4605e96a66cSDavid du Colombier 		dir->mentry = mr->offset;
4615e96a66cSDavid du Colombier 		dir->mgen = mr->gen;
4625e96a66cSDavid du Colombier 	}
4635e96a66cSDavid du Colombier 	dir->size = 0;
4645e96a66cSDavid du Colombier 	if(!fsNextQid(f->fs, &dir->qid))
4655e96a66cSDavid du Colombier 		goto Err;
466d7aba6c3SDavid du Colombier 	dir->uid = vtstrdup(uid);
467d7aba6c3SDavid du Colombier 	dir->gid = vtstrdup(f->dir.gid);
468d7aba6c3SDavid du Colombier 	dir->mid = vtstrdup(uid);
4695e96a66cSDavid du Colombier 	dir->mtime = time(0L);
4705e96a66cSDavid du Colombier 	dir->mcount = 0;
4715e96a66cSDavid du Colombier 	dir->ctime = dir->mtime;
4725e96a66cSDavid du Colombier 	dir->atime = dir->mtime;
4735e96a66cSDavid du Colombier 	dir->mode = mode;
4745e96a66cSDavid du Colombier 
4755e96a66cSDavid du Colombier 	ff->boff = fileMetaAlloc(f, dir, 0);
4765e96a66cSDavid du Colombier 	if(ff->boff == NilBlock)
4775e96a66cSDavid du Colombier 		goto Err;
4785e96a66cSDavid du Colombier 
4795e96a66cSDavid du Colombier 	sourceUnlock(f->source);
4805e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
4815e96a66cSDavid du Colombier 
4825e96a66cSDavid du Colombier 	ff->source = r;
4833b86f2f8SDavid du Colombier 	r->file = ff;			/* point back */
4845e96a66cSDavid du Colombier 	ff->msource = mr;
4855e96a66cSDavid du Colombier 
486fe853e23SDavid du Colombier 	if(mode&ModeTemporary){
487fe853e23SDavid du Colombier 		if(!sourceLock2(r, mr, -1))
488fe853e23SDavid du Colombier 			goto Err1;
489fe853e23SDavid du Colombier 		fileSetTmp(ff, 1);
490fe853e23SDavid du Colombier 		sourceUnlock(r);
491fe853e23SDavid du Colombier 		if(mr)
492fe853e23SDavid du Colombier 			sourceUnlock(mr);
493fe853e23SDavid du Colombier 	}
494fe853e23SDavid du Colombier 
495fe853e23SDavid du Colombier 	/* committed */
496fe853e23SDavid du Colombier 
4975e96a66cSDavid du Colombier 	/* link in and up parent ref count */
4985e96a66cSDavid du Colombier 	ff->next = f->down;
4995e96a66cSDavid du Colombier 	f->down = ff;
5005e96a66cSDavid du Colombier 	ff->up = f;
5015e96a66cSDavid du Colombier 	fileIncRef(f);
5025e96a66cSDavid du Colombier 
5035e96a66cSDavid du Colombier 	fileWAccess(f, uid);
5045e96a66cSDavid du Colombier 
5055e96a66cSDavid du Colombier 	fileUnlock(f);
5065e96a66cSDavid du Colombier 	return ff;
5075e96a66cSDavid du Colombier 
5085e96a66cSDavid du Colombier Err:
5095e96a66cSDavid du Colombier 	sourceUnlock(f->source);
5105e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
5115e96a66cSDavid du Colombier Err1:
512dc5a79c1SDavid du Colombier 	if(r){
513dc5a79c1SDavid du Colombier 		sourceLock(r, -1);
5145e96a66cSDavid du Colombier 		sourceRemove(r);
515dc5a79c1SDavid du Colombier 	}
516dc5a79c1SDavid du Colombier 	if(mr){
517dc5a79c1SDavid du Colombier 		sourceLock(mr, -1);
5185e96a66cSDavid du Colombier 		sourceRemove(mr);
519dc5a79c1SDavid du Colombier 	}
5205e96a66cSDavid du Colombier 	if(ff)
5215e96a66cSDavid du Colombier 		fileDecRef(ff);
5225e96a66cSDavid du Colombier 	fileUnlock(f);
5235e96a66cSDavid du Colombier 	return 0;
5245e96a66cSDavid du Colombier }
5255e96a66cSDavid du Colombier 
5265e96a66cSDavid du Colombier int
fileRead(File * f,void * buf,int cnt,vlong offset)5275e96a66cSDavid du Colombier fileRead(File *f, void *buf, int cnt, vlong offset)
5285e96a66cSDavid du Colombier {
5295e96a66cSDavid du Colombier 	Source *s;
5305e96a66cSDavid du Colombier 	uvlong size;
5315e96a66cSDavid du Colombier 	u32int bn;
5325e96a66cSDavid du Colombier 	int off, dsize, n, nn;
5335e96a66cSDavid du Colombier 	Block *b;
5345e96a66cSDavid du Colombier 	uchar *p;
5355e96a66cSDavid du Colombier 
5365e96a66cSDavid du Colombier if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset);
5375e96a66cSDavid du Colombier 
5385e96a66cSDavid du Colombier 	if(!fileRLock(f))
5395e96a66cSDavid du Colombier 		return -1;
5405e96a66cSDavid du Colombier 
5415e96a66cSDavid du Colombier 	if(offset < 0){
542d7aba6c3SDavid du Colombier 		werrstr(EBadOffset);
5435e96a66cSDavid du Colombier 		goto Err1;
5445e96a66cSDavid du Colombier 	}
5455e96a66cSDavid du Colombier 
5465e96a66cSDavid du Colombier 	fileRAccess(f);
5475e96a66cSDavid du Colombier 
5485e96a66cSDavid du Colombier 	if(!sourceLock(f->source, OReadOnly))
5495e96a66cSDavid du Colombier 		goto Err1;
5505e96a66cSDavid du Colombier 
5515e96a66cSDavid du Colombier 	s = f->source;
5525e96a66cSDavid du Colombier 	dsize = s->dsize;
5535e96a66cSDavid du Colombier 	size = sourceGetSize(s);
5545e96a66cSDavid du Colombier 
5555e96a66cSDavid du Colombier 	if(offset >= size)
5565e96a66cSDavid du Colombier 		offset = size;
5575e96a66cSDavid du Colombier 
5585e96a66cSDavid du Colombier 	if(cnt > size-offset)
5595e96a66cSDavid du Colombier 		cnt = size-offset;
5605e96a66cSDavid du Colombier 	bn = offset/dsize;
5615e96a66cSDavid du Colombier 	off = offset%dsize;
5625e96a66cSDavid du Colombier 	p = buf;
5635e96a66cSDavid du Colombier 	while(cnt > 0){
5645e96a66cSDavid du Colombier 		b = sourceBlock(s, bn, OReadOnly);
5655e96a66cSDavid du Colombier 		if(b == nil)
5665e96a66cSDavid du Colombier 			goto Err;
5675e96a66cSDavid du Colombier 		n = cnt;
5685e96a66cSDavid du Colombier 		if(n > dsize-off)
5695e96a66cSDavid du Colombier 			n = dsize-off;
5705e96a66cSDavid du Colombier 		nn = dsize-off;
5715e96a66cSDavid du Colombier 		if(nn > n)
5725e96a66cSDavid du Colombier 			nn = n;
5735e96a66cSDavid du Colombier 		memmove(p, b->data+off, nn);
5745e96a66cSDavid du Colombier 		memset(p+nn, 0, nn-n);
5755e96a66cSDavid du Colombier 		off = 0;
5765e96a66cSDavid du Colombier 		bn++;
5775e96a66cSDavid du Colombier 		cnt -= n;
5785e96a66cSDavid du Colombier 		p += n;
5795e96a66cSDavid du Colombier 		blockPut(b);
5805e96a66cSDavid du Colombier 	}
5815e96a66cSDavid du Colombier 	sourceUnlock(s);
5825e96a66cSDavid du Colombier 	fileRUnlock(f);
5835e96a66cSDavid du Colombier 	return p-(uchar*)buf;
5845e96a66cSDavid du Colombier 
5855e96a66cSDavid du Colombier Err:
5865e96a66cSDavid du Colombier 	sourceUnlock(s);
5875e96a66cSDavid du Colombier Err1:
5885e96a66cSDavid du Colombier 	fileRUnlock(f);
5895e96a66cSDavid du Colombier 	return -1;
5905e96a66cSDavid du Colombier }
5915e96a66cSDavid du Colombier 
592fe853e23SDavid du Colombier /*
593fe853e23SDavid du Colombier  * Changes the file block bn to be the given block score.
594fe853e23SDavid du Colombier  * Very sneaky.  Only used by flfmt.
595fe853e23SDavid du Colombier  */
596fe853e23SDavid du Colombier int
fileMapBlock(File * f,ulong bn,uchar score[VtScoreSize],ulong tag)597fe853e23SDavid du Colombier fileMapBlock(File *f, ulong bn, uchar score[VtScoreSize], ulong tag)
598fe853e23SDavid du Colombier {
599fe853e23SDavid du Colombier 	Block *b;
600fe853e23SDavid du Colombier 	Entry e;
601fe853e23SDavid du Colombier 	Source *s;
602fe853e23SDavid du Colombier 
603fe853e23SDavid du Colombier 	if(!fileLock(f))
604fe853e23SDavid du Colombier 		return 0;
605fe853e23SDavid du Colombier 
606fe853e23SDavid du Colombier 	s = nil;
607fe853e23SDavid du Colombier 	if(f->dir.mode & ModeDir){
608d7aba6c3SDavid du Colombier 		werrstr(ENotFile);
609fe853e23SDavid du Colombier 		goto Err;
610fe853e23SDavid du Colombier 	}
611fe853e23SDavid du Colombier 
612fe853e23SDavid du Colombier 	if(f->source->mode != OReadWrite){
613d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
614fe853e23SDavid du Colombier 		goto Err;
615fe853e23SDavid du Colombier 	}
616fe853e23SDavid du Colombier 
617fe853e23SDavid du Colombier 	if(!sourceLock(f->source, -1))
618fe853e23SDavid du Colombier 		goto Err;
619fe853e23SDavid du Colombier 
620fe853e23SDavid du Colombier 	s = f->source;
621fe853e23SDavid du Colombier 	b = _sourceBlock(s, bn, OReadWrite, 1, tag);
622fe853e23SDavid du Colombier 	if(b == nil)
623fe853e23SDavid du Colombier 		goto Err;
624fe853e23SDavid du Colombier 
625fe853e23SDavid du Colombier 	if(!sourceGetEntry(s, &e))
626fe853e23SDavid du Colombier 		goto Err;
627fe853e23SDavid du Colombier 	if(b->l.type == BtDir){
628fe853e23SDavid du Colombier 		memmove(e.score, score, VtScoreSize);
629fe853e23SDavid du Colombier 		assert(e.tag == tag || e.tag == 0);
630fe853e23SDavid du Colombier 		e.tag = tag;
631fe853e23SDavid du Colombier 		e.flags |= VtEntryLocal;
632fe853e23SDavid du Colombier 		entryPack(&e, b->data, f->source->offset % f->source->epb);
633fe853e23SDavid du Colombier 	}else
634fe853e23SDavid du Colombier 		memmove(b->data + (bn%(e.psize/VtScoreSize))*VtScoreSize, score, VtScoreSize);
635fe853e23SDavid du Colombier 	blockDirty(b);
636fe853e23SDavid du Colombier 	blockPut(b);
637fe853e23SDavid du Colombier 	sourceUnlock(s);
638fe853e23SDavid du Colombier 	fileUnlock(f);
639fe853e23SDavid du Colombier 	return 1;
640fe853e23SDavid du Colombier 
641fe853e23SDavid du Colombier Err:
642fe853e23SDavid du Colombier 	if(s)
643fe853e23SDavid du Colombier 		sourceUnlock(s);
644fe853e23SDavid du Colombier 	fileUnlock(f);
645fe853e23SDavid du Colombier 	return 0;
646fe853e23SDavid du Colombier }
647fe853e23SDavid du Colombier 
648fe853e23SDavid du Colombier int
fileSetSize(File * f,uvlong size)649fe853e23SDavid du Colombier fileSetSize(File *f, uvlong size)
650fe853e23SDavid du Colombier {
651fe853e23SDavid du Colombier 	int r;
652fe853e23SDavid du Colombier 
653fe853e23SDavid du Colombier 	if(!fileLock(f))
654fe853e23SDavid du Colombier 		return 0;
655fe853e23SDavid du Colombier 	r = 0;
656fe853e23SDavid du Colombier 	if(f->dir.mode & ModeDir){
657d7aba6c3SDavid du Colombier 		werrstr(ENotFile);
658fe853e23SDavid du Colombier 		goto Err;
659fe853e23SDavid du Colombier 	}
660fe853e23SDavid du Colombier 	if(f->source->mode != OReadWrite){
661d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
662fe853e23SDavid du Colombier 		goto Err;
663fe853e23SDavid du Colombier 	}
664fe853e23SDavid du Colombier 	if(!sourceLock(f->source, -1))
665fe853e23SDavid du Colombier 		goto Err;
666fe853e23SDavid du Colombier 	r = sourceSetSize(f->source, size);
667fe853e23SDavid du Colombier 	sourceUnlock(f->source);
668fe853e23SDavid du Colombier Err:
669fe853e23SDavid du Colombier 	fileUnlock(f);
670fe853e23SDavid du Colombier 	return r;
671fe853e23SDavid du Colombier }
672fe853e23SDavid du Colombier 
6735e96a66cSDavid du Colombier int
fileWrite(File * f,void * buf,int cnt,vlong offset,char * uid)6745e96a66cSDavid du Colombier fileWrite(File *f, void *buf, int cnt, vlong offset, char *uid)
6755e96a66cSDavid du Colombier {
6765e96a66cSDavid du Colombier 	Source *s;
6775e96a66cSDavid du Colombier 	ulong bn;
6785e96a66cSDavid du Colombier 	int off, dsize, n;
6795e96a66cSDavid du Colombier 	Block *b;
6805e96a66cSDavid du Colombier 	uchar *p;
6815e96a66cSDavid du Colombier 	vlong eof;
6825e96a66cSDavid du Colombier 
6835e96a66cSDavid du Colombier if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset);
6845e96a66cSDavid du Colombier 
6855e96a66cSDavid du Colombier 	if(!fileLock(f))
6865e96a66cSDavid du Colombier 		return -1;
6875e96a66cSDavid du Colombier 
6885e96a66cSDavid du Colombier 	s = nil;
6895e96a66cSDavid du Colombier 	if(f->dir.mode & ModeDir){
690d7aba6c3SDavid du Colombier 		werrstr(ENotFile);
6915e96a66cSDavid du Colombier 		goto Err;
6925e96a66cSDavid du Colombier 	}
6935e96a66cSDavid du Colombier 
6945e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
695d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
6965e96a66cSDavid du Colombier 		goto Err;
6975e96a66cSDavid du Colombier 	}
6985e96a66cSDavid du Colombier 	if(offset < 0){
699d7aba6c3SDavid du Colombier 		werrstr(EBadOffset);
7005e96a66cSDavid du Colombier 		goto Err;
7015e96a66cSDavid du Colombier 	}
7025e96a66cSDavid du Colombier 
7035e96a66cSDavid du Colombier 	fileWAccess(f, uid);
7045e96a66cSDavid du Colombier 
7055e96a66cSDavid du Colombier 	if(!sourceLock(f->source, -1))
7065e96a66cSDavid du Colombier 		goto Err;
7075e96a66cSDavid du Colombier 	s = f->source;
7085e96a66cSDavid du Colombier 	dsize = s->dsize;
7095e96a66cSDavid du Colombier 
7105e96a66cSDavid du Colombier 	eof = sourceGetSize(s);
7115e96a66cSDavid du Colombier 	if(f->dir.mode & ModeAppend)
7125e96a66cSDavid du Colombier 		offset = eof;
7135e96a66cSDavid du Colombier 	bn = offset/dsize;
7145e96a66cSDavid du Colombier 	off = offset%dsize;
7155e96a66cSDavid du Colombier 	p = buf;
7165e96a66cSDavid du Colombier 	while(cnt > 0){
7175e96a66cSDavid du Colombier 		n = cnt;
7185e96a66cSDavid du Colombier 		if(n > dsize-off)
7195e96a66cSDavid du Colombier 			n = dsize-off;
7205e96a66cSDavid du Colombier 		b = sourceBlock(s, bn, n<dsize?OReadWrite:OOverWrite);
7215e96a66cSDavid du Colombier 		if(b == nil){
7225e96a66cSDavid du Colombier 			if(offset > eof)
7235e96a66cSDavid du Colombier 				sourceSetSize(s, offset);
7245e96a66cSDavid du Colombier 			goto Err;
7255e96a66cSDavid du Colombier 		}
7265e96a66cSDavid du Colombier 		memmove(b->data+off, p, n);
7275e96a66cSDavid du Colombier 		off = 0;
7285e96a66cSDavid du Colombier 		cnt -= n;
7295e96a66cSDavid du Colombier 		p += n;
7305e96a66cSDavid du Colombier 		offset += n;
7315e96a66cSDavid du Colombier 		bn++;
7325e96a66cSDavid du Colombier 		blockDirty(b);
7335e96a66cSDavid du Colombier 		blockPut(b);
7345e96a66cSDavid du Colombier 	}
7355e96a66cSDavid du Colombier 	if(offset > eof && !sourceSetSize(s, offset))
7365e96a66cSDavid du Colombier 		goto Err;
7375e96a66cSDavid du Colombier 	sourceUnlock(s);
7385e96a66cSDavid du Colombier 	fileUnlock(f);
7395e96a66cSDavid du Colombier 	return p-(uchar*)buf;
7405e96a66cSDavid du Colombier Err:
7415e96a66cSDavid du Colombier 	if(s)
7425e96a66cSDavid du Colombier 		sourceUnlock(s);
7435e96a66cSDavid du Colombier 	fileUnlock(f);
7445e96a66cSDavid du Colombier 	return -1;
7455e96a66cSDavid du Colombier }
7465e96a66cSDavid du Colombier 
7475e96a66cSDavid du Colombier int
fileGetDir(File * f,DirEntry * dir)7485e96a66cSDavid du Colombier fileGetDir(File *f, DirEntry *dir)
7495e96a66cSDavid du Colombier {
7505e96a66cSDavid du Colombier 	if(!fileRLock(f))
7515e96a66cSDavid du Colombier 		return 0;
7525e96a66cSDavid du Colombier 
7535e96a66cSDavid du Colombier 	fileMetaLock(f);
7545e96a66cSDavid du Colombier 	deCopy(dir, &f->dir);
7555e96a66cSDavid du Colombier 	fileMetaUnlock(f);
7565e96a66cSDavid du Colombier 
7575e96a66cSDavid du Colombier 	if(!fileIsDir(f)){
7585e96a66cSDavid du Colombier 		if(!sourceLock(f->source, OReadOnly)){
7595e96a66cSDavid du Colombier 			fileRUnlock(f);
7605e96a66cSDavid du Colombier 			return 0;
7615e96a66cSDavid du Colombier 		}
7625e96a66cSDavid du Colombier 		dir->size = sourceGetSize(f->source);
7635e96a66cSDavid du Colombier 		sourceUnlock(f->source);
7645e96a66cSDavid du Colombier 	}
7655e96a66cSDavid du Colombier 	fileRUnlock(f);
7665e96a66cSDavid du Colombier 
7675e96a66cSDavid du Colombier 	return 1;
7685e96a66cSDavid du Colombier }
7695e96a66cSDavid du Colombier 
7705e96a66cSDavid du Colombier int
fileTruncate(File * f,char * uid)7715e96a66cSDavid du Colombier fileTruncate(File *f, char *uid)
7725e96a66cSDavid du Colombier {
7735e96a66cSDavid du Colombier 	if(fileIsDir(f)){
774d7aba6c3SDavid du Colombier 		werrstr(ENotFile);
7755e96a66cSDavid du Colombier 		return 0;
7765e96a66cSDavid du Colombier 	}
7775e96a66cSDavid du Colombier 
7785e96a66cSDavid du Colombier 	if(!fileLock(f))
7795e96a66cSDavid du Colombier 		return 0;
7805e96a66cSDavid du Colombier 
7815e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
782d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
7835e96a66cSDavid du Colombier 		fileUnlock(f);
7845e96a66cSDavid du Colombier 		return 0;
7855e96a66cSDavid du Colombier 	}
7865e96a66cSDavid du Colombier 	if(!sourceLock(f->source, -1)){
7875e96a66cSDavid du Colombier 		fileUnlock(f);
7885e96a66cSDavid du Colombier 		return 0;
7895e96a66cSDavid du Colombier 	}
7905e96a66cSDavid du Colombier 	if(!sourceTruncate(f->source)){
7915e96a66cSDavid du Colombier 		sourceUnlock(f->source);
7925e96a66cSDavid du Colombier 		fileUnlock(f);
7935e96a66cSDavid du Colombier 		return 0;
7945e96a66cSDavid du Colombier 	}
7955e96a66cSDavid du Colombier 	sourceUnlock(f->source);
7965e96a66cSDavid du Colombier 	fileUnlock(f);
7975e96a66cSDavid du Colombier 
798a960ed1cSDavid du Colombier 	fileWAccess(f, uid);
7995e96a66cSDavid du Colombier 
8005e96a66cSDavid du Colombier 	return 1;
8015e96a66cSDavid du Colombier }
8025e96a66cSDavid du Colombier 
8035e96a66cSDavid du Colombier int
fileSetDir(File * f,DirEntry * dir,char * uid)8045e96a66cSDavid du Colombier fileSetDir(File *f, DirEntry *dir, char *uid)
8055e96a66cSDavid du Colombier {
8065e96a66cSDavid du Colombier 	File *ff;
8075e96a66cSDavid du Colombier 	char *oelem;
8085e96a66cSDavid du Colombier 	u32int mask;
8095e96a66cSDavid du Colombier 	u64int size;
810addada52SDavid du Colombier 	int changed;
8115e96a66cSDavid du Colombier 
8125e96a66cSDavid du Colombier 	/* can not set permissions for the root */
8135e96a66cSDavid du Colombier 	if(fileIsRoot(f)){
814d7aba6c3SDavid du Colombier 		werrstr(ERoot);
8155e96a66cSDavid du Colombier 		return 0;
8165e96a66cSDavid du Colombier 	}
8175e96a66cSDavid du Colombier 
8185e96a66cSDavid du Colombier 	if(!fileLock(f))
8195e96a66cSDavid du Colombier 		return 0;
8205e96a66cSDavid du Colombier 
8215e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
822d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
8235e96a66cSDavid du Colombier 		fileUnlock(f);
8245e96a66cSDavid du Colombier 		return 0;
8255e96a66cSDavid du Colombier 	}
8265e96a66cSDavid du Colombier 
8275e96a66cSDavid du Colombier 	fileMetaLock(f);
8285e96a66cSDavid du Colombier 
8295e96a66cSDavid du Colombier 	/* check new name does not already exist */
8305e96a66cSDavid du Colombier 	if(strcmp(f->dir.elem, dir->elem) != 0){
8315e96a66cSDavid du Colombier 		for(ff = f->up->down; ff; ff=ff->next){
8325e96a66cSDavid du Colombier 			if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
833d7aba6c3SDavid du Colombier 				werrstr(EExists);
8345e96a66cSDavid du Colombier 				goto Err;
8355e96a66cSDavid du Colombier 			}
8365e96a66cSDavid du Colombier 		}
8375e96a66cSDavid du Colombier 
8385e96a66cSDavid du Colombier 		ff = dirLookup(f->up, dir->elem);
8395e96a66cSDavid du Colombier 		if(ff != nil){
8405e96a66cSDavid du Colombier 			fileDecRef(ff);
841d7aba6c3SDavid du Colombier 			werrstr(EExists);
8425e96a66cSDavid du Colombier 			goto Err;
8435e96a66cSDavid du Colombier 		}
8445e96a66cSDavid du Colombier 	}
8455e96a66cSDavid du Colombier 
846fe853e23SDavid du Colombier 	if(!sourceLock2(f->source, f->msource, -1))
8475e96a66cSDavid du Colombier 		goto Err;
848addada52SDavid du Colombier 	changed = 0;
849fe853e23SDavid du Colombier 	if(!fileIsDir(f)){
8505e96a66cSDavid du Colombier 		size = sourceGetSize(f->source);
8515e96a66cSDavid du Colombier 		if(size != dir->size){
8525e96a66cSDavid du Colombier 			if(!sourceSetSize(f->source, dir->size)){
8535e96a66cSDavid du Colombier 				sourceUnlock(f->source);
854fe853e23SDavid du Colombier 				if(f->msource)
855fe853e23SDavid du Colombier 					sourceUnlock(f->msource);
8565e96a66cSDavid du Colombier 				goto Err;
8575e96a66cSDavid du Colombier 			}
858addada52SDavid du Colombier 			changed = 1;
8595e96a66cSDavid du Colombier 			/* commited to changing it now */
8605e96a66cSDavid du Colombier 		}
8615e96a66cSDavid du Colombier 	}
8625e96a66cSDavid du Colombier 	/* commited to changing it now */
863fe853e23SDavid du Colombier 	if((f->dir.mode&ModeTemporary) != (dir->mode&ModeTemporary))
864fe853e23SDavid du Colombier 		fileSetTmp(f, dir->mode&ModeTemporary);
865fe853e23SDavid du Colombier 	sourceUnlock(f->source);
866fe853e23SDavid du Colombier 	if(f->msource)
867fe853e23SDavid du Colombier 		sourceUnlock(f->msource);
868fe853e23SDavid du Colombier 
8695e96a66cSDavid du Colombier 	oelem = nil;
8705e96a66cSDavid du Colombier 	if(strcmp(f->dir.elem, dir->elem) != 0){
8715e96a66cSDavid du Colombier 		oelem = f->dir.elem;
872d7aba6c3SDavid du Colombier 		f->dir.elem = vtstrdup(dir->elem);
8735e96a66cSDavid du Colombier 	}
8745e96a66cSDavid du Colombier 
8755e96a66cSDavid du Colombier 	if(strcmp(f->dir.uid, dir->uid) != 0){
876d7aba6c3SDavid du Colombier 		vtfree(f->dir.uid);
877d7aba6c3SDavid du Colombier 		f->dir.uid = vtstrdup(dir->uid);
8785e96a66cSDavid du Colombier 	}
8795e96a66cSDavid du Colombier 
8805e96a66cSDavid du Colombier 	if(strcmp(f->dir.gid, dir->gid) != 0){
881d7aba6c3SDavid du Colombier 		vtfree(f->dir.gid);
882d7aba6c3SDavid du Colombier 		f->dir.gid = vtstrdup(dir->gid);
8835e96a66cSDavid du Colombier 	}
8845e96a66cSDavid du Colombier 
8855e96a66cSDavid du Colombier 	f->dir.mtime = dir->mtime;
8865e96a66cSDavid du Colombier 	f->dir.atime = dir->atime;
8875e96a66cSDavid du Colombier 
8885e96a66cSDavid du Colombier //fprint(2, "mode %x %x ", f->dir.mode, dir->mode);
8895e96a66cSDavid du Colombier 	mask = ~(ModeDir|ModeSnapshot);
8905e96a66cSDavid du Colombier 	f->dir.mode &= ~mask;
8915e96a66cSDavid du Colombier 	f->dir.mode |= mask & dir->mode;
8925e96a66cSDavid du Colombier 	f->dirty = 1;
8935e96a66cSDavid du Colombier //fprint(2, "->%x\n", f->dir.mode);
8945e96a66cSDavid du Colombier 
8955e96a66cSDavid du Colombier 	fileMetaFlush2(f, oelem);
896d7aba6c3SDavid du Colombier 	vtfree(oelem);
8975e96a66cSDavid du Colombier 
8985e96a66cSDavid du Colombier 	fileMetaUnlock(f);
8995e96a66cSDavid du Colombier 	fileUnlock(f);
9005e96a66cSDavid du Colombier 
901addada52SDavid du Colombier 	if(changed)
902addada52SDavid du Colombier 		fileWAccess(f, uid);
9035e96a66cSDavid du Colombier 	fileWAccess(f->up, uid);
9045e96a66cSDavid du Colombier 
9055e96a66cSDavid du Colombier 	return 1;
9065e96a66cSDavid du Colombier Err:
9075e96a66cSDavid du Colombier 	fileMetaUnlock(f);
9085e96a66cSDavid du Colombier 	fileUnlock(f);
9095e96a66cSDavid du Colombier 	return 0;
9105e96a66cSDavid du Colombier }
9115e96a66cSDavid du Colombier 
9125e96a66cSDavid du Colombier int
fileSetQidSpace(File * f,u64int offset,u64int max)9135e96a66cSDavid du Colombier fileSetQidSpace(File *f, u64int offset, u64int max)
9145e96a66cSDavid du Colombier {
9155e96a66cSDavid du Colombier 	int ret;
9165e96a66cSDavid du Colombier 
9175e96a66cSDavid du Colombier 	if(!fileLock(f))
9185e96a66cSDavid du Colombier 		return 0;
9195e96a66cSDavid du Colombier 	fileMetaLock(f);
9205e96a66cSDavid du Colombier 	f->dir.qidSpace = 1;
9215e96a66cSDavid du Colombier 	f->dir.qidOffset = offset;
9225e96a66cSDavid du Colombier 	f->dir.qidMax = max;
923*46710454SDavid du Colombier 	f->dirty = 1;
9240b9a5132SDavid du Colombier 	ret = fileMetaFlush2(f, nil)>=0;
9255e96a66cSDavid du Colombier 	fileMetaUnlock(f);
9265e96a66cSDavid du Colombier 	fileUnlock(f);
9275e96a66cSDavid du Colombier 	return ret;
9285e96a66cSDavid du Colombier }
9295e96a66cSDavid du Colombier 
9305e96a66cSDavid du Colombier 
9315e96a66cSDavid du Colombier uvlong
fileGetId(File * f)9325e96a66cSDavid du Colombier fileGetId(File *f)
9335e96a66cSDavid du Colombier {
9345e96a66cSDavid du Colombier 	/* immutable */
9355e96a66cSDavid du Colombier 	return f->dir.qid;
9365e96a66cSDavid du Colombier }
9375e96a66cSDavid du Colombier 
9385e96a66cSDavid du Colombier ulong
fileGetMcount(File * f)9395e96a66cSDavid du Colombier fileGetMcount(File *f)
9405e96a66cSDavid du Colombier {
9415e96a66cSDavid du Colombier 	ulong mcount;
9425e96a66cSDavid du Colombier 
9435e96a66cSDavid du Colombier 	fileMetaLock(f);
9445e96a66cSDavid du Colombier 	mcount = f->dir.mcount;
9455e96a66cSDavid du Colombier 	fileMetaUnlock(f);
9465e96a66cSDavid du Colombier 	return mcount;
9475e96a66cSDavid du Colombier }
9485e96a66cSDavid du Colombier 
9495e96a66cSDavid du Colombier ulong
fileGetMode(File * f)9505e96a66cSDavid du Colombier fileGetMode(File *f)
9515e96a66cSDavid du Colombier {
9525e96a66cSDavid du Colombier 	ulong mode;
9535e96a66cSDavid du Colombier 
9545e96a66cSDavid du Colombier 	fileMetaLock(f);
9555e96a66cSDavid du Colombier 	mode = f->dir.mode;
9565e96a66cSDavid du Colombier 	fileMetaUnlock(f);
9575e96a66cSDavid du Colombier 	return mode;
9585e96a66cSDavid du Colombier }
9595e96a66cSDavid du Colombier 
9605e96a66cSDavid du Colombier int
fileIsDir(File * f)9615e96a66cSDavid du Colombier fileIsDir(File *f)
9625e96a66cSDavid du Colombier {
9635e96a66cSDavid du Colombier 	/* immutable */
9645e96a66cSDavid du Colombier 	return (f->dir.mode & ModeDir) != 0;
9655e96a66cSDavid du Colombier }
9665e96a66cSDavid du Colombier 
9675e96a66cSDavid du Colombier int
fileIsAppend(File * f)9686bbfed0dSDavid du Colombier fileIsAppend(File *f)
9696bbfed0dSDavid du Colombier {
9706bbfed0dSDavid du Colombier 	return (f->dir.mode & ModeAppend) != 0;
9716bbfed0dSDavid du Colombier }
9726bbfed0dSDavid du Colombier 
9736bbfed0dSDavid du Colombier int
fileIsExclusive(File * f)9746bbfed0dSDavid du Colombier fileIsExclusive(File *f)
9756bbfed0dSDavid du Colombier {
9766bbfed0dSDavid du Colombier 	return (f->dir.mode & ModeExclusive) != 0;
9776bbfed0dSDavid du Colombier }
9786bbfed0dSDavid du Colombier 
9796bbfed0dSDavid du Colombier int
fileIsTemporary(File * f)9806bbfed0dSDavid du Colombier fileIsTemporary(File *f)
9816bbfed0dSDavid du Colombier {
9826bbfed0dSDavid du Colombier 	return (f->dir.mode & ModeTemporary) != 0;
9836bbfed0dSDavid du Colombier }
9846bbfed0dSDavid du Colombier 
9856bbfed0dSDavid du Colombier int
fileIsRoot(File * f)9865e96a66cSDavid du Colombier fileIsRoot(File *f)
9875e96a66cSDavid du Colombier {
9885e96a66cSDavid du Colombier 	return f == f->fs->file;
9895e96a66cSDavid du Colombier }
9905e96a66cSDavid du Colombier 
9915e96a66cSDavid du Colombier int
fileIsRoFs(File * f)9925e96a66cSDavid du Colombier fileIsRoFs(File *f)
9935e96a66cSDavid du Colombier {
9945e96a66cSDavid du Colombier 	return f->fs->mode == OReadOnly;
9955e96a66cSDavid du Colombier }
9965e96a66cSDavid du Colombier 
9975e96a66cSDavid du Colombier int
fileGetSize(File * f,uvlong * size)9985e96a66cSDavid du Colombier fileGetSize(File *f, uvlong *size)
9995e96a66cSDavid du Colombier {
10005e96a66cSDavid du Colombier 	if(!fileRLock(f))
10015e96a66cSDavid du Colombier 		return 0;
10025e96a66cSDavid du Colombier 	if(!sourceLock(f->source, OReadOnly)){
10035e96a66cSDavid du Colombier 		fileRUnlock(f);
10045e96a66cSDavid du Colombier 		return 0;
10055e96a66cSDavid du Colombier 	}
10065e96a66cSDavid du Colombier 	*size = sourceGetSize(f->source);
10075e96a66cSDavid du Colombier 	sourceUnlock(f->source);
10085e96a66cSDavid du Colombier 	fileRUnlock(f);
10095e96a66cSDavid du Colombier 
10105e96a66cSDavid du Colombier 	return 1;
10115e96a66cSDavid du Colombier }
10125e96a66cSDavid du Colombier 
10130b9a5132SDavid du Colombier int
fileMetaFlush(File * f,int rec)10145e96a66cSDavid du Colombier fileMetaFlush(File *f, int rec)
10155e96a66cSDavid du Colombier {
10165e96a66cSDavid du Colombier 	File **kids, *p;
10175e96a66cSDavid du Colombier 	int nkids;
10180b9a5132SDavid du Colombier 	int i, rv;
10195e96a66cSDavid du Colombier 
10205e96a66cSDavid du Colombier 	fileMetaLock(f);
10210b9a5132SDavid du Colombier 	rv = fileMetaFlush2(f, nil);
10225e96a66cSDavid du Colombier 	fileMetaUnlock(f);
10235e96a66cSDavid du Colombier 
10245e96a66cSDavid du Colombier 	if(!rec || !fileIsDir(f))
10250b9a5132SDavid du Colombier 		return rv;
10265e96a66cSDavid du Colombier 
10275e96a66cSDavid du Colombier 	if(!fileLock(f))
10280b9a5132SDavid du Colombier 		return rv;
10295e96a66cSDavid du Colombier 	nkids = 0;
10305e96a66cSDavid du Colombier 	for(p=f->down; p; p=p->next)
10315e96a66cSDavid du Colombier 		nkids++;
1032d7aba6c3SDavid du Colombier 	kids = vtmalloc(nkids*sizeof(File*));
10335e96a66cSDavid du Colombier 	i = 0;
10345e96a66cSDavid du Colombier 	for(p=f->down; p; p=p->next){
10355e96a66cSDavid du Colombier 		kids[i++] = p;
10365e96a66cSDavid du Colombier 		p->ref++;
10375e96a66cSDavid du Colombier 	}
10385e96a66cSDavid du Colombier 	fileUnlock(f);
10395e96a66cSDavid du Colombier 
10405e96a66cSDavid du Colombier 	for(i=0; i<nkids; i++){
10410b9a5132SDavid du Colombier 		rv |= fileMetaFlush(kids[i], 1);
10425e96a66cSDavid du Colombier 		fileDecRef(kids[i]);
10435e96a66cSDavid du Colombier 	}
1044d7aba6c3SDavid du Colombier 	vtfree(kids);
10450b9a5132SDavid du Colombier 	return rv;
10465e96a66cSDavid du Colombier }
10475e96a66cSDavid du Colombier 
10485e96a66cSDavid du Colombier /* assumes metaLock is held */
10495e96a66cSDavid du Colombier static int
fileMetaFlush2(File * f,char * oelem)10505e96a66cSDavid du Colombier fileMetaFlush2(File *f, char *oelem)
10515e96a66cSDavid du Colombier {
10525e96a66cSDavid du Colombier 	File *fp;
10535e96a66cSDavid du Colombier 	Block *b, *bb;
10545e96a66cSDavid du Colombier 	MetaBlock mb;
10555e96a66cSDavid du Colombier 	MetaEntry me, me2;
10565e96a66cSDavid du Colombier 	int i, n;
10575e96a66cSDavid du Colombier 	u32int boff;
10585e96a66cSDavid du Colombier 
10595e96a66cSDavid du Colombier 	if(!f->dirty)
10600b9a5132SDavid du Colombier 		return 0;
10615e96a66cSDavid du Colombier 
10625e96a66cSDavid du Colombier 	if(oelem == nil)
10635e96a66cSDavid du Colombier 		oelem = f->dir.elem;
10645e96a66cSDavid du Colombier 
10655e96a66cSDavid du Colombier //print("fileMetaFlush %s->%s\n", oelem, f->dir.elem);
10665e96a66cSDavid du Colombier 
10675e96a66cSDavid du Colombier 	fp = f->up;
10685e96a66cSDavid du Colombier 
10695e96a66cSDavid du Colombier 	if(!sourceLock(fp->msource, -1))
10700b9a5132SDavid du Colombier 		return -1;
10716042bf6dSDavid du Colombier 	/* can happen if source is clri'ed out from under us */
10726042bf6dSDavid du Colombier 	if(f->boff == NilBlock)
10736042bf6dSDavid du Colombier 		goto Err1;
10745e96a66cSDavid du Colombier 	b = sourceBlock(fp->msource, f->boff, OReadWrite);
10755e96a66cSDavid du Colombier 	if(b == nil)
10765e96a66cSDavid du Colombier 		goto Err1;
10775e96a66cSDavid du Colombier 
10785e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, fp->msource->dsize))
10795e96a66cSDavid du Colombier 		goto Err;
10805e96a66cSDavid du Colombier 	if(!mbSearch(&mb, oelem, &i, &me))
10815e96a66cSDavid du Colombier 		goto Err;
10825e96a66cSDavid du Colombier 
10835e96a66cSDavid du Colombier 	n = deSize(&f->dir);
10845e96a66cSDavid du Colombier if(0)fprint(2, "old size %d new size %d\n", me.size, n);
10855e96a66cSDavid du Colombier 
10865e96a66cSDavid du Colombier 	if(mbResize(&mb, &me, n)){
10875e96a66cSDavid du Colombier 		/* fits in the block */
10885e96a66cSDavid du Colombier 		mbDelete(&mb, i);
10895e96a66cSDavid du Colombier 		if(strcmp(f->dir.elem, oelem) != 0)
10905e96a66cSDavid du Colombier 			mbSearch(&mb, f->dir.elem, &i, &me2);
10915e96a66cSDavid du Colombier 		dePack(&f->dir, &me);
10925e96a66cSDavid du Colombier 		mbInsert(&mb, i, &me);
10935e96a66cSDavid du Colombier 		mbPack(&mb);
10945e96a66cSDavid du Colombier 		blockDirty(b);
10955e96a66cSDavid du Colombier 		blockPut(b);
10965e96a66cSDavid du Colombier 		sourceUnlock(fp->msource);
10975e96a66cSDavid du Colombier 		f->dirty = 0;
10985e96a66cSDavid du Colombier 
10995e96a66cSDavid du Colombier 		return 1;
11005e96a66cSDavid du Colombier 	}
11015e96a66cSDavid du Colombier 
11025e96a66cSDavid du Colombier 	/*
11035e96a66cSDavid du Colombier 	 * moving entry to another block
11045e96a66cSDavid du Colombier 	 * it is feasible for the fs to crash leaving two copies
11055e96a66cSDavid du Colombier 	 * of the directory entry.  This is just too much work to
11065e96a66cSDavid du Colombier 	 * fix.  Given that entries are only allocated in a block that
11075e96a66cSDavid du Colombier 	 * is less than PercentageFull, most modifications of meta data
11085e96a66cSDavid du Colombier 	 * will fit within the block.  i.e. this code should almost
11095e96a66cSDavid du Colombier 	 * never be executed.
11105e96a66cSDavid du Colombier 	 */
11115e96a66cSDavid du Colombier 	boff = fileMetaAlloc(fp, &f->dir, f->boff+1);
11125e96a66cSDavid du Colombier 	if(boff == NilBlock){
11135e96a66cSDavid du Colombier 		/* mbResize might have modified block */
11145e96a66cSDavid du Colombier 		mbPack(&mb);
11155e96a66cSDavid du Colombier 		blockDirty(b);
11165e96a66cSDavid du Colombier 		goto Err;
11175e96a66cSDavid du Colombier 	}
11185e96a66cSDavid du Colombier fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);
11195e96a66cSDavid du Colombier 	f->boff = boff;
11205e96a66cSDavid du Colombier 
11215e96a66cSDavid du Colombier 	/* make sure deletion goes to disk after new entry */
11225e96a66cSDavid du Colombier 	bb = sourceBlock(fp->msource, f->boff, OReadWrite);
11235e96a66cSDavid du Colombier 	mbDelete(&mb, i);
11245e96a66cSDavid du Colombier 	mbPack(&mb);
112561201b97SDavid du Colombier 	blockDependency(b, bb, -1, nil, nil);
11265e96a66cSDavid du Colombier 	blockPut(bb);
11275e96a66cSDavid du Colombier 	blockDirty(b);
11285e96a66cSDavid du Colombier 	blockPut(b);
11295e96a66cSDavid du Colombier 	sourceUnlock(fp->msource);
11305e96a66cSDavid du Colombier 
11315e96a66cSDavid du Colombier 	f->dirty = 0;
11325e96a66cSDavid du Colombier 
11335e96a66cSDavid du Colombier 	return 1;
11345e96a66cSDavid du Colombier 
11355e96a66cSDavid du Colombier Err:
11365e96a66cSDavid du Colombier 	blockPut(b);
11375e96a66cSDavid du Colombier Err1:
11385e96a66cSDavid du Colombier 	sourceUnlock(fp->msource);
11390b9a5132SDavid du Colombier 	return -1;
11405e96a66cSDavid du Colombier }
11415e96a66cSDavid du Colombier 
11425e96a66cSDavid du Colombier static int
fileMetaRemove(File * f,char * uid)11435e96a66cSDavid du Colombier fileMetaRemove(File *f, char *uid)
11445e96a66cSDavid du Colombier {
11455e96a66cSDavid du Colombier 	Block *b;
11465e96a66cSDavid du Colombier 	MetaBlock mb;
11475e96a66cSDavid du Colombier 	MetaEntry me;
11485e96a66cSDavid du Colombier 	int i;
11495e96a66cSDavid du Colombier 	File *up;
11505e96a66cSDavid du Colombier 
11515e96a66cSDavid du Colombier 	up = f->up;
11525e96a66cSDavid du Colombier 
11535e96a66cSDavid du Colombier 	fileWAccess(up, uid);
11545e96a66cSDavid du Colombier 
11555e96a66cSDavid du Colombier 	fileMetaLock(f);
11565e96a66cSDavid du Colombier 
11575e96a66cSDavid du Colombier 	sourceLock(up->msource, OReadWrite);
11585e96a66cSDavid du Colombier 	b = sourceBlock(up->msource, f->boff, OReadWrite);
11595e96a66cSDavid du Colombier 	if(b == nil)
11605e96a66cSDavid du Colombier 		goto Err;
11615e96a66cSDavid du Colombier 
11625e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, up->msource->dsize))
11635e96a66cSDavid du Colombier {
11645e96a66cSDavid du Colombier fprint(2, "U\n");
11655e96a66cSDavid du Colombier 		goto Err;
11665e96a66cSDavid du Colombier }
11675e96a66cSDavid du Colombier 	if(!mbSearch(&mb, f->dir.elem, &i, &me))
11685e96a66cSDavid du Colombier {
11695e96a66cSDavid du Colombier fprint(2, "S\n");
11705e96a66cSDavid du Colombier 		goto Err;
11715e96a66cSDavid du Colombier }
11725e96a66cSDavid du Colombier 	mbDelete(&mb, i);
11735e96a66cSDavid du Colombier 	mbPack(&mb);
11745e96a66cSDavid du Colombier 	sourceUnlock(up->msource);
11755e96a66cSDavid du Colombier 
11765e96a66cSDavid du Colombier 	blockDirty(b);
11775e96a66cSDavid du Colombier 	blockPut(b);
11785e96a66cSDavid du Colombier 
11795e96a66cSDavid du Colombier 	f->removed = 1;
11805e96a66cSDavid du Colombier 	f->boff = NilBlock;
11815e96a66cSDavid du Colombier 	f->dirty = 0;
11825e96a66cSDavid du Colombier 
11835e96a66cSDavid du Colombier 	fileMetaUnlock(f);
11845e96a66cSDavid du Colombier 	return 1;
11855e96a66cSDavid du Colombier 
11865e96a66cSDavid du Colombier Err:
11875e96a66cSDavid du Colombier 	sourceUnlock(up->msource);
11885e96a66cSDavid du Colombier 	blockPut(b);
11895e96a66cSDavid du Colombier 	fileMetaUnlock(f);
11905e96a66cSDavid du Colombier 	return 0;
11915e96a66cSDavid du Colombier }
11925e96a66cSDavid du Colombier 
11935e96a66cSDavid du Colombier /* assume file is locked, assume f->msource is locked */
11945e96a66cSDavid du Colombier static int
fileCheckEmpty(File * f)11955e96a66cSDavid du Colombier fileCheckEmpty(File *f)
11965e96a66cSDavid du Colombier {
11975e96a66cSDavid du Colombier 	u32int i, n;
11985e96a66cSDavid du Colombier 	Block *b;
11995e96a66cSDavid du Colombier 	MetaBlock mb;
12005e96a66cSDavid du Colombier 	Source *r;
12015e96a66cSDavid du Colombier 
12025e96a66cSDavid du Colombier 	r = f->msource;
12035e96a66cSDavid du Colombier 	n = (sourceGetSize(r)+r->dsize-1)/r->dsize;
12045e96a66cSDavid du Colombier 	for(i=0; i<n; i++){
12055e96a66cSDavid du Colombier 		b = sourceBlock(r, i, OReadOnly);
12065e96a66cSDavid du Colombier 		if(b == nil)
12075e96a66cSDavid du Colombier 			goto Err;
12085e96a66cSDavid du Colombier 		if(!mbUnpack(&mb, b->data, r->dsize))
12095e96a66cSDavid du Colombier 			goto Err;
12105e96a66cSDavid du Colombier 		if(mb.nindex > 0){
1211d7aba6c3SDavid du Colombier 			werrstr(ENotEmpty);
12125e96a66cSDavid du Colombier 			goto Err;
12135e96a66cSDavid du Colombier 		}
12145e96a66cSDavid du Colombier 		blockPut(b);
12155e96a66cSDavid du Colombier 	}
12165e96a66cSDavid du Colombier 	return 1;
12175e96a66cSDavid du Colombier Err:
12185e96a66cSDavid du Colombier 	blockPut(b);
12195e96a66cSDavid du Colombier 	return 0;
12205e96a66cSDavid du Colombier }
12215e96a66cSDavid du Colombier 
12225e96a66cSDavid du Colombier int
fileRemove(File * f,char * uid)12235e96a66cSDavid du Colombier fileRemove(File *f, char *uid)
12245e96a66cSDavid du Colombier {
12255e96a66cSDavid du Colombier 	File *ff;
12265e96a66cSDavid du Colombier 
12275e96a66cSDavid du Colombier 	/* can not remove the root */
12285e96a66cSDavid du Colombier 	if(fileIsRoot(f)){
1229d7aba6c3SDavid du Colombier 		werrstr(ERoot);
12305e96a66cSDavid du Colombier 		return 0;
12315e96a66cSDavid du Colombier 	}
12325e96a66cSDavid du Colombier 
12335e96a66cSDavid du Colombier 	if(!fileLock(f))
12345e96a66cSDavid du Colombier 		return 0;
12355e96a66cSDavid du Colombier 
12365e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
1237d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
12385e96a66cSDavid du Colombier 		goto Err1;
12395e96a66cSDavid du Colombier 	}
12405e96a66cSDavid du Colombier 	if(!sourceLock2(f->source, f->msource, -1))
12415e96a66cSDavid du Colombier 		goto Err1;
12425e96a66cSDavid du Colombier 	if(fileIsDir(f) && !fileCheckEmpty(f))
12435e96a66cSDavid du Colombier 		goto Err;
12445e96a66cSDavid du Colombier 
12455e96a66cSDavid du Colombier 	for(ff=f->down; ff; ff=ff->next)
12465e96a66cSDavid du Colombier 		assert(ff->removed);
12475e96a66cSDavid du Colombier 
12485e96a66cSDavid du Colombier 	sourceRemove(f->source);
12493b86f2f8SDavid du Colombier 	f->source->file = nil;		/* erase back pointer */
12505e96a66cSDavid du Colombier 	f->source = nil;
12515e96a66cSDavid du Colombier 	if(f->msource){
12525e96a66cSDavid du Colombier 		sourceRemove(f->msource);
12535e96a66cSDavid du Colombier 		f->msource = nil;
12545e96a66cSDavid du Colombier 	}
12555e96a66cSDavid du Colombier 
12565e96a66cSDavid du Colombier 	fileUnlock(f);
12575e96a66cSDavid du Colombier 
12585e96a66cSDavid du Colombier 	if(!fileMetaRemove(f, uid))
12595e96a66cSDavid du Colombier 		return 0;
12605e96a66cSDavid du Colombier 
12615e96a66cSDavid du Colombier 	return 1;
12625e96a66cSDavid du Colombier 
12635e96a66cSDavid du Colombier Err:
12645e96a66cSDavid du Colombier 	sourceUnlock(f->source);
12655e96a66cSDavid du Colombier 	if(f->msource)
12665e96a66cSDavid du Colombier 		sourceUnlock(f->msource);
12675e96a66cSDavid du Colombier Err1:
12685e96a66cSDavid du Colombier 	fileUnlock(f);
12695e96a66cSDavid du Colombier 	return 0;
12705e96a66cSDavid du Colombier }
12715e96a66cSDavid du Colombier 
1272dc5a79c1SDavid du Colombier static int
clri(File * f,char * uid)1273dc5a79c1SDavid du Colombier clri(File *f, char *uid)
12745e96a66cSDavid du Colombier {
12755e96a66cSDavid du Colombier 	int r;
12765e96a66cSDavid du Colombier 
12775e96a66cSDavid du Colombier 	if(f == nil)
12785e96a66cSDavid du Colombier 		return 0;
12795e96a66cSDavid du Colombier 	if(f->up->source->mode != OReadWrite){
1280d7aba6c3SDavid du Colombier 		werrstr(EReadOnly);
12815e96a66cSDavid du Colombier 		fileDecRef(f);
12825e96a66cSDavid du Colombier 		return 0;
12835e96a66cSDavid du Colombier 	}
12845e96a66cSDavid du Colombier 	r = fileMetaRemove(f, uid);
12855e96a66cSDavid du Colombier 	fileDecRef(f);
12865e96a66cSDavid du Colombier 	return r;
12875e96a66cSDavid du Colombier }
12885e96a66cSDavid du Colombier 
1289dc5a79c1SDavid du Colombier int
fileClriPath(Fs * fs,char * path,char * uid)1290dc5a79c1SDavid du Colombier fileClriPath(Fs *fs, char *path, char *uid)
1291dc5a79c1SDavid du Colombier {
1292dc5a79c1SDavid du Colombier 	return clri(_fileOpen(fs, path, 1), uid);
1293dc5a79c1SDavid du Colombier }
1294dc5a79c1SDavid du Colombier 
1295dc5a79c1SDavid du Colombier int
fileClri(File * dir,char * elem,char * uid)1296dc5a79c1SDavid du Colombier fileClri(File *dir, char *elem, char *uid)
1297dc5a79c1SDavid du Colombier {
1298dc5a79c1SDavid du Colombier 	return clri(_fileWalk(dir, elem, 1), uid);
1299dc5a79c1SDavid du Colombier }
1300dc5a79c1SDavid du Colombier 
13015e96a66cSDavid du Colombier File *
fileIncRef(File * vf)13025e96a66cSDavid du Colombier fileIncRef(File *vf)
13035e96a66cSDavid du Colombier {
13045e96a66cSDavid du Colombier 	fileMetaLock(vf);
13055e96a66cSDavid du Colombier 	assert(vf->ref > 0);
13065e96a66cSDavid du Colombier 	vf->ref++;
13075e96a66cSDavid du Colombier 	fileMetaUnlock(vf);
13085e96a66cSDavid du Colombier 	return vf;
13095e96a66cSDavid du Colombier }
13105e96a66cSDavid du Colombier 
13115e96a66cSDavid du Colombier int
fileDecRef(File * f)13125e96a66cSDavid du Colombier fileDecRef(File *f)
13135e96a66cSDavid du Colombier {
13145e96a66cSDavid du Colombier 	File *p, *q, **qq;
13155e96a66cSDavid du Colombier 
13165e96a66cSDavid du Colombier 	if(f->up == nil){
13175e96a66cSDavid du Colombier 		/* never linked in */
13185e96a66cSDavid du Colombier 		assert(f->ref == 1);
13195e96a66cSDavid du Colombier 		fileFree(f);
13205e96a66cSDavid du Colombier 		return 1;
13215e96a66cSDavid du Colombier 	}
13225e96a66cSDavid du Colombier 
13235e96a66cSDavid du Colombier 	fileMetaLock(f);
13245e96a66cSDavid du Colombier 	f->ref--;
13255e96a66cSDavid du Colombier 	if(f->ref > 0){
13265e96a66cSDavid du Colombier 		fileMetaUnlock(f);
13275e96a66cSDavid du Colombier 		return 0;
13285e96a66cSDavid du Colombier 	}
13295e96a66cSDavid du Colombier 	assert(f->ref == 0);
13305e96a66cSDavid du Colombier 	assert(f->down == nil);
13315e96a66cSDavid du Colombier 
13325e96a66cSDavid du Colombier 	fileMetaFlush2(f, nil);
13335e96a66cSDavid du Colombier 
13345e96a66cSDavid du Colombier 	p = f->up;
13355e96a66cSDavid du Colombier 	qq = &p->down;
13365e96a66cSDavid du Colombier 	for(q = *qq; q; q = *qq){
13375e96a66cSDavid du Colombier 		if(q == f)
13385e96a66cSDavid du Colombier 			break;
13395e96a66cSDavid du Colombier 		qq = &q->next;
13405e96a66cSDavid du Colombier 	}
13415e96a66cSDavid du Colombier 	assert(q != nil);
13425e96a66cSDavid du Colombier 	*qq = f->next;
13435e96a66cSDavid du Colombier 
13445e96a66cSDavid du Colombier 	fileMetaUnlock(f);
13455e96a66cSDavid du Colombier 	fileFree(f);
13465e96a66cSDavid du Colombier 
13475e96a66cSDavid du Colombier 	fileDecRef(p);
13485e96a66cSDavid du Colombier 	return 1;
13495e96a66cSDavid du Colombier }
13505e96a66cSDavid du Colombier 
13515e96a66cSDavid du Colombier File *
fileGetParent(File * f)13525e96a66cSDavid du Colombier fileGetParent(File *f)
13535e96a66cSDavid du Colombier {
13545e96a66cSDavid du Colombier 	if(fileIsRoot(f))
13555e96a66cSDavid du Colombier 		return fileIncRef(f);
13565e96a66cSDavid du Colombier 	return fileIncRef(f->up);
13575e96a66cSDavid du Colombier }
13585e96a66cSDavid du Colombier 
13595e96a66cSDavid du Colombier DirEntryEnum *
deeOpen(File * f)13605e96a66cSDavid du Colombier deeOpen(File *f)
13615e96a66cSDavid du Colombier {
13625e96a66cSDavid du Colombier 	DirEntryEnum *dee;
13635e96a66cSDavid du Colombier 	File *p;
13645e96a66cSDavid du Colombier 
13655e96a66cSDavid du Colombier 	if(!fileIsDir(f)){
1366d7aba6c3SDavid du Colombier 		werrstr(ENotDir);
13675e96a66cSDavid du Colombier 		fileDecRef(f);
13685e96a66cSDavid du Colombier 		return nil;
13695e96a66cSDavid du Colombier 	}
13705e96a66cSDavid du Colombier 
13715e96a66cSDavid du Colombier 	/* flush out meta data */
13725e96a66cSDavid du Colombier 	if(!fileLock(f))
13735e96a66cSDavid du Colombier 		return nil;
13745e96a66cSDavid du Colombier 	for(p=f->down; p; p=p->next)
13755e96a66cSDavid du Colombier 		fileMetaFlush2(p, nil);
13765e96a66cSDavid du Colombier 	fileUnlock(f);
13775e96a66cSDavid du Colombier 
1378d7aba6c3SDavid du Colombier 	dee = vtmallocz(sizeof(DirEntryEnum));
13795e96a66cSDavid du Colombier 	dee->file = fileIncRef(f);
13805e96a66cSDavid du Colombier 
13815e96a66cSDavid du Colombier 	return dee;
13825e96a66cSDavid du Colombier }
13835e96a66cSDavid du Colombier 
13845e96a66cSDavid du Colombier static int
dirEntrySize(Source * s,ulong elem,ulong gen,uvlong * size)13855e96a66cSDavid du Colombier dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size)
13865e96a66cSDavid du Colombier {
13875e96a66cSDavid du Colombier 	Block *b;
13885e96a66cSDavid du Colombier 	ulong bn;
13895e96a66cSDavid du Colombier 	Entry e;
13905e96a66cSDavid du Colombier 	int epb;
13915e96a66cSDavid du Colombier 
13925e96a66cSDavid du Colombier 	epb = s->dsize/VtEntrySize;
13935e96a66cSDavid du Colombier 	bn = elem/epb;
13945e96a66cSDavid du Colombier 	elem -= bn*epb;
13955e96a66cSDavid du Colombier 
13965e96a66cSDavid du Colombier 	b = sourceBlock(s, bn, OReadOnly);
13975e96a66cSDavid du Colombier 	if(b == nil)
13985e96a66cSDavid du Colombier 		goto Err;
13995e96a66cSDavid du Colombier 	if(!entryUnpack(&e, b->data, elem))
14005e96a66cSDavid du Colombier 		goto Err;
14015e96a66cSDavid du Colombier 
14025e96a66cSDavid du Colombier 	/* hanging entries are returned as zero size */
14035e96a66cSDavid du Colombier 	if(!(e.flags & VtEntryActive) || e.gen != gen)
14045e96a66cSDavid du Colombier 		*size = 0;
14055e96a66cSDavid du Colombier 	else
14065e96a66cSDavid du Colombier 		*size = e.size;
14075e96a66cSDavid du Colombier 	blockPut(b);
14085e96a66cSDavid du Colombier 	return 1;
14095e96a66cSDavid du Colombier 
14105e96a66cSDavid du Colombier Err:
14115e96a66cSDavid du Colombier 	blockPut(b);
14125e96a66cSDavid du Colombier 	return 0;
14135e96a66cSDavid du Colombier }
14145e96a66cSDavid du Colombier 
14155e96a66cSDavid du Colombier static int
deeFill(DirEntryEnum * dee)14165e96a66cSDavid du Colombier deeFill(DirEntryEnum *dee)
14175e96a66cSDavid du Colombier {
14185e96a66cSDavid du Colombier 	int i, n;
14195e96a66cSDavid du Colombier 	Source *meta, *source;
14205e96a66cSDavid du Colombier 	MetaBlock mb;
14215e96a66cSDavid du Colombier 	MetaEntry me;
14225e96a66cSDavid du Colombier 	File *f;
14235e96a66cSDavid du Colombier 	Block *b;
14245e96a66cSDavid du Colombier 	DirEntry *de;
14255e96a66cSDavid du Colombier 
14265e96a66cSDavid du Colombier 	/* clean up first */
14275e96a66cSDavid du Colombier 	for(i=dee->i; i<dee->n; i++)
14285e96a66cSDavid du Colombier 		deCleanup(dee->buf+i);
1429d7aba6c3SDavid du Colombier 	vtfree(dee->buf);
14305e96a66cSDavid du Colombier 	dee->buf = nil;
14315e96a66cSDavid du Colombier 	dee->i = 0;
14325e96a66cSDavid du Colombier 	dee->n = 0;
14335e96a66cSDavid du Colombier 
14345e96a66cSDavid du Colombier 	f = dee->file;
14355e96a66cSDavid du Colombier 
14365e96a66cSDavid du Colombier 	source = f->source;
14375e96a66cSDavid du Colombier 	meta = f->msource;
14385e96a66cSDavid du Colombier 
14395e96a66cSDavid du Colombier 	b = sourceBlock(meta, dee->boff, OReadOnly);
14405e96a66cSDavid du Colombier 	if(b == nil)
14415e96a66cSDavid du Colombier 		goto Err;
14425e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, meta->dsize))
14435e96a66cSDavid du Colombier 		goto Err;
14445e96a66cSDavid du Colombier 
14455e96a66cSDavid du Colombier 	n = mb.nindex;
1446d7aba6c3SDavid du Colombier 	dee->buf = vtmalloc(n * sizeof(DirEntry));
14475e96a66cSDavid du Colombier 
14485e96a66cSDavid du Colombier 	for(i=0; i<n; i++){
14495e96a66cSDavid du Colombier 		de = dee->buf + i;
14505e96a66cSDavid du Colombier 		meUnpack(&me, &mb, i);
14515e96a66cSDavid du Colombier 		if(!deUnpack(de, &me))
14525e96a66cSDavid du Colombier 			goto Err;
14535e96a66cSDavid du Colombier 		dee->n++;
14545e96a66cSDavid du Colombier 		if(!(de->mode & ModeDir))
14555e96a66cSDavid du Colombier 		if(!dirEntrySize(source, de->entry, de->gen, &de->size))
14565e96a66cSDavid du Colombier 			goto Err;
14575e96a66cSDavid du Colombier 	}
14585e96a66cSDavid du Colombier 	dee->boff++;
14595e96a66cSDavid du Colombier 	blockPut(b);
14605e96a66cSDavid du Colombier 	return 1;
14615e96a66cSDavid du Colombier Err:
14625e96a66cSDavid du Colombier 	blockPut(b);
14635e96a66cSDavid du Colombier 	return 0;
14645e96a66cSDavid du Colombier }
14655e96a66cSDavid du Colombier 
14665e96a66cSDavid du Colombier int
deeRead(DirEntryEnum * dee,DirEntry * de)14675e96a66cSDavid du Colombier deeRead(DirEntryEnum *dee, DirEntry *de)
14685e96a66cSDavid du Colombier {
14695e96a66cSDavid du Colombier 	int ret, didread;
14705e96a66cSDavid du Colombier 	File *f;
14715e96a66cSDavid du Colombier 	u32int nb;
14725e96a66cSDavid du Colombier 
1473418f3c22SDavid du Colombier 	if(dee == nil){
1474d7aba6c3SDavid du Colombier 		werrstr("cannot happen in deeRead");
1475418f3c22SDavid du Colombier 		return -1;
1476418f3c22SDavid du Colombier 	}
1477418f3c22SDavid du Colombier 
14785e96a66cSDavid du Colombier 	f = dee->file;
14795e96a66cSDavid du Colombier 	if(!fileRLock(f))
14805e96a66cSDavid du Colombier 		return -1;
14815e96a66cSDavid du Colombier 
14825e96a66cSDavid du Colombier 	if(!sourceLock2(f->source, f->msource, OReadOnly)){
14835e96a66cSDavid du Colombier 		fileRUnlock(f);
14845e96a66cSDavid du Colombier 		return -1;
14855e96a66cSDavid du Colombier 	}
14865e96a66cSDavid du Colombier 
14875e96a66cSDavid du Colombier 	nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
14885e96a66cSDavid du Colombier 
14895e96a66cSDavid du Colombier 	didread = 0;
14905e96a66cSDavid du Colombier 	while(dee->i >= dee->n){
14915e96a66cSDavid du Colombier 		if(dee->boff >= nb){
14925e96a66cSDavid du Colombier 			ret = 0;
14935e96a66cSDavid du Colombier 			goto Return;
14945e96a66cSDavid du Colombier 		}
14955e96a66cSDavid du Colombier 		didread = 1;
14965e96a66cSDavid du Colombier 		if(!deeFill(dee)){
14975e96a66cSDavid du Colombier 			ret = -1;
14985e96a66cSDavid du Colombier 			goto Return;
14995e96a66cSDavid du Colombier 		}
15005e96a66cSDavid du Colombier 	}
15015e96a66cSDavid du Colombier 
15025e96a66cSDavid du Colombier 	memmove(de, dee->buf + dee->i, sizeof(DirEntry));
15035e96a66cSDavid du Colombier 	dee->i++;
15045e96a66cSDavid du Colombier 	ret = 1;
15055e96a66cSDavid du Colombier 
15065e96a66cSDavid du Colombier Return:
15075e96a66cSDavid du Colombier 	sourceUnlock(f->source);
15085e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
15095e96a66cSDavid du Colombier 	fileRUnlock(f);
15105e96a66cSDavid du Colombier 
15115e96a66cSDavid du Colombier 	if(didread)
15125e96a66cSDavid du Colombier 		fileRAccess(f);
15135e96a66cSDavid du Colombier 	return ret;
15145e96a66cSDavid du Colombier }
15155e96a66cSDavid du Colombier 
15165e96a66cSDavid du Colombier void
deeClose(DirEntryEnum * dee)15175e96a66cSDavid du Colombier deeClose(DirEntryEnum *dee)
15185e96a66cSDavid du Colombier {
15195e96a66cSDavid du Colombier 	int i;
15205e96a66cSDavid du Colombier 	if(dee == nil)
15215e96a66cSDavid du Colombier 		return;
15225e96a66cSDavid du Colombier 	for(i=dee->i; i<dee->n; i++)
15235e96a66cSDavid du Colombier 		deCleanup(dee->buf+i);
1524d7aba6c3SDavid du Colombier 	vtfree(dee->buf);
15255e96a66cSDavid du Colombier 	fileDecRef(dee->file);
1526d7aba6c3SDavid du Colombier 	vtfree(dee);
15275e96a66cSDavid du Colombier }
15285e96a66cSDavid du Colombier 
15295e96a66cSDavid du Colombier /*
15305e96a66cSDavid du Colombier  * caller must lock f->source and f->msource
15315e96a66cSDavid du Colombier  * caller must NOT lock the source and msource
15325e96a66cSDavid du Colombier  * referenced by dir.
15335e96a66cSDavid du Colombier  */
15345e96a66cSDavid du Colombier static u32int
fileMetaAlloc(File * f,DirEntry * dir,u32int start)15355e96a66cSDavid du Colombier fileMetaAlloc(File *f, DirEntry *dir, u32int start)
15365e96a66cSDavid du Colombier {
15375e96a66cSDavid du Colombier 	u32int nb, bo;
15385e96a66cSDavid du Colombier 	Block *b, *bb;
15395e96a66cSDavid du Colombier 	MetaBlock mb;
15405e96a66cSDavid du Colombier 	int nn;
15415e96a66cSDavid du Colombier 	uchar *p;
15425e96a66cSDavid du Colombier 	int i, n, epb;
15435e96a66cSDavid du Colombier 	MetaEntry me;
15445e96a66cSDavid du Colombier 	Source *s, *ms;
15455e96a66cSDavid du Colombier 
15465e96a66cSDavid du Colombier 	s = f->source;
15475e96a66cSDavid du Colombier 	ms = f->msource;
15485e96a66cSDavid du Colombier 
15495e96a66cSDavid du Colombier 	n = deSize(dir);
15505e96a66cSDavid du Colombier 	nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize;
15515e96a66cSDavid du Colombier 	b = nil;
15525e96a66cSDavid du Colombier 	if(start > nb)
15535e96a66cSDavid du Colombier 		start = nb;
15545e96a66cSDavid du Colombier 	for(bo=start; bo<nb; bo++){
15555e96a66cSDavid du Colombier 		b = sourceBlock(ms, bo, OReadWrite);
15565e96a66cSDavid du Colombier 		if(b == nil)
15575e96a66cSDavid du Colombier 			goto Err;
15585e96a66cSDavid du Colombier 		if(!mbUnpack(&mb, b->data, ms->dsize))
15595e96a66cSDavid du Colombier 			goto Err;
15605e96a66cSDavid du Colombier 		nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
15615e96a66cSDavid du Colombier 		if(n <= nn && mb.nindex < mb.maxindex)
15625e96a66cSDavid du Colombier 			break;
15635e96a66cSDavid du Colombier 		blockPut(b);
15645e96a66cSDavid du Colombier 		b = nil;
15655e96a66cSDavid du Colombier 	}
15665e96a66cSDavid du Colombier 
15675e96a66cSDavid du Colombier 	/* add block to meta file */
15685e96a66cSDavid du Colombier 	if(b == nil){
15695e96a66cSDavid du Colombier 		b = sourceBlock(ms, bo, OReadWrite);
15705e96a66cSDavid du Colombier 		if(b == nil)
15715e96a66cSDavid du Colombier 			goto Err;
15725e96a66cSDavid du Colombier 		sourceSetSize(ms, (nb+1)*ms->dsize);
15735e96a66cSDavid du Colombier 		mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
15745e96a66cSDavid du Colombier 	}
15755e96a66cSDavid du Colombier 
15765e96a66cSDavid du Colombier 	p = mbAlloc(&mb, n);
15775e96a66cSDavid du Colombier 	if(p == nil){
15785e96a66cSDavid du Colombier 		/* mbAlloc might have changed block */
15795e96a66cSDavid du Colombier 		mbPack(&mb);
15805e96a66cSDavid du Colombier 		blockDirty(b);
1581d7aba6c3SDavid du Colombier 		werrstr(EBadMeta);
15825e96a66cSDavid du Colombier 		goto Err;
15835e96a66cSDavid du Colombier 	}
15845e96a66cSDavid du Colombier 
15855e96a66cSDavid du Colombier 	mbSearch(&mb, dir->elem, &i, &me);
15865e96a66cSDavid du Colombier 	assert(me.p == nil);
15875e96a66cSDavid du Colombier 	me.p = p;
15885e96a66cSDavid du Colombier 	me.size = n;
15895e96a66cSDavid du Colombier 	dePack(dir, &me);
15905e96a66cSDavid du Colombier 	mbInsert(&mb, i, &me);
15915e96a66cSDavid du Colombier 	mbPack(&mb);
15925e96a66cSDavid du Colombier 
15935e96a66cSDavid du Colombier 	/* meta block depends on super block for qid ... */
15945e96a66cSDavid du Colombier 	bb = cacheLocal(b->c, PartSuper, 0, OReadOnly);
159561201b97SDavid du Colombier 	blockDependency(b, bb, -1, nil, nil);
15965e96a66cSDavid du Colombier 	blockPut(bb);
15975e96a66cSDavid du Colombier 
15985e96a66cSDavid du Colombier 	/* ... and one or two dir entries */
15995e96a66cSDavid du Colombier 	epb = s->dsize/VtEntrySize;
16005e96a66cSDavid du Colombier 	bb = sourceBlock(s, dir->entry/epb, OReadOnly);
160161201b97SDavid du Colombier 	blockDependency(b, bb, -1, nil, nil);
16025e96a66cSDavid du Colombier 	blockPut(bb);
16035e96a66cSDavid du Colombier 	if(dir->mode & ModeDir){
16045e96a66cSDavid du Colombier 		bb = sourceBlock(s, dir->mentry/epb, OReadOnly);
160561201b97SDavid du Colombier 		blockDependency(b, bb, -1, nil, nil);
16065e96a66cSDavid du Colombier 		blockPut(bb);
16075e96a66cSDavid du Colombier 	}
16085e96a66cSDavid du Colombier 
16095e96a66cSDavid du Colombier 	blockDirty(b);
16105e96a66cSDavid du Colombier 	blockPut(b);
16115e96a66cSDavid du Colombier 	return bo;
16125e96a66cSDavid du Colombier Err:
16135e96a66cSDavid du Colombier 	blockPut(b);
16145e96a66cSDavid du Colombier 	return NilBlock;
16155e96a66cSDavid du Colombier }
16165e96a66cSDavid du Colombier 
16175e96a66cSDavid du Colombier static int
chkSource(File * f)16185e96a66cSDavid du Colombier chkSource(File *f)
16195e96a66cSDavid du Colombier {
16205e96a66cSDavid du Colombier 	if(f->partial)
16215e96a66cSDavid du Colombier 		return 1;
16225e96a66cSDavid du Colombier 
16235e96a66cSDavid du Colombier 	if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){
1624d7aba6c3SDavid du Colombier 		werrstr(ERemoved);
16255e96a66cSDavid du Colombier 		return 0;
16265e96a66cSDavid du Colombier 	}
16275e96a66cSDavid du Colombier 	return 1;
16285e96a66cSDavid du Colombier }
16295e96a66cSDavid du Colombier 
16305e96a66cSDavid du Colombier static int
fileRLock(File * f)16315e96a66cSDavid du Colombier fileRLock(File *f)
16325e96a66cSDavid du Colombier {
1633d7aba6c3SDavid du Colombier 	assert(!canwlock(&f->fs->elk));
1634d7aba6c3SDavid du Colombier 	rlock(&f->lk);
16355e96a66cSDavid du Colombier 	if(!chkSource(f)){
16365e96a66cSDavid du Colombier 		fileRUnlock(f);
16375e96a66cSDavid du Colombier 		return 0;
16385e96a66cSDavid du Colombier 	}
16395e96a66cSDavid du Colombier 	return 1;
16405e96a66cSDavid du Colombier }
16415e96a66cSDavid du Colombier 
16425e96a66cSDavid du Colombier static void
fileRUnlock(File * f)16435e96a66cSDavid du Colombier fileRUnlock(File *f)
16445e96a66cSDavid du Colombier {
1645d7aba6c3SDavid du Colombier 	runlock(&f->lk);
16465e96a66cSDavid du Colombier }
16475e96a66cSDavid du Colombier 
16485e96a66cSDavid du Colombier static int
fileLock(File * f)16495e96a66cSDavid du Colombier fileLock(File *f)
16505e96a66cSDavid du Colombier {
1651d7aba6c3SDavid du Colombier 	assert(!canwlock(&f->fs->elk));
1652d7aba6c3SDavid du Colombier 	wlock(&f->lk);
16535e96a66cSDavid du Colombier 	if(!chkSource(f)){
16545e96a66cSDavid du Colombier 		fileUnlock(f);
16555e96a66cSDavid du Colombier 		return 0;
16565e96a66cSDavid du Colombier 	}
16575e96a66cSDavid du Colombier 	return 1;
16585e96a66cSDavid du Colombier }
16595e96a66cSDavid du Colombier 
16605e96a66cSDavid du Colombier static void
fileUnlock(File * f)16615e96a66cSDavid du Colombier fileUnlock(File *f)
16625e96a66cSDavid du Colombier {
1663d7aba6c3SDavid du Colombier 	wunlock(&f->lk);
16645e96a66cSDavid du Colombier }
16655e96a66cSDavid du Colombier 
16665e96a66cSDavid du Colombier /*
16675e96a66cSDavid du Colombier  * f->source and f->msource must NOT be locked.
16685e96a66cSDavid du Colombier  * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2).
16695e96a66cSDavid du Colombier  * We have to respect that ordering.
16705e96a66cSDavid du Colombier  */
16715e96a66cSDavid du Colombier static void
fileMetaLock(File * f)16725e96a66cSDavid du Colombier fileMetaLock(File *f)
16735e96a66cSDavid du Colombier {
16745e96a66cSDavid du Colombier if(f->up == nil)
16755e96a66cSDavid du Colombier fprint(2, "f->elem = %s\n", f->dir.elem);
16765e96a66cSDavid du Colombier 	assert(f->up != nil);
1677d7aba6c3SDavid du Colombier 	assert(!canwlock(&f->fs->elk));
1678d7aba6c3SDavid du Colombier 	wlock(&f->up->lk);
16795e96a66cSDavid du Colombier }
16805e96a66cSDavid du Colombier 
16815e96a66cSDavid du Colombier static void
fileMetaUnlock(File * f)16825e96a66cSDavid du Colombier fileMetaUnlock(File *f)
16835e96a66cSDavid du Colombier {
1684d7aba6c3SDavid du Colombier 	wunlock(&f->up->lk);
16855e96a66cSDavid du Colombier }
16865e96a66cSDavid du Colombier 
16875e96a66cSDavid du Colombier /*
16885e96a66cSDavid du Colombier  * f->source and f->msource must NOT be locked.
16895e96a66cSDavid du Colombier  * see fileMetaLock.
16905e96a66cSDavid du Colombier  */
16915e96a66cSDavid du Colombier static void
fileRAccess(File * f)16925e96a66cSDavid du Colombier fileRAccess(File* f)
16935e96a66cSDavid du Colombier {
1694f4051287SDavid du Colombier 	if(f->mode == OReadOnly || f->fs->noatimeupd)
16955e96a66cSDavid du Colombier 		return;
16965e96a66cSDavid du Colombier 
16975e96a66cSDavid du Colombier 	fileMetaLock(f);
16985e96a66cSDavid du Colombier 	f->dir.atime = time(0L);
16995e96a66cSDavid du Colombier 	f->dirty = 1;
17005e96a66cSDavid du Colombier 	fileMetaUnlock(f);
17015e96a66cSDavid du Colombier }
17025e96a66cSDavid du Colombier 
17035e96a66cSDavid du Colombier /*
17045e96a66cSDavid du Colombier  * f->source and f->msource must NOT be locked.
17055e96a66cSDavid du Colombier  * see fileMetaLock.
17065e96a66cSDavid du Colombier  */
17075e96a66cSDavid du Colombier static void
fileWAccess(File * f,char * mid)17085e96a66cSDavid du Colombier fileWAccess(File* f, char *mid)
17095e96a66cSDavid du Colombier {
17105e96a66cSDavid du Colombier 	if(f->mode == OReadOnly)
17115e96a66cSDavid du Colombier 		return;
17125e96a66cSDavid du Colombier 
17135e96a66cSDavid du Colombier 	fileMetaLock(f);
17145e96a66cSDavid du Colombier 	f->dir.atime = f->dir.mtime = time(0L);
17155e96a66cSDavid du Colombier 	if(strcmp(f->dir.mid, mid) != 0){
1716d7aba6c3SDavid du Colombier 		vtfree(f->dir.mid);
1717d7aba6c3SDavid du Colombier 		f->dir.mid = vtstrdup(mid);
17185e96a66cSDavid du Colombier 	}
17195e96a66cSDavid du Colombier 	f->dir.mcount++;
17205e96a66cSDavid du Colombier 	f->dirty = 1;
17215e96a66cSDavid du Colombier 	fileMetaUnlock(f);
1722d58da526SDavid du Colombier 
1723d58da526SDavid du Colombier /*RSC: let's try this */
1724d58da526SDavid du Colombier /*presotto - lets not
1725d58da526SDavid du Colombier 	if(f->up)
1726d58da526SDavid du Colombier 		fileWAccess(f->up, mid);
1727d58da526SDavid du Colombier */
17285e96a66cSDavid du Colombier }
17295e96a66cSDavid du Colombier 
17305e96a66cSDavid du Colombier static int
getEntry(Source * r,Entry * e,int checkepoch)1731e569ccb5SDavid du Colombier getEntry(Source *r, Entry *e, int checkepoch)
17325e96a66cSDavid du Colombier {
1733e569ccb5SDavid du Colombier 	u32int epoch;
17345e96a66cSDavid du Colombier 	Block *b;
17355e96a66cSDavid du Colombier 
17365e96a66cSDavid du Colombier 	if(r == nil){
17375e96a66cSDavid du Colombier 		memset(&e, 0, sizeof e);
17385e96a66cSDavid du Colombier 		return 1;
17395e96a66cSDavid du Colombier 	}
17405e96a66cSDavid du Colombier 
17415e96a66cSDavid du Colombier 	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly);
17425e96a66cSDavid du Colombier 	if(b == nil)
17435e96a66cSDavid du Colombier 		return 0;
17445e96a66cSDavid du Colombier 	if(!entryUnpack(e, b->data, r->offset % r->epb)){
17455e96a66cSDavid du Colombier 		blockPut(b);
17465e96a66cSDavid du Colombier 		return 0;
17475e96a66cSDavid du Colombier 	}
1748e569ccb5SDavid du Colombier 	epoch = b->l.epoch;
17495e96a66cSDavid du Colombier 	blockPut(b);
1750e569ccb5SDavid du Colombier 
1751e569ccb5SDavid du Colombier 	if(checkepoch){
1752e569ccb5SDavid du Colombier 		b = cacheGlobal(r->fs->cache, e->score, entryType(e), e->tag, OReadOnly);
1753e569ccb5SDavid du Colombier 		if(b){
1754e569ccb5SDavid du Colombier 			if(b->l.epoch >= epoch)
1755e569ccb5SDavid du Colombier 				fprint(2, "warning: entry %p epoch not older %#.8ux/%d %V/%d in getEntry\n",
1756e569ccb5SDavid du Colombier 					r, b->addr, b->l.epoch, r->score, epoch);
1757e569ccb5SDavid du Colombier 			blockPut(b);
1758e569ccb5SDavid du Colombier 		}
1759e569ccb5SDavid du Colombier 	}
1760e569ccb5SDavid du Colombier 
17615e96a66cSDavid du Colombier 	return 1;
17625e96a66cSDavid du Colombier }
17635e96a66cSDavid du Colombier 
17645e96a66cSDavid du Colombier static int
setEntry(Source * r,Entry * e)17655e96a66cSDavid du Colombier setEntry(Source *r, Entry *e)
17665e96a66cSDavid du Colombier {
17675e96a66cSDavid du Colombier 	Block *b;
17685e96a66cSDavid du Colombier 	Entry oe;
17695e96a66cSDavid du Colombier 
17705e96a66cSDavid du Colombier 	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite);
17715e96a66cSDavid du Colombier 	if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);
17725e96a66cSDavid du Colombier 	if(b == nil)
17735e96a66cSDavid du Colombier 		return 0;
17745e96a66cSDavid du Colombier 	if(!entryUnpack(&oe, b->data, r->offset % r->epb)){
17755e96a66cSDavid du Colombier 		blockPut(b);
17765e96a66cSDavid du Colombier 		return 0;
17775e96a66cSDavid du Colombier 	}
17785e96a66cSDavid du Colombier 	e->gen = oe.gen;
17795e96a66cSDavid du Colombier 	entryPack(e, b->data, r->offset % r->epb);
17805e96a66cSDavid du Colombier 
17815e96a66cSDavid du Colombier 	/* BUG b should depend on the entry pointer */
17825e96a66cSDavid du Colombier 
17835e96a66cSDavid du Colombier 	blockDirty(b);
17845e96a66cSDavid du Colombier 	blockPut(b);
17855e96a66cSDavid du Colombier 	return 1;
17865e96a66cSDavid du Colombier }
17875e96a66cSDavid du Colombier 
17885e96a66cSDavid du Colombier /* assumes hold elk */
17895e96a66cSDavid du Colombier int
fileSnapshot(File * dst,File * src,u32int epoch,int doarchive)17905e96a66cSDavid du Colombier fileSnapshot(File *dst, File *src, u32int epoch, int doarchive)
17915e96a66cSDavid du Colombier {
17925e96a66cSDavid du Colombier 	Entry e, ee;
17935e96a66cSDavid du Colombier 
17945e96a66cSDavid du Colombier 	/* add link to snapshot */
17955e96a66cSDavid du Colombier 	if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))
17965e96a66cSDavid du Colombier 		return 0;
17975e96a66cSDavid du Colombier 
17985e96a66cSDavid du Colombier 	e.snap = epoch;
17995e96a66cSDavid du Colombier 	e.archive = doarchive;
18005e96a66cSDavid du Colombier 	ee.snap = epoch;
18015e96a66cSDavid du Colombier 	ee.archive = doarchive;
18025e96a66cSDavid du Colombier 
18035e96a66cSDavid du Colombier 	if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))
18045e96a66cSDavid du Colombier 		return 0;
18055e96a66cSDavid du Colombier 	return 1;
18065e96a66cSDavid du Colombier }
18075e96a66cSDavid du Colombier 
18085e96a66cSDavid du Colombier int
fileGetSources(File * f,Entry * e,Entry * ee)1809e569ccb5SDavid du Colombier fileGetSources(File *f, Entry *e, Entry *ee)
18105e96a66cSDavid du Colombier {
1811e569ccb5SDavid du Colombier 	if(!getEntry(f->source, e, 0)
1812e569ccb5SDavid du Colombier 	|| !getEntry(f->msource, ee, 0))
18135e96a66cSDavid du Colombier 		return 0;
18145e96a66cSDavid du Colombier 	return 1;
18155e96a66cSDavid du Colombier }
18165e96a66cSDavid du Colombier 
1817e569ccb5SDavid du Colombier /*
1818e569ccb5SDavid du Colombier  * Walk down to the block(s) containing the Entries
1819e569ccb5SDavid du Colombier  * for f->source and f->msource, copying as we go.
1820e569ccb5SDavid du Colombier  */
18215e96a66cSDavid du Colombier int
fileWalkSources(File * f)18225e96a66cSDavid du Colombier fileWalkSources(File *f)
18235e96a66cSDavid du Colombier {
1824e569ccb5SDavid du Colombier 	if(f->mode == OReadOnly){
1825e569ccb5SDavid du Colombier 		fprint(2, "readonly in fileWalkSources\n");
18265e96a66cSDavid du Colombier 		return 1;
1827e569ccb5SDavid du Colombier 	}
1828e569ccb5SDavid du Colombier 	if(!sourceLock2(f->source, f->msource, OReadWrite)){
1829e569ccb5SDavid du Colombier 		fprint(2, "sourceLock2 failed in fileWalkSources\n");
18305e96a66cSDavid du Colombier 		return 0;
1831e569ccb5SDavid du Colombier 	}
18325e96a66cSDavid du Colombier 	sourceUnlock(f->source);
18335e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
18345e96a66cSDavid du Colombier 	return 1;
18355e96a66cSDavid du Colombier }
18363b86f2f8SDavid du Colombier 
18373b86f2f8SDavid du Colombier /*
18383b86f2f8SDavid du Colombier  * convert File* to full path name in malloced string.
18393b86f2f8SDavid du Colombier  * this hasn't been as useful as we hoped it would be.
18403b86f2f8SDavid du Colombier  */
18413b86f2f8SDavid du Colombier char *
fileName(File * f)18423b86f2f8SDavid du Colombier fileName(File *f)
18433b86f2f8SDavid du Colombier {
18443b86f2f8SDavid du Colombier 	char *name, *pname;
18453b86f2f8SDavid du Colombier 	File *p;
18463b86f2f8SDavid du Colombier 	static char root[] = "/";
18473b86f2f8SDavid du Colombier 
18483b86f2f8SDavid du Colombier 	if (f == nil)
1849d7aba6c3SDavid du Colombier 		return vtstrdup("/**GOK**");
18503b86f2f8SDavid du Colombier 
18513b86f2f8SDavid du Colombier 	p = fileGetParent(f);
18523b86f2f8SDavid du Colombier 	if (p == f)
1853d7aba6c3SDavid du Colombier 		name = vtstrdup(root);
18543b86f2f8SDavid du Colombier 	else {
18553b86f2f8SDavid du Colombier 		pname = fileName(p);
18563b86f2f8SDavid du Colombier 		if (strcmp(pname, root) == 0)
18573b86f2f8SDavid du Colombier 			name = smprint("/%s", f->dir.elem);
18583b86f2f8SDavid du Colombier 		else
18593b86f2f8SDavid du Colombier 			name = smprint("%s/%s", pname, f->dir.elem);
18603b86f2f8SDavid du Colombier 		free(pname);
18613b86f2f8SDavid du Colombier 	}
18623b86f2f8SDavid du Colombier 	fileDecRef(p);
18633b86f2f8SDavid du Colombier 	return name;
18643b86f2f8SDavid du Colombier }
1865