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