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 * 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 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 * 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 * 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 * 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 * 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 * 327 fileWalk(File *f, char *elem) 328 { 329 return _fileWalk(f, elem, 0); 330 } 331 332 File * 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* 373 fileOpen(Fs *fs, char *path) 374 { 375 return _fileOpen(fs, path, 0); 376 } 377 378 static void 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 * 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 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 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 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 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 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 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 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 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 ret = fileMetaFlush2(f, nil)>=0; 924 fileMetaUnlock(f); 925 fileUnlock(f); 926 return ret; 927 } 928 929 930 uvlong 931 fileGetId(File *f) 932 { 933 /* immutable */ 934 return f->dir.qid; 935 } 936 937 ulong 938 fileGetMcount(File *f) 939 { 940 ulong mcount; 941 942 fileMetaLock(f); 943 mcount = f->dir.mcount; 944 fileMetaUnlock(f); 945 return mcount; 946 } 947 948 ulong 949 fileGetMode(File *f) 950 { 951 ulong mode; 952 953 fileMetaLock(f); 954 mode = f->dir.mode; 955 fileMetaUnlock(f); 956 return mode; 957 } 958 959 int 960 fileIsDir(File *f) 961 { 962 /* immutable */ 963 return (f->dir.mode & ModeDir) != 0; 964 } 965 966 int 967 fileIsAppend(File *f) 968 { 969 return (f->dir.mode & ModeAppend) != 0; 970 } 971 972 int 973 fileIsExclusive(File *f) 974 { 975 return (f->dir.mode & ModeExclusive) != 0; 976 } 977 978 int 979 fileIsTemporary(File *f) 980 { 981 return (f->dir.mode & ModeTemporary) != 0; 982 } 983 984 int 985 fileIsRoot(File *f) 986 { 987 return f == f->fs->file; 988 } 989 990 int 991 fileIsRoFs(File *f) 992 { 993 return f->fs->mode == OReadOnly; 994 } 995 996 int 997 fileGetSize(File *f, uvlong *size) 998 { 999 if(!fileRLock(f)) 1000 return 0; 1001 if(!sourceLock(f->source, OReadOnly)){ 1002 fileRUnlock(f); 1003 return 0; 1004 } 1005 *size = sourceGetSize(f->source); 1006 sourceUnlock(f->source); 1007 fileRUnlock(f); 1008 1009 return 1; 1010 } 1011 1012 int 1013 fileMetaFlush(File *f, int rec) 1014 { 1015 File **kids, *p; 1016 int nkids; 1017 int i, rv; 1018 1019 fileMetaLock(f); 1020 rv = fileMetaFlush2(f, nil); 1021 fileMetaUnlock(f); 1022 1023 if(!rec || !fileIsDir(f)) 1024 return rv; 1025 1026 if(!fileLock(f)) 1027 return rv; 1028 nkids = 0; 1029 for(p=f->down; p; p=p->next) 1030 nkids++; 1031 kids = vtmalloc(nkids*sizeof(File*)); 1032 i = 0; 1033 for(p=f->down; p; p=p->next){ 1034 kids[i++] = p; 1035 p->ref++; 1036 } 1037 fileUnlock(f); 1038 1039 for(i=0; i<nkids; i++){ 1040 rv |= fileMetaFlush(kids[i], 1); 1041 fileDecRef(kids[i]); 1042 } 1043 vtfree(kids); 1044 return rv; 1045 } 1046 1047 /* assumes metaLock is held */ 1048 static int 1049 fileMetaFlush2(File *f, char *oelem) 1050 { 1051 File *fp; 1052 Block *b, *bb; 1053 MetaBlock mb; 1054 MetaEntry me, me2; 1055 int i, n; 1056 u32int boff; 1057 1058 if(!f->dirty) 1059 return 0; 1060 1061 if(oelem == nil) 1062 oelem = f->dir.elem; 1063 1064 //print("fileMetaFlush %s->%s\n", oelem, f->dir.elem); 1065 1066 fp = f->up; 1067 1068 if(!sourceLock(fp->msource, -1)) 1069 return -1; 1070 /* can happen if source is clri'ed out from under us */ 1071 if(f->boff == NilBlock) 1072 goto Err1; 1073 b = sourceBlock(fp->msource, f->boff, OReadWrite); 1074 if(b == nil) 1075 goto Err1; 1076 1077 if(!mbUnpack(&mb, b->data, fp->msource->dsize)) 1078 goto Err; 1079 if(!mbSearch(&mb, oelem, &i, &me)) 1080 goto Err; 1081 1082 n = deSize(&f->dir); 1083 if(0)fprint(2, "old size %d new size %d\n", me.size, n); 1084 1085 if(mbResize(&mb, &me, n)){ 1086 /* fits in the block */ 1087 mbDelete(&mb, i); 1088 if(strcmp(f->dir.elem, oelem) != 0) 1089 mbSearch(&mb, f->dir.elem, &i, &me2); 1090 dePack(&f->dir, &me); 1091 mbInsert(&mb, i, &me); 1092 mbPack(&mb); 1093 blockDirty(b); 1094 blockPut(b); 1095 sourceUnlock(fp->msource); 1096 f->dirty = 0; 1097 1098 return 1; 1099 } 1100 1101 /* 1102 * moving entry to another block 1103 * it is feasible for the fs to crash leaving two copies 1104 * of the directory entry. This is just too much work to 1105 * fix. Given that entries are only allocated in a block that 1106 * is less than PercentageFull, most modifications of meta data 1107 * will fit within the block. i.e. this code should almost 1108 * never be executed. 1109 */ 1110 boff = fileMetaAlloc(fp, &f->dir, f->boff+1); 1111 if(boff == NilBlock){ 1112 /* mbResize might have modified block */ 1113 mbPack(&mb); 1114 blockDirty(b); 1115 goto Err; 1116 } 1117 fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff); 1118 f->boff = boff; 1119 1120 /* make sure deletion goes to disk after new entry */ 1121 bb = sourceBlock(fp->msource, f->boff, OReadWrite); 1122 mbDelete(&mb, i); 1123 mbPack(&mb); 1124 blockDependency(b, bb, -1, nil, nil); 1125 blockPut(bb); 1126 blockDirty(b); 1127 blockPut(b); 1128 sourceUnlock(fp->msource); 1129 1130 f->dirty = 0; 1131 1132 return 1; 1133 1134 Err: 1135 blockPut(b); 1136 Err1: 1137 sourceUnlock(fp->msource); 1138 return -1; 1139 } 1140 1141 static int 1142 fileMetaRemove(File *f, char *uid) 1143 { 1144 Block *b; 1145 MetaBlock mb; 1146 MetaEntry me; 1147 int i; 1148 File *up; 1149 1150 up = f->up; 1151 1152 fileWAccess(up, uid); 1153 1154 fileMetaLock(f); 1155 1156 sourceLock(up->msource, OReadWrite); 1157 b = sourceBlock(up->msource, f->boff, OReadWrite); 1158 if(b == nil) 1159 goto Err; 1160 1161 if(!mbUnpack(&mb, b->data, up->msource->dsize)) 1162 { 1163 fprint(2, "U\n"); 1164 goto Err; 1165 } 1166 if(!mbSearch(&mb, f->dir.elem, &i, &me)) 1167 { 1168 fprint(2, "S\n"); 1169 goto Err; 1170 } 1171 mbDelete(&mb, i); 1172 mbPack(&mb); 1173 sourceUnlock(up->msource); 1174 1175 blockDirty(b); 1176 blockPut(b); 1177 1178 f->removed = 1; 1179 f->boff = NilBlock; 1180 f->dirty = 0; 1181 1182 fileMetaUnlock(f); 1183 return 1; 1184 1185 Err: 1186 sourceUnlock(up->msource); 1187 blockPut(b); 1188 fileMetaUnlock(f); 1189 return 0; 1190 } 1191 1192 /* assume file is locked, assume f->msource is locked */ 1193 static int 1194 fileCheckEmpty(File *f) 1195 { 1196 u32int i, n; 1197 Block *b; 1198 MetaBlock mb; 1199 Source *r; 1200 1201 r = f->msource; 1202 n = (sourceGetSize(r)+r->dsize-1)/r->dsize; 1203 for(i=0; i<n; i++){ 1204 b = sourceBlock(r, i, OReadOnly); 1205 if(b == nil) 1206 goto Err; 1207 if(!mbUnpack(&mb, b->data, r->dsize)) 1208 goto Err; 1209 if(mb.nindex > 0){ 1210 werrstr(ENotEmpty); 1211 goto Err; 1212 } 1213 blockPut(b); 1214 } 1215 return 1; 1216 Err: 1217 blockPut(b); 1218 return 0; 1219 } 1220 1221 int 1222 fileRemove(File *f, char *uid) 1223 { 1224 File *ff; 1225 1226 /* can not remove the root */ 1227 if(fileIsRoot(f)){ 1228 werrstr(ERoot); 1229 return 0; 1230 } 1231 1232 if(!fileLock(f)) 1233 return 0; 1234 1235 if(f->source->mode != OReadWrite){ 1236 werrstr(EReadOnly); 1237 goto Err1; 1238 } 1239 if(!sourceLock2(f->source, f->msource, -1)) 1240 goto Err1; 1241 if(fileIsDir(f) && !fileCheckEmpty(f)) 1242 goto Err; 1243 1244 for(ff=f->down; ff; ff=ff->next) 1245 assert(ff->removed); 1246 1247 sourceRemove(f->source); 1248 f->source->file = nil; /* erase back pointer */ 1249 f->source = nil; 1250 if(f->msource){ 1251 sourceRemove(f->msource); 1252 f->msource = nil; 1253 } 1254 1255 fileUnlock(f); 1256 1257 if(!fileMetaRemove(f, uid)) 1258 return 0; 1259 1260 return 1; 1261 1262 Err: 1263 sourceUnlock(f->source); 1264 if(f->msource) 1265 sourceUnlock(f->msource); 1266 Err1: 1267 fileUnlock(f); 1268 return 0; 1269 } 1270 1271 static int 1272 clri(File *f, char *uid) 1273 { 1274 int r; 1275 1276 if(f == nil) 1277 return 0; 1278 if(f->up->source->mode != OReadWrite){ 1279 werrstr(EReadOnly); 1280 fileDecRef(f); 1281 return 0; 1282 } 1283 r = fileMetaRemove(f, uid); 1284 fileDecRef(f); 1285 return r; 1286 } 1287 1288 int 1289 fileClriPath(Fs *fs, char *path, char *uid) 1290 { 1291 return clri(_fileOpen(fs, path, 1), uid); 1292 } 1293 1294 int 1295 fileClri(File *dir, char *elem, char *uid) 1296 { 1297 return clri(_fileWalk(dir, elem, 1), uid); 1298 } 1299 1300 File * 1301 fileIncRef(File *vf) 1302 { 1303 fileMetaLock(vf); 1304 assert(vf->ref > 0); 1305 vf->ref++; 1306 fileMetaUnlock(vf); 1307 return vf; 1308 } 1309 1310 int 1311 fileDecRef(File *f) 1312 { 1313 File *p, *q, **qq; 1314 1315 if(f->up == nil){ 1316 /* never linked in */ 1317 assert(f->ref == 1); 1318 fileFree(f); 1319 return 1; 1320 } 1321 1322 fileMetaLock(f); 1323 f->ref--; 1324 if(f->ref > 0){ 1325 fileMetaUnlock(f); 1326 return 0; 1327 } 1328 assert(f->ref == 0); 1329 assert(f->down == nil); 1330 1331 fileMetaFlush2(f, nil); 1332 1333 p = f->up; 1334 qq = &p->down; 1335 for(q = *qq; q; q = *qq){ 1336 if(q == f) 1337 break; 1338 qq = &q->next; 1339 } 1340 assert(q != nil); 1341 *qq = f->next; 1342 1343 fileMetaUnlock(f); 1344 fileFree(f); 1345 1346 fileDecRef(p); 1347 return 1; 1348 } 1349 1350 File * 1351 fileGetParent(File *f) 1352 { 1353 if(fileIsRoot(f)) 1354 return fileIncRef(f); 1355 return fileIncRef(f->up); 1356 } 1357 1358 DirEntryEnum * 1359 deeOpen(File *f) 1360 { 1361 DirEntryEnum *dee; 1362 File *p; 1363 1364 if(!fileIsDir(f)){ 1365 werrstr(ENotDir); 1366 fileDecRef(f); 1367 return nil; 1368 } 1369 1370 /* flush out meta data */ 1371 if(!fileLock(f)) 1372 return nil; 1373 for(p=f->down; p; p=p->next) 1374 fileMetaFlush2(p, nil); 1375 fileUnlock(f); 1376 1377 dee = vtmallocz(sizeof(DirEntryEnum)); 1378 dee->file = fileIncRef(f); 1379 1380 return dee; 1381 } 1382 1383 static int 1384 dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size) 1385 { 1386 Block *b; 1387 ulong bn; 1388 Entry e; 1389 int epb; 1390 1391 epb = s->dsize/VtEntrySize; 1392 bn = elem/epb; 1393 elem -= bn*epb; 1394 1395 b = sourceBlock(s, bn, OReadOnly); 1396 if(b == nil) 1397 goto Err; 1398 if(!entryUnpack(&e, b->data, elem)) 1399 goto Err; 1400 1401 /* hanging entries are returned as zero size */ 1402 if(!(e.flags & VtEntryActive) || e.gen != gen) 1403 *size = 0; 1404 else 1405 *size = e.size; 1406 blockPut(b); 1407 return 1; 1408 1409 Err: 1410 blockPut(b); 1411 return 0; 1412 } 1413 1414 static int 1415 deeFill(DirEntryEnum *dee) 1416 { 1417 int i, n; 1418 Source *meta, *source; 1419 MetaBlock mb; 1420 MetaEntry me; 1421 File *f; 1422 Block *b; 1423 DirEntry *de; 1424 1425 /* clean up first */ 1426 for(i=dee->i; i<dee->n; i++) 1427 deCleanup(dee->buf+i); 1428 vtfree(dee->buf); 1429 dee->buf = nil; 1430 dee->i = 0; 1431 dee->n = 0; 1432 1433 f = dee->file; 1434 1435 source = f->source; 1436 meta = f->msource; 1437 1438 b = sourceBlock(meta, dee->boff, OReadOnly); 1439 if(b == nil) 1440 goto Err; 1441 if(!mbUnpack(&mb, b->data, meta->dsize)) 1442 goto Err; 1443 1444 n = mb.nindex; 1445 dee->buf = vtmalloc(n * sizeof(DirEntry)); 1446 1447 for(i=0; i<n; i++){ 1448 de = dee->buf + i; 1449 meUnpack(&me, &mb, i); 1450 if(!deUnpack(de, &me)) 1451 goto Err; 1452 dee->n++; 1453 if(!(de->mode & ModeDir)) 1454 if(!dirEntrySize(source, de->entry, de->gen, &de->size)) 1455 goto Err; 1456 } 1457 dee->boff++; 1458 blockPut(b); 1459 return 1; 1460 Err: 1461 blockPut(b); 1462 return 0; 1463 } 1464 1465 int 1466 deeRead(DirEntryEnum *dee, DirEntry *de) 1467 { 1468 int ret, didread; 1469 File *f; 1470 u32int nb; 1471 1472 if(dee == nil){ 1473 werrstr("cannot happen in deeRead"); 1474 return -1; 1475 } 1476 1477 f = dee->file; 1478 if(!fileRLock(f)) 1479 return -1; 1480 1481 if(!sourceLock2(f->source, f->msource, OReadOnly)){ 1482 fileRUnlock(f); 1483 return -1; 1484 } 1485 1486 nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize; 1487 1488 didread = 0; 1489 while(dee->i >= dee->n){ 1490 if(dee->boff >= nb){ 1491 ret = 0; 1492 goto Return; 1493 } 1494 didread = 1; 1495 if(!deeFill(dee)){ 1496 ret = -1; 1497 goto Return; 1498 } 1499 } 1500 1501 memmove(de, dee->buf + dee->i, sizeof(DirEntry)); 1502 dee->i++; 1503 ret = 1; 1504 1505 Return: 1506 sourceUnlock(f->source); 1507 sourceUnlock(f->msource); 1508 fileRUnlock(f); 1509 1510 if(didread) 1511 fileRAccess(f); 1512 return ret; 1513 } 1514 1515 void 1516 deeClose(DirEntryEnum *dee) 1517 { 1518 int i; 1519 if(dee == nil) 1520 return; 1521 for(i=dee->i; i<dee->n; i++) 1522 deCleanup(dee->buf+i); 1523 vtfree(dee->buf); 1524 fileDecRef(dee->file); 1525 vtfree(dee); 1526 } 1527 1528 /* 1529 * caller must lock f->source and f->msource 1530 * caller must NOT lock the source and msource 1531 * referenced by dir. 1532 */ 1533 static u32int 1534 fileMetaAlloc(File *f, DirEntry *dir, u32int start) 1535 { 1536 u32int nb, bo; 1537 Block *b, *bb; 1538 MetaBlock mb; 1539 int nn; 1540 uchar *p; 1541 int i, n, epb; 1542 MetaEntry me; 1543 Source *s, *ms; 1544 1545 s = f->source; 1546 ms = f->msource; 1547 1548 n = deSize(dir); 1549 nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize; 1550 b = nil; 1551 if(start > nb) 1552 start = nb; 1553 for(bo=start; bo<nb; bo++){ 1554 b = sourceBlock(ms, bo, OReadWrite); 1555 if(b == nil) 1556 goto Err; 1557 if(!mbUnpack(&mb, b->data, ms->dsize)) 1558 goto Err; 1559 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free; 1560 if(n <= nn && mb.nindex < mb.maxindex) 1561 break; 1562 blockPut(b); 1563 b = nil; 1564 } 1565 1566 /* add block to meta file */ 1567 if(b == nil){ 1568 b = sourceBlock(ms, bo, OReadWrite); 1569 if(b == nil) 1570 goto Err; 1571 sourceSetSize(ms, (nb+1)*ms->dsize); 1572 mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry); 1573 } 1574 1575 p = mbAlloc(&mb, n); 1576 if(p == nil){ 1577 /* mbAlloc might have changed block */ 1578 mbPack(&mb); 1579 blockDirty(b); 1580 werrstr(EBadMeta); 1581 goto Err; 1582 } 1583 1584 mbSearch(&mb, dir->elem, &i, &me); 1585 assert(me.p == nil); 1586 me.p = p; 1587 me.size = n; 1588 dePack(dir, &me); 1589 mbInsert(&mb, i, &me); 1590 mbPack(&mb); 1591 1592 /* meta block depends on super block for qid ... */ 1593 bb = cacheLocal(b->c, PartSuper, 0, OReadOnly); 1594 blockDependency(b, bb, -1, nil, nil); 1595 blockPut(bb); 1596 1597 /* ... and one or two dir entries */ 1598 epb = s->dsize/VtEntrySize; 1599 bb = sourceBlock(s, dir->entry/epb, OReadOnly); 1600 blockDependency(b, bb, -1, nil, nil); 1601 blockPut(bb); 1602 if(dir->mode & ModeDir){ 1603 bb = sourceBlock(s, dir->mentry/epb, OReadOnly); 1604 blockDependency(b, bb, -1, nil, nil); 1605 blockPut(bb); 1606 } 1607 1608 blockDirty(b); 1609 blockPut(b); 1610 return bo; 1611 Err: 1612 blockPut(b); 1613 return NilBlock; 1614 } 1615 1616 static int 1617 chkSource(File *f) 1618 { 1619 if(f->partial) 1620 return 1; 1621 1622 if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){ 1623 werrstr(ERemoved); 1624 return 0; 1625 } 1626 return 1; 1627 } 1628 1629 static int 1630 fileRLock(File *f) 1631 { 1632 assert(!canwlock(&f->fs->elk)); 1633 rlock(&f->lk); 1634 if(!chkSource(f)){ 1635 fileRUnlock(f); 1636 return 0; 1637 } 1638 return 1; 1639 } 1640 1641 static void 1642 fileRUnlock(File *f) 1643 { 1644 runlock(&f->lk); 1645 } 1646 1647 static int 1648 fileLock(File *f) 1649 { 1650 assert(!canwlock(&f->fs->elk)); 1651 wlock(&f->lk); 1652 if(!chkSource(f)){ 1653 fileUnlock(f); 1654 return 0; 1655 } 1656 return 1; 1657 } 1658 1659 static void 1660 fileUnlock(File *f) 1661 { 1662 wunlock(&f->lk); 1663 } 1664 1665 /* 1666 * f->source and f->msource must NOT be locked. 1667 * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). 1668 * We have to respect that ordering. 1669 */ 1670 static void 1671 fileMetaLock(File *f) 1672 { 1673 if(f->up == nil) 1674 fprint(2, "f->elem = %s\n", f->dir.elem); 1675 assert(f->up != nil); 1676 assert(!canwlock(&f->fs->elk)); 1677 wlock(&f->up->lk); 1678 } 1679 1680 static void 1681 fileMetaUnlock(File *f) 1682 { 1683 wunlock(&f->up->lk); 1684 } 1685 1686 /* 1687 * f->source and f->msource must NOT be locked. 1688 * see fileMetaLock. 1689 */ 1690 static void 1691 fileRAccess(File* f) 1692 { 1693 if(f->mode == OReadOnly || f->fs->noatimeupd) 1694 return; 1695 1696 fileMetaLock(f); 1697 f->dir.atime = time(0L); 1698 f->dirty = 1; 1699 fileMetaUnlock(f); 1700 } 1701 1702 /* 1703 * f->source and f->msource must NOT be locked. 1704 * see fileMetaLock. 1705 */ 1706 static void 1707 fileWAccess(File* f, char *mid) 1708 { 1709 if(f->mode == OReadOnly) 1710 return; 1711 1712 fileMetaLock(f); 1713 f->dir.atime = f->dir.mtime = time(0L); 1714 if(strcmp(f->dir.mid, mid) != 0){ 1715 vtfree(f->dir.mid); 1716 f->dir.mid = vtstrdup(mid); 1717 } 1718 f->dir.mcount++; 1719 f->dirty = 1; 1720 fileMetaUnlock(f); 1721 1722 /*RSC: let's try this */ 1723 /*presotto - lets not 1724 if(f->up) 1725 fileWAccess(f->up, mid); 1726 */ 1727 } 1728 1729 static int 1730 getEntry(Source *r, Entry *e, int checkepoch) 1731 { 1732 u32int epoch; 1733 Block *b; 1734 1735 if(r == nil){ 1736 memset(&e, 0, sizeof e); 1737 return 1; 1738 } 1739 1740 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly); 1741 if(b == nil) 1742 return 0; 1743 if(!entryUnpack(e, b->data, r->offset % r->epb)){ 1744 blockPut(b); 1745 return 0; 1746 } 1747 epoch = b->l.epoch; 1748 blockPut(b); 1749 1750 if(checkepoch){ 1751 b = cacheGlobal(r->fs->cache, e->score, entryType(e), e->tag, OReadOnly); 1752 if(b){ 1753 if(b->l.epoch >= epoch) 1754 fprint(2, "warning: entry %p epoch not older %#.8ux/%d %V/%d in getEntry\n", 1755 r, b->addr, b->l.epoch, r->score, epoch); 1756 blockPut(b); 1757 } 1758 } 1759 1760 return 1; 1761 } 1762 1763 static int 1764 setEntry(Source *r, Entry *e) 1765 { 1766 Block *b; 1767 Entry oe; 1768 1769 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); 1770 if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score); 1771 if(b == nil) 1772 return 0; 1773 if(!entryUnpack(&oe, b->data, r->offset % r->epb)){ 1774 blockPut(b); 1775 return 0; 1776 } 1777 e->gen = oe.gen; 1778 entryPack(e, b->data, r->offset % r->epb); 1779 1780 /* BUG b should depend on the entry pointer */ 1781 1782 blockDirty(b); 1783 blockPut(b); 1784 return 1; 1785 } 1786 1787 /* assumes hold elk */ 1788 int 1789 fileSnapshot(File *dst, File *src, u32int epoch, int doarchive) 1790 { 1791 Entry e, ee; 1792 1793 /* add link to snapshot */ 1794 if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1)) 1795 return 0; 1796 1797 e.snap = epoch; 1798 e.archive = doarchive; 1799 ee.snap = epoch; 1800 ee.archive = doarchive; 1801 1802 if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee)) 1803 return 0; 1804 return 1; 1805 } 1806 1807 int 1808 fileGetSources(File *f, Entry *e, Entry *ee) 1809 { 1810 if(!getEntry(f->source, e, 0) 1811 || !getEntry(f->msource, ee, 0)) 1812 return 0; 1813 return 1; 1814 } 1815 1816 /* 1817 * Walk down to the block(s) containing the Entries 1818 * for f->source and f->msource, copying as we go. 1819 */ 1820 int 1821 fileWalkSources(File *f) 1822 { 1823 if(f->mode == OReadOnly){ 1824 fprint(2, "readonly in fileWalkSources\n"); 1825 return 1; 1826 } 1827 if(!sourceLock2(f->source, f->msource, OReadWrite)){ 1828 fprint(2, "sourceLock2 failed in fileWalkSources\n"); 1829 return 0; 1830 } 1831 sourceUnlock(f->source); 1832 sourceUnlock(f->msource); 1833 return 1; 1834 } 1835 1836 /* 1837 * convert File* to full path name in malloced string. 1838 * this hasn't been as useful as we hoped it would be. 1839 */ 1840 char * 1841 fileName(File *f) 1842 { 1843 char *name, *pname; 1844 File *p; 1845 static char root[] = "/"; 1846 1847 if (f == nil) 1848 return vtstrdup("/**GOK**"); 1849 1850 p = fileGetParent(f); 1851 if (p == f) 1852 name = vtstrdup(root); 1853 else { 1854 pname = fileName(p); 1855 if (strcmp(pname, root) == 0) 1856 name = smprint("/%s", f->dir.elem); 1857 else 1858 name = smprint("%s/%s", pname, f->dir.elem); 1859 free(pname); 1860 } 1861 fileDecRef(p); 1862 return name; 1863 } 1864