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