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