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