1 /* 2 * Copyright 2009, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include <new> 10 #include <stdlib.h> 11 #include <string.h> 12 13 #include <dirent.h> 14 15 #include <util/kernel_cpp.h> 16 17 #include <fs_cache.h> 18 #include <fs_info.h> 19 #include <fs_interface.h> 20 21 #include <debug.h> 22 #include <KernelExport.h> 23 #include <NodeMonitor.h> 24 25 26 //#define TRACE_OVERLAY 27 #ifdef TRACE_OVERLAY 28 #define TRACE(x...) dprintf("write_overlay: " x) 29 #define TRACE_VOLUME(x...) dprintf("write_overlay: " x) 30 #define TRACE_ALWAYS(x...) dprintf("write_overlay: " x) 31 #else 32 #define TRACE(x...) /* nothing */ 33 #define TRACE_VOLUME(x...) /* nothing */ 34 #define TRACE_ALWAYS(x...) dprintf("write_overlay: " x) 35 #endif 36 37 38 namespace write_overlay { 39 40 status_t publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, 41 void *privateNode, int type); 42 43 class OverlayInode; 44 45 struct open_cookie { 46 int open_mode; 47 void * super_cookie; 48 }; 49 50 51 struct open_dir_cookie { 52 uint32 index; 53 }; 54 55 56 struct overlay_dirent { 57 ino_t inode_number; 58 char * name; 59 60 void remove_and_dispose(fs_volume *volume, ino_t directoryInode) 61 { 62 notify_entry_removed(volume->id, directoryInode, 63 name, inode_number); 64 remove_vnode(volume, inode_number); 65 free(name); 66 free(this); 67 } 68 }; 69 70 71 struct write_buffer { 72 write_buffer * next; 73 off_t position; 74 size_t length; 75 uint8 buffer[1]; 76 }; 77 78 79 class OverlayVolume { 80 public: 81 OverlayVolume(fs_volume *volume); 82 ~OverlayVolume(); 83 84 fs_volume * Volume() { return fVolume; } 85 fs_volume * SuperVolume() { return fVolume->super_volume; } 86 87 ino_t BuildInodeNumber() { return fCurrentInodeNumber++; } 88 89 private: 90 fs_volume * fVolume; 91 ino_t fCurrentInodeNumber; 92 }; 93 94 95 class OverlayInode { 96 public: 97 OverlayInode(OverlayVolume *volume, 98 fs_vnode *superVnode, ino_t inodeNumber, 99 OverlayInode *parentDir = NULL, 100 const char *name = NULL, mode_t mode = 0); 101 ~OverlayInode(); 102 103 status_t InitCheck(); 104 105 bool IsVirtual() { return fIsVirtual; } 106 107 fs_volume * Volume() { return fVolume->Volume(); } 108 fs_volume * SuperVolume() { return fVolume->SuperVolume(); } 109 fs_vnode * SuperVnode() { return &fSuperVnode; } 110 ino_t InodeNumber() { return fInodeNumber; } 111 112 void CreateCache(); 113 114 void SetParentDir(OverlayInode *parentDir); 115 OverlayInode * ParentDir() { return fParentDir; } 116 117 status_t Lookup(const char *name, ino_t *inodeNumber); 118 void SetName(const char *name); 119 status_t GetName(char *buffer, size_t bufferSize); 120 121 status_t ReadStat(struct stat *stat); 122 status_t WriteStat(const struct stat *stat, uint32 statMask); 123 124 status_t Create(const char *name, int openMode, int perms, 125 void **cookie, ino_t *newInodeNumber); 126 status_t Open(int openMode, void **cookie); 127 status_t Close(void *cookie); 128 status_t FreeCookie(void *cookie); 129 status_t Read(void *cookie, off_t position, void *buffer, 130 size_t *length, bool readPages); 131 status_t Write(void *cookie, off_t position, 132 const void *buffer, size_t *length); 133 status_t SetFlags(void *cookie, int flags); 134 135 status_t CreateDir(const char *name, int perms); 136 status_t RemoveDir(const char *name); 137 status_t OpenDir(void **cookie); 138 status_t CloseDir(void *cookie); 139 status_t FreeDirCookie(void *cookie); 140 status_t ReadDir(void *cookie, struct dirent *buffer, 141 size_t bufferSize, uint32 *num); 142 status_t RewindDir(void *cookie); 143 144 status_t CreateSymlink(const char *name, const char *path, 145 int mode); 146 status_t ReadSymlink(char *buffer, size_t *bufferSize); 147 148 status_t AddEntry(overlay_dirent *entry); 149 status_t RemoveEntry(const char *name, 150 overlay_dirent **entry); 151 152 private: 153 status_t _PopulateDirents(); 154 status_t _CreateCommon(const char *name, int type, int perms, 155 ino_t *newInodeNumber, OverlayInode **node); 156 157 OverlayVolume * fVolume; 158 OverlayInode * fParentDir; 159 const char * fName; 160 fs_vnode fSuperVnode; 161 ino_t fInodeNumber; 162 write_buffer * fWriteBuffers; 163 off_t fOriginalNodeLength; 164 overlay_dirent ** fDirents; 165 uint32 fDirentCount; 166 struct stat fStat; 167 bool fHasStat; 168 bool fHasDirents; 169 bool fIsVirtual; 170 void * fFileCache; 171 }; 172 173 174 // #pragma mark OverlayVolume 175 176 177 OverlayVolume::OverlayVolume(fs_volume *volume) 178 : fVolume(volume), 179 fCurrentInodeNumber((ino_t)1 << 60) 180 { 181 } 182 183 184 OverlayVolume::~OverlayVolume() 185 { 186 } 187 188 189 // #pragma mark OverlayInode 190 191 192 OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode, 193 ino_t inodeNumber, OverlayInode *parentDir, const char *name, mode_t mode) 194 : fVolume(volume), 195 fParentDir(parentDir), 196 fName(name), 197 fInodeNumber(inodeNumber), 198 fWriteBuffers(NULL), 199 fOriginalNodeLength(-1), 200 fDirents(NULL), 201 fDirentCount(0), 202 fHasStat(false), 203 fHasDirents(false), 204 fIsVirtual(superVnode == NULL), 205 fFileCache(NULL) 206 { 207 TRACE("inode created %lld\n", fInodeNumber); 208 209 if (superVnode != NULL) 210 fSuperVnode = *superVnode; 211 else { 212 fStat.st_dev = SuperVolume()->id; 213 fStat.st_ino = fInodeNumber; 214 fStat.st_mode = mode; 215 fStat.st_nlink = 1; 216 fStat.st_uid = 0; 217 fStat.st_gid = 0; 218 fStat.st_size = 0; 219 fStat.st_rdev = 0; 220 fStat.st_blksize = 1024; 221 fStat.st_atime = fStat.st_mtime = fStat.st_ctime = fStat.st_crtime 222 = time(NULL); 223 fStat.st_type = 0; 224 fHasStat = true; 225 } 226 } 227 228 229 OverlayInode::~OverlayInode() 230 { 231 TRACE("inode destroyed %lld\n", fInodeNumber); 232 if (fFileCache != NULL) 233 file_cache_delete(fFileCache); 234 235 write_buffer *element = fWriteBuffers; 236 while (element) { 237 write_buffer *next = element->next; 238 free(element); 239 element = next; 240 } 241 242 for (uint32 i = 0; i < fDirentCount; i++) 243 free(fDirents[i]); 244 free(fDirents); 245 } 246 247 248 status_t 249 OverlayInode::InitCheck() 250 { 251 return B_OK; 252 } 253 254 255 void 256 OverlayInode::CreateCache() 257 { 258 if (!S_ISDIR(fStat.st_mode) && !S_ISLNK(fStat.st_mode)) { 259 fFileCache = file_cache_create(fStat.st_dev, fStat.st_ino, 0); 260 if (fFileCache != NULL) 261 file_cache_disable(fFileCache); 262 } 263 } 264 265 266 void 267 OverlayInode::SetParentDir(OverlayInode *parentDir) 268 { 269 fParentDir = parentDir; 270 } 271 272 273 status_t 274 OverlayInode::Lookup(const char *name, ino_t *inodeNumber) 275 { 276 if (!fHasDirents) 277 _PopulateDirents(); 278 279 for (uint32 i = 0; i < fDirentCount; i++) { 280 if (strcmp(fDirents[i]->name, name) == 0) { 281 *inodeNumber = fDirents[i]->inode_number; 282 283 OverlayInode *node = NULL; 284 status_t result = get_vnode(Volume(), *inodeNumber, 285 (void **)&node); 286 if (result == B_OK && node != NULL) 287 node->SetParentDir(this); 288 return result; 289 } 290 } 291 292 return B_ENTRY_NOT_FOUND; 293 } 294 295 296 void 297 OverlayInode::SetName(const char *name) 298 { 299 fName = name; 300 } 301 302 303 status_t 304 OverlayInode::GetName(char *buffer, size_t bufferSize) 305 { 306 if (fName != NULL) { 307 strlcpy(buffer, fName, bufferSize); 308 return B_OK; 309 } 310 311 if (fIsVirtual) 312 return B_UNSUPPORTED; 313 314 if (fSuperVnode.ops->get_vnode_name == NULL) 315 return B_UNSUPPORTED; 316 317 return fSuperVnode.ops->get_vnode_name(SuperVolume(), &fSuperVnode, buffer, 318 bufferSize); 319 } 320 321 322 status_t 323 OverlayInode::ReadStat(struct stat *stat) 324 { 325 if (!fHasStat) { 326 if (fSuperVnode.ops->read_stat == NULL) 327 return B_UNSUPPORTED; 328 329 status_t result = fSuperVnode.ops->read_stat(SuperVolume(), 330 &fSuperVnode, &fStat); 331 if (result != B_OK) 332 return result; 333 334 fHasStat = true; 335 } 336 337 if (stat == NULL) 338 return B_OK; 339 340 memcpy(stat, &fStat, sizeof(struct stat)); 341 stat->st_blocks = (stat->st_size + stat->st_blksize - 1) / stat->st_blksize; 342 return B_OK; 343 } 344 345 346 status_t 347 OverlayInode::WriteStat(const struct stat *stat, uint32 statMask) 348 { 349 if (!fHasStat) 350 ReadStat(NULL); 351 352 if (statMask & B_STAT_SIZE) 353 fStat.st_size = stat->st_size; 354 355 if (statMask & B_STAT_MODE) 356 fStat.st_mode = (fStat.st_mode & ~S_IUMSK) | (stat->st_mode & S_IUMSK); 357 if (statMask & B_STAT_UID) 358 fStat.st_uid = stat->st_uid; 359 if (statMask & B_STAT_GID) 360 fStat.st_gid = stat->st_gid; 361 362 if (statMask & B_STAT_MODIFICATION_TIME) 363 fStat.st_mtime = stat->st_mtime; 364 if (statMask & B_STAT_CREATION_TIME) 365 fStat.st_crtime = stat->st_crtime; 366 367 if ((statMask & (B_STAT_MODE | B_STAT_UID | B_STAT_GID)) != 0 368 && (statMask & B_STAT_MODIFICATION_TIME) == 0) { 369 fStat.st_mtime = time(NULL); 370 statMask |= B_STAT_MODIFICATION_TIME; 371 } 372 373 notify_stat_changed(SuperVolume()->id, fInodeNumber, statMask); 374 return B_OK; 375 } 376 377 378 status_t 379 OverlayInode::Create(const char *name, int openMode, int perms, void **cookie, 380 ino_t *newInodeNumber) 381 { 382 OverlayInode *newNode = NULL; 383 status_t result = _CreateCommon(name, S_IFREG, perms, newInodeNumber, 384 &newNode); 385 if (result != B_OK) 386 return result; 387 388 return newNode->Open(openMode, cookie); 389 } 390 391 392 status_t 393 OverlayInode::Open(int openMode, void **_cookie) 394 { 395 if (!fHasStat) 396 ReadStat(NULL); 397 398 open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie)); 399 if (cookie == NULL) 400 return B_NO_MEMORY; 401 402 cookie->open_mode = openMode; 403 *_cookie = cookie; 404 405 if (fIsVirtual) { 406 if (openMode & O_TRUNC) 407 fStat.st_size = 0; 408 409 return B_OK; 410 } 411 412 if (fSuperVnode.ops->open == NULL) 413 return B_UNSUPPORTED; 414 415 if (fOriginalNodeLength < 0) { 416 struct stat stat; 417 status_t result = fSuperVnode.ops->read_stat(SuperVolume(), 418 &fSuperVnode, &stat); 419 if (result != B_OK) 420 return result; 421 422 fOriginalNodeLength = stat.st_size; 423 } 424 425 if (openMode & O_TRUNC) 426 fStat.st_size = 0; 427 428 openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT); 429 status_t result = fSuperVnode.ops->open(SuperVolume(), &fSuperVnode, 430 openMode, &cookie->super_cookie); 431 if (result != B_OK) { 432 free(cookie); 433 return result; 434 } 435 436 return B_OK; 437 } 438 439 440 status_t 441 OverlayInode::Close(void *_cookie) 442 { 443 if (fIsVirtual) 444 return B_OK; 445 446 open_cookie *cookie = (open_cookie *)_cookie; 447 return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode, 448 cookie->super_cookie); 449 } 450 451 452 status_t 453 OverlayInode::FreeCookie(void *_cookie) 454 { 455 status_t result = B_OK; 456 open_cookie *cookie = (open_cookie *)_cookie; 457 if (!fIsVirtual) { 458 result = fSuperVnode.ops->free_cookie(SuperVolume(), 459 &fSuperVnode, cookie->super_cookie); 460 } 461 462 free(cookie); 463 return result; 464 } 465 466 467 status_t 468 OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length, 469 bool readPages) 470 { 471 if (position >= fStat.st_size) { 472 *length = 0; 473 return B_OK; 474 } 475 476 uint8 *pointer = (uint8 *)buffer; 477 write_buffer *element = fWriteBuffers; 478 size_t bytesLeft = MIN(fStat.st_size - position, *length); 479 *length = bytesLeft; 480 481 void *superCookie = _cookie; 482 if (!fIsVirtual && !readPages && _cookie != NULL) 483 superCookie = ((open_cookie *)_cookie)->super_cookie; 484 485 while (bytesLeft > 0) { 486 size_t gapSize = bytesLeft; 487 if (element != NULL) { 488 gapSize = MIN(bytesLeft, element->position > position ? 489 element->position - position : 0); 490 } 491 492 if (gapSize > 0 && !fIsVirtual && position < fOriginalNodeLength) { 493 // there's a part missing between the read position and our 494 // next position, fill the gap with original file content 495 size_t readLength = MIN(fOriginalNodeLength - position, gapSize); 496 status_t result = B_ERROR; 497 if (readPages) { 498 iovec vector; 499 vector.iov_base = pointer; 500 vector.iov_len = readLength; 501 502 result = fSuperVnode.ops->read_pages(SuperVolume(), 503 &fSuperVnode, superCookie, position, &vector, 1, 504 &readLength); 505 } else { 506 result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode, 507 superCookie, position, pointer, &readLength); 508 } 509 510 if (result != B_OK) 511 return result; 512 513 pointer += readLength; 514 position += readLength; 515 bytesLeft -= readLength; 516 gapSize -= readLength; 517 } 518 519 if (gapSize > 0) { 520 // there's a gap before our next position which we cannot 521 // fill with original file content, zero it out 522 memset(pointer, 0, gapSize); 523 bytesLeft -= gapSize; 524 position += gapSize; 525 pointer += gapSize; 526 } 527 528 // we've reached the end 529 if (bytesLeft == 0 || element == NULL) 530 break; 531 532 off_t elementEnd = element->position + element->length; 533 if (elementEnd > position) { 534 size_t copyLength = MIN(elementEnd - position, bytesLeft); 535 memcpy(pointer, element->buffer + (position - element->position), 536 copyLength); 537 538 bytesLeft -= copyLength; 539 position += copyLength; 540 pointer += copyLength; 541 } 542 543 element = element->next; 544 } 545 546 return B_OK; 547 } 548 549 550 status_t 551 OverlayInode::Write(void *_cookie, off_t position, const void *buffer, 552 size_t *length) 553 { 554 if (_cookie != NULL) { 555 open_cookie *cookie = (open_cookie *)_cookie; 556 if (cookie->open_mode & O_APPEND) 557 position = fStat.st_size; 558 } 559 560 // find insertion point 561 write_buffer **link = &fWriteBuffers; 562 write_buffer *other = fWriteBuffers; 563 write_buffer *swallow = NULL; 564 off_t newPosition = position; 565 size_t newLength = *length; 566 uint32 swallowCount = 0; 567 568 while (other) { 569 off_t newEnd = newPosition + newLength; 570 off_t otherEnd = other->position + other->length; 571 if (otherEnd < newPosition) { 572 // other is completely before us 573 link = &other->next; 574 other = other->next; 575 continue; 576 } 577 578 if (other->position > newEnd) { 579 // other is completely past us 580 break; 581 } 582 583 swallowCount++; 584 if (swallow == NULL) 585 swallow = other; 586 587 if (other->position <= newPosition) { 588 if (swallowCount == 1 && otherEnd >= newEnd) { 589 // other chunk completely covers us, just copy 590 memcpy(other->buffer + (newPosition - other->position), 591 buffer, *length); 592 593 fStat.st_mtime = time(NULL); 594 notify_stat_changed(SuperVolume()->id, fInodeNumber, 595 B_STAT_MODIFICATION_TIME); 596 return B_OK; 597 } 598 599 newLength += newPosition - other->position; 600 newPosition = other->position; 601 } 602 603 if (otherEnd > newEnd) 604 newLength += otherEnd - newEnd; 605 606 other = other->next; 607 } 608 609 write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1 610 + newLength); 611 if (element == NULL) 612 return B_NO_MEMORY; 613 614 element->next = *link; 615 element->position = newPosition; 616 element->length = newLength; 617 *link = element; 618 619 bool sizeChanged = false; 620 off_t newEnd = newPosition + newLength; 621 if (newEnd > fStat.st_size) { 622 fStat.st_size = newEnd; 623 sizeChanged = true; 624 625 if (fFileCache) 626 file_cache_set_size(fFileCache, newEnd); 627 } 628 629 // populate the buffer with the existing chunks 630 if (swallowCount > 0) { 631 while (swallowCount-- > 0) { 632 memcpy(element->buffer + (swallow->position - newPosition), 633 swallow->buffer, swallow->length); 634 635 element->next = swallow->next; 636 free(swallow); 637 swallow = element->next; 638 } 639 } 640 641 memcpy(element->buffer + (position - newPosition), buffer, *length); 642 643 fStat.st_mtime = time(NULL); 644 notify_stat_changed(SuperVolume()->id, fInodeNumber, 645 B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0)); 646 return B_OK; 647 } 648 649 650 status_t 651 OverlayInode::SetFlags(void *_cookie, int flags) 652 { 653 // we can only handle O_APPEND, O_NONBLOCK is ignored. 654 open_cookie *cookie = (open_cookie *)_cookie; 655 cookie->open_mode = (cookie->open_mode & ~O_APPEND) | (flags & ~O_APPEND); 656 return B_OK; 657 } 658 659 660 status_t 661 OverlayInode::CreateDir(const char *name, int perms) 662 { 663 return _CreateCommon(name, S_IFDIR, perms, NULL, NULL); 664 } 665 666 667 status_t 668 OverlayInode::RemoveDir(const char *name) 669 { 670 return RemoveEntry(name, NULL); 671 } 672 673 674 status_t 675 OverlayInode::OpenDir(void **cookie) 676 { 677 if (!fHasDirents) 678 _PopulateDirents(); 679 680 open_dir_cookie *dirCookie = (open_dir_cookie *)malloc( 681 sizeof(open_dir_cookie)); 682 if (dirCookie == NULL) 683 return B_NO_MEMORY; 684 685 dirCookie->index = 0; 686 *cookie = dirCookie; 687 return B_OK; 688 } 689 690 691 status_t 692 OverlayInode::CloseDir(void *cookie) 693 { 694 return B_OK; 695 } 696 697 698 status_t 699 OverlayInode::FreeDirCookie(void *cookie) 700 { 701 free(cookie); 702 return B_OK; 703 } 704 705 706 status_t 707 OverlayInode::ReadDir(void *cookie, struct dirent *buffer, size_t bufferSize, 708 uint32 *num) 709 { 710 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie; 711 if (dirCookie->index >= fDirentCount) { 712 *num = 0; 713 return B_OK; 714 } 715 716 overlay_dirent *dirent = fDirents[dirCookie->index++]; 717 size_t nameLength = MIN(strlen(dirent->name), 718 bufferSize - sizeof(struct dirent)) + 1; 719 720 buffer->d_dev = SuperVolume()->id; 721 buffer->d_pdev = 0; 722 buffer->d_ino = dirent->inode_number; 723 buffer->d_pino = 0; 724 buffer->d_reclen = sizeof(struct dirent) + nameLength; 725 strlcpy(buffer->d_name, dirent->name, nameLength); 726 727 *num = 1; 728 return B_OK; 729 } 730 731 732 status_t 733 OverlayInode::RewindDir(void *cookie) 734 { 735 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie; 736 dirCookie->index = 0; 737 return B_OK; 738 } 739 740 741 status_t 742 OverlayInode::CreateSymlink(const char *name, const char *path, int mode) 743 { 744 OverlayInode *newNode = NULL; 745 // TODO: find out why mode is ignored 746 status_t result = _CreateCommon(name, S_IFLNK, 0777, NULL, &newNode); 747 if (result != B_OK) 748 return result; 749 750 size_t writeLength = strlen(path); 751 return newNode->Write(NULL, 0, path, &writeLength); 752 } 753 754 755 status_t 756 OverlayInode::ReadSymlink(char *buffer, size_t *bufferSize) 757 { 758 if (fIsVirtual) { 759 if (!S_ISLNK(fStat.st_mode)) 760 return B_BAD_VALUE; 761 762 return Read(NULL, 0, buffer, bufferSize, false); 763 } 764 765 if (fSuperVnode.ops->read_symlink == NULL) 766 return B_UNSUPPORTED; 767 768 return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer, 769 bufferSize); 770 } 771 772 773 status_t 774 OverlayInode::AddEntry(overlay_dirent *entry) 775 { 776 if (!fHasDirents) 777 _PopulateDirents(); 778 779 status_t result = RemoveEntry(entry->name, NULL); 780 if (result != B_OK && result != B_ENTRY_NOT_FOUND) 781 return B_FILE_EXISTS; 782 783 overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents, 784 sizeof(overlay_dirent *) * (fDirentCount + 1)); 785 if (newDirents == NULL) 786 return B_NO_MEMORY; 787 788 fDirents = newDirents; 789 fDirents[fDirentCount++] = entry; 790 return B_OK; 791 } 792 793 794 status_t 795 OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry) 796 { 797 if (!fHasDirents) 798 _PopulateDirents(); 799 800 // TODO: we may not simply remove non-empty directories 801 for (uint32 i = 0; i < fDirentCount; i++) { 802 overlay_dirent *entry = fDirents[i]; 803 if (strcmp(entry->name, name) == 0) { 804 for (uint32 j = i + 1; j < fDirentCount; j++) 805 fDirents[j - 1] = fDirents[j]; 806 fDirentCount--; 807 808 if (_entry != NULL) 809 *_entry = entry; 810 else 811 entry->remove_and_dispose(Volume(), fInodeNumber); 812 813 return B_OK; 814 } 815 } 816 817 return B_ENTRY_NOT_FOUND; 818 } 819 820 821 status_t 822 OverlayInode::_PopulateDirents() 823 { 824 if (fHasDirents) 825 return B_OK; 826 827 fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2); 828 if (fDirents == NULL) 829 return B_NO_MEMORY; 830 831 const char *names[] = { ".", ".." }; 832 ino_t inodes[] = { fInodeNumber, 833 fParentDir != NULL ? fParentDir->InodeNumber() : 0 }; 834 for (uint32 i = 0; i < 2; i++) { 835 fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent)); 836 if (fDirents[i] == NULL) 837 return B_NO_MEMORY; 838 839 fDirents[i]->inode_number = inodes[i]; 840 fDirents[i]->name = strdup(names[i]); 841 if (fDirents[i]->name == NULL) { 842 free(fDirents[i]); 843 return B_NO_MEMORY; 844 } 845 846 fDirentCount++; 847 } 848 849 fHasDirents = true; 850 if (fIsVirtual || fSuperVnode.ops->open_dir == NULL 851 || fSuperVnode.ops->read_dir == NULL) 852 return B_OK; 853 854 // we don't really care about errors from here on 855 void *superCookie = NULL; 856 status_t result = fSuperVnode.ops->open_dir(SuperVolume(), 857 &fSuperVnode, &superCookie); 858 if (result != B_OK) 859 return B_OK; 860 861 size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH; 862 struct dirent *buffer = (struct dirent *)malloc(bufferSize); 863 if (buffer == NULL) 864 goto close_dir; 865 866 while (true) { 867 uint32 num = 1; 868 result = fSuperVnode.ops->read_dir(SuperVolume(), 869 &fSuperVnode, superCookie, buffer, bufferSize, &num); 870 if (result != B_OK || num == 0) 871 break; 872 873 overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents, 874 sizeof(overlay_dirent *) * (fDirentCount + num)); 875 if (newDirents == NULL) { 876 TRACE_ALWAYS("failed to allocate storage for dirents\n"); 877 break; 878 } 879 880 fDirents = newDirents; 881 struct dirent *dirent = buffer; 882 for (uint32 i = 0; i < num; i++) { 883 if (strcmp(dirent->d_name, ".") != 0 884 && strcmp(dirent->d_name, "..") != 0) { 885 overlay_dirent *entry = (overlay_dirent *)malloc( 886 sizeof(overlay_dirent)); 887 if (entry == NULL) { 888 TRACE_ALWAYS("failed to allocate storage for dirent\n"); 889 break; 890 } 891 892 entry->inode_number = dirent->d_ino; 893 entry->name = strdup(dirent->d_name); 894 if (entry->name == NULL) { 895 TRACE_ALWAYS("failed to duplicate dirent entry name\n"); 896 free(entry); 897 break; 898 } 899 900 fDirents[fDirentCount++] = entry; 901 } 902 903 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen); 904 } 905 } 906 907 free(buffer); 908 909 close_dir: 910 if (fSuperVnode.ops->close_dir != NULL) 911 fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie); 912 913 if (fSuperVnode.ops->free_dir_cookie != NULL) { 914 fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode, 915 superCookie); 916 } 917 918 return B_OK; 919 } 920 921 922 status_t 923 OverlayInode::_CreateCommon(const char *name, int type, int perms, 924 ino_t *newInodeNumber, OverlayInode **_node) 925 { 926 if (!fHasStat) 927 ReadStat(NULL); 928 929 if (!S_ISDIR(fStat.st_mode)) 930 return B_NOT_A_DIRECTORY; 931 932 overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent)); 933 if (entry == NULL) 934 return B_NO_MEMORY; 935 936 entry->name = strdup(name); 937 if (entry->name == NULL) { 938 free(entry); 939 return B_NO_MEMORY; 940 } 941 942 entry->inode_number = fVolume->BuildInodeNumber(); 943 944 OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL, 945 entry->inode_number, this, entry->name, (perms & S_IUMSK) | type); 946 if (node == NULL) { 947 free(entry->name); 948 free(entry); 949 return B_NO_MEMORY; 950 } 951 952 status_t result = AddEntry(entry); 953 if (result != B_OK) { 954 free(entry->name); 955 free(entry); 956 delete node; 957 return result; 958 } 959 960 result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number, 961 node, type); 962 if (result != B_OK) { 963 RemoveEntry(entry->name, NULL); 964 delete node; 965 return result; 966 } 967 968 node->CreateCache(); 969 970 if (newInodeNumber != NULL) 971 *newInodeNumber = entry->inode_number; 972 if (_node != NULL) 973 *_node = node; 974 975 notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name, 976 entry->inode_number); 977 978 return B_OK; 979 } 980 981 982 // #pragma mark - vnode ops 983 984 985 #define OVERLAY_CALL(op, params...) \ 986 TRACE("relaying op: " #op "\n"); \ 987 OverlayInode *node = (OverlayInode *)vnode->private_node; \ 988 if (node->IsVirtual()) \ 989 return B_UNSUPPORTED; \ 990 fs_vnode *superVnode = node->SuperVnode(); \ 991 if (superVnode->ops->op != NULL) \ 992 return superVnode->ops->op(volume->super_volume, superVnode, params); \ 993 return B_UNSUPPORTED; 994 995 996 static status_t 997 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 998 { 999 TRACE("put_vnode\n"); 1000 OverlayInode *node = (OverlayInode *)vnode->private_node; 1001 if (node->IsVirtual()) { 1002 delete node; 1003 return B_OK; 1004 } 1005 1006 status_t result = B_OK; 1007 fs_vnode *superVnode = node->SuperVnode(); 1008 if (superVnode->ops->put_vnode != NULL) { 1009 result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 1010 reenter); 1011 } 1012 1013 delete node; 1014 return result; 1015 } 1016 1017 1018 static status_t 1019 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 1020 { 1021 TRACE("remove_vnode\n"); 1022 OverlayInode *node = (OverlayInode *)vnode->private_node; 1023 if (node->IsVirtual()) { 1024 delete node; 1025 return B_OK; 1026 } 1027 1028 status_t result = B_OK; 1029 fs_vnode *superVnode = node->SuperVnode(); 1030 if (superVnode->ops->put_vnode != NULL) { 1031 result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 1032 reenter); 1033 } 1034 1035 delete node; 1036 return result; 1037 } 1038 1039 1040 static status_t 1041 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, 1042 fs_volume *superVolume, fs_vnode *_superVnode) 1043 { 1044 if (volume == superVolume) { 1045 *_superVnode = *vnode; 1046 return B_OK; 1047 } 1048 1049 OverlayInode *node = (OverlayInode *)vnode->private_node; 1050 if (node->IsVirtual()) { 1051 *_superVnode = *vnode; 1052 return B_OK; 1053 } 1054 1055 fs_vnode *superVnode = node->SuperVnode(); 1056 if (superVnode->ops->get_super_vnode != NULL) { 1057 return superVnode->ops->get_super_vnode(volume->super_volume, 1058 superVnode, superVolume, _superVnode); 1059 } 1060 1061 *_superVnode = *superVnode; 1062 return B_OK; 1063 } 1064 1065 1066 static status_t 1067 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) 1068 { 1069 TRACE("lookup: \"%s\"\n", name); 1070 return ((OverlayInode *)vnode->private_node)->Lookup(name, id); 1071 } 1072 1073 1074 static status_t 1075 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, 1076 size_t bufferSize) 1077 { 1078 return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize); 1079 } 1080 1081 1082 static bool 1083 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) 1084 { 1085 TRACE("relaying op: can_page\n"); 1086 OverlayInode *node = (OverlayInode *)vnode->private_node; 1087 if (node->IsVirtual()) 1088 return false; 1089 1090 fs_vnode *superVnode = node->SuperVnode(); 1091 if (superVnode->ops->can_page != NULL) { 1092 return superVnode->ops->can_page(volume->super_volume, superVnode, 1093 cookie); 1094 } 1095 1096 return false; 1097 } 1098 1099 1100 static status_t 1101 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1102 const iovec *vecs, size_t count, size_t *numBytes) 1103 { 1104 OverlayInode *node = (OverlayInode *)vnode->private_node; 1105 size_t bytesLeft = *numBytes; 1106 1107 for (size_t i = 0; i < count; i++) { 1108 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft); 1109 status_t result = node->Read(cookie, pos, vecs[i].iov_base, 1110 &transferBytes, true); 1111 if (result != B_OK) { 1112 *numBytes -= bytesLeft; 1113 return result; 1114 } 1115 1116 bytesLeft -= transferBytes; 1117 if (bytesLeft == 0) 1118 return B_OK; 1119 1120 if (transferBytes < vecs[i].iov_len) { 1121 *numBytes -= bytesLeft; 1122 return B_OK; 1123 } 1124 1125 pos += transferBytes; 1126 } 1127 1128 *numBytes = 0; 1129 return B_OK; 1130 } 1131 1132 1133 static status_t 1134 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1135 const iovec *vecs, size_t count, size_t *numBytes) 1136 { 1137 OverlayInode *node = (OverlayInode *)vnode->private_node; 1138 size_t bytesLeft = *numBytes; 1139 1140 for (size_t i = 0; i < count; i++) { 1141 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft); 1142 status_t result = node->Write(cookie, pos, vecs[i].iov_base, 1143 &transferBytes); 1144 if (result != B_OK) { 1145 *numBytes -= bytesLeft; 1146 return result; 1147 } 1148 1149 bytesLeft -= transferBytes; 1150 if (bytesLeft == 0) 1151 return B_OK; 1152 1153 if (transferBytes < vecs[i].iov_len) { 1154 *numBytes -= bytesLeft; 1155 return B_OK; 1156 } 1157 1158 pos += transferBytes; 1159 } 1160 1161 *numBytes = 0; 1162 return B_OK; 1163 } 1164 1165 1166 #if 0 1167 static status_t 1168 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1169 io_request *request) 1170 { 1171 OVERLAY_CALL(io, cookie, request) 1172 } 1173 #endif 1174 1175 1176 static status_t 1177 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1178 io_request *request) 1179 { 1180 OVERLAY_CALL(cancel_io, cookie, request) 1181 } 1182 1183 1184 static status_t 1185 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, 1186 size_t size, struct file_io_vec *vecs, size_t *count) 1187 { 1188 OVERLAY_CALL(get_file_map, offset, size, vecs, count) 1189 } 1190 1191 1192 static status_t 1193 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, ulong op, 1194 void *buffer, size_t length) 1195 { 1196 OVERLAY_CALL(ioctl, cookie, op, buffer, length) 1197 } 1198 1199 1200 static status_t 1201 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, 1202 int flags) 1203 { 1204 return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags); 1205 } 1206 1207 1208 static status_t 1209 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1210 selectsync *sync) 1211 { 1212 OVERLAY_CALL(select, cookie, event, sync) 1213 } 1214 1215 1216 static status_t 1217 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1218 selectsync *sync) 1219 { 1220 OVERLAY_CALL(deselect, cookie, event, sync) 1221 } 1222 1223 1224 static status_t 1225 overlay_fsync(fs_volume *volume, fs_vnode *vnode) 1226 { 1227 return B_OK; 1228 } 1229 1230 1231 static status_t 1232 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, 1233 size_t *bufferSize) 1234 { 1235 TRACE("read_symlink\n"); 1236 return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer, 1237 bufferSize); 1238 } 1239 1240 1241 static status_t 1242 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, 1243 const char *path, int mode) 1244 { 1245 TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path); 1246 return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path, 1247 mode); 1248 } 1249 1250 1251 static status_t 1252 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, 1253 fs_vnode *target) 1254 { 1255 return B_UNSUPPORTED; 1256 } 1257 1258 1259 static status_t 1260 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) 1261 { 1262 TRACE("unlink: \"%s\"\n", name); 1263 return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL); 1264 } 1265 1266 1267 static status_t 1268 overlay_rename(fs_volume *volume, fs_vnode *vnode, 1269 const char *fromName, fs_vnode *toVnode, const char *toName) 1270 { 1271 TRACE("rename: \"%s\" -> \"%s\"\n", fromName, toName); 1272 OverlayInode *fromNode = (OverlayInode *)vnode->private_node; 1273 OverlayInode *toNode = (OverlayInode *)toVnode->private_node; 1274 overlay_dirent *entry = NULL; 1275 1276 status_t result = fromNode->RemoveEntry(fromName, &entry); 1277 if (result != B_OK) 1278 return result; 1279 1280 char *oldName = entry->name; 1281 entry->name = strdup(toName); 1282 if (entry->name == NULL) { 1283 entry->name = oldName; 1284 if (fromNode->AddEntry(entry) != B_OK) 1285 entry->remove_and_dispose(volume, fromNode->InodeNumber()); 1286 1287 return B_NO_MEMORY; 1288 } 1289 1290 result = toNode->AddEntry(entry); 1291 if (result != B_OK) { 1292 free(entry->name); 1293 entry->name = oldName; 1294 if (fromNode->AddEntry(entry) != B_OK) 1295 entry->remove_and_dispose(volume, fromNode->InodeNumber()); 1296 1297 return result; 1298 } 1299 1300 OverlayInode *node = NULL; 1301 result = get_vnode(volume, entry->inode_number, (void **)&node); 1302 if (result == B_OK && node != NULL) { 1303 node->SetName(entry->name); 1304 node->SetParentDir(toNode); 1305 put_vnode(volume, entry->inode_number); 1306 } 1307 1308 free(oldName); 1309 notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName, 1310 toNode->InodeNumber(), toName, entry->inode_number); 1311 return B_OK; 1312 } 1313 1314 1315 static status_t 1316 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode) 1317 { 1318 // TODO: implement 1319 return B_OK; 1320 } 1321 1322 1323 static status_t 1324 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) 1325 { 1326 TRACE("read_stat\n"); 1327 return ((OverlayInode *)vnode->private_node)->ReadStat(stat); 1328 } 1329 1330 1331 static status_t 1332 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, 1333 uint32 statMask) 1334 { 1335 TRACE("write_stat\n"); 1336 return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask); 1337 } 1338 1339 1340 static status_t 1341 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, 1342 int openMode, int perms, void **cookie, ino_t *newVnodeID) 1343 { 1344 TRACE("create: \"%s\"\n", name); 1345 return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 1346 perms, cookie, newVnodeID); 1347 } 1348 1349 1350 static status_t 1351 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) 1352 { 1353 TRACE("open\n"); 1354 return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie); 1355 } 1356 1357 1358 static status_t 1359 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) 1360 { 1361 TRACE("close\n"); 1362 return ((OverlayInode *)vnode->private_node)->Close(cookie); 1363 } 1364 1365 1366 static status_t 1367 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1368 { 1369 TRACE("free_cookie\n"); 1370 return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie); 1371 } 1372 1373 1374 static status_t 1375 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1376 void *buffer, size_t *length) 1377 { 1378 TRACE("read\n"); 1379 return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer, 1380 length, false); 1381 } 1382 1383 1384 static status_t 1385 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1386 const void *buffer, size_t *length) 1387 { 1388 TRACE("write\n"); 1389 return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer, 1390 length); 1391 } 1392 1393 1394 static status_t 1395 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, 1396 int perms) 1397 { 1398 TRACE("create_dir: \"%s\"\n", name); 1399 return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms); 1400 } 1401 1402 1403 static status_t 1404 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) 1405 { 1406 TRACE("remove_dir: \"%s\"\n", name); 1407 return ((OverlayInode *)vnode->private_node)->RemoveDir(name); 1408 } 1409 1410 1411 static status_t 1412 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1413 { 1414 TRACE("open_dir\n"); 1415 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie); 1416 } 1417 1418 1419 static status_t 1420 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1421 { 1422 TRACE("close_dir\n"); 1423 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie); 1424 } 1425 1426 1427 static status_t 1428 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1429 { 1430 TRACE("free_dir_cookie\n"); 1431 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie); 1432 } 1433 1434 1435 static status_t 1436 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1437 struct dirent *buffer, size_t bufferSize, uint32 *num) 1438 { 1439 TRACE("read_dir\n"); 1440 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer, 1441 bufferSize, num); 1442 } 1443 1444 1445 static status_t 1446 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1447 { 1448 TRACE("rewind_dir\n"); 1449 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie); 1450 } 1451 1452 1453 static status_t 1454 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1455 { 1456 OVERLAY_CALL(open_attr_dir, cookie) 1457 } 1458 1459 1460 static status_t 1461 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1462 { 1463 OVERLAY_CALL(close_attr_dir, cookie) 1464 } 1465 1466 1467 static status_t 1468 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1469 { 1470 OVERLAY_CALL(free_attr_dir_cookie, cookie) 1471 } 1472 1473 1474 static status_t 1475 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1476 struct dirent *buffer, size_t bufferSize, uint32 *num) 1477 { 1478 OVERLAY_CALL(read_attr_dir, cookie, buffer, bufferSize, num) 1479 } 1480 1481 1482 static status_t 1483 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1484 { 1485 OVERLAY_CALL(rewind_attr_dir, cookie) 1486 } 1487 1488 1489 static status_t 1490 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 1491 uint32 type, int openMode, void **cookie) 1492 { 1493 OVERLAY_CALL(create_attr, name, type, openMode, cookie) 1494 } 1495 1496 1497 static status_t 1498 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 1499 int openMode, void **cookie) 1500 { 1501 OVERLAY_CALL(open_attr, name, openMode, cookie) 1502 } 1503 1504 1505 static status_t 1506 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie) 1507 { 1508 OVERLAY_CALL(close_attr, cookie) 1509 } 1510 1511 1512 static status_t 1513 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1514 { 1515 OVERLAY_CALL(free_attr_cookie, cookie) 1516 } 1517 1518 1519 static status_t 1520 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1521 void *buffer, size_t *length) 1522 { 1523 OVERLAY_CALL(read_attr, cookie, pos, buffer, length) 1524 } 1525 1526 1527 static status_t 1528 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1529 const void *buffer, size_t *length) 1530 { 1531 OVERLAY_CALL(write_attr, cookie, pos, buffer, length) 1532 } 1533 1534 1535 static status_t 1536 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, 1537 struct stat *stat) 1538 { 1539 OVERLAY_CALL(read_attr_stat, cookie, stat) 1540 } 1541 1542 1543 static status_t 1544 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, 1545 const struct stat *stat, int statMask) 1546 { 1547 OVERLAY_CALL(write_attr_stat, cookie, stat, statMask) 1548 } 1549 1550 1551 static status_t 1552 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, 1553 const char *fromName, fs_vnode *toVnode, const char *toName) 1554 { 1555 OVERLAY_CALL(rename_attr, fromName, toVnode, toName) 1556 } 1557 1558 1559 static status_t 1560 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) 1561 { 1562 OVERLAY_CALL(remove_attr, name) 1563 } 1564 1565 1566 static status_t 1567 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, 1568 const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, 1569 fs_vnode *_superVnode, ino_t *nodeID) 1570 { 1571 OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID) 1572 } 1573 1574 1575 static fs_vnode_ops sOverlayVnodeOps = { 1576 &overlay_lookup, 1577 &overlay_get_vnode_name, 1578 1579 &overlay_put_vnode, 1580 &overlay_remove_vnode, 1581 1582 &overlay_can_page, 1583 &overlay_read_pages, 1584 &overlay_write_pages, 1585 1586 // TODO: the io scheduler uses it when available but we may simply 1587 // return B_UNSUPPORTED and I'm not sure it then falls back correctly 1588 NULL, //&overlay_io, 1589 &overlay_cancel_io, 1590 1591 &overlay_get_file_map, 1592 1593 /* common */ 1594 &overlay_ioctl, 1595 &overlay_set_flags, 1596 &overlay_select, 1597 &overlay_deselect, 1598 &overlay_fsync, 1599 1600 &overlay_read_symlink, 1601 &overlay_create_symlink, 1602 &overlay_link, 1603 &overlay_unlink, 1604 &overlay_rename, 1605 1606 &overlay_access, 1607 &overlay_read_stat, 1608 &overlay_write_stat, 1609 1610 /* file */ 1611 &overlay_create, 1612 &overlay_open, 1613 &overlay_close, 1614 &overlay_free_cookie, 1615 &overlay_read, 1616 &overlay_write, 1617 1618 /* directory */ 1619 &overlay_create_dir, 1620 &overlay_remove_dir, 1621 &overlay_open_dir, 1622 &overlay_close_dir, 1623 &overlay_free_dir_cookie, 1624 &overlay_read_dir, 1625 &overlay_rewind_dir, 1626 1627 /* attribute directory operations */ 1628 &overlay_open_attr_dir, 1629 &overlay_close_attr_dir, 1630 &overlay_free_attr_dir_cookie, 1631 &overlay_read_attr_dir, 1632 &overlay_rewind_attr_dir, 1633 1634 /* attribute operations */ 1635 &overlay_create_attr, 1636 &overlay_open_attr, 1637 &overlay_close_attr, 1638 &overlay_free_attr_cookie, 1639 &overlay_read_attr, 1640 &overlay_write_attr, 1641 1642 &overlay_read_attr_stat, 1643 &overlay_write_attr_stat, 1644 &overlay_rename_attr, 1645 &overlay_remove_attr, 1646 1647 /* support for node and FS layers */ 1648 &overlay_create_special_node, 1649 &overlay_get_super_vnode 1650 }; 1651 1652 1653 // #pragma mark - volume ops 1654 1655 1656 #define OVERLAY_VOLUME_CALL(op, params...) \ 1657 TRACE_VOLUME("relaying volume op: " #op "\n"); \ 1658 if (volume->super_volume->ops->op != NULL) \ 1659 return volume->super_volume->ops->op(volume->super_volume, params); 1660 1661 1662 static status_t 1663 overlay_unmount(fs_volume *volume) 1664 { 1665 TRACE_VOLUME("relaying volume op: unmount\n"); 1666 if (volume->super_volume != NULL 1667 && volume->super_volume->ops != NULL 1668 && volume->super_volume->ops->unmount != NULL) 1669 volume->super_volume->ops->unmount(volume->super_volume); 1670 1671 delete (OverlayVolume *)volume->private_volume; 1672 return B_OK; 1673 } 1674 1675 1676 static status_t 1677 overlay_read_fs_info(fs_volume *volume, struct fs_info *info) 1678 { 1679 TRACE_VOLUME("relaying volume op: read_fs_info\n"); 1680 status_t result = B_UNSUPPORTED; 1681 if (volume->super_volume->ops->read_fs_info != NULL) { 1682 result = volume->super_volume->ops->read_fs_info(volume->super_volume, 1683 info); 1684 if (result != B_OK) 1685 return result; 1686 1687 info->flags &= ~B_FS_IS_READONLY; 1688 1689 // TODO: maybe calculate based on available ram 1690 off_t available = 1024 * 1024 * 100 / info->block_size; 1691 info->total_blocks += available; 1692 info->free_blocks += available; 1693 return B_OK; 1694 } 1695 1696 return B_UNSUPPORTED; 1697 } 1698 1699 1700 static status_t 1701 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info, 1702 uint32 mask) 1703 { 1704 OVERLAY_VOLUME_CALL(write_fs_info, info, mask) 1705 return B_UNSUPPORTED; 1706 } 1707 1708 1709 static status_t 1710 overlay_sync(fs_volume *volume) 1711 { 1712 TRACE_VOLUME("relaying volume op: sync\n"); 1713 if (volume->super_volume->ops->sync != NULL) 1714 return volume->super_volume->ops->sync(volume->super_volume); 1715 return B_UNSUPPORTED; 1716 } 1717 1718 1719 static status_t 1720 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type, 1721 uint32 *_flags, bool reenter) 1722 { 1723 TRACE_VOLUME("relaying volume op: get_vnode\n"); 1724 if (volume->super_volume->ops->get_vnode != NULL) { 1725 status_t status = volume->super_volume->ops->get_vnode( 1726 volume->super_volume, id, vnode, _type, _flags, reenter); 1727 if (status != B_OK) 1728 return status; 1729 1730 OverlayInode *node = new(std::nothrow) OverlayInode( 1731 (OverlayVolume *)volume->private_volume, vnode, id); 1732 if (node == NULL) { 1733 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 1734 return B_NO_MEMORY; 1735 } 1736 1737 status = node->InitCheck(); 1738 if (status != B_OK) { 1739 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 1740 delete node; 1741 return status; 1742 } 1743 1744 vnode->private_node = node; 1745 vnode->ops = &sOverlayVnodeOps; 1746 return B_OK; 1747 } 1748 1749 return B_UNSUPPORTED; 1750 } 1751 1752 1753 static status_t 1754 overlay_open_index_dir(fs_volume *volume, void **cookie) 1755 { 1756 OVERLAY_VOLUME_CALL(open_index_dir, cookie) 1757 return B_UNSUPPORTED; 1758 } 1759 1760 1761 static status_t 1762 overlay_close_index_dir(fs_volume *volume, void *cookie) 1763 { 1764 OVERLAY_VOLUME_CALL(close_index_dir, cookie) 1765 return B_UNSUPPORTED; 1766 } 1767 1768 1769 static status_t 1770 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie) 1771 { 1772 OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie) 1773 return B_UNSUPPORTED; 1774 } 1775 1776 1777 static status_t 1778 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer, 1779 size_t bufferSize, uint32 *_num) 1780 { 1781 OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num) 1782 return B_UNSUPPORTED; 1783 } 1784 1785 1786 static status_t 1787 overlay_rewind_index_dir(fs_volume *volume, void *cookie) 1788 { 1789 OVERLAY_VOLUME_CALL(rewind_index_dir, cookie) 1790 return B_UNSUPPORTED; 1791 } 1792 1793 1794 static status_t 1795 overlay_create_index(fs_volume *volume, const char *name, uint32 type, 1796 uint32 flags) 1797 { 1798 OVERLAY_VOLUME_CALL(create_index, name, type, flags) 1799 return B_UNSUPPORTED; 1800 } 1801 1802 1803 static status_t 1804 overlay_remove_index(fs_volume *volume, const char *name) 1805 { 1806 OVERLAY_VOLUME_CALL(remove_index, name) 1807 return B_UNSUPPORTED; 1808 } 1809 1810 1811 static status_t 1812 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat) 1813 { 1814 OVERLAY_VOLUME_CALL(read_index_stat, name, stat) 1815 return B_UNSUPPORTED; 1816 } 1817 1818 1819 static status_t 1820 overlay_open_query(fs_volume *volume, const char *query, uint32 flags, 1821 port_id port, uint32 token, void **_cookie) 1822 { 1823 OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie) 1824 return B_UNSUPPORTED; 1825 } 1826 1827 1828 static status_t 1829 overlay_close_query(fs_volume *volume, void *cookie) 1830 { 1831 OVERLAY_VOLUME_CALL(close_query, cookie) 1832 return B_UNSUPPORTED; 1833 } 1834 1835 1836 static status_t 1837 overlay_free_query_cookie(fs_volume *volume, void *cookie) 1838 { 1839 OVERLAY_VOLUME_CALL(free_query_cookie, cookie) 1840 return B_UNSUPPORTED; 1841 } 1842 1843 1844 static status_t 1845 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer, 1846 size_t bufferSize, uint32 *_num) 1847 { 1848 OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num) 1849 return B_UNSUPPORTED; 1850 } 1851 1852 1853 static status_t 1854 overlay_rewind_query(fs_volume *volume, void *cookie) 1855 { 1856 OVERLAY_VOLUME_CALL(rewind_query, cookie) 1857 return B_UNSUPPORTED; 1858 } 1859 1860 1861 static status_t 1862 overlay_all_layers_mounted(fs_volume *volume) 1863 { 1864 return B_OK; 1865 } 1866 1867 1868 static status_t 1869 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode) 1870 { 1871 OverlayInode *node = new(std::nothrow) OverlayInode( 1872 (OverlayVolume *)volume->private_volume, vnode, id); 1873 if (node == NULL) 1874 return B_NO_MEMORY; 1875 1876 status_t status = node->InitCheck(); 1877 if (status != B_OK) { 1878 delete node; 1879 return status; 1880 } 1881 1882 vnode->private_node = node; 1883 vnode->ops = &sOverlayVnodeOps; 1884 return B_OK; 1885 } 1886 1887 1888 static status_t 1889 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode) 1890 { 1891 delete (OverlayInode *)vnode; 1892 return B_OK; 1893 } 1894 1895 1896 static fs_volume_ops sOverlayVolumeOps = { 1897 &overlay_unmount, 1898 1899 &overlay_read_fs_info, 1900 &overlay_write_fs_info, 1901 &overlay_sync, 1902 1903 &overlay_get_vnode, 1904 &overlay_open_index_dir, 1905 &overlay_close_index_dir, 1906 &overlay_free_index_dir_cookie, 1907 &overlay_read_index_dir, 1908 &overlay_rewind_index_dir, 1909 1910 &overlay_create_index, 1911 &overlay_remove_index, 1912 &overlay_read_index_stat, 1913 1914 &overlay_open_query, 1915 &overlay_close_query, 1916 &overlay_free_query_cookie, 1917 &overlay_read_query, 1918 &overlay_rewind_query, 1919 1920 &overlay_all_layers_mounted, 1921 &overlay_create_sub_vnode, 1922 &overlay_delete_sub_vnode 1923 }; 1924 1925 1926 // #pragma mark - filesystem module 1927 1928 1929 static status_t 1930 overlay_mount(fs_volume *volume, const char *device, uint32 flags, 1931 const char *args, ino_t *rootID) 1932 { 1933 TRACE_VOLUME("mounting write overlay\n"); 1934 volume->private_volume = new(std::nothrow) OverlayVolume(volume); 1935 if (volume->private_volume == NULL) 1936 return B_NO_MEMORY; 1937 1938 volume->ops = &sOverlayVolumeOps; 1939 return B_OK; 1940 } 1941 1942 1943 static status_t 1944 overlay_std_ops(int32 op, ...) 1945 { 1946 switch (op) { 1947 case B_MODULE_INIT: 1948 case B_MODULE_UNINIT: 1949 return B_OK; 1950 default: 1951 return B_ERROR; 1952 } 1953 } 1954 1955 1956 static file_system_module_info sOverlayFileSystem = { 1957 { 1958 "file_systems/write_overlay"B_CURRENT_FS_API_VERSION, 1959 0, 1960 overlay_std_ops, 1961 }, 1962 1963 "write_overlay", // short_name 1964 "Write Overlay File System", // pretty_name 1965 0, // DDM flags 1966 1967 // scanning 1968 NULL, // identify_partition 1969 NULL, // scan_partition 1970 NULL, // free_identify_partition_cookie 1971 NULL, // free_partition_content_cookie 1972 1973 // general operations 1974 &overlay_mount, 1975 1976 // capability querying 1977 NULL, // get_supported_operations 1978 1979 NULL, // validate_resize 1980 NULL, // validate_move 1981 NULL, // validate_set_content_name 1982 NULL, // validate_set_content_parameters 1983 NULL, // validate_initialize 1984 1985 // shadow partition modification 1986 NULL, // shadow_changed 1987 1988 // writing 1989 NULL, // defragment 1990 NULL, // repair 1991 NULL, // resize 1992 NULL, // move 1993 NULL, // set_content_name 1994 NULL, // set_content_parameters 1995 NULL // initialize 1996 }; 1997 1998 1999 status_t 2000 publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode, 2001 int type) 2002 { 2003 return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps, 2004 type, 0); 2005 } 2006 2007 } // namespace write_overlay 2008 2009 using namespace write_overlay; 2010 2011 module_info *modules[] = { 2012 (module_info *)&sOverlayFileSystem, 2013 NULL, 2014 }; 2015