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