xref: /plan9-contrib/sys/src/cmd/fossil/file.c (revision 5e96a66c77eb9140492ca53f857cbbf108e128ed)
1*5e96a66cSDavid du Colombier #include "stdinc.h"
2*5e96a66cSDavid du Colombier #include "dat.h"
3*5e96a66cSDavid du Colombier #include "fns.h"
4*5e96a66cSDavid du Colombier #include "error.h"
5*5e96a66cSDavid du Colombier 
6*5e96a66cSDavid du Colombier /*
7*5e96a66cSDavid du Colombier  * locking order is upwards.  A thread can hold the lock for a File
8*5e96a66cSDavid du Colombier  * and then acquire the lock of its parent
9*5e96a66cSDavid du Colombier  */
10*5e96a66cSDavid du Colombier 
11*5e96a66cSDavid du Colombier struct File {
12*5e96a66cSDavid du Colombier 	Fs	*fs;		/* immutable */
13*5e96a66cSDavid du Colombier 
14*5e96a66cSDavid du Colombier 	/* meta data for file: protected by the lk in the parent */
15*5e96a66cSDavid du Colombier 	int	ref;		/* holds this data structure up */
16*5e96a66cSDavid du Colombier 
17*5e96a66cSDavid du Colombier 	int	partial;	/* file was never really open */
18*5e96a66cSDavid du Colombier 	int	removed;	/* file has been removed */
19*5e96a66cSDavid du Colombier 	int	dirty;		/* dir is dirty with respect to meta data in block */
20*5e96a66cSDavid du Colombier 	u32int	boff;		/* block offset within msource for this file's meta data */
21*5e96a66cSDavid du Colombier 
22*5e96a66cSDavid du Colombier 	DirEntry dir;		/* meta data for this file */
23*5e96a66cSDavid du Colombier 
24*5e96a66cSDavid du Colombier 	File	*up;		/* parent file */
25*5e96a66cSDavid du Colombier 	File	*next;		/* sibling */
26*5e96a66cSDavid du Colombier 
27*5e96a66cSDavid du Colombier 	/* data for file */
28*5e96a66cSDavid du Colombier 	VtLock	*lk;		/* lock for the following */
29*5e96a66cSDavid du Colombier 	Source	*source;
30*5e96a66cSDavid du Colombier 	Source	*msource;	/* for directories: meta data for children */
31*5e96a66cSDavid du Colombier 	File	*down;		/* children */
32*5e96a66cSDavid du Colombier 
33*5e96a66cSDavid du Colombier 	int	mode;
34*5e96a66cSDavid du Colombier };
35*5e96a66cSDavid du Colombier 
36*5e96a66cSDavid du Colombier static int fileMetaFlush2(File*, char*);
37*5e96a66cSDavid du Colombier static u32int fileMetaAlloc(File*, DirEntry*, u32int);
38*5e96a66cSDavid du Colombier static int fileRLock(File*);
39*5e96a66cSDavid du Colombier static void fileRUnlock(File*);
40*5e96a66cSDavid du Colombier static int fileLock(File*);
41*5e96a66cSDavid du Colombier static void fileUnlock(File*);
42*5e96a66cSDavid du Colombier static void fileMetaLock(File*);
43*5e96a66cSDavid du Colombier static void fileMetaUnlock(File*);
44*5e96a66cSDavid du Colombier static void fileRAccess(File*);
45*5e96a66cSDavid du Colombier static void fileWAccess(File*, char*);
46*5e96a66cSDavid du Colombier 
47*5e96a66cSDavid du Colombier static File *
48*5e96a66cSDavid du Colombier fileAlloc(Fs *fs)
49*5e96a66cSDavid du Colombier {
50*5e96a66cSDavid du Colombier 	File *f;
51*5e96a66cSDavid du Colombier 
52*5e96a66cSDavid du Colombier 	f = vtMemAllocZ(sizeof(File));
53*5e96a66cSDavid du Colombier 	f->lk = vtLockAlloc();
54*5e96a66cSDavid du Colombier 	f->ref = 1;
55*5e96a66cSDavid du Colombier 	f->fs = fs;
56*5e96a66cSDavid du Colombier 	f->boff = NilBlock;
57*5e96a66cSDavid du Colombier 	f->mode = fs->mode;
58*5e96a66cSDavid du Colombier 	return f;
59*5e96a66cSDavid du Colombier }
60*5e96a66cSDavid du Colombier 
61*5e96a66cSDavid du Colombier static void
62*5e96a66cSDavid du Colombier fileFree(File *f)
63*5e96a66cSDavid du Colombier {
64*5e96a66cSDavid du Colombier 	sourceClose(f->source);
65*5e96a66cSDavid du Colombier 	vtLockFree(f->lk);
66*5e96a66cSDavid du Colombier 	sourceClose(f->msource);
67*5e96a66cSDavid du Colombier 	deCleanup(&f->dir);
68*5e96a66cSDavid du Colombier 
69*5e96a66cSDavid du Colombier 	memset(f, ~0, sizeof(File));
70*5e96a66cSDavid du Colombier 	vtMemFree(f);
71*5e96a66cSDavid du Colombier }
72*5e96a66cSDavid du Colombier 
73*5e96a66cSDavid du Colombier /*
74*5e96a66cSDavid du Colombier  * the file is locked already
75*5e96a66cSDavid du Colombier  * f->msource is unlocked
76*5e96a66cSDavid du Colombier  */
77*5e96a66cSDavid du Colombier static File *
78*5e96a66cSDavid du Colombier dirLookup(File *f, char *elem)
79*5e96a66cSDavid du Colombier {
80*5e96a66cSDavid du Colombier 	int i;
81*5e96a66cSDavid du Colombier 	MetaBlock mb;
82*5e96a66cSDavid du Colombier 	MetaEntry me;
83*5e96a66cSDavid du Colombier 	Block *b;
84*5e96a66cSDavid du Colombier 	Source *meta;
85*5e96a66cSDavid du Colombier 	File *ff;
86*5e96a66cSDavid du Colombier 	u32int bo, nb;
87*5e96a66cSDavid du Colombier 
88*5e96a66cSDavid du Colombier 	meta = f->msource;
89*5e96a66cSDavid du Colombier 	b = nil;
90*5e96a66cSDavid du Colombier 	if(!sourceLock(meta, -1))
91*5e96a66cSDavid du Colombier 		return nil;
92*5e96a66cSDavid du Colombier 	nb = (sourceGetSize(meta)+meta->dsize-1)/meta->dsize;
93*5e96a66cSDavid du Colombier 	for(bo=0; bo<nb; bo++){
94*5e96a66cSDavid du Colombier 		b = sourceBlock(meta, bo, OReadOnly);
95*5e96a66cSDavid du Colombier 		if(b == nil)
96*5e96a66cSDavid du Colombier 			goto Err;
97*5e96a66cSDavid du Colombier 		if(!mbUnpack(&mb, b->data, meta->dsize))
98*5e96a66cSDavid du Colombier 			goto Err;
99*5e96a66cSDavid du Colombier 		if(mbSearch(&mb, elem, &i, &me)){
100*5e96a66cSDavid du Colombier 			ff = fileAlloc(f->fs);
101*5e96a66cSDavid du Colombier 			if(!deUnpack(&ff->dir, &me)){
102*5e96a66cSDavid du Colombier 				fileFree(ff);
103*5e96a66cSDavid du Colombier 				goto Err;
104*5e96a66cSDavid du Colombier 			}
105*5e96a66cSDavid du Colombier 			sourceUnlock(meta);
106*5e96a66cSDavid du Colombier 			blockPut(b);
107*5e96a66cSDavid du Colombier 			ff->boff = bo;
108*5e96a66cSDavid du Colombier 			ff->mode = f->mode;
109*5e96a66cSDavid du Colombier 			return ff;
110*5e96a66cSDavid du Colombier 		}
111*5e96a66cSDavid du Colombier 
112*5e96a66cSDavid du Colombier 		blockPut(b);
113*5e96a66cSDavid du Colombier 		b = nil;
114*5e96a66cSDavid du Colombier 	}
115*5e96a66cSDavid du Colombier 	vtSetError(ENoFile);
116*5e96a66cSDavid du Colombier 	/* fall through */
117*5e96a66cSDavid du Colombier Err:
118*5e96a66cSDavid du Colombier 	sourceUnlock(meta);
119*5e96a66cSDavid du Colombier 	blockPut(b);
120*5e96a66cSDavid du Colombier 	return nil;
121*5e96a66cSDavid du Colombier }
122*5e96a66cSDavid du Colombier 
123*5e96a66cSDavid du Colombier File *
124*5e96a66cSDavid du Colombier fileRoot(Source *r)
125*5e96a66cSDavid du Colombier {
126*5e96a66cSDavid du Colombier 	Block *b;
127*5e96a66cSDavid du Colombier 	Source *r0, *r1, *r2;
128*5e96a66cSDavid du Colombier 	MetaBlock mb;
129*5e96a66cSDavid du Colombier 	MetaEntry me;
130*5e96a66cSDavid du Colombier 	File *root, *mr;
131*5e96a66cSDavid du Colombier 	Fs *fs;
132*5e96a66cSDavid du Colombier 
133*5e96a66cSDavid du Colombier 	b = nil;
134*5e96a66cSDavid du Colombier 	root = nil;
135*5e96a66cSDavid du Colombier 	mr = nil;
136*5e96a66cSDavid du Colombier 	r1 = nil;
137*5e96a66cSDavid du Colombier 	r2 = nil;
138*5e96a66cSDavid du Colombier 
139*5e96a66cSDavid du Colombier 	fs = r->fs;
140*5e96a66cSDavid du Colombier 	if(!sourceLock(r, -1))
141*5e96a66cSDavid du Colombier 		return nil;
142*5e96a66cSDavid du Colombier 	r0 = sourceOpen(r, 0, fs->mode);
143*5e96a66cSDavid du Colombier 	if(r0 == nil)
144*5e96a66cSDavid du Colombier 		goto Err;
145*5e96a66cSDavid du Colombier 	r1 = sourceOpen(r, 1, fs->mode);
146*5e96a66cSDavid du Colombier 	if(r1 == nil)
147*5e96a66cSDavid du Colombier 		goto Err;
148*5e96a66cSDavid du Colombier 	r2 = sourceOpen(r, 2, fs->mode);
149*5e96a66cSDavid du Colombier 	if(r2 == nil)
150*5e96a66cSDavid du Colombier 		goto Err;
151*5e96a66cSDavid du Colombier 
152*5e96a66cSDavid du Colombier 	mr = fileAlloc(fs);
153*5e96a66cSDavid du Colombier 	mr->msource = r2;
154*5e96a66cSDavid du Colombier 	r2 = nil;
155*5e96a66cSDavid du Colombier 
156*5e96a66cSDavid du Colombier 	root = fileAlloc(fs);
157*5e96a66cSDavid du Colombier 	root->boff = 0;
158*5e96a66cSDavid du Colombier 	root->up = mr;
159*5e96a66cSDavid du Colombier 	root->source = r0;
160*5e96a66cSDavid du Colombier 	r0 = nil;
161*5e96a66cSDavid du Colombier 	root->msource = r1;
162*5e96a66cSDavid du Colombier 	r1 = nil;
163*5e96a66cSDavid du Colombier 
164*5e96a66cSDavid du Colombier 	mr->down = root;
165*5e96a66cSDavid du Colombier 
166*5e96a66cSDavid du Colombier 	if(!sourceLock(mr->msource, -1))
167*5e96a66cSDavid du Colombier 		goto Err;
168*5e96a66cSDavid du Colombier 	b = sourceBlock(mr->msource, 0, OReadOnly);
169*5e96a66cSDavid du Colombier 	sourceUnlock(mr->msource);
170*5e96a66cSDavid du Colombier 	if(b == nil)
171*5e96a66cSDavid du Colombier 		goto Err;
172*5e96a66cSDavid du Colombier 
173*5e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, mr->msource->dsize))
174*5e96a66cSDavid du Colombier 		goto Err;
175*5e96a66cSDavid du Colombier 
176*5e96a66cSDavid du Colombier 	meUnpack(&me, &mb, 0);
177*5e96a66cSDavid du Colombier 	if(!deUnpack(&root->dir, &me))
178*5e96a66cSDavid du Colombier 		goto Err;
179*5e96a66cSDavid du Colombier 	blockPut(b);
180*5e96a66cSDavid du Colombier 	sourceUnlock(r);
181*5e96a66cSDavid du Colombier 	fileRAccess(root);
182*5e96a66cSDavid du Colombier 
183*5e96a66cSDavid du Colombier 	return root;
184*5e96a66cSDavid du Colombier Err:
185*5e96a66cSDavid du Colombier 	blockPut(b);
186*5e96a66cSDavid du Colombier 	if(r0)
187*5e96a66cSDavid du Colombier 		sourceClose(r0);
188*5e96a66cSDavid du Colombier 	if(r1)
189*5e96a66cSDavid du Colombier 		sourceClose(r1);
190*5e96a66cSDavid du Colombier 	if(r2)
191*5e96a66cSDavid du Colombier 		sourceClose(r2);
192*5e96a66cSDavid du Colombier 	if(mr)
193*5e96a66cSDavid du Colombier 		fileFree(mr);
194*5e96a66cSDavid du Colombier 	if(root)
195*5e96a66cSDavid du Colombier 		fileFree(root);
196*5e96a66cSDavid du Colombier 	sourceUnlock(r);
197*5e96a66cSDavid du Colombier 
198*5e96a66cSDavid du Colombier 	return nil;
199*5e96a66cSDavid du Colombier }
200*5e96a66cSDavid du Colombier 
201*5e96a66cSDavid du Colombier static Source *
202*5e96a66cSDavid du Colombier fileOpenSource(File *f, u32int offset, u32int gen, int dir, uint mode)
203*5e96a66cSDavid du Colombier {
204*5e96a66cSDavid du Colombier 	Source *r;
205*5e96a66cSDavid du Colombier 
206*5e96a66cSDavid du Colombier 	if(!sourceLock(f->source, mode))
207*5e96a66cSDavid du Colombier 		return nil;
208*5e96a66cSDavid du Colombier 	r = sourceOpen(f->source, offset, mode);
209*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
210*5e96a66cSDavid du Colombier 	if(r == nil)
211*5e96a66cSDavid du Colombier 		return nil;
212*5e96a66cSDavid du Colombier 	if(r->gen != gen){
213*5e96a66cSDavid du Colombier 		vtSetError(ERemoved);
214*5e96a66cSDavid du Colombier 		goto Err;
215*5e96a66cSDavid du Colombier 	}
216*5e96a66cSDavid du Colombier 	if(r->dir != dir && r->mode != -1){
217*5e96a66cSDavid du Colombier fprint(2, "fileOpenSource: dir mismatch %d %d\n", r->dir, dir);
218*5e96a66cSDavid du Colombier 		vtSetError(EBadMeta);
219*5e96a66cSDavid du Colombier 		goto Err;
220*5e96a66cSDavid du Colombier 	}
221*5e96a66cSDavid du Colombier 	return r;
222*5e96a66cSDavid du Colombier Err:
223*5e96a66cSDavid du Colombier 	sourceClose(r);
224*5e96a66cSDavid du Colombier 	return nil;
225*5e96a66cSDavid du Colombier }
226*5e96a66cSDavid du Colombier 
227*5e96a66cSDavid du Colombier File *
228*5e96a66cSDavid du Colombier _fileWalk(File *f, char *elem, int partial)
229*5e96a66cSDavid du Colombier {
230*5e96a66cSDavid du Colombier 	File *ff;
231*5e96a66cSDavid du Colombier 
232*5e96a66cSDavid du Colombier 	fileRAccess(f);
233*5e96a66cSDavid du Colombier 
234*5e96a66cSDavid du Colombier 	if(elem[0] == 0){
235*5e96a66cSDavid du Colombier 		vtSetError(EBadPath);
236*5e96a66cSDavid du Colombier 		return nil;
237*5e96a66cSDavid du Colombier 	}
238*5e96a66cSDavid du Colombier 
239*5e96a66cSDavid du Colombier 	if(!fileIsDir(f)){
240*5e96a66cSDavid du Colombier 		vtSetError(ENotDir);
241*5e96a66cSDavid du Colombier 		return nil;
242*5e96a66cSDavid du Colombier 	}
243*5e96a66cSDavid du Colombier 
244*5e96a66cSDavid du Colombier 	if(strcmp(elem, ".") == 0){
245*5e96a66cSDavid du Colombier 		return fileIncRef(f);
246*5e96a66cSDavid du Colombier 	}
247*5e96a66cSDavid du Colombier 
248*5e96a66cSDavid du Colombier 	if(strcmp(elem, "..") == 0){
249*5e96a66cSDavid du Colombier 		if(fileIsRoot(f))
250*5e96a66cSDavid du Colombier 			return fileIncRef(f);
251*5e96a66cSDavid du Colombier 		return fileIncRef(f->up);
252*5e96a66cSDavid du Colombier 	}
253*5e96a66cSDavid du Colombier 
254*5e96a66cSDavid du Colombier 	if(!fileLock(f))
255*5e96a66cSDavid du Colombier 		return nil;
256*5e96a66cSDavid du Colombier 
257*5e96a66cSDavid du Colombier 	for(ff = f->down; ff; ff=ff->next){
258*5e96a66cSDavid du Colombier 		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
259*5e96a66cSDavid du Colombier 			ff->ref++;
260*5e96a66cSDavid du Colombier 			goto Exit;
261*5e96a66cSDavid du Colombier 		}
262*5e96a66cSDavid du Colombier 	}
263*5e96a66cSDavid du Colombier 
264*5e96a66cSDavid du Colombier 	ff = dirLookup(f, elem);
265*5e96a66cSDavid du Colombier 	if(ff == nil)
266*5e96a66cSDavid du Colombier 		goto Err;
267*5e96a66cSDavid du Colombier 
268*5e96a66cSDavid du Colombier 	if(ff->dir.mode & ModeSnapshot)
269*5e96a66cSDavid du Colombier 		ff->mode = OReadOnly;
270*5e96a66cSDavid du Colombier 
271*5e96a66cSDavid du Colombier 	if(partial){
272*5e96a66cSDavid du Colombier 		/*
273*5e96a66cSDavid du Colombier 		 * Do nothing.  We're opening this file only so we can clri it.
274*5e96a66cSDavid du Colombier 		 * Usually the sources can't be opened, hence we won't even bother.
275*5e96a66cSDavid du Colombier 		 * Be VERY careful with the returned file.  If you hand it to a routine
276*5e96a66cSDavid du Colombier 		 * expecting ff->source and/or ff->msource to be non-nil, we're
277*5e96a66cSDavid du Colombier 		 * likely to dereference nil.  FileClri should be the only routine
278*5e96a66cSDavid du Colombier 		 * setting partial.
279*5e96a66cSDavid du Colombier 		 */
280*5e96a66cSDavid du Colombier 		ff->partial = 1;
281*5e96a66cSDavid du Colombier 	}else if(ff->dir.mode & ModeDir){
282*5e96a66cSDavid du Colombier 		ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, 1, ff->mode);
283*5e96a66cSDavid du Colombier 		ff->msource = fileOpenSource(f, ff->dir.mentry, ff->dir.mgen, 0, ff->mode);
284*5e96a66cSDavid du Colombier 		if(ff->source == nil || ff->msource == nil)
285*5e96a66cSDavid du Colombier 			goto Err;
286*5e96a66cSDavid du Colombier 	}else{
287*5e96a66cSDavid du Colombier 		ff->source = fileOpenSource(f, ff->dir.entry, ff->dir.gen, 0, ff->mode);
288*5e96a66cSDavid du Colombier 		if(ff->source == nil)
289*5e96a66cSDavid du Colombier 			goto Err;
290*5e96a66cSDavid du Colombier 	}
291*5e96a66cSDavid du Colombier 
292*5e96a66cSDavid du Colombier 	/* link in and up parent ref count */
293*5e96a66cSDavid du Colombier 	ff->next = f->down;
294*5e96a66cSDavid du Colombier 	f->down = ff;
295*5e96a66cSDavid du Colombier 	ff->up = f;
296*5e96a66cSDavid du Colombier 	fileIncRef(f);
297*5e96a66cSDavid du Colombier Exit:
298*5e96a66cSDavid du Colombier 	fileUnlock(f);
299*5e96a66cSDavid du Colombier 	return ff;
300*5e96a66cSDavid du Colombier Err:
301*5e96a66cSDavid du Colombier 	fileUnlock(f);
302*5e96a66cSDavid du Colombier 	if(ff != nil)
303*5e96a66cSDavid du Colombier 		fileDecRef(ff);
304*5e96a66cSDavid du Colombier 	return nil;
305*5e96a66cSDavid du Colombier }
306*5e96a66cSDavid du Colombier 
307*5e96a66cSDavid du Colombier File *
308*5e96a66cSDavid du Colombier fileWalk(File *f, char *elem)
309*5e96a66cSDavid du Colombier {
310*5e96a66cSDavid du Colombier 	return _fileWalk(f, elem, 0);
311*5e96a66cSDavid du Colombier }
312*5e96a66cSDavid du Colombier 
313*5e96a66cSDavid du Colombier File *
314*5e96a66cSDavid du Colombier _fileOpen(Fs *fs, char *path, int partial)
315*5e96a66cSDavid du Colombier {
316*5e96a66cSDavid du Colombier 	File *f, *ff;
317*5e96a66cSDavid du Colombier 	char *p, elem[VtMaxStringSize];
318*5e96a66cSDavid du Colombier 	int n;
319*5e96a66cSDavid du Colombier 
320*5e96a66cSDavid du Colombier 	f = fs->file;
321*5e96a66cSDavid du Colombier 	fileIncRef(f);
322*5e96a66cSDavid du Colombier 	while(*path != 0){
323*5e96a66cSDavid du Colombier 		for(p = path; *p && *p != '/'; p++)
324*5e96a66cSDavid du Colombier 			;
325*5e96a66cSDavid du Colombier 		n = p - path;
326*5e96a66cSDavid du Colombier 		if(n > 0){
327*5e96a66cSDavid du Colombier 			if(n > VtMaxStringSize){
328*5e96a66cSDavid du Colombier 				vtSetError(EBadPath);
329*5e96a66cSDavid du Colombier 				goto Err;
330*5e96a66cSDavid du Colombier 			}
331*5e96a66cSDavid du Colombier 			memmove(elem, path, n);
332*5e96a66cSDavid du Colombier 			elem[n] = 0;
333*5e96a66cSDavid du Colombier 			ff = _fileWalk(f, elem, partial && *p=='\0');
334*5e96a66cSDavid du Colombier 			if(ff == nil)
335*5e96a66cSDavid du Colombier 				goto Err;
336*5e96a66cSDavid du Colombier 			fileDecRef(f);
337*5e96a66cSDavid du Colombier 			f = ff;
338*5e96a66cSDavid du Colombier 		}
339*5e96a66cSDavid du Colombier 		if(*p == '/')
340*5e96a66cSDavid du Colombier 			p++;
341*5e96a66cSDavid du Colombier 		path = p;
342*5e96a66cSDavid du Colombier 	}
343*5e96a66cSDavid du Colombier 	return f;
344*5e96a66cSDavid du Colombier Err:
345*5e96a66cSDavid du Colombier 	fileDecRef(f);
346*5e96a66cSDavid du Colombier 	return nil;
347*5e96a66cSDavid du Colombier }
348*5e96a66cSDavid du Colombier 
349*5e96a66cSDavid du Colombier File*
350*5e96a66cSDavid du Colombier fileOpen(Fs *fs, char *path)
351*5e96a66cSDavid du Colombier {
352*5e96a66cSDavid du Colombier 	return _fileOpen(fs, path, 0);
353*5e96a66cSDavid du Colombier }
354*5e96a66cSDavid du Colombier 
355*5e96a66cSDavid du Colombier File *
356*5e96a66cSDavid du Colombier fileCreate(File *f, char *elem, ulong mode, char *uid)
357*5e96a66cSDavid du Colombier {
358*5e96a66cSDavid du Colombier 	File *ff;
359*5e96a66cSDavid du Colombier 	DirEntry *dir;
360*5e96a66cSDavid du Colombier 	Source *pr, *r, *mr;
361*5e96a66cSDavid du Colombier 	int isdir;
362*5e96a66cSDavid du Colombier 
363*5e96a66cSDavid du Colombier 	if(!fileLock(f))
364*5e96a66cSDavid du Colombier 		return nil;
365*5e96a66cSDavid du Colombier 
366*5e96a66cSDavid du Colombier 	r = nil;
367*5e96a66cSDavid du Colombier 	mr = nil;
368*5e96a66cSDavid du Colombier 	for(ff = f->down; ff; ff=ff->next){
369*5e96a66cSDavid du Colombier 		if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){
370*5e96a66cSDavid du Colombier 			ff = nil;
371*5e96a66cSDavid du Colombier 			vtSetError(EExists);
372*5e96a66cSDavid du Colombier 			goto Err1;
373*5e96a66cSDavid du Colombier 		}
374*5e96a66cSDavid du Colombier 	}
375*5e96a66cSDavid du Colombier 
376*5e96a66cSDavid du Colombier 	ff = dirLookup(f, elem);
377*5e96a66cSDavid du Colombier 	if(ff != nil){
378*5e96a66cSDavid du Colombier 		vtSetError(EExists);
379*5e96a66cSDavid du Colombier 		goto Err1;
380*5e96a66cSDavid du Colombier 	}
381*5e96a66cSDavid du Colombier 
382*5e96a66cSDavid du Colombier 	pr = f->source;
383*5e96a66cSDavid du Colombier 	if(pr->mode != OReadWrite){
384*5e96a66cSDavid du Colombier 		vtSetError(EReadOnly);
385*5e96a66cSDavid du Colombier 		goto Err1;
386*5e96a66cSDavid du Colombier 	}
387*5e96a66cSDavid du Colombier 
388*5e96a66cSDavid du Colombier 	if(!sourceLock2(f->source, f->msource, -1))
389*5e96a66cSDavid du Colombier 		goto Err1;
390*5e96a66cSDavid du Colombier 
391*5e96a66cSDavid du Colombier 	ff = fileAlloc(f->fs);
392*5e96a66cSDavid du Colombier 	isdir = mode & ModeDir;
393*5e96a66cSDavid du Colombier 
394*5e96a66cSDavid du Colombier 	r = sourceCreate(pr, pr->dsize, isdir, 0);
395*5e96a66cSDavid du Colombier 	if(r == nil)
396*5e96a66cSDavid du Colombier 		goto Err;
397*5e96a66cSDavid du Colombier 	if(isdir){
398*5e96a66cSDavid du Colombier 		mr = sourceCreate(pr, pr->dsize, 0, r->offset);
399*5e96a66cSDavid du Colombier 		if(mr == nil)
400*5e96a66cSDavid du Colombier 			goto Err;
401*5e96a66cSDavid du Colombier 	}
402*5e96a66cSDavid du Colombier 
403*5e96a66cSDavid du Colombier 	dir = &ff->dir;
404*5e96a66cSDavid du Colombier 	dir->elem = vtStrDup(elem);
405*5e96a66cSDavid du Colombier 	dir->entry = r->offset;
406*5e96a66cSDavid du Colombier 	dir->gen = r->gen;
407*5e96a66cSDavid du Colombier 	if(isdir){
408*5e96a66cSDavid du Colombier 		dir->mentry = mr->offset;
409*5e96a66cSDavid du Colombier 		dir->mgen = mr->gen;
410*5e96a66cSDavid du Colombier 	}
411*5e96a66cSDavid du Colombier 	dir->size = 0;
412*5e96a66cSDavid du Colombier 	if(!fsNextQid(f->fs, &dir->qid))
413*5e96a66cSDavid du Colombier 		goto Err;
414*5e96a66cSDavid du Colombier 	dir->uid = vtStrDup(uid);
415*5e96a66cSDavid du Colombier 	dir->gid = vtStrDup(f->dir.gid);
416*5e96a66cSDavid du Colombier 	dir->mid = vtStrDup(uid);
417*5e96a66cSDavid du Colombier 	dir->mtime = time(0L);
418*5e96a66cSDavid du Colombier 	dir->mcount = 0;
419*5e96a66cSDavid du Colombier 	dir->ctime = dir->mtime;
420*5e96a66cSDavid du Colombier 	dir->atime = dir->mtime;
421*5e96a66cSDavid du Colombier 	dir->mode = mode;
422*5e96a66cSDavid du Colombier 
423*5e96a66cSDavid du Colombier 	ff->boff = fileMetaAlloc(f, dir, 0);
424*5e96a66cSDavid du Colombier 	if(ff->boff == NilBlock)
425*5e96a66cSDavid du Colombier 		goto Err;
426*5e96a66cSDavid du Colombier 
427*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
428*5e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
429*5e96a66cSDavid du Colombier 
430*5e96a66cSDavid du Colombier 	ff->source = r;
431*5e96a66cSDavid du Colombier 	ff->msource = mr;
432*5e96a66cSDavid du Colombier 
433*5e96a66cSDavid du Colombier 	/* link in and up parent ref count */
434*5e96a66cSDavid du Colombier 	ff->next = f->down;
435*5e96a66cSDavid du Colombier 	f->down = ff;
436*5e96a66cSDavid du Colombier 	ff->up = f;
437*5e96a66cSDavid du Colombier 	fileIncRef(f);
438*5e96a66cSDavid du Colombier 
439*5e96a66cSDavid du Colombier 	fileWAccess(f, uid);
440*5e96a66cSDavid du Colombier 
441*5e96a66cSDavid du Colombier 	fileUnlock(f);
442*5e96a66cSDavid du Colombier 	return ff;
443*5e96a66cSDavid du Colombier 
444*5e96a66cSDavid du Colombier Err:
445*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
446*5e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
447*5e96a66cSDavid du Colombier Err1:
448*5e96a66cSDavid du Colombier 	if(r)
449*5e96a66cSDavid du Colombier 		sourceRemove(r);
450*5e96a66cSDavid du Colombier 	if(mr)
451*5e96a66cSDavid du Colombier 		sourceRemove(mr);
452*5e96a66cSDavid du Colombier 	if(ff)
453*5e96a66cSDavid du Colombier 		fileDecRef(ff);
454*5e96a66cSDavid du Colombier 	fileUnlock(f);
455*5e96a66cSDavid du Colombier 	return 0;
456*5e96a66cSDavid du Colombier }
457*5e96a66cSDavid du Colombier 
458*5e96a66cSDavid du Colombier int
459*5e96a66cSDavid du Colombier fileRead(File *f, void *buf, int cnt, vlong offset)
460*5e96a66cSDavid du Colombier {
461*5e96a66cSDavid du Colombier 	Source *s;
462*5e96a66cSDavid du Colombier 	uvlong size;
463*5e96a66cSDavid du Colombier 	u32int bn;
464*5e96a66cSDavid du Colombier 	int off, dsize, n, nn;
465*5e96a66cSDavid du Colombier 	Block *b;
466*5e96a66cSDavid du Colombier 	uchar *p;
467*5e96a66cSDavid du Colombier 
468*5e96a66cSDavid du Colombier if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset);
469*5e96a66cSDavid du Colombier 
470*5e96a66cSDavid du Colombier 	if(!fileRLock(f))
471*5e96a66cSDavid du Colombier 		return -1;
472*5e96a66cSDavid du Colombier 
473*5e96a66cSDavid du Colombier 	if(offset < 0){
474*5e96a66cSDavid du Colombier 		vtSetError(EBadOffset);
475*5e96a66cSDavid du Colombier 		goto Err1;
476*5e96a66cSDavid du Colombier 	}
477*5e96a66cSDavid du Colombier 
478*5e96a66cSDavid du Colombier 	fileRAccess(f);
479*5e96a66cSDavid du Colombier 
480*5e96a66cSDavid du Colombier 	if(!sourceLock(f->source, OReadOnly))
481*5e96a66cSDavid du Colombier 		goto Err1;
482*5e96a66cSDavid du Colombier 
483*5e96a66cSDavid du Colombier 	s = f->source;
484*5e96a66cSDavid du Colombier 	dsize = s->dsize;
485*5e96a66cSDavid du Colombier 	size = sourceGetSize(s);
486*5e96a66cSDavid du Colombier 
487*5e96a66cSDavid du Colombier 	if(offset >= size)
488*5e96a66cSDavid du Colombier 		offset = size;
489*5e96a66cSDavid du Colombier 
490*5e96a66cSDavid du Colombier 	if(cnt > size-offset)
491*5e96a66cSDavid du Colombier 		cnt = size-offset;
492*5e96a66cSDavid du Colombier 	bn = offset/dsize;
493*5e96a66cSDavid du Colombier 	off = offset%dsize;
494*5e96a66cSDavid du Colombier 	p = buf;
495*5e96a66cSDavid du Colombier 	while(cnt > 0){
496*5e96a66cSDavid du Colombier 		b = sourceBlock(s, bn, OReadOnly);
497*5e96a66cSDavid du Colombier 		if(b == nil)
498*5e96a66cSDavid du Colombier 			goto Err;
499*5e96a66cSDavid du Colombier 		n = cnt;
500*5e96a66cSDavid du Colombier 		if(n > dsize-off)
501*5e96a66cSDavid du Colombier 			n = dsize-off;
502*5e96a66cSDavid du Colombier 		nn = dsize-off;
503*5e96a66cSDavid du Colombier 		if(nn > n)
504*5e96a66cSDavid du Colombier 			nn = n;
505*5e96a66cSDavid du Colombier 		memmove(p, b->data+off, nn);
506*5e96a66cSDavid du Colombier 		memset(p+nn, 0, nn-n);
507*5e96a66cSDavid du Colombier 		off = 0;
508*5e96a66cSDavid du Colombier 		bn++;
509*5e96a66cSDavid du Colombier 		cnt -= n;
510*5e96a66cSDavid du Colombier 		p += n;
511*5e96a66cSDavid du Colombier 		blockPut(b);
512*5e96a66cSDavid du Colombier 	}
513*5e96a66cSDavid du Colombier 	sourceUnlock(s);
514*5e96a66cSDavid du Colombier 	fileRUnlock(f);
515*5e96a66cSDavid du Colombier 	return p-(uchar*)buf;
516*5e96a66cSDavid du Colombier 
517*5e96a66cSDavid du Colombier Err:
518*5e96a66cSDavid du Colombier 	sourceUnlock(s);
519*5e96a66cSDavid du Colombier Err1:
520*5e96a66cSDavid du Colombier 	fileRUnlock(f);
521*5e96a66cSDavid du Colombier 	return -1;
522*5e96a66cSDavid du Colombier }
523*5e96a66cSDavid du Colombier 
524*5e96a66cSDavid du Colombier int
525*5e96a66cSDavid du Colombier fileWrite(File *f, void *buf, int cnt, vlong offset, char *uid)
526*5e96a66cSDavid du Colombier {
527*5e96a66cSDavid du Colombier 	Source *s;
528*5e96a66cSDavid du Colombier 	ulong bn;
529*5e96a66cSDavid du Colombier 	int off, dsize, n;
530*5e96a66cSDavid du Colombier 	Block *b;
531*5e96a66cSDavid du Colombier 	uchar *p;
532*5e96a66cSDavid du Colombier 	vlong eof;
533*5e96a66cSDavid du Colombier 
534*5e96a66cSDavid du Colombier if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset);
535*5e96a66cSDavid du Colombier 
536*5e96a66cSDavid du Colombier 	if(!fileLock(f))
537*5e96a66cSDavid du Colombier 		return -1;
538*5e96a66cSDavid du Colombier 
539*5e96a66cSDavid du Colombier 	s = nil;
540*5e96a66cSDavid du Colombier 	if(f->dir.mode & ModeDir){
541*5e96a66cSDavid du Colombier 		vtSetError(ENotFile);
542*5e96a66cSDavid du Colombier 		goto Err;
543*5e96a66cSDavid du Colombier 	}
544*5e96a66cSDavid du Colombier 
545*5e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
546*5e96a66cSDavid du Colombier 		vtSetError(EReadOnly);
547*5e96a66cSDavid du Colombier 		goto Err;
548*5e96a66cSDavid du Colombier 	}
549*5e96a66cSDavid du Colombier 	if(offset < 0){
550*5e96a66cSDavid du Colombier 		vtSetError(EBadOffset);
551*5e96a66cSDavid du Colombier 		goto Err;
552*5e96a66cSDavid du Colombier 	}
553*5e96a66cSDavid du Colombier 
554*5e96a66cSDavid du Colombier 	fileWAccess(f, uid);
555*5e96a66cSDavid du Colombier 
556*5e96a66cSDavid du Colombier 	if(!sourceLock(f->source, -1))
557*5e96a66cSDavid du Colombier 		goto Err;
558*5e96a66cSDavid du Colombier 	s = f->source;
559*5e96a66cSDavid du Colombier 	dsize = s->dsize;
560*5e96a66cSDavid du Colombier 
561*5e96a66cSDavid du Colombier 	eof = sourceGetSize(s);
562*5e96a66cSDavid du Colombier 	if(f->dir.mode & ModeAppend)
563*5e96a66cSDavid du Colombier 		offset = eof;
564*5e96a66cSDavid du Colombier 	bn = offset/dsize;
565*5e96a66cSDavid du Colombier 	off = offset%dsize;
566*5e96a66cSDavid du Colombier 	p = buf;
567*5e96a66cSDavid du Colombier 	while(cnt > 0){
568*5e96a66cSDavid du Colombier 		n = cnt;
569*5e96a66cSDavid du Colombier 		if(n > dsize-off)
570*5e96a66cSDavid du Colombier 			n = dsize-off;
571*5e96a66cSDavid du Colombier 		b = sourceBlock(s, bn, n<dsize?OReadWrite:OOverWrite);
572*5e96a66cSDavid du Colombier 		if(b == nil){
573*5e96a66cSDavid du Colombier 			if(offset > eof)
574*5e96a66cSDavid du Colombier 				sourceSetSize(s, offset);
575*5e96a66cSDavid du Colombier 			goto Err;
576*5e96a66cSDavid du Colombier 		}
577*5e96a66cSDavid du Colombier 		memmove(b->data+off, p, n);
578*5e96a66cSDavid du Colombier 		off = 0;
579*5e96a66cSDavid du Colombier 		cnt -= n;
580*5e96a66cSDavid du Colombier 		p += n;
581*5e96a66cSDavid du Colombier 		offset += n;
582*5e96a66cSDavid du Colombier 		bn++;
583*5e96a66cSDavid du Colombier 		blockDirty(b);
584*5e96a66cSDavid du Colombier 		blockPut(b);
585*5e96a66cSDavid du Colombier 	}
586*5e96a66cSDavid du Colombier 	if(offset > eof && !sourceSetSize(s, offset))
587*5e96a66cSDavid du Colombier 		goto Err;
588*5e96a66cSDavid du Colombier 	sourceUnlock(s);
589*5e96a66cSDavid du Colombier 	fileUnlock(f);
590*5e96a66cSDavid du Colombier 	return p-(uchar*)buf;
591*5e96a66cSDavid du Colombier Err:
592*5e96a66cSDavid du Colombier 	if(s)
593*5e96a66cSDavid du Colombier 		sourceUnlock(s);
594*5e96a66cSDavid du Colombier 	fileUnlock(f);
595*5e96a66cSDavid du Colombier 	return -1;
596*5e96a66cSDavid du Colombier }
597*5e96a66cSDavid du Colombier 
598*5e96a66cSDavid du Colombier int
599*5e96a66cSDavid du Colombier fileGetDir(File *f, DirEntry *dir)
600*5e96a66cSDavid du Colombier {
601*5e96a66cSDavid du Colombier 	if(!fileRLock(f))
602*5e96a66cSDavid du Colombier 		return 0;
603*5e96a66cSDavid du Colombier 
604*5e96a66cSDavid du Colombier 	fileMetaLock(f);
605*5e96a66cSDavid du Colombier 	deCopy(dir, &f->dir);
606*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
607*5e96a66cSDavid du Colombier 
608*5e96a66cSDavid du Colombier 	if(!fileIsDir(f)){
609*5e96a66cSDavid du Colombier 		if(!sourceLock(f->source, OReadOnly)){
610*5e96a66cSDavid du Colombier 			fileRUnlock(f);
611*5e96a66cSDavid du Colombier 			return 0;
612*5e96a66cSDavid du Colombier 		}
613*5e96a66cSDavid du Colombier 		dir->size = sourceGetSize(f->source);
614*5e96a66cSDavid du Colombier 		sourceUnlock(f->source);
615*5e96a66cSDavid du Colombier 	}
616*5e96a66cSDavid du Colombier 	fileRUnlock(f);
617*5e96a66cSDavid du Colombier 
618*5e96a66cSDavid du Colombier 	return 1;
619*5e96a66cSDavid du Colombier }
620*5e96a66cSDavid du Colombier 
621*5e96a66cSDavid du Colombier int
622*5e96a66cSDavid du Colombier fileTruncate(File *f, char *uid)
623*5e96a66cSDavid du Colombier {
624*5e96a66cSDavid du Colombier 	if(fileIsDir(f)){
625*5e96a66cSDavid du Colombier 		vtSetError(ENotFile);
626*5e96a66cSDavid du Colombier 		return 0;
627*5e96a66cSDavid du Colombier 	}
628*5e96a66cSDavid du Colombier 
629*5e96a66cSDavid du Colombier 	if(!fileLock(f))
630*5e96a66cSDavid du Colombier 		return 0;
631*5e96a66cSDavid du Colombier 
632*5e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
633*5e96a66cSDavid du Colombier 		vtSetError(EReadOnly);
634*5e96a66cSDavid du Colombier 		fileUnlock(f);
635*5e96a66cSDavid du Colombier 		return 0;
636*5e96a66cSDavid du Colombier 	}
637*5e96a66cSDavid du Colombier 	if(!sourceLock(f->source, -1)){
638*5e96a66cSDavid du Colombier 		fileUnlock(f);
639*5e96a66cSDavid du Colombier 		return 0;
640*5e96a66cSDavid du Colombier 	}
641*5e96a66cSDavid du Colombier 	if(!sourceTruncate(f->source)){
642*5e96a66cSDavid du Colombier 		sourceUnlock(f->source);
643*5e96a66cSDavid du Colombier 		fileUnlock(f);
644*5e96a66cSDavid du Colombier 		return 0;
645*5e96a66cSDavid du Colombier 	}
646*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
647*5e96a66cSDavid du Colombier 	fileUnlock(f);
648*5e96a66cSDavid du Colombier 
649*5e96a66cSDavid du Colombier 	fileWAccess(f->up, uid);
650*5e96a66cSDavid du Colombier 
651*5e96a66cSDavid du Colombier 	return 1;
652*5e96a66cSDavid du Colombier }
653*5e96a66cSDavid du Colombier 
654*5e96a66cSDavid du Colombier int
655*5e96a66cSDavid du Colombier fileSetDir(File *f, DirEntry *dir, char *uid)
656*5e96a66cSDavid du Colombier {
657*5e96a66cSDavid du Colombier 	File *ff;
658*5e96a66cSDavid du Colombier 	char *oelem;
659*5e96a66cSDavid du Colombier 	u32int mask;
660*5e96a66cSDavid du Colombier 	u64int size;
661*5e96a66cSDavid du Colombier 
662*5e96a66cSDavid du Colombier 	/* can not set permissions for the root */
663*5e96a66cSDavid du Colombier 	if(fileIsRoot(f)){
664*5e96a66cSDavid du Colombier 		vtSetError(ERoot);
665*5e96a66cSDavid du Colombier 		return 0;
666*5e96a66cSDavid du Colombier 	}
667*5e96a66cSDavid du Colombier 
668*5e96a66cSDavid du Colombier 	if(!fileLock(f))
669*5e96a66cSDavid du Colombier 		return 0;
670*5e96a66cSDavid du Colombier 
671*5e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
672*5e96a66cSDavid du Colombier 		vtSetError(EReadOnly);
673*5e96a66cSDavid du Colombier 		fileUnlock(f);
674*5e96a66cSDavid du Colombier 		return 0;
675*5e96a66cSDavid du Colombier 	}
676*5e96a66cSDavid du Colombier 
677*5e96a66cSDavid du Colombier 	fileMetaLock(f);
678*5e96a66cSDavid du Colombier 
679*5e96a66cSDavid du Colombier 	/* check new name does not already exist */
680*5e96a66cSDavid du Colombier 	if(strcmp(f->dir.elem, dir->elem) != 0){
681*5e96a66cSDavid du Colombier 		for(ff = f->up->down; ff; ff=ff->next){
682*5e96a66cSDavid du Colombier 			if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){
683*5e96a66cSDavid du Colombier 				vtSetError(EExists);
684*5e96a66cSDavid du Colombier 				goto Err;
685*5e96a66cSDavid du Colombier 			}
686*5e96a66cSDavid du Colombier 		}
687*5e96a66cSDavid du Colombier 
688*5e96a66cSDavid du Colombier 		ff = dirLookup(f->up, dir->elem);
689*5e96a66cSDavid du Colombier 		if(ff != nil){
690*5e96a66cSDavid du Colombier 			fileDecRef(ff);
691*5e96a66cSDavid du Colombier 			vtSetError(EExists);
692*5e96a66cSDavid du Colombier 			goto Err;
693*5e96a66cSDavid du Colombier 		}
694*5e96a66cSDavid du Colombier 	}
695*5e96a66cSDavid du Colombier 
696*5e96a66cSDavid du Colombier 	if(!fileIsDir(f)){
697*5e96a66cSDavid du Colombier 		if(!sourceLock(f->source, -1))
698*5e96a66cSDavid du Colombier 			goto Err;
699*5e96a66cSDavid du Colombier 		size = sourceGetSize(f->source);
700*5e96a66cSDavid du Colombier 		if(size != dir->size){
701*5e96a66cSDavid du Colombier 			if(!sourceSetSize(f->source, dir->size)){
702*5e96a66cSDavid du Colombier 				sourceUnlock(f->source);
703*5e96a66cSDavid du Colombier 				goto Err;
704*5e96a66cSDavid du Colombier 			}
705*5e96a66cSDavid du Colombier 			/* commited to changing it now */
706*5e96a66cSDavid du Colombier 		}
707*5e96a66cSDavid du Colombier 		sourceUnlock(f->source);
708*5e96a66cSDavid du Colombier 	}
709*5e96a66cSDavid du Colombier 
710*5e96a66cSDavid du Colombier 	/* commited to changing it now */
711*5e96a66cSDavid du Colombier 	oelem = nil;
712*5e96a66cSDavid du Colombier 	if(strcmp(f->dir.elem, dir->elem) != 0){
713*5e96a66cSDavid du Colombier 		oelem = f->dir.elem;
714*5e96a66cSDavid du Colombier 		f->dir.elem = vtStrDup(dir->elem);
715*5e96a66cSDavid du Colombier 	}
716*5e96a66cSDavid du Colombier 
717*5e96a66cSDavid du Colombier 	if(strcmp(f->dir.uid, dir->uid) != 0){
718*5e96a66cSDavid du Colombier 		vtMemFree(f->dir.uid);
719*5e96a66cSDavid du Colombier 		f->dir.uid = vtStrDup(dir->uid);
720*5e96a66cSDavid du Colombier 	}
721*5e96a66cSDavid du Colombier 
722*5e96a66cSDavid du Colombier 	if(strcmp(f->dir.gid, dir->gid) != 0){
723*5e96a66cSDavid du Colombier 		vtMemFree(f->dir.gid);
724*5e96a66cSDavid du Colombier 		f->dir.gid = vtStrDup(dir->gid);
725*5e96a66cSDavid du Colombier 	}
726*5e96a66cSDavid du Colombier 
727*5e96a66cSDavid du Colombier 	f->dir.mtime = dir->mtime;
728*5e96a66cSDavid du Colombier 	f->dir.atime = dir->atime;
729*5e96a66cSDavid du Colombier 
730*5e96a66cSDavid du Colombier //fprint(2, "mode %x %x ", f->dir.mode, dir->mode);
731*5e96a66cSDavid du Colombier 	mask = ~(ModeDir|ModeSnapshot);
732*5e96a66cSDavid du Colombier 	f->dir.mode &= ~mask;
733*5e96a66cSDavid du Colombier 	f->dir.mode |= mask & dir->mode;
734*5e96a66cSDavid du Colombier 	f->dirty = 1;
735*5e96a66cSDavid du Colombier //fprint(2, "->%x\n", f->dir.mode);
736*5e96a66cSDavid du Colombier 
737*5e96a66cSDavid du Colombier 	fileMetaFlush2(f, oelem);
738*5e96a66cSDavid du Colombier 	vtMemFree(oelem);
739*5e96a66cSDavid du Colombier 
740*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
741*5e96a66cSDavid du Colombier 	fileUnlock(f);
742*5e96a66cSDavid du Colombier 
743*5e96a66cSDavid du Colombier 	fileWAccess(f->up, uid);
744*5e96a66cSDavid du Colombier 
745*5e96a66cSDavid du Colombier 	return 1;
746*5e96a66cSDavid du Colombier Err:
747*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
748*5e96a66cSDavid du Colombier 	fileUnlock(f);
749*5e96a66cSDavid du Colombier 	return 0;
750*5e96a66cSDavid du Colombier }
751*5e96a66cSDavid du Colombier 
752*5e96a66cSDavid du Colombier int
753*5e96a66cSDavid du Colombier fileSetQidSpace(File *f, u64int offset, u64int max)
754*5e96a66cSDavid du Colombier {
755*5e96a66cSDavid du Colombier 	int ret;
756*5e96a66cSDavid du Colombier 
757*5e96a66cSDavid du Colombier 	if(!fileLock(f))
758*5e96a66cSDavid du Colombier 		return 0;
759*5e96a66cSDavid du Colombier 	fileMetaLock(f);
760*5e96a66cSDavid du Colombier 	f->dir.qidSpace = 1;
761*5e96a66cSDavid du Colombier 	f->dir.qidOffset = offset;
762*5e96a66cSDavid du Colombier 	f->dir.qidMax = max;
763*5e96a66cSDavid du Colombier 	ret = fileMetaFlush2(f, nil);
764*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
765*5e96a66cSDavid du Colombier 	fileUnlock(f);
766*5e96a66cSDavid du Colombier 	return ret;
767*5e96a66cSDavid du Colombier }
768*5e96a66cSDavid du Colombier 
769*5e96a66cSDavid du Colombier 
770*5e96a66cSDavid du Colombier uvlong
771*5e96a66cSDavid du Colombier fileGetId(File *f)
772*5e96a66cSDavid du Colombier {
773*5e96a66cSDavid du Colombier 	/* immutable */
774*5e96a66cSDavid du Colombier 	return f->dir.qid;
775*5e96a66cSDavid du Colombier }
776*5e96a66cSDavid du Colombier 
777*5e96a66cSDavid du Colombier ulong
778*5e96a66cSDavid du Colombier fileGetMcount(File *f)
779*5e96a66cSDavid du Colombier {
780*5e96a66cSDavid du Colombier 	ulong mcount;
781*5e96a66cSDavid du Colombier 
782*5e96a66cSDavid du Colombier 	fileMetaLock(f);
783*5e96a66cSDavid du Colombier 	mcount = f->dir.mcount;
784*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
785*5e96a66cSDavid du Colombier 	return mcount;
786*5e96a66cSDavid du Colombier }
787*5e96a66cSDavid du Colombier 
788*5e96a66cSDavid du Colombier ulong
789*5e96a66cSDavid du Colombier fileGetMode(File *f)
790*5e96a66cSDavid du Colombier {
791*5e96a66cSDavid du Colombier 	ulong mode;
792*5e96a66cSDavid du Colombier 
793*5e96a66cSDavid du Colombier 	fileMetaLock(f);
794*5e96a66cSDavid du Colombier 	mode = f->dir.mode;
795*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
796*5e96a66cSDavid du Colombier 	return mode;
797*5e96a66cSDavid du Colombier }
798*5e96a66cSDavid du Colombier 
799*5e96a66cSDavid du Colombier int
800*5e96a66cSDavid du Colombier fileIsDir(File *f)
801*5e96a66cSDavid du Colombier {
802*5e96a66cSDavid du Colombier 	/* immutable */
803*5e96a66cSDavid du Colombier 	return (f->dir.mode & ModeDir) != 0;
804*5e96a66cSDavid du Colombier }
805*5e96a66cSDavid du Colombier 
806*5e96a66cSDavid du Colombier int
807*5e96a66cSDavid du Colombier fileIsRoot(File *f)
808*5e96a66cSDavid du Colombier {
809*5e96a66cSDavid du Colombier 	return f == f->fs->file;
810*5e96a66cSDavid du Colombier }
811*5e96a66cSDavid du Colombier 
812*5e96a66cSDavid du Colombier int
813*5e96a66cSDavid du Colombier fileIsRoFs(File *f)
814*5e96a66cSDavid du Colombier {
815*5e96a66cSDavid du Colombier 	return f->fs->mode == OReadOnly;
816*5e96a66cSDavid du Colombier }
817*5e96a66cSDavid du Colombier 
818*5e96a66cSDavid du Colombier int
819*5e96a66cSDavid du Colombier fileGetSize(File *f, uvlong *size)
820*5e96a66cSDavid du Colombier {
821*5e96a66cSDavid du Colombier 	if(!fileRLock(f))
822*5e96a66cSDavid du Colombier 		return 0;
823*5e96a66cSDavid du Colombier 	if(!sourceLock(f->source, OReadOnly)){
824*5e96a66cSDavid du Colombier 		fileRUnlock(f);
825*5e96a66cSDavid du Colombier 		return 0;
826*5e96a66cSDavid du Colombier 	}
827*5e96a66cSDavid du Colombier 	*size = sourceGetSize(f->source);
828*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
829*5e96a66cSDavid du Colombier 	fileRUnlock(f);
830*5e96a66cSDavid du Colombier 
831*5e96a66cSDavid du Colombier 	return 1;
832*5e96a66cSDavid du Colombier }
833*5e96a66cSDavid du Colombier 
834*5e96a66cSDavid du Colombier void
835*5e96a66cSDavid du Colombier fileMetaFlush(File *f, int rec)
836*5e96a66cSDavid du Colombier {
837*5e96a66cSDavid du Colombier 	File **kids, *p;
838*5e96a66cSDavid du Colombier 	int nkids;
839*5e96a66cSDavid du Colombier 	int i;
840*5e96a66cSDavid du Colombier 
841*5e96a66cSDavid du Colombier 	fileMetaLock(f);
842*5e96a66cSDavid du Colombier 	fileMetaFlush2(f, nil);
843*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
844*5e96a66cSDavid du Colombier 
845*5e96a66cSDavid du Colombier 	if(!rec || !fileIsDir(f))
846*5e96a66cSDavid du Colombier 		return;
847*5e96a66cSDavid du Colombier 
848*5e96a66cSDavid du Colombier 	if(!fileLock(f))
849*5e96a66cSDavid du Colombier 		return;
850*5e96a66cSDavid du Colombier 	nkids = 0;
851*5e96a66cSDavid du Colombier 	for(p=f->down; p; p=p->next)
852*5e96a66cSDavid du Colombier 		nkids++;
853*5e96a66cSDavid du Colombier 	kids = vtMemAlloc(nkids*sizeof(File*));
854*5e96a66cSDavid du Colombier 	i = 0;
855*5e96a66cSDavid du Colombier 	for(p=f->down; p; p=p->next){
856*5e96a66cSDavid du Colombier 		kids[i++] = p;
857*5e96a66cSDavid du Colombier 		p->ref++;
858*5e96a66cSDavid du Colombier 	}
859*5e96a66cSDavid du Colombier 	fileUnlock(f);
860*5e96a66cSDavid du Colombier 
861*5e96a66cSDavid du Colombier 	for(i=0; i<nkids; i++){
862*5e96a66cSDavid du Colombier 		fileMetaFlush(kids[i], 1);
863*5e96a66cSDavid du Colombier 		fileDecRef(kids[i]);
864*5e96a66cSDavid du Colombier 	}
865*5e96a66cSDavid du Colombier 	vtMemFree(kids);
866*5e96a66cSDavid du Colombier }
867*5e96a66cSDavid du Colombier 
868*5e96a66cSDavid du Colombier /* assumes metaLock is held */
869*5e96a66cSDavid du Colombier static int
870*5e96a66cSDavid du Colombier fileMetaFlush2(File *f, char *oelem)
871*5e96a66cSDavid du Colombier {
872*5e96a66cSDavid du Colombier 	File *fp;
873*5e96a66cSDavid du Colombier 	Block *b, *bb;
874*5e96a66cSDavid du Colombier 	MetaBlock mb;
875*5e96a66cSDavid du Colombier 	MetaEntry me, me2;
876*5e96a66cSDavid du Colombier 	int i, n;
877*5e96a66cSDavid du Colombier 	u32int boff;
878*5e96a66cSDavid du Colombier 
879*5e96a66cSDavid du Colombier 	if(!f->dirty)
880*5e96a66cSDavid du Colombier 		return 1;
881*5e96a66cSDavid du Colombier 
882*5e96a66cSDavid du Colombier 	if(oelem == nil)
883*5e96a66cSDavid du Colombier 		oelem = f->dir.elem;
884*5e96a66cSDavid du Colombier 
885*5e96a66cSDavid du Colombier //print("fileMetaFlush %s->%s\n", oelem, f->dir.elem);
886*5e96a66cSDavid du Colombier 
887*5e96a66cSDavid du Colombier 	fp = f->up;
888*5e96a66cSDavid du Colombier 
889*5e96a66cSDavid du Colombier 	if(!sourceLock(fp->msource, -1))
890*5e96a66cSDavid du Colombier 		return 0;
891*5e96a66cSDavid du Colombier 	b = sourceBlock(fp->msource, f->boff, OReadWrite);
892*5e96a66cSDavid du Colombier 	if(b == nil)
893*5e96a66cSDavid du Colombier 		goto Err1;
894*5e96a66cSDavid du Colombier 
895*5e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, fp->msource->dsize))
896*5e96a66cSDavid du Colombier 		goto Err;
897*5e96a66cSDavid du Colombier 	if(!mbSearch(&mb, oelem, &i, &me))
898*5e96a66cSDavid du Colombier 		goto Err;
899*5e96a66cSDavid du Colombier 
900*5e96a66cSDavid du Colombier 	n = deSize(&f->dir);
901*5e96a66cSDavid du Colombier if(0)fprint(2, "old size %d new size %d\n", me.size, n);
902*5e96a66cSDavid du Colombier 
903*5e96a66cSDavid du Colombier 	if(mbResize(&mb, &me, n)){
904*5e96a66cSDavid du Colombier 		/* fits in the block */
905*5e96a66cSDavid du Colombier 		mbDelete(&mb, i);
906*5e96a66cSDavid du Colombier 		if(strcmp(f->dir.elem, oelem) != 0)
907*5e96a66cSDavid du Colombier 			mbSearch(&mb, f->dir.elem, &i, &me2);
908*5e96a66cSDavid du Colombier 		dePack(&f->dir, &me);
909*5e96a66cSDavid du Colombier 		mbInsert(&mb, i, &me);
910*5e96a66cSDavid du Colombier 		mbPack(&mb);
911*5e96a66cSDavid du Colombier 		blockDirty(b);
912*5e96a66cSDavid du Colombier 		blockPut(b);
913*5e96a66cSDavid du Colombier 		sourceUnlock(fp->msource);
914*5e96a66cSDavid du Colombier 		f->dirty = 0;
915*5e96a66cSDavid du Colombier 
916*5e96a66cSDavid du Colombier 		return 1;
917*5e96a66cSDavid du Colombier 	}
918*5e96a66cSDavid du Colombier 
919*5e96a66cSDavid du Colombier 	/*
920*5e96a66cSDavid du Colombier 	 * moving entry to another block
921*5e96a66cSDavid du Colombier 	 * it is feasible for the fs to crash leaving two copies
922*5e96a66cSDavid du Colombier 	 * of the directory entry.  This is just too much work to
923*5e96a66cSDavid du Colombier 	 * fix.  Given that entries are only allocated in a block that
924*5e96a66cSDavid du Colombier 	 * is less than PercentageFull, most modifications of meta data
925*5e96a66cSDavid du Colombier 	 * will fit within the block.  i.e. this code should almost
926*5e96a66cSDavid du Colombier 	 * never be executed.
927*5e96a66cSDavid du Colombier 	 */
928*5e96a66cSDavid du Colombier 	boff = fileMetaAlloc(fp, &f->dir, f->boff+1);
929*5e96a66cSDavid du Colombier 	if(boff == NilBlock){
930*5e96a66cSDavid du Colombier 		/* mbResize might have modified block */
931*5e96a66cSDavid du Colombier 		mbPack(&mb);
932*5e96a66cSDavid du Colombier 		blockDirty(b);
933*5e96a66cSDavid du Colombier 		goto Err;
934*5e96a66cSDavid du Colombier 	}
935*5e96a66cSDavid du Colombier fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff);
936*5e96a66cSDavid du Colombier 	f->boff = boff;
937*5e96a66cSDavid du Colombier 
938*5e96a66cSDavid du Colombier 	/* make sure deletion goes to disk after new entry */
939*5e96a66cSDavid du Colombier 	bb = sourceBlock(fp->msource, f->boff, OReadWrite);
940*5e96a66cSDavid du Colombier 	mbDelete(&mb, i);
941*5e96a66cSDavid du Colombier 	mbPack(&mb);
942*5e96a66cSDavid du Colombier 	blockDependency(b, bb, -1, nil);
943*5e96a66cSDavid du Colombier 	blockPut(bb);
944*5e96a66cSDavid du Colombier 	blockDirty(b);
945*5e96a66cSDavid du Colombier 	blockPut(b);
946*5e96a66cSDavid du Colombier 	sourceUnlock(fp->msource);
947*5e96a66cSDavid du Colombier 
948*5e96a66cSDavid du Colombier 	f->dirty = 0;
949*5e96a66cSDavid du Colombier 
950*5e96a66cSDavid du Colombier 	return 1;
951*5e96a66cSDavid du Colombier 
952*5e96a66cSDavid du Colombier Err:
953*5e96a66cSDavid du Colombier 	blockPut(b);
954*5e96a66cSDavid du Colombier Err1:
955*5e96a66cSDavid du Colombier 	sourceUnlock(fp->msource);
956*5e96a66cSDavid du Colombier 	return 0;
957*5e96a66cSDavid du Colombier }
958*5e96a66cSDavid du Colombier 
959*5e96a66cSDavid du Colombier static int
960*5e96a66cSDavid du Colombier fileMetaRemove(File *f, char *uid)
961*5e96a66cSDavid du Colombier {
962*5e96a66cSDavid du Colombier 	Block *b;
963*5e96a66cSDavid du Colombier 	MetaBlock mb;
964*5e96a66cSDavid du Colombier 	MetaEntry me;
965*5e96a66cSDavid du Colombier 	int i;
966*5e96a66cSDavid du Colombier 	File *up;
967*5e96a66cSDavid du Colombier 
968*5e96a66cSDavid du Colombier 	up = f->up;
969*5e96a66cSDavid du Colombier 
970*5e96a66cSDavid du Colombier 	fileWAccess(up, uid);
971*5e96a66cSDavid du Colombier 
972*5e96a66cSDavid du Colombier 	fileMetaLock(f);
973*5e96a66cSDavid du Colombier 
974*5e96a66cSDavid du Colombier 	sourceLock(up->msource, OReadWrite);
975*5e96a66cSDavid du Colombier 	b = sourceBlock(up->msource, f->boff, OReadWrite);
976*5e96a66cSDavid du Colombier 	if(b == nil)
977*5e96a66cSDavid du Colombier 		goto Err;
978*5e96a66cSDavid du Colombier 
979*5e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, up->msource->dsize))
980*5e96a66cSDavid du Colombier {
981*5e96a66cSDavid du Colombier fprint(2, "U\n");
982*5e96a66cSDavid du Colombier 		goto Err;
983*5e96a66cSDavid du Colombier }
984*5e96a66cSDavid du Colombier 	if(!mbSearch(&mb, f->dir.elem, &i, &me))
985*5e96a66cSDavid du Colombier {
986*5e96a66cSDavid du Colombier fprint(2, "S\n");
987*5e96a66cSDavid du Colombier 		goto Err;
988*5e96a66cSDavid du Colombier }
989*5e96a66cSDavid du Colombier 	mbDelete(&mb, i);
990*5e96a66cSDavid du Colombier 	mbPack(&mb);
991*5e96a66cSDavid du Colombier 	sourceUnlock(up->msource);
992*5e96a66cSDavid du Colombier 
993*5e96a66cSDavid du Colombier 	blockDirty(b);
994*5e96a66cSDavid du Colombier 	blockPut(b);
995*5e96a66cSDavid du Colombier 
996*5e96a66cSDavid du Colombier 	f->removed = 1;
997*5e96a66cSDavid du Colombier 	f->boff = NilBlock;
998*5e96a66cSDavid du Colombier 	f->dirty = 0;
999*5e96a66cSDavid du Colombier 
1000*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
1001*5e96a66cSDavid du Colombier 	return 1;
1002*5e96a66cSDavid du Colombier 
1003*5e96a66cSDavid du Colombier Err:
1004*5e96a66cSDavid du Colombier 	sourceUnlock(up->msource);
1005*5e96a66cSDavid du Colombier 	blockPut(b);
1006*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
1007*5e96a66cSDavid du Colombier 	return 0;
1008*5e96a66cSDavid du Colombier }
1009*5e96a66cSDavid du Colombier 
1010*5e96a66cSDavid du Colombier /* assume file is locked, assume f->msource is locked */
1011*5e96a66cSDavid du Colombier static int
1012*5e96a66cSDavid du Colombier fileCheckEmpty(File *f)
1013*5e96a66cSDavid du Colombier {
1014*5e96a66cSDavid du Colombier 	u32int i, n;
1015*5e96a66cSDavid du Colombier 	Block *b;
1016*5e96a66cSDavid du Colombier 	MetaBlock mb;
1017*5e96a66cSDavid du Colombier 	Source *r;
1018*5e96a66cSDavid du Colombier 
1019*5e96a66cSDavid du Colombier 	r = f->msource;
1020*5e96a66cSDavid du Colombier 	n = (sourceGetSize(r)+r->dsize-1)/r->dsize;
1021*5e96a66cSDavid du Colombier 	for(i=0; i<n; i++){
1022*5e96a66cSDavid du Colombier 		b = sourceBlock(r, i, OReadOnly);
1023*5e96a66cSDavid du Colombier 		if(b == nil)
1024*5e96a66cSDavid du Colombier 			goto Err;
1025*5e96a66cSDavid du Colombier 		if(!mbUnpack(&mb, b->data, r->dsize))
1026*5e96a66cSDavid du Colombier 			goto Err;
1027*5e96a66cSDavid du Colombier 		if(mb.nindex > 0){
1028*5e96a66cSDavid du Colombier 			vtSetError(ENotEmpty);
1029*5e96a66cSDavid du Colombier 			goto Err;
1030*5e96a66cSDavid du Colombier 		}
1031*5e96a66cSDavid du Colombier 		blockPut(b);
1032*5e96a66cSDavid du Colombier 	}
1033*5e96a66cSDavid du Colombier 	return 1;
1034*5e96a66cSDavid du Colombier Err:
1035*5e96a66cSDavid du Colombier 	blockPut(b);
1036*5e96a66cSDavid du Colombier 	return 0;
1037*5e96a66cSDavid du Colombier }
1038*5e96a66cSDavid du Colombier 
1039*5e96a66cSDavid du Colombier int
1040*5e96a66cSDavid du Colombier fileRemove(File *f, char *uid)
1041*5e96a66cSDavid du Colombier {
1042*5e96a66cSDavid du Colombier 	File *ff;
1043*5e96a66cSDavid du Colombier 
1044*5e96a66cSDavid du Colombier 	/* can not remove the root */
1045*5e96a66cSDavid du Colombier 	if(fileIsRoot(f)){
1046*5e96a66cSDavid du Colombier 		vtSetError(ERoot);
1047*5e96a66cSDavid du Colombier 		return 0;
1048*5e96a66cSDavid du Colombier 	}
1049*5e96a66cSDavid du Colombier 
1050*5e96a66cSDavid du Colombier 	if(!fileLock(f))
1051*5e96a66cSDavid du Colombier 		return 0;
1052*5e96a66cSDavid du Colombier 
1053*5e96a66cSDavid du Colombier 	if(f->source->mode != OReadWrite){
1054*5e96a66cSDavid du Colombier 		vtSetError(EReadOnly);
1055*5e96a66cSDavid du Colombier 		goto Err1;
1056*5e96a66cSDavid du Colombier 	}
1057*5e96a66cSDavid du Colombier 	if(!sourceLock2(f->source, f->msource, -1))
1058*5e96a66cSDavid du Colombier 		goto Err1;
1059*5e96a66cSDavid du Colombier 	if(fileIsDir(f) && !fileCheckEmpty(f))
1060*5e96a66cSDavid du Colombier 		goto Err;
1061*5e96a66cSDavid du Colombier 
1062*5e96a66cSDavid du Colombier 	for(ff=f->down; ff; ff=ff->next)
1063*5e96a66cSDavid du Colombier 		assert(ff->removed);
1064*5e96a66cSDavid du Colombier 
1065*5e96a66cSDavid du Colombier 	sourceRemove(f->source);
1066*5e96a66cSDavid du Colombier 	f->source = nil;
1067*5e96a66cSDavid du Colombier 	if(f->msource){
1068*5e96a66cSDavid du Colombier 		sourceRemove(f->msource);
1069*5e96a66cSDavid du Colombier 		f->msource = nil;
1070*5e96a66cSDavid du Colombier 	}
1071*5e96a66cSDavid du Colombier 
1072*5e96a66cSDavid du Colombier 	fileUnlock(f);
1073*5e96a66cSDavid du Colombier 
1074*5e96a66cSDavid du Colombier 	if(!fileMetaRemove(f, uid))
1075*5e96a66cSDavid du Colombier 		return 0;
1076*5e96a66cSDavid du Colombier 
1077*5e96a66cSDavid du Colombier 	return 1;
1078*5e96a66cSDavid du Colombier 
1079*5e96a66cSDavid du Colombier Err:
1080*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
1081*5e96a66cSDavid du Colombier 	if(f->msource)
1082*5e96a66cSDavid du Colombier 		sourceUnlock(f->msource);
1083*5e96a66cSDavid du Colombier Err1:
1084*5e96a66cSDavid du Colombier 	fileUnlock(f);
1085*5e96a66cSDavid du Colombier 	return 0;
1086*5e96a66cSDavid du Colombier }
1087*5e96a66cSDavid du Colombier 
1088*5e96a66cSDavid du Colombier int
1089*5e96a66cSDavid du Colombier fileClri(Fs *fs, char *path, char *uid)
1090*5e96a66cSDavid du Colombier {
1091*5e96a66cSDavid du Colombier 	int r;
1092*5e96a66cSDavid du Colombier 	File *f;
1093*5e96a66cSDavid du Colombier 
1094*5e96a66cSDavid du Colombier 	f = _fileOpen(fs, path, 1);
1095*5e96a66cSDavid du Colombier 	if(f == nil)
1096*5e96a66cSDavid du Colombier 		return 0;
1097*5e96a66cSDavid du Colombier 	if(f->up->source->mode != OReadWrite){
1098*5e96a66cSDavid du Colombier 		vtSetError(EReadOnly);
1099*5e96a66cSDavid du Colombier 		fileDecRef(f);
1100*5e96a66cSDavid du Colombier 		return 0;
1101*5e96a66cSDavid du Colombier 	}
1102*5e96a66cSDavid du Colombier 	r = fileMetaRemove(f, uid);
1103*5e96a66cSDavid du Colombier 	fileDecRef(f);
1104*5e96a66cSDavid du Colombier 	return r;
1105*5e96a66cSDavid du Colombier }
1106*5e96a66cSDavid du Colombier 
1107*5e96a66cSDavid du Colombier File *
1108*5e96a66cSDavid du Colombier fileIncRef(File *vf)
1109*5e96a66cSDavid du Colombier {
1110*5e96a66cSDavid du Colombier 	fileMetaLock(vf);
1111*5e96a66cSDavid du Colombier 	assert(vf->ref > 0);
1112*5e96a66cSDavid du Colombier 	vf->ref++;
1113*5e96a66cSDavid du Colombier 	fileMetaUnlock(vf);
1114*5e96a66cSDavid du Colombier 	return vf;
1115*5e96a66cSDavid du Colombier }
1116*5e96a66cSDavid du Colombier 
1117*5e96a66cSDavid du Colombier int
1118*5e96a66cSDavid du Colombier fileDecRef(File *f)
1119*5e96a66cSDavid du Colombier {
1120*5e96a66cSDavid du Colombier 	File *p, *q, **qq;
1121*5e96a66cSDavid du Colombier 
1122*5e96a66cSDavid du Colombier 	if(f->up == nil){
1123*5e96a66cSDavid du Colombier 		/* never linked in */
1124*5e96a66cSDavid du Colombier 		assert(f->ref == 1);
1125*5e96a66cSDavid du Colombier 		fileFree(f);
1126*5e96a66cSDavid du Colombier 		return 1;
1127*5e96a66cSDavid du Colombier 	}
1128*5e96a66cSDavid du Colombier 
1129*5e96a66cSDavid du Colombier 	fileMetaLock(f);
1130*5e96a66cSDavid du Colombier 	f->ref--;
1131*5e96a66cSDavid du Colombier 	if(f->ref > 0){
1132*5e96a66cSDavid du Colombier 		fileMetaUnlock(f);
1133*5e96a66cSDavid du Colombier 		return 0;
1134*5e96a66cSDavid du Colombier 	}
1135*5e96a66cSDavid du Colombier 	assert(f->ref == 0);
1136*5e96a66cSDavid du Colombier 	assert(f->down == nil);
1137*5e96a66cSDavid du Colombier 
1138*5e96a66cSDavid du Colombier 	fileMetaFlush2(f, nil);
1139*5e96a66cSDavid du Colombier 
1140*5e96a66cSDavid du Colombier 	p = f->up;
1141*5e96a66cSDavid du Colombier 	qq = &p->down;
1142*5e96a66cSDavid du Colombier 	for(q = *qq; q; q = *qq){
1143*5e96a66cSDavid du Colombier 		if(q == f)
1144*5e96a66cSDavid du Colombier 			break;
1145*5e96a66cSDavid du Colombier 		qq = &q->next;
1146*5e96a66cSDavid du Colombier 	}
1147*5e96a66cSDavid du Colombier 	assert(q != nil);
1148*5e96a66cSDavid du Colombier 	*qq = f->next;
1149*5e96a66cSDavid du Colombier 
1150*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
1151*5e96a66cSDavid du Colombier 	fileFree(f);
1152*5e96a66cSDavid du Colombier 
1153*5e96a66cSDavid du Colombier 	fileDecRef(p);
1154*5e96a66cSDavid du Colombier 	return 1;
1155*5e96a66cSDavid du Colombier }
1156*5e96a66cSDavid du Colombier 
1157*5e96a66cSDavid du Colombier File *
1158*5e96a66cSDavid du Colombier fileGetParent(File *f)
1159*5e96a66cSDavid du Colombier {
1160*5e96a66cSDavid du Colombier 	if(fileIsRoot(f))
1161*5e96a66cSDavid du Colombier 		return fileIncRef(f);
1162*5e96a66cSDavid du Colombier 	return fileIncRef(f->up);
1163*5e96a66cSDavid du Colombier }
1164*5e96a66cSDavid du Colombier 
1165*5e96a66cSDavid du Colombier DirEntryEnum *
1166*5e96a66cSDavid du Colombier deeOpen(File *f)
1167*5e96a66cSDavid du Colombier {
1168*5e96a66cSDavid du Colombier 	DirEntryEnum *dee;
1169*5e96a66cSDavid du Colombier 	File *p;
1170*5e96a66cSDavid du Colombier 
1171*5e96a66cSDavid du Colombier 	if(!fileIsDir(f)){
1172*5e96a66cSDavid du Colombier 		vtSetError(ENotDir);
1173*5e96a66cSDavid du Colombier 		fileDecRef(f);
1174*5e96a66cSDavid du Colombier 		return nil;
1175*5e96a66cSDavid du Colombier 	}
1176*5e96a66cSDavid du Colombier 
1177*5e96a66cSDavid du Colombier 	/* flush out meta data */
1178*5e96a66cSDavid du Colombier 	if(!fileLock(f))
1179*5e96a66cSDavid du Colombier 		return nil;
1180*5e96a66cSDavid du Colombier 	for(p=f->down; p; p=p->next)
1181*5e96a66cSDavid du Colombier 		fileMetaFlush2(p, nil);
1182*5e96a66cSDavid du Colombier 	fileUnlock(f);
1183*5e96a66cSDavid du Colombier 
1184*5e96a66cSDavid du Colombier 	dee = vtMemAllocZ(sizeof(DirEntryEnum));
1185*5e96a66cSDavid du Colombier 	dee->file = fileIncRef(f);
1186*5e96a66cSDavid du Colombier 
1187*5e96a66cSDavid du Colombier 	return dee;
1188*5e96a66cSDavid du Colombier }
1189*5e96a66cSDavid du Colombier 
1190*5e96a66cSDavid du Colombier static int
1191*5e96a66cSDavid du Colombier dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size)
1192*5e96a66cSDavid du Colombier {
1193*5e96a66cSDavid du Colombier 	Block *b;
1194*5e96a66cSDavid du Colombier 	ulong bn;
1195*5e96a66cSDavid du Colombier 	Entry e;
1196*5e96a66cSDavid du Colombier 	int epb;
1197*5e96a66cSDavid du Colombier 
1198*5e96a66cSDavid du Colombier 	epb = s->dsize/VtEntrySize;
1199*5e96a66cSDavid du Colombier 	bn = elem/epb;
1200*5e96a66cSDavid du Colombier 	elem -= bn*epb;
1201*5e96a66cSDavid du Colombier 
1202*5e96a66cSDavid du Colombier 	b = sourceBlock(s, bn, OReadOnly);
1203*5e96a66cSDavid du Colombier 	if(b == nil)
1204*5e96a66cSDavid du Colombier 		goto Err;
1205*5e96a66cSDavid du Colombier 	if(!entryUnpack(&e, b->data, elem))
1206*5e96a66cSDavid du Colombier 		goto Err;
1207*5e96a66cSDavid du Colombier 
1208*5e96a66cSDavid du Colombier 	/* hanging entries are returned as zero size */
1209*5e96a66cSDavid du Colombier 	if(!(e.flags & VtEntryActive) || e.gen != gen)
1210*5e96a66cSDavid du Colombier 		*size = 0;
1211*5e96a66cSDavid du Colombier 	else
1212*5e96a66cSDavid du Colombier 		*size = e.size;
1213*5e96a66cSDavid du Colombier 	blockPut(b);
1214*5e96a66cSDavid du Colombier 	return 1;
1215*5e96a66cSDavid du Colombier 
1216*5e96a66cSDavid du Colombier Err:
1217*5e96a66cSDavid du Colombier 	blockPut(b);
1218*5e96a66cSDavid du Colombier 	return 0;
1219*5e96a66cSDavid du Colombier }
1220*5e96a66cSDavid du Colombier 
1221*5e96a66cSDavid du Colombier static int
1222*5e96a66cSDavid du Colombier deeFill(DirEntryEnum *dee)
1223*5e96a66cSDavid du Colombier {
1224*5e96a66cSDavid du Colombier 	int i, n;
1225*5e96a66cSDavid du Colombier 	Source *meta, *source;
1226*5e96a66cSDavid du Colombier 	MetaBlock mb;
1227*5e96a66cSDavid du Colombier 	MetaEntry me;
1228*5e96a66cSDavid du Colombier 	File *f;
1229*5e96a66cSDavid du Colombier 	Block *b;
1230*5e96a66cSDavid du Colombier 	DirEntry *de;
1231*5e96a66cSDavid du Colombier 
1232*5e96a66cSDavid du Colombier 	/* clean up first */
1233*5e96a66cSDavid du Colombier 	for(i=dee->i; i<dee->n; i++)
1234*5e96a66cSDavid du Colombier 		deCleanup(dee->buf+i);
1235*5e96a66cSDavid du Colombier 	vtMemFree(dee->buf);
1236*5e96a66cSDavid du Colombier 	dee->buf = nil;
1237*5e96a66cSDavid du Colombier 	dee->i = 0;
1238*5e96a66cSDavid du Colombier 	dee->n = 0;
1239*5e96a66cSDavid du Colombier 
1240*5e96a66cSDavid du Colombier 	f = dee->file;
1241*5e96a66cSDavid du Colombier 
1242*5e96a66cSDavid du Colombier 	source = f->source;
1243*5e96a66cSDavid du Colombier 	meta = f->msource;
1244*5e96a66cSDavid du Colombier 
1245*5e96a66cSDavid du Colombier 	b = sourceBlock(meta, dee->boff, OReadOnly);
1246*5e96a66cSDavid du Colombier 	if(b == nil)
1247*5e96a66cSDavid du Colombier 		goto Err;
1248*5e96a66cSDavid du Colombier 	if(!mbUnpack(&mb, b->data, meta->dsize))
1249*5e96a66cSDavid du Colombier 		goto Err;
1250*5e96a66cSDavid du Colombier 
1251*5e96a66cSDavid du Colombier 	n = mb.nindex;
1252*5e96a66cSDavid du Colombier 	dee->buf = vtMemAlloc(n * sizeof(DirEntry));
1253*5e96a66cSDavid du Colombier 
1254*5e96a66cSDavid du Colombier 	for(i=0; i<n; i++){
1255*5e96a66cSDavid du Colombier 		de = dee->buf + i;
1256*5e96a66cSDavid du Colombier 		meUnpack(&me, &mb, i);
1257*5e96a66cSDavid du Colombier 		if(!deUnpack(de, &me))
1258*5e96a66cSDavid du Colombier 			goto Err;
1259*5e96a66cSDavid du Colombier 		dee->n++;
1260*5e96a66cSDavid du Colombier 		if(!(de->mode & ModeDir))
1261*5e96a66cSDavid du Colombier 		if(!dirEntrySize(source, de->entry, de->gen, &de->size))
1262*5e96a66cSDavid du Colombier 			goto Err;
1263*5e96a66cSDavid du Colombier 	}
1264*5e96a66cSDavid du Colombier 	dee->boff++;
1265*5e96a66cSDavid du Colombier 	blockPut(b);
1266*5e96a66cSDavid du Colombier 	return 1;
1267*5e96a66cSDavid du Colombier Err:
1268*5e96a66cSDavid du Colombier 	blockPut(b);
1269*5e96a66cSDavid du Colombier 	return 0;
1270*5e96a66cSDavid du Colombier }
1271*5e96a66cSDavid du Colombier 
1272*5e96a66cSDavid du Colombier int
1273*5e96a66cSDavid du Colombier deeRead(DirEntryEnum *dee, DirEntry *de)
1274*5e96a66cSDavid du Colombier {
1275*5e96a66cSDavid du Colombier 	int ret, didread;
1276*5e96a66cSDavid du Colombier 	File *f;
1277*5e96a66cSDavid du Colombier 	u32int nb;
1278*5e96a66cSDavid du Colombier 
1279*5e96a66cSDavid du Colombier 	f = dee->file;
1280*5e96a66cSDavid du Colombier 	if(!fileRLock(f))
1281*5e96a66cSDavid du Colombier 		return -1;
1282*5e96a66cSDavid du Colombier 
1283*5e96a66cSDavid du Colombier 	if(!sourceLock2(f->source, f->msource, OReadOnly)){
1284*5e96a66cSDavid du Colombier 		fileRUnlock(f);
1285*5e96a66cSDavid du Colombier 		return -1;
1286*5e96a66cSDavid du Colombier 	}
1287*5e96a66cSDavid du Colombier 
1288*5e96a66cSDavid du Colombier 	nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize;
1289*5e96a66cSDavid du Colombier 
1290*5e96a66cSDavid du Colombier 	didread = 0;
1291*5e96a66cSDavid du Colombier 	while(dee->i >= dee->n){
1292*5e96a66cSDavid du Colombier 		if(dee->boff >= nb){
1293*5e96a66cSDavid du Colombier 			ret = 0;
1294*5e96a66cSDavid du Colombier 			goto Return;
1295*5e96a66cSDavid du Colombier 		}
1296*5e96a66cSDavid du Colombier 		didread = 1;
1297*5e96a66cSDavid du Colombier 		if(!deeFill(dee)){
1298*5e96a66cSDavid du Colombier 			ret = -1;
1299*5e96a66cSDavid du Colombier 			goto Return;
1300*5e96a66cSDavid du Colombier 		}
1301*5e96a66cSDavid du Colombier 	}
1302*5e96a66cSDavid du Colombier 
1303*5e96a66cSDavid du Colombier 	memmove(de, dee->buf + dee->i, sizeof(DirEntry));
1304*5e96a66cSDavid du Colombier 	dee->i++;
1305*5e96a66cSDavid du Colombier 	ret = 1;
1306*5e96a66cSDavid du Colombier 
1307*5e96a66cSDavid du Colombier Return:
1308*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
1309*5e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
1310*5e96a66cSDavid du Colombier 	fileRUnlock(f);
1311*5e96a66cSDavid du Colombier 
1312*5e96a66cSDavid du Colombier 	if(didread)
1313*5e96a66cSDavid du Colombier 		fileRAccess(f);
1314*5e96a66cSDavid du Colombier 	return ret;
1315*5e96a66cSDavid du Colombier }
1316*5e96a66cSDavid du Colombier 
1317*5e96a66cSDavid du Colombier void
1318*5e96a66cSDavid du Colombier deeClose(DirEntryEnum *dee)
1319*5e96a66cSDavid du Colombier {
1320*5e96a66cSDavid du Colombier 	int i;
1321*5e96a66cSDavid du Colombier 	if(dee == nil)
1322*5e96a66cSDavid du Colombier 		return;
1323*5e96a66cSDavid du Colombier 	for(i=dee->i; i<dee->n; i++)
1324*5e96a66cSDavid du Colombier 		deCleanup(dee->buf+i);
1325*5e96a66cSDavid du Colombier 	vtMemFree(dee->buf);
1326*5e96a66cSDavid du Colombier 	fileDecRef(dee->file);
1327*5e96a66cSDavid du Colombier 	vtMemFree(dee);
1328*5e96a66cSDavid du Colombier }
1329*5e96a66cSDavid du Colombier 
1330*5e96a66cSDavid du Colombier /*
1331*5e96a66cSDavid du Colombier  * caller must lock f->source and f->msource
1332*5e96a66cSDavid du Colombier  * caller must NOT lock the source and msource
1333*5e96a66cSDavid du Colombier  * referenced by dir.
1334*5e96a66cSDavid du Colombier  */
1335*5e96a66cSDavid du Colombier static u32int
1336*5e96a66cSDavid du Colombier fileMetaAlloc(File *f, DirEntry *dir, u32int start)
1337*5e96a66cSDavid du Colombier {
1338*5e96a66cSDavid du Colombier 	u32int nb, bo;
1339*5e96a66cSDavid du Colombier 	Block *b, *bb;
1340*5e96a66cSDavid du Colombier 	MetaBlock mb;
1341*5e96a66cSDavid du Colombier 	int nn;
1342*5e96a66cSDavid du Colombier 	uchar *p;
1343*5e96a66cSDavid du Colombier 	int i, n, epb;
1344*5e96a66cSDavid du Colombier 	MetaEntry me;
1345*5e96a66cSDavid du Colombier 	Source *s, *ms;
1346*5e96a66cSDavid du Colombier 
1347*5e96a66cSDavid du Colombier 	s = f->source;
1348*5e96a66cSDavid du Colombier 	ms = f->msource;
1349*5e96a66cSDavid du Colombier 
1350*5e96a66cSDavid du Colombier 	n = deSize(dir);
1351*5e96a66cSDavid du Colombier 	nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize;
1352*5e96a66cSDavid du Colombier 	b = nil;
1353*5e96a66cSDavid du Colombier 	if(start > nb)
1354*5e96a66cSDavid du Colombier 		start = nb;
1355*5e96a66cSDavid du Colombier 	for(bo=start; bo<nb; bo++){
1356*5e96a66cSDavid du Colombier 		b = sourceBlock(ms, bo, OReadWrite);
1357*5e96a66cSDavid du Colombier 		if(b == nil)
1358*5e96a66cSDavid du Colombier 			goto Err;
1359*5e96a66cSDavid du Colombier 		if(!mbUnpack(&mb, b->data, ms->dsize))
1360*5e96a66cSDavid du Colombier 			goto Err;
1361*5e96a66cSDavid du Colombier 		nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free;
1362*5e96a66cSDavid du Colombier 		if(n <= nn && mb.nindex < mb.maxindex)
1363*5e96a66cSDavid du Colombier 			break;
1364*5e96a66cSDavid du Colombier 		blockPut(b);
1365*5e96a66cSDavid du Colombier 		b = nil;
1366*5e96a66cSDavid du Colombier 	}
1367*5e96a66cSDavid du Colombier 
1368*5e96a66cSDavid du Colombier 	/* add block to meta file */
1369*5e96a66cSDavid du Colombier 	if(b == nil){
1370*5e96a66cSDavid du Colombier 		b = sourceBlock(ms, bo, OReadWrite);
1371*5e96a66cSDavid du Colombier 		if(b == nil)
1372*5e96a66cSDavid du Colombier 			goto Err;
1373*5e96a66cSDavid du Colombier 		sourceSetSize(ms, (nb+1)*ms->dsize);
1374*5e96a66cSDavid du Colombier 		mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry);
1375*5e96a66cSDavid du Colombier 	}
1376*5e96a66cSDavid du Colombier 
1377*5e96a66cSDavid du Colombier 	p = mbAlloc(&mb, n);
1378*5e96a66cSDavid du Colombier 	if(p == nil){
1379*5e96a66cSDavid du Colombier 		/* mbAlloc might have changed block */
1380*5e96a66cSDavid du Colombier 		mbPack(&mb);
1381*5e96a66cSDavid du Colombier 		blockDirty(b);
1382*5e96a66cSDavid du Colombier 		vtSetError(EBadMeta);
1383*5e96a66cSDavid du Colombier 		goto Err;
1384*5e96a66cSDavid du Colombier 	}
1385*5e96a66cSDavid du Colombier 
1386*5e96a66cSDavid du Colombier 	mbSearch(&mb, dir->elem, &i, &me);
1387*5e96a66cSDavid du Colombier 	assert(me.p == nil);
1388*5e96a66cSDavid du Colombier 	me.p = p;
1389*5e96a66cSDavid du Colombier 	me.size = n;
1390*5e96a66cSDavid du Colombier 	dePack(dir, &me);
1391*5e96a66cSDavid du Colombier 	mbInsert(&mb, i, &me);
1392*5e96a66cSDavid du Colombier 	mbPack(&mb);
1393*5e96a66cSDavid du Colombier 
1394*5e96a66cSDavid du Colombier 	/* meta block depends on super block for qid ... */
1395*5e96a66cSDavid du Colombier 	bb = cacheLocal(b->c, PartSuper, 0, OReadOnly);
1396*5e96a66cSDavid du Colombier 	blockDependency(b, bb, -1, nil);
1397*5e96a66cSDavid du Colombier 	blockPut(bb);
1398*5e96a66cSDavid du Colombier 
1399*5e96a66cSDavid du Colombier 	/* ... and one or two dir entries */
1400*5e96a66cSDavid du Colombier 	epb = s->dsize/VtEntrySize;
1401*5e96a66cSDavid du Colombier 	bb = sourceBlock(s, dir->entry/epb, OReadOnly);
1402*5e96a66cSDavid du Colombier 	blockDependency(b, bb, -1, nil);
1403*5e96a66cSDavid du Colombier 	blockPut(bb);
1404*5e96a66cSDavid du Colombier 	if(dir->mode & ModeDir){
1405*5e96a66cSDavid du Colombier 		bb = sourceBlock(s, dir->mentry/epb, OReadOnly);
1406*5e96a66cSDavid du Colombier 		blockDependency(b, bb, -1, nil);
1407*5e96a66cSDavid du Colombier 		blockPut(bb);
1408*5e96a66cSDavid du Colombier 	}
1409*5e96a66cSDavid du Colombier 
1410*5e96a66cSDavid du Colombier 	blockDirty(b);
1411*5e96a66cSDavid du Colombier 	blockPut(b);
1412*5e96a66cSDavid du Colombier 	return bo;
1413*5e96a66cSDavid du Colombier Err:
1414*5e96a66cSDavid du Colombier 	blockPut(b);
1415*5e96a66cSDavid du Colombier 	return NilBlock;
1416*5e96a66cSDavid du Colombier }
1417*5e96a66cSDavid du Colombier 
1418*5e96a66cSDavid du Colombier static int
1419*5e96a66cSDavid du Colombier chkSource(File *f)
1420*5e96a66cSDavid du Colombier {
1421*5e96a66cSDavid du Colombier 	if(f->partial)
1422*5e96a66cSDavid du Colombier 		return 1;
1423*5e96a66cSDavid du Colombier 
1424*5e96a66cSDavid du Colombier 	if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){
1425*5e96a66cSDavid du Colombier 		vtSetError(ERemoved);
1426*5e96a66cSDavid du Colombier 		return 0;
1427*5e96a66cSDavid du Colombier 	}
1428*5e96a66cSDavid du Colombier 	return 1;
1429*5e96a66cSDavid du Colombier }
1430*5e96a66cSDavid du Colombier 
1431*5e96a66cSDavid du Colombier static int
1432*5e96a66cSDavid du Colombier fileRLock(File *f)
1433*5e96a66cSDavid du Colombier {
1434*5e96a66cSDavid du Colombier 	assert(!vtCanLock(f->fs->elk));
1435*5e96a66cSDavid du Colombier 	vtRLock(f->lk);
1436*5e96a66cSDavid du Colombier 	if(!chkSource(f)){
1437*5e96a66cSDavid du Colombier 		fileRUnlock(f);
1438*5e96a66cSDavid du Colombier 		return 0;
1439*5e96a66cSDavid du Colombier 	}
1440*5e96a66cSDavid du Colombier 	return 1;
1441*5e96a66cSDavid du Colombier }
1442*5e96a66cSDavid du Colombier 
1443*5e96a66cSDavid du Colombier static void
1444*5e96a66cSDavid du Colombier fileRUnlock(File *f)
1445*5e96a66cSDavid du Colombier {
1446*5e96a66cSDavid du Colombier 	vtRUnlock(f->lk);
1447*5e96a66cSDavid du Colombier }
1448*5e96a66cSDavid du Colombier 
1449*5e96a66cSDavid du Colombier static int
1450*5e96a66cSDavid du Colombier fileLock(File *f)
1451*5e96a66cSDavid du Colombier {
1452*5e96a66cSDavid du Colombier 	assert(!vtCanLock(f->fs->elk));
1453*5e96a66cSDavid du Colombier 	vtLock(f->lk);
1454*5e96a66cSDavid du Colombier 	if(!chkSource(f)){
1455*5e96a66cSDavid du Colombier 		fileUnlock(f);
1456*5e96a66cSDavid du Colombier 		return 0;
1457*5e96a66cSDavid du Colombier 	}
1458*5e96a66cSDavid du Colombier 	return 1;
1459*5e96a66cSDavid du Colombier }
1460*5e96a66cSDavid du Colombier 
1461*5e96a66cSDavid du Colombier static void
1462*5e96a66cSDavid du Colombier fileUnlock(File *f)
1463*5e96a66cSDavid du Colombier {
1464*5e96a66cSDavid du Colombier 	vtUnlock(f->lk);
1465*5e96a66cSDavid du Colombier }
1466*5e96a66cSDavid du Colombier 
1467*5e96a66cSDavid du Colombier /*
1468*5e96a66cSDavid du Colombier  * f->source and f->msource must NOT be locked.
1469*5e96a66cSDavid du Colombier  * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2).
1470*5e96a66cSDavid du Colombier  * We have to respect that ordering.
1471*5e96a66cSDavid du Colombier  */
1472*5e96a66cSDavid du Colombier static void
1473*5e96a66cSDavid du Colombier fileMetaLock(File *f)
1474*5e96a66cSDavid du Colombier {
1475*5e96a66cSDavid du Colombier if(f->up == nil)
1476*5e96a66cSDavid du Colombier fprint(2, "f->elem = %s\n", f->dir.elem);
1477*5e96a66cSDavid du Colombier 	assert(f->up != nil);
1478*5e96a66cSDavid du Colombier 	assert(!vtCanLock(f->fs->elk));
1479*5e96a66cSDavid du Colombier 	vtLock(f->up->lk);
1480*5e96a66cSDavid du Colombier }
1481*5e96a66cSDavid du Colombier 
1482*5e96a66cSDavid du Colombier static void
1483*5e96a66cSDavid du Colombier fileMetaUnlock(File *f)
1484*5e96a66cSDavid du Colombier {
1485*5e96a66cSDavid du Colombier 	vtUnlock(f->up->lk);
1486*5e96a66cSDavid du Colombier }
1487*5e96a66cSDavid du Colombier 
1488*5e96a66cSDavid du Colombier /*
1489*5e96a66cSDavid du Colombier  * f->source and f->msource must NOT be locked.
1490*5e96a66cSDavid du Colombier  * see fileMetaLock.
1491*5e96a66cSDavid du Colombier  */
1492*5e96a66cSDavid du Colombier static void
1493*5e96a66cSDavid du Colombier fileRAccess(File* f)
1494*5e96a66cSDavid du Colombier {
1495*5e96a66cSDavid du Colombier 	if(f->mode == OReadOnly)
1496*5e96a66cSDavid du Colombier 		return;
1497*5e96a66cSDavid du Colombier 
1498*5e96a66cSDavid du Colombier 	fileMetaLock(f);
1499*5e96a66cSDavid du Colombier 	f->dir.atime = time(0L);
1500*5e96a66cSDavid du Colombier 	f->dirty = 1;
1501*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
1502*5e96a66cSDavid du Colombier }
1503*5e96a66cSDavid du Colombier 
1504*5e96a66cSDavid du Colombier /*
1505*5e96a66cSDavid du Colombier  * f->source and f->msource must NOT be locked.
1506*5e96a66cSDavid du Colombier  * see fileMetaLock.
1507*5e96a66cSDavid du Colombier  */
1508*5e96a66cSDavid du Colombier static void
1509*5e96a66cSDavid du Colombier fileWAccess(File* f, char *mid)
1510*5e96a66cSDavid du Colombier {
1511*5e96a66cSDavid du Colombier 	if(f->mode == OReadOnly)
1512*5e96a66cSDavid du Colombier 		return;
1513*5e96a66cSDavid du Colombier 
1514*5e96a66cSDavid du Colombier 	fileMetaLock(f);
1515*5e96a66cSDavid du Colombier 	f->dir.atime = f->dir.mtime = time(0L);
1516*5e96a66cSDavid du Colombier 	if(strcmp(f->dir.mid, mid) != 0){
1517*5e96a66cSDavid du Colombier 		vtMemFree(f->dir.mid);
1518*5e96a66cSDavid du Colombier 		f->dir.mid = vtStrDup(mid);
1519*5e96a66cSDavid du Colombier 	}
1520*5e96a66cSDavid du Colombier 	f->dir.mcount++;
1521*5e96a66cSDavid du Colombier 	f->dirty = 1;
1522*5e96a66cSDavid du Colombier 	fileMetaUnlock(f);
1523*5e96a66cSDavid du Colombier }
1524*5e96a66cSDavid du Colombier 
1525*5e96a66cSDavid du Colombier static void
1526*5e96a66cSDavid du Colombier markCopied(Block *b)
1527*5e96a66cSDavid du Colombier {
1528*5e96a66cSDavid du Colombier 	Block *lb;
1529*5e96a66cSDavid du Colombier 	Label l;
1530*5e96a66cSDavid du Colombier 
1531*5e96a66cSDavid du Colombier 	if(globalToLocal(b->score) == NilBlock)
1532*5e96a66cSDavid du Colombier 		return;
1533*5e96a66cSDavid du Colombier 
1534*5e96a66cSDavid du Colombier 	if(!(b->l.state & BsCopied)){
1535*5e96a66cSDavid du Colombier 		/*
1536*5e96a66cSDavid du Colombier 		 * We need to record that there are now pointers in
1537*5e96a66cSDavid du Colombier 		 * b that are not unique to b.  We do this by marking
1538*5e96a66cSDavid du Colombier 		 * b as copied.  Since we don't return the label block,
1539*5e96a66cSDavid du Colombier 		 * the caller can't get the dependencies right.  So we have
1540*5e96a66cSDavid du Colombier 		 * to flush the block ourselves.  This is a rare occurrence.
1541*5e96a66cSDavid du Colombier 		 */
1542*5e96a66cSDavid du Colombier 		l = b->l;
1543*5e96a66cSDavid du Colombier 		l.state |= BsCopied;
1544*5e96a66cSDavid du Colombier 		lb = _blockSetLabel(b, &l);
1545*5e96a66cSDavid du Colombier 	WriteAgain:
1546*5e96a66cSDavid du Colombier 		while(!blockWrite(lb)){
1547*5e96a66cSDavid du Colombier 			fprint(2, "getEntry: could not write label block\n");
1548*5e96a66cSDavid du Colombier 			sleep(10*1000);
1549*5e96a66cSDavid du Colombier 		}
1550*5e96a66cSDavid du Colombier 		while(lb->iostate != BioClean && lb->iostate != BioDirty){
1551*5e96a66cSDavid du Colombier 			assert(lb->iostate == BioWriting);
1552*5e96a66cSDavid du Colombier 			vtSleep(lb->ioready);
1553*5e96a66cSDavid du Colombier 		}
1554*5e96a66cSDavid du Colombier 		if(lb->iostate == BioDirty)
1555*5e96a66cSDavid du Colombier 			goto WriteAgain;
1556*5e96a66cSDavid du Colombier 		blockPut(lb);
1557*5e96a66cSDavid du Colombier 	}
1558*5e96a66cSDavid du Colombier }
1559*5e96a66cSDavid du Colombier 
1560*5e96a66cSDavid du Colombier static int
1561*5e96a66cSDavid du Colombier getEntry(Source *r, Entry *e, int mark)
1562*5e96a66cSDavid du Colombier {
1563*5e96a66cSDavid du Colombier 	Block *b;
1564*5e96a66cSDavid du Colombier 
1565*5e96a66cSDavid du Colombier 	if(r == nil){
1566*5e96a66cSDavid du Colombier 		memset(&e, 0, sizeof e);
1567*5e96a66cSDavid du Colombier 		return 1;
1568*5e96a66cSDavid du Colombier 	}
1569*5e96a66cSDavid du Colombier 
1570*5e96a66cSDavid du Colombier 	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly);
1571*5e96a66cSDavid du Colombier 	if(b == nil)
1572*5e96a66cSDavid du Colombier 		return 0;
1573*5e96a66cSDavid du Colombier 	if(!entryUnpack(e, b->data, r->offset % r->epb)){
1574*5e96a66cSDavid du Colombier 		blockPut(b);
1575*5e96a66cSDavid du Colombier 		return 0;
1576*5e96a66cSDavid du Colombier 	}
1577*5e96a66cSDavid du Colombier 
1578*5e96a66cSDavid du Colombier 	if(mark)
1579*5e96a66cSDavid du Colombier 		markCopied(b);
1580*5e96a66cSDavid du Colombier 	blockPut(b);
1581*5e96a66cSDavid du Colombier 	return 1;
1582*5e96a66cSDavid du Colombier }
1583*5e96a66cSDavid du Colombier 
1584*5e96a66cSDavid du Colombier static int
1585*5e96a66cSDavid du Colombier setEntry(Source *r, Entry *e)
1586*5e96a66cSDavid du Colombier {
1587*5e96a66cSDavid du Colombier 	Block *b;
1588*5e96a66cSDavid du Colombier 	Entry oe;
1589*5e96a66cSDavid du Colombier 
1590*5e96a66cSDavid du Colombier 	b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite);
1591*5e96a66cSDavid du Colombier 	if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score);
1592*5e96a66cSDavid du Colombier 	if(b == nil)
1593*5e96a66cSDavid du Colombier 		return 0;
1594*5e96a66cSDavid du Colombier 	if(!entryUnpack(&oe, b->data, r->offset % r->epb)){
1595*5e96a66cSDavid du Colombier 		blockPut(b);
1596*5e96a66cSDavid du Colombier 		return 0;
1597*5e96a66cSDavid du Colombier 	}
1598*5e96a66cSDavid du Colombier 	e->gen = oe.gen;
1599*5e96a66cSDavid du Colombier 	entryPack(e, b->data, r->offset % r->epb);
1600*5e96a66cSDavid du Colombier 
1601*5e96a66cSDavid du Colombier 	/* BUG b should depend on the entry pointer */
1602*5e96a66cSDavid du Colombier 
1603*5e96a66cSDavid du Colombier 	markCopied(b);
1604*5e96a66cSDavid du Colombier 	blockDirty(b);
1605*5e96a66cSDavid du Colombier 	blockPut(b);
1606*5e96a66cSDavid du Colombier 	return 1;
1607*5e96a66cSDavid du Colombier }
1608*5e96a66cSDavid du Colombier 
1609*5e96a66cSDavid du Colombier /* assumes hold elk */
1610*5e96a66cSDavid du Colombier int
1611*5e96a66cSDavid du Colombier fileSnapshot(File *dst, File *src, u32int epoch, int doarchive)
1612*5e96a66cSDavid du Colombier {
1613*5e96a66cSDavid du Colombier 	Entry e, ee;
1614*5e96a66cSDavid du Colombier 
1615*5e96a66cSDavid du Colombier 	/* add link to snapshot */
1616*5e96a66cSDavid du Colombier 	if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1))
1617*5e96a66cSDavid du Colombier 		return 0;
1618*5e96a66cSDavid du Colombier 
1619*5e96a66cSDavid du Colombier 	e.snap = epoch;
1620*5e96a66cSDavid du Colombier 	e.archive = doarchive;
1621*5e96a66cSDavid du Colombier 	ee.snap = epoch;
1622*5e96a66cSDavid du Colombier 	ee.archive = doarchive;
1623*5e96a66cSDavid du Colombier 
1624*5e96a66cSDavid du Colombier 	if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee))
1625*5e96a66cSDavid du Colombier 		return 0;
1626*5e96a66cSDavid du Colombier 	return 1;
1627*5e96a66cSDavid du Colombier }
1628*5e96a66cSDavid du Colombier 
1629*5e96a66cSDavid du Colombier int
1630*5e96a66cSDavid du Colombier fileGetSources(File *f, Entry *e, Entry *ee, int mark)
1631*5e96a66cSDavid du Colombier {
1632*5e96a66cSDavid du Colombier 	if(!getEntry(f->source, e, mark)
1633*5e96a66cSDavid du Colombier 	|| !getEntry(f->msource, ee, mark))
1634*5e96a66cSDavid du Colombier 		return 0;
1635*5e96a66cSDavid du Colombier 	return 1;
1636*5e96a66cSDavid du Colombier }
1637*5e96a66cSDavid du Colombier 
1638*5e96a66cSDavid du Colombier int
1639*5e96a66cSDavid du Colombier fileWalkSources(File *f)
1640*5e96a66cSDavid du Colombier {
1641*5e96a66cSDavid du Colombier 	if(f->mode == OReadOnly)
1642*5e96a66cSDavid du Colombier 		return 1;
1643*5e96a66cSDavid du Colombier 	if(!sourceLock2(f->source, f->msource, OReadWrite))
1644*5e96a66cSDavid du Colombier 		return 0;
1645*5e96a66cSDavid du Colombier 	sourceUnlock(f->source);
1646*5e96a66cSDavid du Colombier 	sourceUnlock(f->msource);
1647*5e96a66cSDavid du Colombier 	return 1;
1648*5e96a66cSDavid du Colombier }
1649