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