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 } 1861