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]; 318 int n; 319 320 f = fs->file; 321 fileIncRef(f); 322 while(*path != 0){ 323 for(p = path; *p && *p != '/'; p++) 324 ; 325 n = p - path; 326 if(n > 0){ 327 if(n > VtMaxStringSize){ 328 vtSetError(EBadPath); 329 goto Err; 330 } 331 memmove(elem, path, n); 332 elem[n] = 0; 333 ff = _fileWalk(f, elem, partial && *p=='\0'); 334 if(ff == nil) 335 goto Err; 336 fileDecRef(f); 337 f = ff; 338 } 339 if(*p == '/') 340 p++; 341 path = p; 342 } 343 return f; 344 Err: 345 fileDecRef(f); 346 return nil; 347 } 348 349 File* 350 fileOpen(Fs *fs, char *path) 351 { 352 return _fileOpen(fs, path, 0); 353 } 354 355 File * 356 fileCreate(File *f, char *elem, ulong mode, char *uid) 357 { 358 File *ff; 359 DirEntry *dir; 360 Source *pr, *r, *mr; 361 int isdir; 362 363 if(!fileLock(f)) 364 return nil; 365 366 r = nil; 367 mr = nil; 368 for(ff = f->down; ff; ff=ff->next){ 369 if(strcmp(elem, ff->dir.elem) == 0 && !ff->removed){ 370 ff = nil; 371 vtSetError(EExists); 372 goto Err1; 373 } 374 } 375 376 ff = dirLookup(f, elem); 377 if(ff != nil){ 378 vtSetError(EExists); 379 goto Err1; 380 } 381 382 pr = f->source; 383 if(pr->mode != OReadWrite){ 384 vtSetError(EReadOnly); 385 goto Err1; 386 } 387 388 if(!sourceLock2(f->source, f->msource, -1)) 389 goto Err1; 390 391 ff = fileAlloc(f->fs); 392 isdir = mode & ModeDir; 393 394 r = sourceCreate(pr, pr->dsize, isdir, 0); 395 if(r == nil) 396 goto Err; 397 if(isdir){ 398 mr = sourceCreate(pr, pr->dsize, 0, r->offset); 399 if(mr == nil) 400 goto Err; 401 } 402 403 dir = &ff->dir; 404 dir->elem = vtStrDup(elem); 405 dir->entry = r->offset; 406 dir->gen = r->gen; 407 if(isdir){ 408 dir->mentry = mr->offset; 409 dir->mgen = mr->gen; 410 } 411 dir->size = 0; 412 if(!fsNextQid(f->fs, &dir->qid)) 413 goto Err; 414 dir->uid = vtStrDup(uid); 415 dir->gid = vtStrDup(f->dir.gid); 416 dir->mid = vtStrDup(uid); 417 dir->mtime = time(0L); 418 dir->mcount = 0; 419 dir->ctime = dir->mtime; 420 dir->atime = dir->mtime; 421 dir->mode = mode; 422 423 ff->boff = fileMetaAlloc(f, dir, 0); 424 if(ff->boff == NilBlock) 425 goto Err; 426 427 sourceUnlock(f->source); 428 sourceUnlock(f->msource); 429 430 ff->source = r; 431 ff->msource = mr; 432 433 /* link in and up parent ref count */ 434 ff->next = f->down; 435 f->down = ff; 436 ff->up = f; 437 fileIncRef(f); 438 439 fileWAccess(f, uid); 440 441 fileUnlock(f); 442 return ff; 443 444 Err: 445 sourceUnlock(f->source); 446 sourceUnlock(f->msource); 447 Err1: 448 if(r) 449 sourceRemove(r); 450 if(mr) 451 sourceRemove(mr); 452 if(ff) 453 fileDecRef(ff); 454 fileUnlock(f); 455 return 0; 456 } 457 458 int 459 fileRead(File *f, void *buf, int cnt, vlong offset) 460 { 461 Source *s; 462 uvlong size; 463 u32int bn; 464 int off, dsize, n, nn; 465 Block *b; 466 uchar *p; 467 468 if(0)fprint(2, "fileRead: %s %d, %lld\n", f->dir.elem, cnt, offset); 469 470 if(!fileRLock(f)) 471 return -1; 472 473 if(offset < 0){ 474 vtSetError(EBadOffset); 475 goto Err1; 476 } 477 478 fileRAccess(f); 479 480 if(!sourceLock(f->source, OReadOnly)) 481 goto Err1; 482 483 s = f->source; 484 dsize = s->dsize; 485 size = sourceGetSize(s); 486 487 if(offset >= size) 488 offset = size; 489 490 if(cnt > size-offset) 491 cnt = size-offset; 492 bn = offset/dsize; 493 off = offset%dsize; 494 p = buf; 495 while(cnt > 0){ 496 b = sourceBlock(s, bn, OReadOnly); 497 if(b == nil) 498 goto Err; 499 n = cnt; 500 if(n > dsize-off) 501 n = dsize-off; 502 nn = dsize-off; 503 if(nn > n) 504 nn = n; 505 memmove(p, b->data+off, nn); 506 memset(p+nn, 0, nn-n); 507 off = 0; 508 bn++; 509 cnt -= n; 510 p += n; 511 blockPut(b); 512 } 513 sourceUnlock(s); 514 fileRUnlock(f); 515 return p-(uchar*)buf; 516 517 Err: 518 sourceUnlock(s); 519 Err1: 520 fileRUnlock(f); 521 return -1; 522 } 523 524 int 525 fileWrite(File *f, void *buf, int cnt, vlong offset, char *uid) 526 { 527 Source *s; 528 ulong bn; 529 int off, dsize, n; 530 Block *b; 531 uchar *p; 532 vlong eof; 533 534 if(0)fprint(2, "fileWrite: %s %d, %lld\n", f->dir.elem, cnt, offset); 535 536 if(!fileLock(f)) 537 return -1; 538 539 s = nil; 540 if(f->dir.mode & ModeDir){ 541 vtSetError(ENotFile); 542 goto Err; 543 } 544 545 if(f->source->mode != OReadWrite){ 546 vtSetError(EReadOnly); 547 goto Err; 548 } 549 if(offset < 0){ 550 vtSetError(EBadOffset); 551 goto Err; 552 } 553 554 fileWAccess(f, uid); 555 556 if(!sourceLock(f->source, -1)) 557 goto Err; 558 s = f->source; 559 dsize = s->dsize; 560 561 eof = sourceGetSize(s); 562 if(f->dir.mode & ModeAppend) 563 offset = eof; 564 bn = offset/dsize; 565 off = offset%dsize; 566 p = buf; 567 while(cnt > 0){ 568 n = cnt; 569 if(n > dsize-off) 570 n = dsize-off; 571 b = sourceBlock(s, bn, n<dsize?OReadWrite:OOverWrite); 572 if(b == nil){ 573 if(offset > eof) 574 sourceSetSize(s, offset); 575 goto Err; 576 } 577 memmove(b->data+off, p, n); 578 off = 0; 579 cnt -= n; 580 p += n; 581 offset += n; 582 bn++; 583 blockDirty(b); 584 blockPut(b); 585 } 586 if(offset > eof && !sourceSetSize(s, offset)) 587 goto Err; 588 sourceUnlock(s); 589 fileUnlock(f); 590 return p-(uchar*)buf; 591 Err: 592 if(s) 593 sourceUnlock(s); 594 fileUnlock(f); 595 return -1; 596 } 597 598 int 599 fileGetDir(File *f, DirEntry *dir) 600 { 601 if(!fileRLock(f)) 602 return 0; 603 604 fileMetaLock(f); 605 deCopy(dir, &f->dir); 606 fileMetaUnlock(f); 607 608 if(!fileIsDir(f)){ 609 if(!sourceLock(f->source, OReadOnly)){ 610 fileRUnlock(f); 611 return 0; 612 } 613 dir->size = sourceGetSize(f->source); 614 sourceUnlock(f->source); 615 } 616 fileRUnlock(f); 617 618 return 1; 619 } 620 621 int 622 fileTruncate(File *f, char *uid) 623 { 624 if(fileIsDir(f)){ 625 vtSetError(ENotFile); 626 return 0; 627 } 628 629 if(!fileLock(f)) 630 return 0; 631 632 if(f->source->mode != OReadWrite){ 633 vtSetError(EReadOnly); 634 fileUnlock(f); 635 return 0; 636 } 637 if(!sourceLock(f->source, -1)){ 638 fileUnlock(f); 639 return 0; 640 } 641 if(!sourceTruncate(f->source)){ 642 sourceUnlock(f->source); 643 fileUnlock(f); 644 return 0; 645 } 646 sourceUnlock(f->source); 647 fileUnlock(f); 648 649 fileWAccess(f->up, uid); 650 651 return 1; 652 } 653 654 int 655 fileSetDir(File *f, DirEntry *dir, char *uid) 656 { 657 File *ff; 658 char *oelem; 659 u32int mask; 660 u64int size; 661 662 /* can not set permissions for the root */ 663 if(fileIsRoot(f)){ 664 vtSetError(ERoot); 665 return 0; 666 } 667 668 if(!fileLock(f)) 669 return 0; 670 671 if(f->source->mode != OReadWrite){ 672 vtSetError(EReadOnly); 673 fileUnlock(f); 674 return 0; 675 } 676 677 fileMetaLock(f); 678 679 /* check new name does not already exist */ 680 if(strcmp(f->dir.elem, dir->elem) != 0){ 681 for(ff = f->up->down; ff; ff=ff->next){ 682 if(strcmp(dir->elem, ff->dir.elem) == 0 && !ff->removed){ 683 vtSetError(EExists); 684 goto Err; 685 } 686 } 687 688 ff = dirLookup(f->up, dir->elem); 689 if(ff != nil){ 690 fileDecRef(ff); 691 vtSetError(EExists); 692 goto Err; 693 } 694 } 695 696 if(!fileIsDir(f)){ 697 if(!sourceLock(f->source, -1)) 698 goto Err; 699 size = sourceGetSize(f->source); 700 if(size != dir->size){ 701 if(!sourceSetSize(f->source, dir->size)){ 702 sourceUnlock(f->source); 703 goto Err; 704 } 705 /* commited to changing it now */ 706 } 707 sourceUnlock(f->source); 708 } 709 710 /* commited to changing it now */ 711 oelem = nil; 712 if(strcmp(f->dir.elem, dir->elem) != 0){ 713 oelem = f->dir.elem; 714 f->dir.elem = vtStrDup(dir->elem); 715 } 716 717 if(strcmp(f->dir.uid, dir->uid) != 0){ 718 vtMemFree(f->dir.uid); 719 f->dir.uid = vtStrDup(dir->uid); 720 } 721 722 if(strcmp(f->dir.gid, dir->gid) != 0){ 723 vtMemFree(f->dir.gid); 724 f->dir.gid = vtStrDup(dir->gid); 725 } 726 727 f->dir.mtime = dir->mtime; 728 f->dir.atime = dir->atime; 729 730 //fprint(2, "mode %x %x ", f->dir.mode, dir->mode); 731 mask = ~(ModeDir|ModeSnapshot); 732 f->dir.mode &= ~mask; 733 f->dir.mode |= mask & dir->mode; 734 f->dirty = 1; 735 //fprint(2, "->%x\n", f->dir.mode); 736 737 fileMetaFlush2(f, oelem); 738 vtMemFree(oelem); 739 740 fileMetaUnlock(f); 741 fileUnlock(f); 742 743 fileWAccess(f->up, uid); 744 745 return 1; 746 Err: 747 fileMetaUnlock(f); 748 fileUnlock(f); 749 return 0; 750 } 751 752 int 753 fileSetQidSpace(File *f, u64int offset, u64int max) 754 { 755 int ret; 756 757 if(!fileLock(f)) 758 return 0; 759 fileMetaLock(f); 760 f->dir.qidSpace = 1; 761 f->dir.qidOffset = offset; 762 f->dir.qidMax = max; 763 ret = fileMetaFlush2(f, nil); 764 fileMetaUnlock(f); 765 fileUnlock(f); 766 return ret; 767 } 768 769 770 uvlong 771 fileGetId(File *f) 772 { 773 /* immutable */ 774 return f->dir.qid; 775 } 776 777 ulong 778 fileGetMcount(File *f) 779 { 780 ulong mcount; 781 782 fileMetaLock(f); 783 mcount = f->dir.mcount; 784 fileMetaUnlock(f); 785 return mcount; 786 } 787 788 ulong 789 fileGetMode(File *f) 790 { 791 ulong mode; 792 793 fileMetaLock(f); 794 mode = f->dir.mode; 795 fileMetaUnlock(f); 796 return mode; 797 } 798 799 int 800 fileIsDir(File *f) 801 { 802 /* immutable */ 803 return (f->dir.mode & ModeDir) != 0; 804 } 805 806 int 807 fileIsRoot(File *f) 808 { 809 return f == f->fs->file; 810 } 811 812 int 813 fileIsRoFs(File *f) 814 { 815 return f->fs->mode == OReadOnly; 816 } 817 818 int 819 fileGetSize(File *f, uvlong *size) 820 { 821 if(!fileRLock(f)) 822 return 0; 823 if(!sourceLock(f->source, OReadOnly)){ 824 fileRUnlock(f); 825 return 0; 826 } 827 *size = sourceGetSize(f->source); 828 sourceUnlock(f->source); 829 fileRUnlock(f); 830 831 return 1; 832 } 833 834 void 835 fileMetaFlush(File *f, int rec) 836 { 837 File **kids, *p; 838 int nkids; 839 int i; 840 841 fileMetaLock(f); 842 fileMetaFlush2(f, nil); 843 fileMetaUnlock(f); 844 845 if(!rec || !fileIsDir(f)) 846 return; 847 848 if(!fileLock(f)) 849 return; 850 nkids = 0; 851 for(p=f->down; p; p=p->next) 852 nkids++; 853 kids = vtMemAlloc(nkids*sizeof(File*)); 854 i = 0; 855 for(p=f->down; p; p=p->next){ 856 kids[i++] = p; 857 p->ref++; 858 } 859 fileUnlock(f); 860 861 for(i=0; i<nkids; i++){ 862 fileMetaFlush(kids[i], 1); 863 fileDecRef(kids[i]); 864 } 865 vtMemFree(kids); 866 } 867 868 /* assumes metaLock is held */ 869 static int 870 fileMetaFlush2(File *f, char *oelem) 871 { 872 File *fp; 873 Block *b, *bb; 874 MetaBlock mb; 875 MetaEntry me, me2; 876 int i, n; 877 u32int boff; 878 879 if(!f->dirty) 880 return 1; 881 882 if(oelem == nil) 883 oelem = f->dir.elem; 884 885 //print("fileMetaFlush %s->%s\n", oelem, f->dir.elem); 886 887 fp = f->up; 888 889 if(!sourceLock(fp->msource, -1)) 890 return 0; 891 b = sourceBlock(fp->msource, f->boff, OReadWrite); 892 if(b == nil) 893 goto Err1; 894 895 if(!mbUnpack(&mb, b->data, fp->msource->dsize)) 896 goto Err; 897 if(!mbSearch(&mb, oelem, &i, &me)) 898 goto Err; 899 900 n = deSize(&f->dir); 901 if(0)fprint(2, "old size %d new size %d\n", me.size, n); 902 903 if(mbResize(&mb, &me, n)){ 904 /* fits in the block */ 905 mbDelete(&mb, i); 906 if(strcmp(f->dir.elem, oelem) != 0) 907 mbSearch(&mb, f->dir.elem, &i, &me2); 908 dePack(&f->dir, &me); 909 mbInsert(&mb, i, &me); 910 mbPack(&mb); 911 blockDirty(b); 912 blockPut(b); 913 sourceUnlock(fp->msource); 914 f->dirty = 0; 915 916 return 1; 917 } 918 919 /* 920 * moving entry to another block 921 * it is feasible for the fs to crash leaving two copies 922 * of the directory entry. This is just too much work to 923 * fix. Given that entries are only allocated in a block that 924 * is less than PercentageFull, most modifications of meta data 925 * will fit within the block. i.e. this code should almost 926 * never be executed. 927 */ 928 boff = fileMetaAlloc(fp, &f->dir, f->boff+1); 929 if(boff == NilBlock){ 930 /* mbResize might have modified block */ 931 mbPack(&mb); 932 blockDirty(b); 933 goto Err; 934 } 935 fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff); 936 f->boff = boff; 937 938 /* make sure deletion goes to disk after new entry */ 939 bb = sourceBlock(fp->msource, f->boff, OReadWrite); 940 mbDelete(&mb, i); 941 mbPack(&mb); 942 blockDependency(b, bb, -1, nil); 943 blockPut(bb); 944 blockDirty(b); 945 blockPut(b); 946 sourceUnlock(fp->msource); 947 948 f->dirty = 0; 949 950 return 1; 951 952 Err: 953 blockPut(b); 954 Err1: 955 sourceUnlock(fp->msource); 956 return 0; 957 } 958 959 static int 960 fileMetaRemove(File *f, char *uid) 961 { 962 Block *b; 963 MetaBlock mb; 964 MetaEntry me; 965 int i; 966 File *up; 967 968 up = f->up; 969 970 fileWAccess(up, uid); 971 972 fileMetaLock(f); 973 974 sourceLock(up->msource, OReadWrite); 975 b = sourceBlock(up->msource, f->boff, OReadWrite); 976 if(b == nil) 977 goto Err; 978 979 if(!mbUnpack(&mb, b->data, up->msource->dsize)) 980 { 981 fprint(2, "U\n"); 982 goto Err; 983 } 984 if(!mbSearch(&mb, f->dir.elem, &i, &me)) 985 { 986 fprint(2, "S\n"); 987 goto Err; 988 } 989 mbDelete(&mb, i); 990 mbPack(&mb); 991 sourceUnlock(up->msource); 992 993 blockDirty(b); 994 blockPut(b); 995 996 f->removed = 1; 997 f->boff = NilBlock; 998 f->dirty = 0; 999 1000 fileMetaUnlock(f); 1001 return 1; 1002 1003 Err: 1004 sourceUnlock(up->msource); 1005 blockPut(b); 1006 fileMetaUnlock(f); 1007 return 0; 1008 } 1009 1010 /* assume file is locked, assume f->msource is locked */ 1011 static int 1012 fileCheckEmpty(File *f) 1013 { 1014 u32int i, n; 1015 Block *b; 1016 MetaBlock mb; 1017 Source *r; 1018 1019 r = f->msource; 1020 n = (sourceGetSize(r)+r->dsize-1)/r->dsize; 1021 for(i=0; i<n; i++){ 1022 b = sourceBlock(r, i, OReadOnly); 1023 if(b == nil) 1024 goto Err; 1025 if(!mbUnpack(&mb, b->data, r->dsize)) 1026 goto Err; 1027 if(mb.nindex > 0){ 1028 vtSetError(ENotEmpty); 1029 goto Err; 1030 } 1031 blockPut(b); 1032 } 1033 return 1; 1034 Err: 1035 blockPut(b); 1036 return 0; 1037 } 1038 1039 int 1040 fileRemove(File *f, char *uid) 1041 { 1042 File *ff; 1043 1044 /* can not remove the root */ 1045 if(fileIsRoot(f)){ 1046 vtSetError(ERoot); 1047 return 0; 1048 } 1049 1050 if(!fileLock(f)) 1051 return 0; 1052 1053 if(f->source->mode != OReadWrite){ 1054 vtSetError(EReadOnly); 1055 goto Err1; 1056 } 1057 if(!sourceLock2(f->source, f->msource, -1)) 1058 goto Err1; 1059 if(fileIsDir(f) && !fileCheckEmpty(f)) 1060 goto Err; 1061 1062 for(ff=f->down; ff; ff=ff->next) 1063 assert(ff->removed); 1064 1065 sourceRemove(f->source); 1066 f->source = nil; 1067 if(f->msource){ 1068 sourceRemove(f->msource); 1069 f->msource = nil; 1070 } 1071 1072 fileUnlock(f); 1073 1074 if(!fileMetaRemove(f, uid)) 1075 return 0; 1076 1077 return 1; 1078 1079 Err: 1080 sourceUnlock(f->source); 1081 if(f->msource) 1082 sourceUnlock(f->msource); 1083 Err1: 1084 fileUnlock(f); 1085 return 0; 1086 } 1087 1088 int 1089 fileClri(Fs *fs, char *path, char *uid) 1090 { 1091 int r; 1092 File *f; 1093 1094 f = _fileOpen(fs, path, 1); 1095 if(f == nil) 1096 return 0; 1097 if(f->up->source->mode != OReadWrite){ 1098 vtSetError(EReadOnly); 1099 fileDecRef(f); 1100 return 0; 1101 } 1102 r = fileMetaRemove(f, uid); 1103 fileDecRef(f); 1104 return r; 1105 } 1106 1107 File * 1108 fileIncRef(File *vf) 1109 { 1110 fileMetaLock(vf); 1111 assert(vf->ref > 0); 1112 vf->ref++; 1113 fileMetaUnlock(vf); 1114 return vf; 1115 } 1116 1117 int 1118 fileDecRef(File *f) 1119 { 1120 File *p, *q, **qq; 1121 1122 if(f->up == nil){ 1123 /* never linked in */ 1124 assert(f->ref == 1); 1125 fileFree(f); 1126 return 1; 1127 } 1128 1129 fileMetaLock(f); 1130 f->ref--; 1131 if(f->ref > 0){ 1132 fileMetaUnlock(f); 1133 return 0; 1134 } 1135 assert(f->ref == 0); 1136 assert(f->down == nil); 1137 1138 fileMetaFlush2(f, nil); 1139 1140 p = f->up; 1141 qq = &p->down; 1142 for(q = *qq; q; q = *qq){ 1143 if(q == f) 1144 break; 1145 qq = &q->next; 1146 } 1147 assert(q != nil); 1148 *qq = f->next; 1149 1150 fileMetaUnlock(f); 1151 fileFree(f); 1152 1153 fileDecRef(p); 1154 return 1; 1155 } 1156 1157 File * 1158 fileGetParent(File *f) 1159 { 1160 if(fileIsRoot(f)) 1161 return fileIncRef(f); 1162 return fileIncRef(f->up); 1163 } 1164 1165 DirEntryEnum * 1166 deeOpen(File *f) 1167 { 1168 DirEntryEnum *dee; 1169 File *p; 1170 1171 if(!fileIsDir(f)){ 1172 vtSetError(ENotDir); 1173 fileDecRef(f); 1174 return nil; 1175 } 1176 1177 /* flush out meta data */ 1178 if(!fileLock(f)) 1179 return nil; 1180 for(p=f->down; p; p=p->next) 1181 fileMetaFlush2(p, nil); 1182 fileUnlock(f); 1183 1184 dee = vtMemAllocZ(sizeof(DirEntryEnum)); 1185 dee->file = fileIncRef(f); 1186 1187 return dee; 1188 } 1189 1190 static int 1191 dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size) 1192 { 1193 Block *b; 1194 ulong bn; 1195 Entry e; 1196 int epb; 1197 1198 epb = s->dsize/VtEntrySize; 1199 bn = elem/epb; 1200 elem -= bn*epb; 1201 1202 b = sourceBlock(s, bn, OReadOnly); 1203 if(b == nil) 1204 goto Err; 1205 if(!entryUnpack(&e, b->data, elem)) 1206 goto Err; 1207 1208 /* hanging entries are returned as zero size */ 1209 if(!(e.flags & VtEntryActive) || e.gen != gen) 1210 *size = 0; 1211 else 1212 *size = e.size; 1213 blockPut(b); 1214 return 1; 1215 1216 Err: 1217 blockPut(b); 1218 return 0; 1219 } 1220 1221 static int 1222 deeFill(DirEntryEnum *dee) 1223 { 1224 int i, n; 1225 Source *meta, *source; 1226 MetaBlock mb; 1227 MetaEntry me; 1228 File *f; 1229 Block *b; 1230 DirEntry *de; 1231 1232 /* clean up first */ 1233 for(i=dee->i; i<dee->n; i++) 1234 deCleanup(dee->buf+i); 1235 vtMemFree(dee->buf); 1236 dee->buf = nil; 1237 dee->i = 0; 1238 dee->n = 0; 1239 1240 f = dee->file; 1241 1242 source = f->source; 1243 meta = f->msource; 1244 1245 b = sourceBlock(meta, dee->boff, OReadOnly); 1246 if(b == nil) 1247 goto Err; 1248 if(!mbUnpack(&mb, b->data, meta->dsize)) 1249 goto Err; 1250 1251 n = mb.nindex; 1252 dee->buf = vtMemAlloc(n * sizeof(DirEntry)); 1253 1254 for(i=0; i<n; i++){ 1255 de = dee->buf + i; 1256 meUnpack(&me, &mb, i); 1257 if(!deUnpack(de, &me)) 1258 goto Err; 1259 dee->n++; 1260 if(!(de->mode & ModeDir)) 1261 if(!dirEntrySize(source, de->entry, de->gen, &de->size)) 1262 goto Err; 1263 } 1264 dee->boff++; 1265 blockPut(b); 1266 return 1; 1267 Err: 1268 blockPut(b); 1269 return 0; 1270 } 1271 1272 int 1273 deeRead(DirEntryEnum *dee, DirEntry *de) 1274 { 1275 int ret, didread; 1276 File *f; 1277 u32int nb; 1278 1279 f = dee->file; 1280 if(!fileRLock(f)) 1281 return -1; 1282 1283 if(!sourceLock2(f->source, f->msource, OReadOnly)){ 1284 fileRUnlock(f); 1285 return -1; 1286 } 1287 1288 nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize; 1289 1290 didread = 0; 1291 while(dee->i >= dee->n){ 1292 if(dee->boff >= nb){ 1293 ret = 0; 1294 goto Return; 1295 } 1296 didread = 1; 1297 if(!deeFill(dee)){ 1298 ret = -1; 1299 goto Return; 1300 } 1301 } 1302 1303 memmove(de, dee->buf + dee->i, sizeof(DirEntry)); 1304 dee->i++; 1305 ret = 1; 1306 1307 Return: 1308 sourceUnlock(f->source); 1309 sourceUnlock(f->msource); 1310 fileRUnlock(f); 1311 1312 if(didread) 1313 fileRAccess(f); 1314 return ret; 1315 } 1316 1317 void 1318 deeClose(DirEntryEnum *dee) 1319 { 1320 int i; 1321 if(dee == nil) 1322 return; 1323 for(i=dee->i; i<dee->n; i++) 1324 deCleanup(dee->buf+i); 1325 vtMemFree(dee->buf); 1326 fileDecRef(dee->file); 1327 vtMemFree(dee); 1328 } 1329 1330 /* 1331 * caller must lock f->source and f->msource 1332 * caller must NOT lock the source and msource 1333 * referenced by dir. 1334 */ 1335 static u32int 1336 fileMetaAlloc(File *f, DirEntry *dir, u32int start) 1337 { 1338 u32int nb, bo; 1339 Block *b, *bb; 1340 MetaBlock mb; 1341 int nn; 1342 uchar *p; 1343 int i, n, epb; 1344 MetaEntry me; 1345 Source *s, *ms; 1346 1347 s = f->source; 1348 ms = f->msource; 1349 1350 n = deSize(dir); 1351 nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize; 1352 b = nil; 1353 if(start > nb) 1354 start = nb; 1355 for(bo=start; bo<nb; bo++){ 1356 b = sourceBlock(ms, bo, OReadWrite); 1357 if(b == nil) 1358 goto Err; 1359 if(!mbUnpack(&mb, b->data, ms->dsize)) 1360 goto Err; 1361 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free; 1362 if(n <= nn && mb.nindex < mb.maxindex) 1363 break; 1364 blockPut(b); 1365 b = nil; 1366 } 1367 1368 /* add block to meta file */ 1369 if(b == nil){ 1370 b = sourceBlock(ms, bo, OReadWrite); 1371 if(b == nil) 1372 goto Err; 1373 sourceSetSize(ms, (nb+1)*ms->dsize); 1374 mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry); 1375 } 1376 1377 p = mbAlloc(&mb, n); 1378 if(p == nil){ 1379 /* mbAlloc might have changed block */ 1380 mbPack(&mb); 1381 blockDirty(b); 1382 vtSetError(EBadMeta); 1383 goto Err; 1384 } 1385 1386 mbSearch(&mb, dir->elem, &i, &me); 1387 assert(me.p == nil); 1388 me.p = p; 1389 me.size = n; 1390 dePack(dir, &me); 1391 mbInsert(&mb, i, &me); 1392 mbPack(&mb); 1393 1394 /* meta block depends on super block for qid ... */ 1395 bb = cacheLocal(b->c, PartSuper, 0, OReadOnly); 1396 blockDependency(b, bb, -1, nil); 1397 blockPut(bb); 1398 1399 /* ... and one or two dir entries */ 1400 epb = s->dsize/VtEntrySize; 1401 bb = sourceBlock(s, dir->entry/epb, OReadOnly); 1402 blockDependency(b, bb, -1, nil); 1403 blockPut(bb); 1404 if(dir->mode & ModeDir){ 1405 bb = sourceBlock(s, dir->mentry/epb, OReadOnly); 1406 blockDependency(b, bb, -1, nil); 1407 blockPut(bb); 1408 } 1409 1410 blockDirty(b); 1411 blockPut(b); 1412 return bo; 1413 Err: 1414 blockPut(b); 1415 return NilBlock; 1416 } 1417 1418 static int 1419 chkSource(File *f) 1420 { 1421 if(f->partial) 1422 return 1; 1423 1424 if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){ 1425 vtSetError(ERemoved); 1426 return 0; 1427 } 1428 return 1; 1429 } 1430 1431 static int 1432 fileRLock(File *f) 1433 { 1434 assert(!vtCanLock(f->fs->elk)); 1435 vtRLock(f->lk); 1436 if(!chkSource(f)){ 1437 fileRUnlock(f); 1438 return 0; 1439 } 1440 return 1; 1441 } 1442 1443 static void 1444 fileRUnlock(File *f) 1445 { 1446 vtRUnlock(f->lk); 1447 } 1448 1449 static int 1450 fileLock(File *f) 1451 { 1452 assert(!vtCanLock(f->fs->elk)); 1453 vtLock(f->lk); 1454 if(!chkSource(f)){ 1455 fileUnlock(f); 1456 return 0; 1457 } 1458 return 1; 1459 } 1460 1461 static void 1462 fileUnlock(File *f) 1463 { 1464 vtUnlock(f->lk); 1465 } 1466 1467 /* 1468 * f->source and f->msource must NOT be locked. 1469 * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). 1470 * We have to respect that ordering. 1471 */ 1472 static void 1473 fileMetaLock(File *f) 1474 { 1475 if(f->up == nil) 1476 fprint(2, "f->elem = %s\n", f->dir.elem); 1477 assert(f->up != nil); 1478 assert(!vtCanLock(f->fs->elk)); 1479 vtLock(f->up->lk); 1480 } 1481 1482 static void 1483 fileMetaUnlock(File *f) 1484 { 1485 vtUnlock(f->up->lk); 1486 } 1487 1488 /* 1489 * f->source and f->msource must NOT be locked. 1490 * see fileMetaLock. 1491 */ 1492 static void 1493 fileRAccess(File* f) 1494 { 1495 if(f->mode == OReadOnly) 1496 return; 1497 1498 fileMetaLock(f); 1499 f->dir.atime = time(0L); 1500 f->dirty = 1; 1501 fileMetaUnlock(f); 1502 } 1503 1504 /* 1505 * f->source and f->msource must NOT be locked. 1506 * see fileMetaLock. 1507 */ 1508 static void 1509 fileWAccess(File* f, char *mid) 1510 { 1511 if(f->mode == OReadOnly) 1512 return; 1513 1514 fileMetaLock(f); 1515 f->dir.atime = f->dir.mtime = time(0L); 1516 if(strcmp(f->dir.mid, mid) != 0){ 1517 vtMemFree(f->dir.mid); 1518 f->dir.mid = vtStrDup(mid); 1519 } 1520 f->dir.mcount++; 1521 f->dirty = 1; 1522 fileMetaUnlock(f); 1523 } 1524 1525 static void 1526 markCopied(Block *b) 1527 { 1528 Block *lb; 1529 Label l; 1530 1531 if(globalToLocal(b->score) == NilBlock) 1532 return; 1533 1534 if(!(b->l.state & BsCopied)){ 1535 /* 1536 * We need to record that there are now pointers in 1537 * b that are not unique to b. We do this by marking 1538 * b as copied. Since we don't return the label block, 1539 * the caller can't get the dependencies right. So we have 1540 * to flush the block ourselves. This is a rare occurrence. 1541 */ 1542 l = b->l; 1543 l.state |= BsCopied; 1544 lb = _blockSetLabel(b, &l); 1545 WriteAgain: 1546 while(!blockWrite(lb)){ 1547 fprint(2, "getEntry: could not write label block\n"); 1548 sleep(10*1000); 1549 } 1550 while(lb->iostate != BioClean && lb->iostate != BioDirty){ 1551 assert(lb->iostate == BioWriting); 1552 vtSleep(lb->ioready); 1553 } 1554 if(lb->iostate == BioDirty) 1555 goto WriteAgain; 1556 blockPut(lb); 1557 } 1558 } 1559 1560 static int 1561 getEntry(Source *r, Entry *e, int mark) 1562 { 1563 Block *b; 1564 1565 if(r == nil){ 1566 memset(&e, 0, sizeof e); 1567 return 1; 1568 } 1569 1570 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly); 1571 if(b == nil) 1572 return 0; 1573 if(!entryUnpack(e, b->data, r->offset % r->epb)){ 1574 blockPut(b); 1575 return 0; 1576 } 1577 1578 if(mark) 1579 markCopied(b); 1580 blockPut(b); 1581 return 1; 1582 } 1583 1584 static int 1585 setEntry(Source *r, Entry *e) 1586 { 1587 Block *b; 1588 Entry oe; 1589 1590 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); 1591 if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score); 1592 if(b == nil) 1593 return 0; 1594 if(!entryUnpack(&oe, b->data, r->offset % r->epb)){ 1595 blockPut(b); 1596 return 0; 1597 } 1598 e->gen = oe.gen; 1599 entryPack(e, b->data, r->offset % r->epb); 1600 1601 /* BUG b should depend on the entry pointer */ 1602 1603 markCopied(b); 1604 blockDirty(b); 1605 blockPut(b); 1606 return 1; 1607 } 1608 1609 /* assumes hold elk */ 1610 int 1611 fileSnapshot(File *dst, File *src, u32int epoch, int doarchive) 1612 { 1613 Entry e, ee; 1614 1615 /* add link to snapshot */ 1616 if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1)) 1617 return 0; 1618 1619 e.snap = epoch; 1620 e.archive = doarchive; 1621 ee.snap = epoch; 1622 ee.archive = doarchive; 1623 1624 if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee)) 1625 return 0; 1626 return 1; 1627 } 1628 1629 int 1630 fileGetSources(File *f, Entry *e, Entry *ee, int mark) 1631 { 1632 if(!getEntry(f->source, e, mark) 1633 || !getEntry(f->msource, ee, mark)) 1634 return 0; 1635 return 1; 1636 } 1637 1638 int 1639 fileWalkSources(File *f) 1640 { 1641 if(f->mode == OReadOnly) 1642 return 1; 1643 if(!sourceLock2(f->source, f->msource, OReadWrite)) 1644 return 0; 1645 sourceUnlock(f->source); 1646 sourceUnlock(f->msource); 1647 return 1; 1648 } 1649