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