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 *
fileAlloc(Fs * fs)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
fileFree(File * f)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 *
dirLookup(File * f,char * elem)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 *
fileRoot(Source * r)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 *
fileOpenSource(File * f,u32int offset,u32int gen,int dir,uint mode,int issnapshot)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 *
_fileWalk(File * f,char * elem,int partial)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 *
fileWalk(File * f,char * elem)329 fileWalk(File *f, char *elem)
330 {
331 return _fileWalk(f, elem, 0);
332 }
333
334 File *
_fileOpen(Fs * fs,char * path,int partial)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*
fileOpen(Fs * fs,char * path)375 fileOpen(Fs *fs, char *path)
376 {
377 return _fileOpen(fs, path, 0);
378 }
379
380 static void
fileSetTmp(File * f,int istmp)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 *
fileCreate(File * f,char * elem,ulong mode,char * uid)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
fileRead(File * f,void * buf,int cnt,vlong offset)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
fileMapBlock(File * f,ulong bn,uchar score[VtScoreSize],ulong tag)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
fileSetSize(File * f,uvlong size)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
fileWrite(File * f,void * buf,int cnt,vlong offset,char * uid)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
fileGetDir(File * f,DirEntry * dir)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
fileTruncate(File * f,char * uid)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
fileSetDir(File * f,DirEntry * dir,char * uid)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
fileSetQidSpace(File * f,u64int offset,u64int max)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
fileGetId(File * f)928 fileGetId(File *f)
929 {
930 /* immutable */
931 return f->dir.qid;
932 }
933
934 ulong
fileGetMcount(File * f)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
fileGetMode(File * f)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
fileIsDir(File * f)957 fileIsDir(File *f)
958 {
959 /* immutable */
960 return (f->dir.mode & ModeDir) != 0;
961 }
962
963 int
fileIsAppend(File * f)964 fileIsAppend(File *f)
965 {
966 return (f->dir.mode & ModeAppend) != 0;
967 }
968
969 int
fileIsExclusive(File * f)970 fileIsExclusive(File *f)
971 {
972 return (f->dir.mode & ModeExclusive) != 0;
973 }
974
975 int
fileIsTemporary(File * f)976 fileIsTemporary(File *f)
977 {
978 return (f->dir.mode & ModeTemporary) != 0;
979 }
980
981 int
fileIsRoot(File * f)982 fileIsRoot(File *f)
983 {
984 return f == f->fs->file;
985 }
986
987 int
fileIsRoFs(File * f)988 fileIsRoFs(File *f)
989 {
990 return f->fs->mode == OReadOnly;
991 }
992
993 int
fileGetSize(File * f,uvlong * size)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
fileMetaFlush(File * f,int rec)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
fileMetaFlush2(File * f,char * oelem)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
fileMetaRemove(File * f,char * uid)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
fileCheckEmpty(File * f)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
fileRemove(File * f,char * uid)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
clri(File * f,char * uid)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
fileClriPath(Fs * fs,char * path,char * uid)1286 fileClriPath(Fs *fs, char *path, char *uid)
1287 {
1288 return clri(_fileOpen(fs, path, 1), uid);
1289 }
1290
1291 int
fileClri(File * dir,char * elem,char * uid)1292 fileClri(File *dir, char *elem, char *uid)
1293 {
1294 return clri(_fileWalk(dir, elem, 1), uid);
1295 }
1296
1297 File *
fileIncRef(File * vf)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
fileDecRef(File * f)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 *
fileGetParent(File * f)1348 fileGetParent(File *f)
1349 {
1350 if(fileIsRoot(f))
1351 return fileIncRef(f);
1352 return fileIncRef(f->up);
1353 }
1354
1355 DirEntryEnum *
deeOpen(File * f)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
dirEntrySize(Source * s,ulong elem,ulong gen,uvlong * size)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
deeFill(DirEntryEnum * dee)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
deeRead(DirEntryEnum * dee,DirEntry * de)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
deeClose(DirEntryEnum * dee)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
fileMetaAlloc(File * f,DirEntry * dir,u32int start)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
chkSource(File * f)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
fileRLock(File * f)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
fileRUnlock(File * f)1639 fileRUnlock(File *f)
1640 {
1641 vtRUnlock(f->lk);
1642 }
1643
1644 static int
fileLock(File * f)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
fileUnlock(File * f)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
fileMetaLock(File * f)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
fileMetaUnlock(File * f)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
fileRAccess(File * f)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
fileWAccess(File * f,char * mid)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
getEntry(Source * r,Entry * e,int checkepoch)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
setEntry(Source * r,Entry * e)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
fileSnapshot(File * dst,File * src,u32int epoch,int doarchive)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
fileGetSources(File * f,Entry * e,Entry * ee)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
fileWalkSources(File * f)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 *
fileName(File * f)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 }
1861