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->up, 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 b = sourceBlock(fp->msource, f->boff, OReadWrite); 900 if(b == nil) 901 goto Err1; 902 903 if(!mbUnpack(&mb, b->data, fp->msource->dsize)) 904 goto Err; 905 if(!mbSearch(&mb, oelem, &i, &me)) 906 goto Err; 907 908 n = deSize(&f->dir); 909 if(0)fprint(2, "old size %d new size %d\n", me.size, n); 910 911 if(mbResize(&mb, &me, n)){ 912 /* fits in the block */ 913 mbDelete(&mb, i); 914 if(strcmp(f->dir.elem, oelem) != 0) 915 mbSearch(&mb, f->dir.elem, &i, &me2); 916 dePack(&f->dir, &me); 917 mbInsert(&mb, i, &me); 918 mbPack(&mb); 919 blockDirty(b); 920 blockPut(b); 921 sourceUnlock(fp->msource); 922 f->dirty = 0; 923 924 return 1; 925 } 926 927 /* 928 * moving entry to another block 929 * it is feasible for the fs to crash leaving two copies 930 * of the directory entry. This is just too much work to 931 * fix. Given that entries are only allocated in a block that 932 * is less than PercentageFull, most modifications of meta data 933 * will fit within the block. i.e. this code should almost 934 * never be executed. 935 */ 936 boff = fileMetaAlloc(fp, &f->dir, f->boff+1); 937 if(boff == NilBlock){ 938 /* mbResize might have modified block */ 939 mbPack(&mb); 940 blockDirty(b); 941 goto Err; 942 } 943 fprint(2, "fileMetaFlush moving entry from %ud -> %ud\n", f->boff, boff); 944 f->boff = boff; 945 946 /* make sure deletion goes to disk after new entry */ 947 bb = sourceBlock(fp->msource, f->boff, OReadWrite); 948 mbDelete(&mb, i); 949 mbPack(&mb); 950 blockDependency(b, bb, -1, nil, nil); 951 blockPut(bb); 952 blockDirty(b); 953 blockPut(b); 954 sourceUnlock(fp->msource); 955 956 f->dirty = 0; 957 958 return 1; 959 960 Err: 961 blockPut(b); 962 Err1: 963 sourceUnlock(fp->msource); 964 return 0; 965 } 966 967 static int 968 fileMetaRemove(File *f, char *uid) 969 { 970 Block *b; 971 MetaBlock mb; 972 MetaEntry me; 973 int i; 974 File *up; 975 976 up = f->up; 977 978 fileWAccess(up, uid); 979 980 fileMetaLock(f); 981 982 sourceLock(up->msource, OReadWrite); 983 b = sourceBlock(up->msource, f->boff, OReadWrite); 984 if(b == nil) 985 goto Err; 986 987 if(!mbUnpack(&mb, b->data, up->msource->dsize)) 988 { 989 fprint(2, "U\n"); 990 goto Err; 991 } 992 if(!mbSearch(&mb, f->dir.elem, &i, &me)) 993 { 994 fprint(2, "S\n"); 995 goto Err; 996 } 997 mbDelete(&mb, i); 998 mbPack(&mb); 999 sourceUnlock(up->msource); 1000 1001 blockDirty(b); 1002 blockPut(b); 1003 1004 f->removed = 1; 1005 f->boff = NilBlock; 1006 f->dirty = 0; 1007 1008 fileMetaUnlock(f); 1009 return 1; 1010 1011 Err: 1012 sourceUnlock(up->msource); 1013 blockPut(b); 1014 fileMetaUnlock(f); 1015 return 0; 1016 } 1017 1018 /* assume file is locked, assume f->msource is locked */ 1019 static int 1020 fileCheckEmpty(File *f) 1021 { 1022 u32int i, n; 1023 Block *b; 1024 MetaBlock mb; 1025 Source *r; 1026 1027 r = f->msource; 1028 n = (sourceGetSize(r)+r->dsize-1)/r->dsize; 1029 for(i=0; i<n; i++){ 1030 b = sourceBlock(r, i, OReadOnly); 1031 if(b == nil) 1032 goto Err; 1033 if(!mbUnpack(&mb, b->data, r->dsize)) 1034 goto Err; 1035 if(mb.nindex > 0){ 1036 vtSetError(ENotEmpty); 1037 goto Err; 1038 } 1039 blockPut(b); 1040 } 1041 return 1; 1042 Err: 1043 blockPut(b); 1044 return 0; 1045 } 1046 1047 int 1048 fileRemove(File *f, char *uid) 1049 { 1050 File *ff; 1051 1052 /* can not remove the root */ 1053 if(fileIsRoot(f)){ 1054 vtSetError(ERoot); 1055 return 0; 1056 } 1057 1058 if(!fileLock(f)) 1059 return 0; 1060 1061 if(f->source->mode != OReadWrite){ 1062 vtSetError(EReadOnly); 1063 goto Err1; 1064 } 1065 if(!sourceLock2(f->source, f->msource, -1)) 1066 goto Err1; 1067 if(fileIsDir(f) && !fileCheckEmpty(f)) 1068 goto Err; 1069 1070 for(ff=f->down; ff; ff=ff->next) 1071 assert(ff->removed); 1072 1073 sourceRemove(f->source); 1074 f->source = nil; 1075 if(f->msource){ 1076 sourceRemove(f->msource); 1077 f->msource = nil; 1078 } 1079 1080 fileUnlock(f); 1081 1082 if(!fileMetaRemove(f, uid)) 1083 return 0; 1084 1085 return 1; 1086 1087 Err: 1088 sourceUnlock(f->source); 1089 if(f->msource) 1090 sourceUnlock(f->msource); 1091 Err1: 1092 fileUnlock(f); 1093 return 0; 1094 } 1095 1096 static int 1097 clri(File *f, char *uid) 1098 { 1099 int r; 1100 1101 if(f == nil) 1102 return 0; 1103 if(f->up->source->mode != OReadWrite){ 1104 vtSetError(EReadOnly); 1105 fileDecRef(f); 1106 return 0; 1107 } 1108 r = fileMetaRemove(f, uid); 1109 fileDecRef(f); 1110 return r; 1111 } 1112 1113 int 1114 fileClriPath(Fs *fs, char *path, char *uid) 1115 { 1116 return clri(_fileOpen(fs, path, 1), uid); 1117 } 1118 1119 int 1120 fileClri(File *dir, char *elem, char *uid) 1121 { 1122 return clri(_fileWalk(dir, elem, 1), uid); 1123 } 1124 1125 File * 1126 fileIncRef(File *vf) 1127 { 1128 fileMetaLock(vf); 1129 assert(vf->ref > 0); 1130 vf->ref++; 1131 fileMetaUnlock(vf); 1132 return vf; 1133 } 1134 1135 int 1136 fileDecRef(File *f) 1137 { 1138 File *p, *q, **qq; 1139 1140 if(f->up == nil){ 1141 /* never linked in */ 1142 assert(f->ref == 1); 1143 fileFree(f); 1144 return 1; 1145 } 1146 1147 fileMetaLock(f); 1148 f->ref--; 1149 if(f->ref > 0){ 1150 fileMetaUnlock(f); 1151 return 0; 1152 } 1153 assert(f->ref == 0); 1154 assert(f->down == nil); 1155 1156 fileMetaFlush2(f, nil); 1157 1158 p = f->up; 1159 qq = &p->down; 1160 for(q = *qq; q; q = *qq){ 1161 if(q == f) 1162 break; 1163 qq = &q->next; 1164 } 1165 assert(q != nil); 1166 *qq = f->next; 1167 1168 fileMetaUnlock(f); 1169 fileFree(f); 1170 1171 fileDecRef(p); 1172 return 1; 1173 } 1174 1175 File * 1176 fileGetParent(File *f) 1177 { 1178 if(fileIsRoot(f)) 1179 return fileIncRef(f); 1180 return fileIncRef(f->up); 1181 } 1182 1183 DirEntryEnum * 1184 deeOpen(File *f) 1185 { 1186 DirEntryEnum *dee; 1187 File *p; 1188 1189 if(!fileIsDir(f)){ 1190 vtSetError(ENotDir); 1191 fileDecRef(f); 1192 return nil; 1193 } 1194 1195 /* flush out meta data */ 1196 if(!fileLock(f)) 1197 return nil; 1198 for(p=f->down; p; p=p->next) 1199 fileMetaFlush2(p, nil); 1200 fileUnlock(f); 1201 1202 dee = vtMemAllocZ(sizeof(DirEntryEnum)); 1203 dee->file = fileIncRef(f); 1204 1205 return dee; 1206 } 1207 1208 static int 1209 dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size) 1210 { 1211 Block *b; 1212 ulong bn; 1213 Entry e; 1214 int epb; 1215 1216 epb = s->dsize/VtEntrySize; 1217 bn = elem/epb; 1218 elem -= bn*epb; 1219 1220 b = sourceBlock(s, bn, OReadOnly); 1221 if(b == nil) 1222 goto Err; 1223 if(!entryUnpack(&e, b->data, elem)) 1224 goto Err; 1225 1226 /* hanging entries are returned as zero size */ 1227 if(!(e.flags & VtEntryActive) || e.gen != gen) 1228 *size = 0; 1229 else 1230 *size = e.size; 1231 blockPut(b); 1232 return 1; 1233 1234 Err: 1235 blockPut(b); 1236 return 0; 1237 } 1238 1239 static int 1240 deeFill(DirEntryEnum *dee) 1241 { 1242 int i, n; 1243 Source *meta, *source; 1244 MetaBlock mb; 1245 MetaEntry me; 1246 File *f; 1247 Block *b; 1248 DirEntry *de; 1249 1250 /* clean up first */ 1251 for(i=dee->i; i<dee->n; i++) 1252 deCleanup(dee->buf+i); 1253 vtMemFree(dee->buf); 1254 dee->buf = nil; 1255 dee->i = 0; 1256 dee->n = 0; 1257 1258 f = dee->file; 1259 1260 source = f->source; 1261 meta = f->msource; 1262 1263 b = sourceBlock(meta, dee->boff, OReadOnly); 1264 if(b == nil) 1265 goto Err; 1266 if(!mbUnpack(&mb, b->data, meta->dsize)) 1267 goto Err; 1268 1269 n = mb.nindex; 1270 dee->buf = vtMemAlloc(n * sizeof(DirEntry)); 1271 1272 for(i=0; i<n; i++){ 1273 de = dee->buf + i; 1274 meUnpack(&me, &mb, i); 1275 if(!deUnpack(de, &me)) 1276 goto Err; 1277 dee->n++; 1278 if(!(de->mode & ModeDir)) 1279 if(!dirEntrySize(source, de->entry, de->gen, &de->size)) 1280 goto Err; 1281 } 1282 dee->boff++; 1283 blockPut(b); 1284 return 1; 1285 Err: 1286 blockPut(b); 1287 return 0; 1288 } 1289 1290 int 1291 deeRead(DirEntryEnum *dee, DirEntry *de) 1292 { 1293 int ret, didread; 1294 File *f; 1295 u32int nb; 1296 1297 f = dee->file; 1298 if(!fileRLock(f)) 1299 return -1; 1300 1301 if(!sourceLock2(f->source, f->msource, OReadOnly)){ 1302 fileRUnlock(f); 1303 return -1; 1304 } 1305 1306 nb = (sourceGetSize(f->msource)+f->msource->dsize-1)/f->msource->dsize; 1307 1308 didread = 0; 1309 while(dee->i >= dee->n){ 1310 if(dee->boff >= nb){ 1311 ret = 0; 1312 goto Return; 1313 } 1314 didread = 1; 1315 if(!deeFill(dee)){ 1316 ret = -1; 1317 goto Return; 1318 } 1319 } 1320 1321 memmove(de, dee->buf + dee->i, sizeof(DirEntry)); 1322 dee->i++; 1323 ret = 1; 1324 1325 Return: 1326 sourceUnlock(f->source); 1327 sourceUnlock(f->msource); 1328 fileRUnlock(f); 1329 1330 if(didread) 1331 fileRAccess(f); 1332 return ret; 1333 } 1334 1335 void 1336 deeClose(DirEntryEnum *dee) 1337 { 1338 int i; 1339 if(dee == nil) 1340 return; 1341 for(i=dee->i; i<dee->n; i++) 1342 deCleanup(dee->buf+i); 1343 vtMemFree(dee->buf); 1344 fileDecRef(dee->file); 1345 vtMemFree(dee); 1346 } 1347 1348 /* 1349 * caller must lock f->source and f->msource 1350 * caller must NOT lock the source and msource 1351 * referenced by dir. 1352 */ 1353 static u32int 1354 fileMetaAlloc(File *f, DirEntry *dir, u32int start) 1355 { 1356 u32int nb, bo; 1357 Block *b, *bb; 1358 MetaBlock mb; 1359 int nn; 1360 uchar *p; 1361 int i, n, epb; 1362 MetaEntry me; 1363 Source *s, *ms; 1364 1365 s = f->source; 1366 ms = f->msource; 1367 1368 n = deSize(dir); 1369 nb = (sourceGetSize(ms)+ms->dsize-1)/ms->dsize; 1370 b = nil; 1371 if(start > nb) 1372 start = nb; 1373 for(bo=start; bo<nb; bo++){ 1374 b = sourceBlock(ms, bo, OReadWrite); 1375 if(b == nil) 1376 goto Err; 1377 if(!mbUnpack(&mb, b->data, ms->dsize)) 1378 goto Err; 1379 nn = (mb.maxsize*FullPercentage/100) - mb.size + mb.free; 1380 if(n <= nn && mb.nindex < mb.maxindex) 1381 break; 1382 blockPut(b); 1383 b = nil; 1384 } 1385 1386 /* add block to meta file */ 1387 if(b == nil){ 1388 b = sourceBlock(ms, bo, OReadWrite); 1389 if(b == nil) 1390 goto Err; 1391 sourceSetSize(ms, (nb+1)*ms->dsize); 1392 mbInit(&mb, b->data, ms->dsize, ms->dsize/BytesPerEntry); 1393 } 1394 1395 p = mbAlloc(&mb, n); 1396 if(p == nil){ 1397 /* mbAlloc might have changed block */ 1398 mbPack(&mb); 1399 blockDirty(b); 1400 vtSetError(EBadMeta); 1401 goto Err; 1402 } 1403 1404 mbSearch(&mb, dir->elem, &i, &me); 1405 assert(me.p == nil); 1406 me.p = p; 1407 me.size = n; 1408 dePack(dir, &me); 1409 mbInsert(&mb, i, &me); 1410 mbPack(&mb); 1411 1412 /* meta block depends on super block for qid ... */ 1413 bb = cacheLocal(b->c, PartSuper, 0, OReadOnly); 1414 blockDependency(b, bb, -1, nil, nil); 1415 blockPut(bb); 1416 1417 /* ... and one or two dir entries */ 1418 epb = s->dsize/VtEntrySize; 1419 bb = sourceBlock(s, dir->entry/epb, OReadOnly); 1420 blockDependency(b, bb, -1, nil, nil); 1421 blockPut(bb); 1422 if(dir->mode & ModeDir){ 1423 bb = sourceBlock(s, dir->mentry/epb, OReadOnly); 1424 blockDependency(b, bb, -1, nil, nil); 1425 blockPut(bb); 1426 } 1427 1428 blockDirty(b); 1429 blockPut(b); 1430 return bo; 1431 Err: 1432 blockPut(b); 1433 return NilBlock; 1434 } 1435 1436 static int 1437 chkSource(File *f) 1438 { 1439 if(f->partial) 1440 return 1; 1441 1442 if(f->source == nil || (f->dir.mode & ModeDir) && f->msource == nil){ 1443 vtSetError(ERemoved); 1444 return 0; 1445 } 1446 return 1; 1447 } 1448 1449 static int 1450 fileRLock(File *f) 1451 { 1452 assert(!vtCanLock(f->fs->elk)); 1453 vtRLock(f->lk); 1454 if(!chkSource(f)){ 1455 fileRUnlock(f); 1456 return 0; 1457 } 1458 return 1; 1459 } 1460 1461 static void 1462 fileRUnlock(File *f) 1463 { 1464 vtRUnlock(f->lk); 1465 } 1466 1467 static int 1468 fileLock(File *f) 1469 { 1470 assert(!vtCanLock(f->fs->elk)); 1471 vtLock(f->lk); 1472 if(!chkSource(f)){ 1473 fileUnlock(f); 1474 return 0; 1475 } 1476 return 1; 1477 } 1478 1479 static void 1480 fileUnlock(File *f) 1481 { 1482 vtUnlock(f->lk); 1483 } 1484 1485 /* 1486 * f->source and f->msource must NOT be locked. 1487 * fileMetaFlush locks the fileMeta and then the source (in fileMetaFlush2). 1488 * We have to respect that ordering. 1489 */ 1490 static void 1491 fileMetaLock(File *f) 1492 { 1493 if(f->up == nil) 1494 fprint(2, "f->elem = %s\n", f->dir.elem); 1495 assert(f->up != nil); 1496 assert(!vtCanLock(f->fs->elk)); 1497 vtLock(f->up->lk); 1498 } 1499 1500 static void 1501 fileMetaUnlock(File *f) 1502 { 1503 vtUnlock(f->up->lk); 1504 } 1505 1506 /* 1507 * f->source and f->msource must NOT be locked. 1508 * see fileMetaLock. 1509 */ 1510 static void 1511 fileRAccess(File* f) 1512 { 1513 if(f->mode == OReadOnly) 1514 return; 1515 1516 fileMetaLock(f); 1517 f->dir.atime = time(0L); 1518 f->dirty = 1; 1519 fileMetaUnlock(f); 1520 } 1521 1522 /* 1523 * f->source and f->msource must NOT be locked. 1524 * see fileMetaLock. 1525 */ 1526 static void 1527 fileWAccess(File* f, char *mid) 1528 { 1529 if(f->mode == OReadOnly) 1530 return; 1531 1532 fileMetaLock(f); 1533 f->dir.atime = f->dir.mtime = time(0L); 1534 if(strcmp(f->dir.mid, mid) != 0){ 1535 vtMemFree(f->dir.mid); 1536 f->dir.mid = vtStrDup(mid); 1537 } 1538 f->dir.mcount++; 1539 f->dirty = 1; 1540 fileMetaUnlock(f); 1541 } 1542 1543 static void 1544 markCopied(Block *b) 1545 { 1546 Block *lb; 1547 Label l; 1548 1549 if(globalToLocal(b->score) == NilBlock) 1550 return; 1551 1552 if(!(b->l.state & BsCopied)){ 1553 /* 1554 * We need to record that there are now pointers in 1555 * b that are not unique to b. We do this by marking 1556 * b as copied. Since we don't return the label block, 1557 * the caller can't get the dependencies right. So we have 1558 * to flush the block ourselves. This is a rare occurrence. 1559 */ 1560 l = b->l; 1561 l.state |= BsCopied; 1562 lb = _blockSetLabel(b, &l); 1563 WriteAgain: 1564 while(!blockWrite(lb)){ 1565 fprint(2, "getEntry: could not write label block\n"); 1566 sleep(10*1000); 1567 } 1568 while(lb->iostate != BioClean && lb->iostate != BioDirty){ 1569 assert(lb->iostate == BioWriting); 1570 vtSleep(lb->ioready); 1571 } 1572 if(lb->iostate == BioDirty) 1573 goto WriteAgain; 1574 blockPut(lb); 1575 } 1576 } 1577 1578 static int 1579 getEntry(Source *r, Entry *e, int mark) 1580 { 1581 Block *b; 1582 1583 if(r == nil){ 1584 memset(&e, 0, sizeof e); 1585 return 1; 1586 } 1587 1588 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadOnly); 1589 if(b == nil) 1590 return 0; 1591 if(!entryUnpack(e, b->data, r->offset % r->epb)){ 1592 blockPut(b); 1593 return 0; 1594 } 1595 1596 if(mark) 1597 markCopied(b); 1598 blockPut(b); 1599 return 1; 1600 } 1601 1602 static int 1603 setEntry(Source *r, Entry *e) 1604 { 1605 Block *b; 1606 Entry oe; 1607 1608 b = cacheGlobal(r->fs->cache, r->score, BtDir, r->tag, OReadWrite); 1609 if(0) fprint(2, "setEntry: b %#ux %d score=%V\n", b->addr, r->offset % r->epb, e->score); 1610 if(b == nil) 1611 return 0; 1612 if(!entryUnpack(&oe, b->data, r->offset % r->epb)){ 1613 blockPut(b); 1614 return 0; 1615 } 1616 e->gen = oe.gen; 1617 entryPack(e, b->data, r->offset % r->epb); 1618 1619 /* BUG b should depend on the entry pointer */ 1620 1621 markCopied(b); 1622 blockDirty(b); 1623 blockPut(b); 1624 return 1; 1625 } 1626 1627 /* assumes hold elk */ 1628 int 1629 fileSnapshot(File *dst, File *src, u32int epoch, int doarchive) 1630 { 1631 Entry e, ee; 1632 1633 /* add link to snapshot */ 1634 if(!getEntry(src->source, &e, 1) || !getEntry(src->msource, &ee, 1)) 1635 return 0; 1636 1637 e.snap = epoch; 1638 e.archive = doarchive; 1639 ee.snap = epoch; 1640 ee.archive = doarchive; 1641 1642 if(!setEntry(dst->source, &e) || !setEntry(dst->msource, &ee)) 1643 return 0; 1644 return 1; 1645 } 1646 1647 int 1648 fileGetSources(File *f, Entry *e, Entry *ee, int mark) 1649 { 1650 if(!getEntry(f->source, e, mark) 1651 || !getEntry(f->msource, ee, mark)) 1652 return 0; 1653 return 1; 1654 } 1655 1656 int 1657 fileWalkSources(File *f) 1658 { 1659 if(f->mode == OReadOnly) 1660 return 1; 1661 if(!sourceLock2(f->source, f->msource, OReadWrite)) 1662 return 0; 1663 sourceUnlock(f->source); 1664 sourceUnlock(f->msource); 1665 return 1; 1666 } 1667