Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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