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