1 /* 2 * Copyright 2009-2016, 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 #include <util/AutoLock.h> 17 18 #include <fs_cache.h> 19 #include <fs_info.h> 20 #include <fs_interface.h> 21 #include <io_requests.h> 22 23 #include <debug.h> 24 #include <KernelExport.h> 25 #include <NodeMonitor.h> 26 27 #include "IORequest.h" 28 29 30 //#define TRACE_OVERLAY 31 #ifdef TRACE_OVERLAY 32 #define TRACE(x...) dprintf("write_overlay: " x) 33 #define TRACE_VOLUME(x...) dprintf("write_overlay: " x) 34 #define TRACE_ALWAYS(x...) dprintf("write_overlay: " x) 35 #else 36 #define TRACE(x...) /* nothing */ 37 #define TRACE_VOLUME(x...) /* nothing */ 38 #define TRACE_ALWAYS(x...) dprintf("write_overlay: " x) 39 #endif 40 41 42 namespace write_overlay { 43 44 status_t publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, 45 void *privateNode, int type); 46 47 class OverlayInode; 48 49 struct open_cookie { 50 OverlayInode * node; 51 int open_mode; 52 void * super_cookie; 53 }; 54 55 56 struct open_dir_cookie { 57 uint32 index; 58 }; 59 60 61 struct overlay_dirent { 62 ino_t inode_number; 63 char * name; 64 OverlayInode * node; // only for attributes 65 66 void remove_and_dispose(fs_volume *volume, ino_t directoryInode) 67 { 68 notify_entry_removed(volume->id, directoryInode, 69 name, inode_number); 70 remove_vnode(volume, inode_number); 71 free(name); 72 free(this); 73 } 74 75 void dispose_attribute(fs_volume *volume, ino_t fileInode) 76 { 77 notify_attribute_changed(volume->id, -1, fileInode, 78 name, B_ATTR_REMOVED); 79 free(name); 80 free(this); 81 } 82 }; 83 84 85 struct write_buffer { 86 write_buffer * next; 87 off_t position; 88 size_t length; 89 uint8 buffer[1]; 90 }; 91 92 93 class OverlayVolume { 94 public: 95 OverlayVolume(fs_volume *volume); 96 ~OverlayVolume(); 97 98 fs_volume * Volume() { return fVolume; } 99 fs_volume * SuperVolume() { return fVolume->super_volume; } 100 101 ino_t BuildInodeNumber() { return fCurrentInodeNumber++; } 102 103 private: 104 fs_volume * fVolume; 105 ino_t fCurrentInodeNumber; 106 }; 107 108 109 class OverlayInode { 110 public: 111 OverlayInode(OverlayVolume *volume, 112 fs_vnode *superVnode, ino_t inodeNumber, 113 OverlayInode *parentDir = NULL, 114 const char *name = NULL, mode_t mode = 0, 115 bool attribute = false, 116 type_code attributeType = 0); 117 ~OverlayInode(); 118 119 status_t InitCheck(); 120 121 bool Lock() { return recursive_lock_lock(&fLock) == B_OK; } 122 void Unlock() { recursive_lock_unlock(&fLock); } 123 124 bool IsVirtual() { return fIsVirtual; } 125 bool IsModified() { return fIsModified; } 126 bool IsDataModified() { return fIsDataModified; } 127 bool IsAttribute() { return fIsAttribute; } 128 129 fs_volume * Volume() { return fVolume->Volume(); } 130 fs_volume * SuperVolume() { return fVolume->SuperVolume(); } 131 132 void SetSuperVnode(fs_vnode *superVnode); 133 fs_vnode * SuperVnode() { return &fSuperVnode; } 134 135 void SetInodeNumber(ino_t inodeNumber); 136 ino_t InodeNumber() { return fInodeNumber; } 137 138 void SetModified(); 139 void SetDataModified(); 140 void CreateCache(); 141 142 void SetParentDir(OverlayInode *parentDir); 143 OverlayInode * ParentDir() { return fParentDir; } 144 145 bool IsNonEmptyDirectory(); 146 147 status_t Lookup(const char *name, ino_t *inodeNumber); 148 status_t LookupAttribute(const char *name, 149 OverlayInode **node); 150 151 void SetName(const char *name); 152 status_t GetName(char *buffer, size_t bufferSize); 153 154 status_t ReadStat(struct stat *stat); 155 status_t WriteStat(const struct stat *stat, uint32 statMask); 156 157 status_t Create(const char *name, int openMode, int perms, 158 void **cookie, ino_t *newInodeNumber, 159 bool attribute = false, 160 type_code attributeType = 0); 161 status_t Open(int openMode, void **cookie); 162 status_t Close(void *cookie); 163 status_t FreeCookie(void *cookie); 164 status_t Read(void *cookie, off_t position, void *buffer, 165 size_t *length, bool readPages, 166 IORequest *ioRequest); 167 status_t Write(void *cookie, off_t position, 168 const void *buffer, size_t length, 169 IORequest *request); 170 171 status_t SynchronousIO(void *cookie, IORequest *request); 172 173 status_t SetFlags(void *cookie, int flags); 174 175 status_t CreateDir(const char *name, int perms); 176 status_t RemoveDir(const char *name); 177 status_t OpenDir(void **cookie, bool attribute = false); 178 status_t CloseDir(void *cookie); 179 status_t FreeDirCookie(void *cookie); 180 status_t ReadDir(void *cookie, struct dirent *buffer, 181 size_t bufferSize, uint32 *num, 182 bool attribute = false); 183 status_t RewindDir(void *cookie); 184 185 status_t CreateSymlink(const char *name, const char *path, 186 int mode); 187 status_t ReadSymlink(char *buffer, size_t *bufferSize); 188 189 status_t AddEntry(overlay_dirent *entry, 190 bool attribute = false); 191 status_t RemoveEntry(const char *name, 192 overlay_dirent **entry, bool attribute = false); 193 194 private: 195 void _TrimBuffers(); 196 197 status_t _PopulateStat(); 198 status_t _PopulateDirents(); 199 status_t _PopulateAttributeDirents(); 200 status_t _CreateCommon(const char *name, int type, int perms, 201 ino_t *newInodeNumber, OverlayInode **node, 202 bool attribute, type_code attributeType); 203 204 recursive_lock fLock; 205 OverlayVolume * fVolume; 206 OverlayInode * fParentDir; 207 const char * fName; 208 fs_vnode fSuperVnode; 209 ino_t fInodeNumber; 210 write_buffer * fWriteBuffers; 211 off_t fOriginalNodeLength; 212 overlay_dirent ** fDirents; 213 uint32 fDirentCount; 214 overlay_dirent ** fAttributeDirents; 215 uint32 fAttributeDirentCount; 216 struct stat fStat; 217 bool fHasStat; 218 bool fHasDirents; 219 bool fHasAttributeDirents; 220 bool fIsVirtual; 221 bool fIsAttribute; 222 bool fIsModified; 223 bool fIsDataModified; 224 void * fFileCache; 225 }; 226 227 228 // #pragma mark OverlayVolume 229 230 231 OverlayVolume::OverlayVolume(fs_volume *volume) 232 : fVolume(volume), 233 fCurrentInodeNumber((ino_t)1 << 60) 234 { 235 } 236 237 238 OverlayVolume::~OverlayVolume() 239 { 240 } 241 242 243 // #pragma mark OverlayInode 244 245 246 OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode, 247 ino_t inodeNumber, OverlayInode *parentDir, const char *name, mode_t mode, 248 bool attribute, type_code attributeType) 249 : fVolume(volume), 250 fParentDir(parentDir), 251 fName(name), 252 fInodeNumber(inodeNumber), 253 fWriteBuffers(NULL), 254 fOriginalNodeLength(-1), 255 fDirents(NULL), 256 fDirentCount(0), 257 fAttributeDirents(NULL), 258 fAttributeDirentCount(0), 259 fHasStat(false), 260 fHasDirents(false), 261 fHasAttributeDirents(false), 262 fIsVirtual(superVnode == NULL), 263 fIsAttribute(attribute), 264 fIsModified(false), 265 fIsDataModified(false), 266 fFileCache(NULL) 267 { 268 TRACE("inode created %" B_PRIdINO "\n", fInodeNumber); 269 270 recursive_lock_init(&fLock, "write overlay inode lock"); 271 if (superVnode != NULL) 272 fSuperVnode = *superVnode; 273 else { 274 fStat.st_dev = SuperVolume()->id; 275 fStat.st_ino = fInodeNumber; 276 fStat.st_mode = mode; 277 fStat.st_nlink = 1; 278 fStat.st_uid = 0; 279 fStat.st_gid = 0; 280 fStat.st_size = 0; 281 fStat.st_rdev = 0; 282 fStat.st_blksize = 1024; 283 fStat.st_atime = fStat.st_mtime = fStat.st_ctime = fStat.st_crtime 284 = time(NULL); 285 fStat.st_type = attributeType; 286 fHasStat = true; 287 } 288 } 289 290 291 OverlayInode::~OverlayInode() 292 { 293 TRACE("inode destroyed %" B_PRIdINO "\n", fInodeNumber); 294 if (fFileCache != NULL) 295 file_cache_delete(fFileCache); 296 297 write_buffer *element = fWriteBuffers; 298 while (element) { 299 write_buffer *next = element->next; 300 free(element); 301 element = next; 302 } 303 304 for (uint32 i = 0; i < fDirentCount; i++) { 305 free(fDirents[i]->name); 306 free(fDirents[i]); 307 } 308 free(fDirents); 309 310 for (uint32 i = 0; i < fAttributeDirentCount; i++) { 311 free(fAttributeDirents[i]->name); 312 free(fAttributeDirents[i]); 313 } 314 free(fAttributeDirents); 315 316 recursive_lock_destroy(&fLock); 317 } 318 319 320 status_t 321 OverlayInode::InitCheck() 322 { 323 return B_OK; 324 } 325 326 327 void 328 OverlayInode::SetSuperVnode(fs_vnode *superVnode) 329 { 330 RecursiveLocker locker(fLock); 331 fSuperVnode = *superVnode; 332 } 333 334 335 void 336 OverlayInode::SetInodeNumber(ino_t inodeNumber) 337 { 338 RecursiveLocker locker(fLock); 339 fInodeNumber = inodeNumber; 340 } 341 342 343 void 344 OverlayInode::SetModified() 345 { 346 if (fIsAttribute) { 347 fIsModified = true; 348 return; 349 } 350 351 // we must ensure that a modified node never get's put, as we cannot get it 352 // from the underlying filesystem, so we get an additional reference here 353 // and deliberately leak it 354 // TODO: what about non-force unmounting then? 355 void *unused = NULL; 356 get_vnode(Volume(), fInodeNumber, &unused); 357 fIsModified = true; 358 } 359 360 361 void 362 OverlayInode::SetDataModified() 363 { 364 fIsDataModified = true; 365 if (!fIsModified) 366 SetModified(); 367 } 368 369 370 void 371 OverlayInode::CreateCache() 372 { 373 if (!S_ISDIR(fStat.st_mode) && !S_ISLNK(fStat.st_mode)) { 374 fFileCache = file_cache_create(fStat.st_dev, fStat.st_ino, 0); 375 if (fFileCache != NULL) 376 file_cache_disable(fFileCache); 377 } 378 } 379 380 381 void 382 OverlayInode::SetParentDir(OverlayInode *parentDir) 383 { 384 RecursiveLocker locker(fLock); 385 fParentDir = parentDir; 386 if (fHasDirents && fDirentCount >= 2) 387 fDirents[1]->inode_number = parentDir->InodeNumber(); 388 } 389 390 391 bool 392 OverlayInode::IsNonEmptyDirectory() 393 { 394 RecursiveLocker locker(fLock); 395 if (!fHasStat) 396 _PopulateStat(); 397 398 if (!S_ISDIR(fStat.st_mode)) 399 return false; 400 401 if (!fHasDirents) 402 _PopulateDirents(); 403 404 return fDirentCount > 2; // accounting for "." and ".." entries 405 } 406 407 408 status_t 409 OverlayInode::Lookup(const char *name, ino_t *inodeNumber) 410 { 411 RecursiveLocker locker(fLock); 412 if (!fHasDirents) 413 _PopulateDirents(); 414 415 for (uint32 i = 0; i < fDirentCount; i++) { 416 if (strcmp(fDirents[i]->name, name) == 0) { 417 *inodeNumber = fDirents[i]->inode_number; 418 locker.Unlock(); 419 420 OverlayInode *node = NULL; 421 status_t result = get_vnode(Volume(), *inodeNumber, 422 (void **)&node); 423 if (result == B_OK && node != NULL && i >= 2) 424 node->SetParentDir(this); 425 return result; 426 } 427 } 428 429 return B_ENTRY_NOT_FOUND; 430 } 431 432 433 status_t 434 OverlayInode::LookupAttribute(const char *name, OverlayInode **node) 435 { 436 RecursiveLocker locker(fLock); 437 if (!fHasAttributeDirents) 438 _PopulateAttributeDirents(); 439 440 for (uint32 i = 0; i < fAttributeDirentCount; i++) { 441 overlay_dirent *dirent = fAttributeDirents[i]; 442 if (strcmp(dirent->name, name) == 0) { 443 if (dirent->node == NULL) { 444 OverlayInode *newNode = new(std::nothrow) OverlayInode(fVolume, 445 SuperVnode(), fInodeNumber, NULL, dirent->name, 0, true, 0); 446 if (newNode == NULL) 447 return B_NO_MEMORY; 448 449 status_t result = newNode->InitCheck(); 450 if (result != B_OK) { 451 delete newNode; 452 return result; 453 } 454 455 dirent->node = newNode; 456 } 457 458 *node = dirent->node; 459 return B_OK; 460 } 461 } 462 463 return B_ENTRY_NOT_FOUND; 464 } 465 466 467 void 468 OverlayInode::SetName(const char *name) 469 { 470 RecursiveLocker locker(fLock); 471 fName = name; 472 if (!fIsModified) 473 SetModified(); 474 } 475 476 477 status_t 478 OverlayInode::GetName(char *buffer, size_t bufferSize) 479 { 480 RecursiveLocker locker(fLock); 481 if (fName != NULL) { 482 strlcpy(buffer, fName, bufferSize); 483 return B_OK; 484 } 485 486 if (fIsVirtual || fIsAttribute) 487 return B_UNSUPPORTED; 488 489 if (fSuperVnode.ops->get_vnode_name == NULL) 490 return B_UNSUPPORTED; 491 492 return fSuperVnode.ops->get_vnode_name(SuperVolume(), &fSuperVnode, buffer, 493 bufferSize); 494 } 495 496 497 status_t 498 OverlayInode::ReadStat(struct stat *stat) 499 { 500 RecursiveLocker locker(fLock); 501 if (!fHasStat) 502 _PopulateStat(); 503 504 memcpy(stat, &fStat, sizeof(struct stat)); 505 stat->st_blocks = (stat->st_size + stat->st_blksize - 1) / stat->st_blksize; 506 return B_OK; 507 } 508 509 510 status_t 511 OverlayInode::WriteStat(const struct stat *stat, uint32 statMask) 512 { 513 if (fIsAttribute) 514 return B_UNSUPPORTED; 515 516 RecursiveLocker locker(fLock); 517 if (!fHasStat) 518 _PopulateStat(); 519 520 if (statMask & B_STAT_SIZE) { 521 if (fStat.st_size != stat->st_size) { 522 fStat.st_size = stat->st_size; 523 if (!fIsDataModified) 524 SetDataModified(); 525 _TrimBuffers(); 526 } 527 } 528 529 if (statMask & B_STAT_MODE) 530 fStat.st_mode = (fStat.st_mode & ~S_IUMSK) | (stat->st_mode & S_IUMSK); 531 if (statMask & B_STAT_UID) 532 fStat.st_uid = stat->st_uid; 533 if (statMask & B_STAT_GID) 534 fStat.st_gid = stat->st_gid; 535 536 if (statMask & B_STAT_MODIFICATION_TIME) 537 fStat.st_mtime = stat->st_mtime; 538 if (statMask & B_STAT_CREATION_TIME) 539 fStat.st_crtime = stat->st_crtime; 540 541 if ((statMask & (B_STAT_MODE | B_STAT_UID | B_STAT_GID)) != 0 542 && (statMask & B_STAT_MODIFICATION_TIME) == 0) { 543 fStat.st_mtime = time(NULL); 544 statMask |= B_STAT_MODIFICATION_TIME; 545 } 546 547 if (!fIsModified) 548 SetModified(); 549 550 notify_stat_changed(SuperVolume()->id, -1, fInodeNumber, statMask); 551 return B_OK; 552 } 553 554 555 status_t 556 OverlayInode::Create(const char *name, int openMode, int perms, void **cookie, 557 ino_t *newInodeNumber, bool attribute, type_code attributeType) 558 { 559 OverlayInode *newNode = NULL; 560 status_t result = _CreateCommon(name, attribute ? S_ATTR : S_IFREG, perms, 561 newInodeNumber, &newNode, attribute, attributeType); 562 if (result != B_OK) 563 return result; 564 565 return newNode->Open(openMode, cookie); 566 } 567 568 569 status_t 570 OverlayInode::Open(int openMode, void **_cookie) 571 { 572 RecursiveLocker locker(fLock); 573 if (!fHasStat) 574 _PopulateStat(); 575 576 open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie)); 577 if (cookie == NULL) 578 return B_NO_MEMORY; 579 580 cookie->open_mode = openMode; 581 cookie->node = this; 582 *_cookie = cookie; 583 584 if (fIsVirtual) { 585 if (openMode & O_TRUNC) { 586 fStat.st_size = 0; 587 _TrimBuffers(); 588 } 589 590 return B_OK; 591 } 592 593 if ((fIsAttribute && fSuperVnode.ops->open_attr == NULL) 594 || (!fIsAttribute && fSuperVnode.ops->open == NULL)) 595 return B_UNSUPPORTED; 596 597 if (openMode & O_TRUNC) { 598 if (fStat.st_size != 0) { 599 fStat.st_size = 0; 600 _TrimBuffers(); 601 if (!fIsDataModified) 602 SetDataModified(); 603 } 604 } 605 606 openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT); 607 status_t result; 608 if (fIsAttribute) { 609 result = fSuperVnode.ops->open_attr(SuperVolume(), &fSuperVnode, 610 fName, openMode, &cookie->super_cookie); 611 } else { 612 result = fSuperVnode.ops->open(SuperVolume(), &fSuperVnode, 613 openMode, &cookie->super_cookie); 614 } 615 616 if (result != B_OK) { 617 free(cookie); 618 return result; 619 } 620 621 if (fOriginalNodeLength < 0) { 622 struct stat stat; 623 if (fIsAttribute) { 624 result = fSuperVnode.ops->read_attr_stat(SuperVolume(), 625 &fSuperVnode, cookie->super_cookie, &stat); 626 } else { 627 result = fSuperVnode.ops->read_stat(SuperVolume(), 628 &fSuperVnode, &stat); 629 } 630 631 if (result != B_OK) 632 return result; 633 634 fOriginalNodeLength = stat.st_size; 635 } 636 637 return B_OK; 638 } 639 640 641 status_t 642 OverlayInode::Close(void *_cookie) 643 { 644 if (fIsVirtual) 645 return B_OK; 646 647 open_cookie *cookie = (open_cookie *)_cookie; 648 if (fIsAttribute) { 649 return fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode, 650 cookie->super_cookie); 651 } 652 653 return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode, 654 cookie->super_cookie); 655 } 656 657 658 status_t 659 OverlayInode::FreeCookie(void *_cookie) 660 { 661 status_t result = B_OK; 662 open_cookie *cookie = (open_cookie *)_cookie; 663 if (!fIsVirtual) { 664 if (fIsAttribute) { 665 result = fSuperVnode.ops->free_attr_cookie(SuperVolume(), 666 &fSuperVnode, cookie->super_cookie); 667 } else { 668 result = fSuperVnode.ops->free_cookie(SuperVolume(), 669 &fSuperVnode, cookie->super_cookie); 670 } 671 } 672 673 free(cookie); 674 return result; 675 } 676 677 678 status_t 679 OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length, 680 bool readPages, IORequest *ioRequest) 681 { 682 RecursiveLocker locker(fLock); 683 if (position >= fStat.st_size) { 684 *length = 0; 685 return B_OK; 686 } 687 688 uint8 *pointer = (uint8 *)buffer; 689 write_buffer *element = fWriteBuffers; 690 size_t bytesLeft = (size_t)MIN(fStat.st_size - position, (off_t)*length); 691 *length = bytesLeft; 692 693 void *superCookie = _cookie; 694 if (!fIsVirtual && !readPages && _cookie != NULL) 695 superCookie = ((open_cookie *)_cookie)->super_cookie; 696 697 while (bytesLeft > 0) { 698 size_t gapSize = bytesLeft; 699 if (element != NULL) { 700 gapSize = (size_t)MIN((off_t)bytesLeft, element->position > position ? 701 element->position - position : 0); 702 } 703 704 if (gapSize > 0 && !fIsVirtual && position < fOriginalNodeLength) { 705 // there's a part missing between the read position and our 706 // next position, fill the gap with original file content 707 size_t readLength = (size_t)MIN(fOriginalNodeLength - position, 708 (off_t)gapSize); 709 status_t result = B_ERROR; 710 if (readPages) { 711 iovec vector; 712 vector.iov_base = pointer; 713 vector.iov_len = readLength; 714 715 result = fSuperVnode.ops->read_pages(SuperVolume(), 716 &fSuperVnode, superCookie, position, &vector, 1, 717 &readLength); 718 } else if (ioRequest != NULL) { 719 IORequest *subRequest; 720 result = ioRequest->CreateSubRequest(position, position, 721 readLength, subRequest); 722 if (result != B_OK) 723 return result; 724 725 bool wereSuppressed = ioRequest->SuppressChildNotifications(); 726 ioRequest->SetSuppressChildNotifications(true); 727 result = fSuperVnode.ops->io(SuperVolume(), &fSuperVnode, 728 superCookie, subRequest); 729 if (result != B_OK) 730 return result; 731 732 result = subRequest->Wait(0, 0); 733 readLength = subRequest->TransferredBytes(); 734 ioRequest->SetSuppressChildNotifications(wereSuppressed); 735 } else if (fIsAttribute) { 736 result = fSuperVnode.ops->read_attr(SuperVolume(), &fSuperVnode, 737 superCookie, position, pointer, &readLength); 738 } else { 739 result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode, 740 superCookie, position, pointer, &readLength); 741 } 742 743 if (result != B_OK) 744 return result; 745 746 pointer += readLength; 747 position += readLength; 748 bytesLeft -= readLength; 749 gapSize -= readLength; 750 } 751 752 if (gapSize > 0) { 753 // there's a gap before our next position which we cannot 754 // fill with original file content, zero it out 755 if (ioRequest != NULL) 756 ;// TODO: handle this case 757 else 758 memset(pointer, 0, gapSize); 759 760 bytesLeft -= gapSize; 761 position += gapSize; 762 pointer += gapSize; 763 } 764 765 // we've reached the end 766 if (bytesLeft == 0 || element == NULL) 767 break; 768 769 off_t elementEnd = element->position + element->length; 770 if (elementEnd > position) { 771 size_t copyLength = (size_t)MIN(elementEnd - position, 772 (off_t)bytesLeft); 773 774 const void *source = element->buffer + (position 775 - element->position); 776 if (ioRequest != NULL) { 777 ioRequest->CopyData(source, ioRequest->Offset() 778 + ((addr_t)pointer - (addr_t)buffer), copyLength); 779 } else 780 memcpy(pointer, source, copyLength); 781 782 bytesLeft -= copyLength; 783 position += copyLength; 784 pointer += copyLength; 785 } 786 787 element = element->next; 788 } 789 790 return B_OK; 791 } 792 793 794 status_t 795 OverlayInode::Write(void *_cookie, off_t position, const void *buffer, 796 size_t length, IORequest *ioRequest) 797 { 798 RecursiveLocker locker(fLock); 799 if (_cookie != NULL) { 800 open_cookie *cookie = (open_cookie *)_cookie; 801 if (cookie->open_mode & O_APPEND) 802 position = fStat.st_size; 803 } 804 805 if (!fIsDataModified) 806 SetDataModified(); 807 808 // find insertion point 809 write_buffer **link = &fWriteBuffers; 810 write_buffer *other = fWriteBuffers; 811 write_buffer *swallow = NULL; 812 off_t newPosition = position; 813 size_t newLength = length; 814 uint32 swallowCount = 0; 815 816 while (other) { 817 off_t newEnd = newPosition + newLength; 818 off_t otherEnd = other->position + other->length; 819 if (otherEnd < newPosition) { 820 // other is completely before us 821 link = &other->next; 822 other = other->next; 823 continue; 824 } 825 826 if (other->position > newEnd) { 827 // other is completely past us 828 break; 829 } 830 831 swallowCount++; 832 if (swallow == NULL) 833 swallow = other; 834 835 if (other->position <= newPosition) { 836 if (swallowCount == 1 && otherEnd >= newEnd) { 837 // other chunk completely covers us, just copy 838 void *target = other->buffer + (newPosition - other->position); 839 if (ioRequest != NULL) 840 ioRequest->CopyData(ioRequest->Offset(), target, length); 841 else 842 memcpy(target, buffer, length); 843 844 fStat.st_mtime = time(NULL); 845 if (fIsAttribute) { 846 notify_attribute_changed(SuperVolume()->id, -1, 847 fInodeNumber, fName, B_ATTR_CHANGED); 848 } else { 849 notify_stat_changed(SuperVolume()->id, -1, fInodeNumber, 850 B_STAT_MODIFICATION_TIME); 851 } 852 return B_OK; 853 } 854 855 newLength += newPosition - other->position; 856 newPosition = other->position; 857 } 858 859 if (otherEnd > newEnd) 860 newLength += otherEnd - newEnd; 861 862 other = other->next; 863 } 864 865 write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1 866 + newLength); 867 if (element == NULL) 868 return B_NO_MEMORY; 869 870 element->next = *link; 871 element->position = newPosition; 872 element->length = newLength; 873 *link = element; 874 875 bool sizeChanged = false; 876 off_t newEnd = newPosition + newLength; 877 if (newEnd > fStat.st_size) { 878 fStat.st_size = newEnd; 879 sizeChanged = true; 880 881 if (fFileCache) 882 file_cache_set_size(fFileCache, newEnd); 883 } 884 885 // populate the buffer with the existing chunks 886 if (swallowCount > 0) { 887 while (swallowCount-- > 0) { 888 memcpy(element->buffer + (swallow->position - newPosition), 889 swallow->buffer, swallow->length); 890 891 element->next = swallow->next; 892 free(swallow); 893 swallow = element->next; 894 } 895 } 896 897 void *target = element->buffer + (position - newPosition); 898 if (ioRequest != NULL) 899 ioRequest->CopyData(0, target, length); 900 else 901 memcpy(target, buffer, length); 902 903 fStat.st_mtime = time(NULL); 904 905 if (fIsAttribute) { 906 notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber, fName, 907 B_ATTR_CHANGED); 908 } else { 909 notify_stat_changed(SuperVolume()->id, -1, fInodeNumber, 910 B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0)); 911 } 912 913 return B_OK; 914 } 915 916 917 status_t 918 OverlayInode::SynchronousIO(void *cookie, IORequest *request) 919 { 920 status_t result; 921 size_t length = request->Length(); 922 if (request->IsWrite()) 923 result = Write(cookie, request->Offset(), NULL, length, request); 924 else 925 result = Read(cookie, request->Offset(), NULL, &length, false, request); 926 927 if (result == B_OK) 928 request->SetTransferredBytes(false, length); 929 930 request->SetStatusAndNotify(result); 931 return result; 932 } 933 934 935 status_t 936 OverlayInode::SetFlags(void *_cookie, int flags) 937 { 938 // we can only handle O_APPEND, O_NONBLOCK is ignored. 939 open_cookie *cookie = (open_cookie *)_cookie; 940 cookie->open_mode = (cookie->open_mode & ~O_APPEND) | (flags & ~O_APPEND); 941 return B_OK; 942 } 943 944 945 status_t 946 OverlayInode::CreateDir(const char *name, int perms) 947 { 948 return _CreateCommon(name, S_IFDIR, perms, NULL, NULL, false, 0); 949 } 950 951 952 status_t 953 OverlayInode::RemoveDir(const char *name) 954 { 955 return RemoveEntry(name, NULL); 956 } 957 958 959 status_t 960 OverlayInode::OpenDir(void **cookie, bool attribute) 961 { 962 RecursiveLocker locker(fLock); 963 if (!attribute) { 964 if (!fHasStat) 965 _PopulateStat(); 966 967 if (!S_ISDIR(fStat.st_mode)) 968 return B_NOT_A_DIRECTORY; 969 } 970 971 if (!attribute && !fHasDirents) 972 _PopulateDirents(); 973 else if (attribute && !fHasAttributeDirents) 974 _PopulateAttributeDirents(); 975 976 open_dir_cookie *dirCookie = (open_dir_cookie *)malloc( 977 sizeof(open_dir_cookie)); 978 if (dirCookie == NULL) 979 return B_NO_MEMORY; 980 981 dirCookie->index = 0; 982 *cookie = dirCookie; 983 return B_OK; 984 } 985 986 987 status_t 988 OverlayInode::CloseDir(void *cookie) 989 { 990 return B_OK; 991 } 992 993 994 status_t 995 OverlayInode::FreeDirCookie(void *cookie) 996 { 997 free(cookie); 998 return B_OK; 999 } 1000 1001 1002 status_t 1003 OverlayInode::ReadDir(void *cookie, struct dirent *buffer, size_t bufferSize, 1004 uint32 *num, bool attribute) 1005 { 1006 RecursiveLocker locker(fLock); 1007 uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount; 1008 overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents; 1009 1010 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie; 1011 if (dirCookie->index >= direntCount) { 1012 *num = 0; 1013 return B_OK; 1014 } 1015 1016 overlay_dirent *dirent = dirents[dirCookie->index++]; 1017 size_t nameLength = MIN(strlen(dirent->name), 1018 bufferSize - sizeof(struct dirent)) + 1; 1019 1020 buffer->d_dev = SuperVolume()->id; 1021 buffer->d_pdev = 0; 1022 buffer->d_ino = dirent->inode_number; 1023 buffer->d_pino = 0; 1024 buffer->d_reclen = sizeof(struct dirent) + nameLength; 1025 strlcpy(buffer->d_name, dirent->name, nameLength); 1026 1027 *num = 1; 1028 return B_OK; 1029 } 1030 1031 1032 status_t 1033 OverlayInode::RewindDir(void *cookie) 1034 { 1035 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie; 1036 dirCookie->index = 0; 1037 return B_OK; 1038 } 1039 1040 1041 status_t 1042 OverlayInode::CreateSymlink(const char *name, const char *path, int mode) 1043 { 1044 OverlayInode *newNode = NULL; 1045 // TODO: find out why mode is ignored 1046 status_t result = _CreateCommon(name, S_IFLNK, 0777, NULL, &newNode, 1047 false, 0); 1048 if (result != B_OK) 1049 return result; 1050 1051 return newNode->Write(NULL, 0, path, strlen(path), NULL); 1052 } 1053 1054 1055 status_t 1056 OverlayInode::ReadSymlink(char *buffer, size_t *bufferSize) 1057 { 1058 if (fIsVirtual) { 1059 if (!S_ISLNK(fStat.st_mode)) 1060 return B_BAD_VALUE; 1061 1062 return Read(NULL, 0, buffer, bufferSize, false, NULL); 1063 } 1064 1065 if (fSuperVnode.ops->read_symlink == NULL) 1066 return B_UNSUPPORTED; 1067 1068 return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer, 1069 bufferSize); 1070 } 1071 1072 1073 status_t 1074 OverlayInode::AddEntry(overlay_dirent *entry, bool attribute) 1075 { 1076 RecursiveLocker locker(fLock); 1077 if (!attribute && !fHasDirents) 1078 _PopulateDirents(); 1079 else if (attribute && !fHasAttributeDirents) 1080 _PopulateAttributeDirents(); 1081 1082 status_t result = RemoveEntry(entry->name, NULL, attribute); 1083 if (result != B_OK && result != B_ENTRY_NOT_FOUND) 1084 return B_FILE_EXISTS; 1085 1086 overlay_dirent **newDirents = (overlay_dirent **)realloc( 1087 attribute ? fAttributeDirents : fDirents, 1088 sizeof(overlay_dirent *) 1089 * ((attribute ? fAttributeDirentCount : fDirentCount) + 1)); 1090 if (newDirents == NULL) 1091 return B_NO_MEMORY; 1092 1093 if (attribute) { 1094 fAttributeDirents = newDirents; 1095 fAttributeDirents[fAttributeDirentCount++] = entry; 1096 } else { 1097 fDirents = newDirents; 1098 fDirents[fDirentCount++] = entry; 1099 } 1100 1101 if (!fIsModified) 1102 SetModified(); 1103 1104 return B_OK; 1105 } 1106 1107 1108 status_t 1109 OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry, 1110 bool attribute) 1111 { 1112 RecursiveLocker locker(fLock); 1113 if (!attribute && !fHasDirents) 1114 _PopulateDirents(); 1115 else if (attribute && !fHasAttributeDirents) 1116 _PopulateAttributeDirents(); 1117 1118 uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount; 1119 overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents; 1120 for (uint32 i = 0; i < direntCount; i++) { 1121 overlay_dirent *entry = dirents[i]; 1122 if (strcmp(entry->name, name) == 0) { 1123 if (_entry == NULL && !attribute) { 1124 // check for non-empty directories when trying 1125 // to dispose the entry 1126 OverlayInode *node = NULL; 1127 status_t result = get_vnode(Volume(), entry->inode_number, 1128 (void **)&node); 1129 if (result != B_OK) 1130 return result; 1131 1132 if (node->IsNonEmptyDirectory()) 1133 result = B_DIRECTORY_NOT_EMPTY; 1134 1135 put_vnode(Volume(), entry->inode_number); 1136 if (result != B_OK) 1137 return result; 1138 } 1139 1140 for (uint32 j = i + 1; j < direntCount; j++) 1141 dirents[j - 1] = dirents[j]; 1142 1143 if (attribute) 1144 fAttributeDirentCount--; 1145 else 1146 fDirentCount--; 1147 1148 if (_entry != NULL) 1149 *_entry = entry; 1150 else if (attribute) 1151 entry->dispose_attribute(Volume(), fInodeNumber); 1152 else 1153 entry->remove_and_dispose(Volume(), fInodeNumber); 1154 1155 if (!fIsModified) 1156 SetModified(); 1157 1158 return B_OK; 1159 } 1160 } 1161 1162 return B_ENTRY_NOT_FOUND; 1163 } 1164 1165 1166 void 1167 OverlayInode::_TrimBuffers() 1168 { 1169 // the file size has been changed and we want to trim 1170 // off everything that goes beyond the new size 1171 write_buffer **link = &fWriteBuffers; 1172 write_buffer *buffer = fWriteBuffers; 1173 1174 while (buffer != NULL) { 1175 off_t bufferEnd = buffer->position + buffer->length; 1176 if (bufferEnd > fStat.st_size) 1177 break; 1178 1179 link = &buffer->next; 1180 buffer = buffer->next; 1181 } 1182 1183 if (buffer == NULL) { 1184 // didn't find anything crossing or past the end 1185 return; 1186 } 1187 1188 if (buffer->position < fStat.st_size) { 1189 // got a crossing buffer to resize 1190 size_t newLength = fStat.st_size - buffer->position; 1191 write_buffer *newBuffer = (write_buffer *)realloc(buffer, 1192 sizeof(write_buffer) - 1 + newLength); 1193 1194 if (newBuffer != NULL) { 1195 buffer = newBuffer; 1196 *link = newBuffer; 1197 } else { 1198 // we don't really care if it worked, if it didn't we simply 1199 // keep the old buffer and reset it's size 1200 } 1201 1202 buffer->length = newLength; 1203 link = &buffer->next; 1204 buffer = buffer->next; 1205 } 1206 1207 // everything else we can throw away 1208 *link = NULL; 1209 while (buffer != NULL) { 1210 write_buffer *next = buffer->next; 1211 free(buffer); 1212 buffer = next; 1213 } 1214 } 1215 1216 1217 status_t 1218 OverlayInode::_PopulateStat() 1219 { 1220 if (fHasStat) 1221 return B_OK; 1222 1223 fHasStat = true; 1224 if (fIsAttribute) { 1225 if (fName == NULL || fSuperVnode.ops->open_attr == NULL 1226 || fSuperVnode.ops->read_attr_stat == NULL) 1227 return B_UNSUPPORTED; 1228 1229 void *cookie = NULL; 1230 status_t result = fSuperVnode.ops->open_attr(SuperVolume(), 1231 &fSuperVnode, fName, O_RDONLY, &cookie); 1232 if (result != B_OK) 1233 return result; 1234 1235 result = fSuperVnode.ops->read_attr_stat(SuperVolume(), &fSuperVnode, 1236 cookie, &fStat); 1237 1238 if (fSuperVnode.ops->close_attr != NULL) 1239 fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode, cookie); 1240 1241 if (fSuperVnode.ops->free_attr_cookie != NULL) { 1242 fSuperVnode.ops->free_attr_cookie(SuperVolume(), &fSuperVnode, 1243 cookie); 1244 } 1245 1246 return B_OK; 1247 } 1248 1249 if (fSuperVnode.ops->read_stat == NULL) 1250 return B_UNSUPPORTED; 1251 1252 return fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode, &fStat); 1253 } 1254 1255 1256 status_t 1257 OverlayInode::_PopulateDirents() 1258 { 1259 if (fHasDirents) 1260 return B_OK; 1261 1262 fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2); 1263 if (fDirents == NULL) 1264 return B_NO_MEMORY; 1265 1266 const char *names[] = { ".", ".." }; 1267 ino_t inodes[] = { fInodeNumber, 1268 fParentDir != NULL ? fParentDir->InodeNumber() : 0 }; 1269 for (uint32 i = 0; i < 2; i++) { 1270 fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent)); 1271 if (fDirents[i] == NULL) 1272 return B_NO_MEMORY; 1273 1274 fDirents[i]->inode_number = inodes[i]; 1275 fDirents[i]->name = strdup(names[i]); 1276 if (fDirents[i]->name == NULL) { 1277 free(fDirents[i]); 1278 return B_NO_MEMORY; 1279 } 1280 1281 fDirentCount++; 1282 } 1283 1284 fHasDirents = true; 1285 if (fIsVirtual || fSuperVnode.ops->open_dir == NULL 1286 || fSuperVnode.ops->read_dir == NULL) 1287 return B_OK; 1288 1289 // we don't really care about errors from here on 1290 void *superCookie = NULL; 1291 status_t result = fSuperVnode.ops->open_dir(SuperVolume(), 1292 &fSuperVnode, &superCookie); 1293 if (result != B_OK) 1294 return B_OK; 1295 1296 size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH; 1297 struct dirent *buffer = (struct dirent *)malloc(bufferSize); 1298 if (buffer == NULL) 1299 goto close_dir; 1300 1301 while (true) { 1302 uint32 num = 1; 1303 result = fSuperVnode.ops->read_dir(SuperVolume(), 1304 &fSuperVnode, superCookie, buffer, bufferSize, &num); 1305 if (result != B_OK || num == 0) 1306 break; 1307 1308 overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents, 1309 sizeof(overlay_dirent *) * (fDirentCount + num)); 1310 if (newDirents == NULL) { 1311 TRACE_ALWAYS("failed to allocate storage for dirents\n"); 1312 break; 1313 } 1314 1315 fDirents = newDirents; 1316 struct dirent *dirent = buffer; 1317 for (uint32 i = 0; i < num; i++) { 1318 if (strcmp(dirent->d_name, ".") != 0 1319 && strcmp(dirent->d_name, "..") != 0) { 1320 overlay_dirent *entry = (overlay_dirent *)malloc( 1321 sizeof(overlay_dirent)); 1322 if (entry == NULL) { 1323 TRACE_ALWAYS("failed to allocate storage for dirent\n"); 1324 break; 1325 } 1326 1327 entry->inode_number = dirent->d_ino; 1328 entry->name = strdup(dirent->d_name); 1329 if (entry->name == NULL) { 1330 TRACE_ALWAYS("failed to duplicate dirent entry name\n"); 1331 free(entry); 1332 break; 1333 } 1334 1335 fDirents[fDirentCount++] = entry; 1336 } 1337 1338 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen); 1339 } 1340 } 1341 1342 free(buffer); 1343 1344 close_dir: 1345 if (fSuperVnode.ops->close_dir != NULL) 1346 fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie); 1347 1348 if (fSuperVnode.ops->free_dir_cookie != NULL) { 1349 fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode, 1350 superCookie); 1351 } 1352 1353 return B_OK; 1354 } 1355 1356 1357 status_t 1358 OverlayInode::_PopulateAttributeDirents() 1359 { 1360 if (fHasAttributeDirents) 1361 return B_OK; 1362 1363 fHasAttributeDirents = true; 1364 if (fIsVirtual || fSuperVnode.ops->open_attr_dir == NULL 1365 || fSuperVnode.ops->read_attr_dir == NULL) 1366 return B_OK; 1367 1368 // we don't really care about errors from here on 1369 void *superCookie = NULL; 1370 status_t result = fSuperVnode.ops->open_attr_dir(SuperVolume(), 1371 &fSuperVnode, &superCookie); 1372 if (result != B_OK) 1373 return B_OK; 1374 1375 size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH; 1376 struct dirent *buffer = (struct dirent *)malloc(bufferSize); 1377 if (buffer == NULL) 1378 goto close_attr_dir; 1379 1380 while (true) { 1381 uint32 num = 1; 1382 result = fSuperVnode.ops->read_attr_dir(SuperVolume(), 1383 &fSuperVnode, superCookie, buffer, bufferSize, &num); 1384 if (result != B_OK || num == 0) 1385 break; 1386 1387 overlay_dirent **newDirents = (overlay_dirent **)realloc( 1388 fAttributeDirents, sizeof(overlay_dirent *) 1389 * (fAttributeDirentCount + num)); 1390 if (newDirents == NULL) { 1391 TRACE_ALWAYS("failed to allocate storage for attribute dirents\n"); 1392 break; 1393 } 1394 1395 fAttributeDirents = newDirents; 1396 struct dirent *dirent = buffer; 1397 for (uint32 i = 0; i < num; i++) { 1398 overlay_dirent *entry = (overlay_dirent *)malloc( 1399 sizeof(overlay_dirent)); 1400 if (entry == NULL) { 1401 TRACE_ALWAYS("failed to allocate storage for attr dirent\n"); 1402 break; 1403 } 1404 1405 entry->node = NULL; 1406 entry->inode_number = fInodeNumber; 1407 entry->name = strdup(dirent->d_name); 1408 if (entry->name == NULL) { 1409 TRACE_ALWAYS("failed to duplicate dirent entry name\n"); 1410 free(entry); 1411 break; 1412 } 1413 1414 fAttributeDirents[fAttributeDirentCount++] = entry; 1415 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen); 1416 } 1417 } 1418 1419 free(buffer); 1420 1421 close_attr_dir: 1422 if (fSuperVnode.ops->close_attr_dir != NULL) { 1423 fSuperVnode.ops->close_attr_dir(SuperVolume(), &fSuperVnode, 1424 superCookie); 1425 } 1426 1427 if (fSuperVnode.ops->free_attr_dir_cookie != NULL) { 1428 fSuperVnode.ops->free_attr_dir_cookie(SuperVolume(), &fSuperVnode, 1429 superCookie); 1430 } 1431 1432 return B_OK; 1433 } 1434 1435 1436 status_t 1437 OverlayInode::_CreateCommon(const char *name, int type, int perms, 1438 ino_t *newInodeNumber, OverlayInode **_node, bool attribute, 1439 type_code attributeType) 1440 { 1441 RecursiveLocker locker(fLock); 1442 if (!fHasStat) 1443 _PopulateStat(); 1444 1445 if (!attribute && !S_ISDIR(fStat.st_mode)) 1446 return B_NOT_A_DIRECTORY; 1447 1448 locker.Unlock(); 1449 1450 overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent)); 1451 if (entry == NULL) 1452 return B_NO_MEMORY; 1453 1454 entry->node = NULL; 1455 entry->name = strdup(name); 1456 if (entry->name == NULL) { 1457 free(entry); 1458 return B_NO_MEMORY; 1459 } 1460 1461 if (attribute) 1462 entry->inode_number = fInodeNumber; 1463 else 1464 entry->inode_number = fVolume->BuildInodeNumber(); 1465 1466 OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL, 1467 entry->inode_number, this, entry->name, (perms & S_IUMSK) | type 1468 | (attribute ? S_ATTR : 0), attribute, attributeType); 1469 if (node == NULL) { 1470 free(entry->name); 1471 free(entry); 1472 return B_NO_MEMORY; 1473 } 1474 1475 status_t result = AddEntry(entry, attribute); 1476 if (result != B_OK) { 1477 free(entry->name); 1478 free(entry); 1479 delete node; 1480 return result; 1481 } 1482 1483 if (!attribute) { 1484 result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number, 1485 node, type); 1486 if (result != B_OK) { 1487 RemoveEntry(entry->name, NULL); 1488 delete node; 1489 return result; 1490 } 1491 } else 1492 entry->node = node; 1493 1494 node->Lock(); 1495 node->SetDataModified(); 1496 if (!attribute) 1497 node->CreateCache(); 1498 node->Unlock(); 1499 1500 if (newInodeNumber != NULL) 1501 *newInodeNumber = entry->inode_number; 1502 if (_node != NULL) 1503 *_node = node; 1504 1505 if (attribute) { 1506 notify_attribute_changed(SuperVolume()->id, -1, fInodeNumber, 1507 entry->name, B_ATTR_CREATED); 1508 } else { 1509 notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name, 1510 entry->inode_number); 1511 } 1512 1513 return B_OK; 1514 } 1515 1516 1517 // #pragma mark - vnode ops 1518 1519 1520 #define OVERLAY_CALL(op, params...) \ 1521 TRACE("relaying op: " #op "\n"); \ 1522 OverlayInode *node = (OverlayInode *)vnode->private_node; \ 1523 if (node->IsVirtual()) \ 1524 return B_UNSUPPORTED; \ 1525 fs_vnode *superVnode = node->SuperVnode(); \ 1526 if (superVnode->ops->op != NULL) \ 1527 return superVnode->ops->op(volume->super_volume, superVnode, params); \ 1528 return B_UNSUPPORTED; 1529 1530 1531 static status_t 1532 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 1533 { 1534 TRACE("put_vnode\n"); 1535 OverlayInode *node = (OverlayInode *)vnode->private_node; 1536 if (node->IsVirtual() || node->IsModified()) { 1537 panic("loosing virtual/modified node\n"); 1538 delete node; 1539 return B_OK; 1540 } 1541 1542 status_t result = B_OK; 1543 fs_vnode *superVnode = node->SuperVnode(); 1544 if (superVnode->ops->put_vnode != NULL) { 1545 result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 1546 reenter); 1547 } 1548 1549 delete node; 1550 return result; 1551 } 1552 1553 1554 static status_t 1555 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 1556 { 1557 TRACE("remove_vnode\n"); 1558 OverlayInode *node = (OverlayInode *)vnode->private_node; 1559 if (node->IsVirtual()) { 1560 delete node; 1561 return B_OK; 1562 } 1563 1564 status_t result = B_OK; 1565 fs_vnode *superVnode = node->SuperVnode(); 1566 if (superVnode->ops->put_vnode != NULL) { 1567 result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 1568 reenter); 1569 } 1570 1571 delete node; 1572 return result; 1573 } 1574 1575 1576 static status_t 1577 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, 1578 fs_volume *superVolume, fs_vnode *_superVnode) 1579 { 1580 if (volume == superVolume) { 1581 *_superVnode = *vnode; 1582 return B_OK; 1583 } 1584 1585 OverlayInode *node = (OverlayInode *)vnode->private_node; 1586 if (node->IsVirtual()) { 1587 *_superVnode = *vnode; 1588 return B_OK; 1589 } 1590 1591 fs_vnode *superVnode = node->SuperVnode(); 1592 if (superVnode->ops->get_super_vnode != NULL) { 1593 return superVnode->ops->get_super_vnode(volume->super_volume, 1594 superVnode, superVolume, _superVnode); 1595 } 1596 1597 *_superVnode = *superVnode; 1598 return B_OK; 1599 } 1600 1601 1602 static status_t 1603 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) 1604 { 1605 TRACE("lookup: \"%s\"\n", name); 1606 return ((OverlayInode *)vnode->private_node)->Lookup(name, id); 1607 } 1608 1609 1610 static status_t 1611 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, 1612 size_t bufferSize) 1613 { 1614 return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize); 1615 } 1616 1617 1618 static bool 1619 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) 1620 { 1621 TRACE("relaying op: can_page\n"); 1622 OverlayInode *node = (OverlayInode *)vnode->private_node; 1623 if (node->IsVirtual()) 1624 return false; 1625 1626 fs_vnode *superVnode = node->SuperVnode(); 1627 if (superVnode->ops->can_page != NULL) { 1628 return superVnode->ops->can_page(volume->super_volume, superVnode, 1629 cookie); 1630 } 1631 1632 return false; 1633 } 1634 1635 1636 static status_t 1637 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1638 const iovec *vecs, size_t count, size_t *numBytes) 1639 { 1640 OverlayInode *node = (OverlayInode *)vnode->private_node; 1641 size_t bytesLeft = *numBytes; 1642 1643 for (size_t i = 0; i < count; i++) { 1644 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft); 1645 status_t result = node->Read(cookie, pos, vecs[i].iov_base, 1646 &transferBytes, true, NULL); 1647 if (result != B_OK) { 1648 *numBytes -= bytesLeft; 1649 return result; 1650 } 1651 1652 bytesLeft -= transferBytes; 1653 if (bytesLeft == 0) 1654 return B_OK; 1655 1656 if (transferBytes < vecs[i].iov_len) { 1657 *numBytes -= bytesLeft; 1658 return B_OK; 1659 } 1660 1661 pos += transferBytes; 1662 } 1663 1664 *numBytes = 0; 1665 return B_OK; 1666 } 1667 1668 1669 static status_t 1670 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1671 const iovec *vecs, size_t count, size_t *numBytes) 1672 { 1673 OverlayInode *node = (OverlayInode *)vnode->private_node; 1674 size_t bytesLeft = *numBytes; 1675 1676 for (size_t i = 0; i < count; i++) { 1677 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft); 1678 status_t result = node->Write(cookie, pos, vecs[i].iov_base, 1679 transferBytes, NULL); 1680 if (result != B_OK) { 1681 *numBytes -= bytesLeft; 1682 return result; 1683 } 1684 1685 bytesLeft -= transferBytes; 1686 if (bytesLeft == 0) 1687 return B_OK; 1688 1689 if (transferBytes < vecs[i].iov_len) { 1690 *numBytes -= bytesLeft; 1691 return B_OK; 1692 } 1693 1694 pos += transferBytes; 1695 } 1696 1697 *numBytes = 0; 1698 return B_OK; 1699 } 1700 1701 1702 static status_t 1703 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1704 io_request *request) 1705 { 1706 OverlayInode *node = (OverlayInode *)vnode->private_node; 1707 if (io_request_is_write(request) || node->IsModified()) 1708 return node->SynchronousIO(cookie, (IORequest *)request); 1709 1710 TRACE("relaying op: io\n"); 1711 fs_vnode *superVnode = node->SuperVnode(); 1712 if (superVnode->ops->io != NULL) { 1713 return superVnode->ops->io(volume->super_volume, superVnode, 1714 cookie != NULL ? ((open_cookie *)cookie)->super_cookie : NULL, 1715 request); 1716 } 1717 1718 return B_UNSUPPORTED; 1719 } 1720 1721 1722 static status_t 1723 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1724 io_request *request) 1725 { 1726 OVERLAY_CALL(cancel_io, cookie, request) 1727 } 1728 1729 1730 static status_t 1731 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, 1732 size_t size, struct file_io_vec *vecs, size_t *count) 1733 { 1734 OVERLAY_CALL(get_file_map, offset, size, vecs, count) 1735 } 1736 1737 1738 static status_t 1739 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op, 1740 void *buffer, size_t length) 1741 { 1742 OVERLAY_CALL(ioctl, cookie, op, buffer, length) 1743 } 1744 1745 1746 static status_t 1747 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, 1748 int flags) 1749 { 1750 return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags); 1751 } 1752 1753 1754 static status_t 1755 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1756 selectsync *sync) 1757 { 1758 OVERLAY_CALL(select, cookie, event, sync) 1759 } 1760 1761 1762 static status_t 1763 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1764 selectsync *sync) 1765 { 1766 OVERLAY_CALL(deselect, cookie, event, sync) 1767 } 1768 1769 1770 static status_t 1771 overlay_fsync(fs_volume *volume, fs_vnode *vnode) 1772 { 1773 return B_OK; 1774 } 1775 1776 1777 static status_t 1778 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, 1779 size_t *bufferSize) 1780 { 1781 TRACE("read_symlink\n"); 1782 return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer, 1783 bufferSize); 1784 } 1785 1786 1787 static status_t 1788 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, 1789 const char *path, int mode) 1790 { 1791 TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path); 1792 return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path, 1793 mode); 1794 } 1795 1796 1797 static status_t 1798 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, 1799 fs_vnode *target) 1800 { 1801 return B_UNSUPPORTED; 1802 } 1803 1804 1805 static status_t 1806 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) 1807 { 1808 TRACE("unlink: \"%s\"\n", name); 1809 return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL); 1810 } 1811 1812 1813 static status_t 1814 overlay_rename(fs_volume *volume, fs_vnode *vnode, 1815 const char *fromName, fs_vnode *toVnode, const char *toName) 1816 { 1817 TRACE("rename: \"%s\" -> \"%s\"\n", fromName, toName); 1818 OverlayInode *fromNode = (OverlayInode *)vnode->private_node; 1819 OverlayInode *toNode = (OverlayInode *)toVnode->private_node; 1820 overlay_dirent *entry = NULL; 1821 1822 status_t result = fromNode->RemoveEntry(fromName, &entry); 1823 if (result != B_OK) 1824 return result; 1825 1826 char *oldName = entry->name; 1827 entry->name = strdup(toName); 1828 if (entry->name == NULL) { 1829 entry->name = oldName; 1830 if (fromNode->AddEntry(entry) != B_OK) 1831 entry->remove_and_dispose(volume, fromNode->InodeNumber()); 1832 1833 return B_NO_MEMORY; 1834 } 1835 1836 result = toNode->AddEntry(entry); 1837 if (result != B_OK) { 1838 free(entry->name); 1839 entry->name = oldName; 1840 if (fromNode->AddEntry(entry) != B_OK) 1841 entry->remove_and_dispose(volume, fromNode->InodeNumber()); 1842 1843 return result; 1844 } 1845 1846 OverlayInode *node = NULL; 1847 result = get_vnode(volume, entry->inode_number, (void **)&node); 1848 if (result == B_OK && node != NULL) { 1849 node->SetName(entry->name); 1850 node->SetParentDir(toNode); 1851 put_vnode(volume, entry->inode_number); 1852 } 1853 1854 free(oldName); 1855 notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName, 1856 toNode->InodeNumber(), toName, entry->inode_number); 1857 return B_OK; 1858 } 1859 1860 1861 static status_t 1862 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode) 1863 { 1864 // TODO: implement 1865 return B_OK; 1866 } 1867 1868 1869 static status_t 1870 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) 1871 { 1872 TRACE("read_stat\n"); 1873 return ((OverlayInode *)vnode->private_node)->ReadStat(stat); 1874 } 1875 1876 1877 static status_t 1878 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, 1879 uint32 statMask) 1880 { 1881 TRACE("write_stat\n"); 1882 return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask); 1883 } 1884 1885 1886 static status_t 1887 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, 1888 int openMode, int perms, void **cookie, ino_t *newVnodeID) 1889 { 1890 TRACE("create: \"%s\"\n", name); 1891 return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 1892 perms, cookie, newVnodeID); 1893 } 1894 1895 1896 static status_t 1897 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) 1898 { 1899 TRACE("open\n"); 1900 return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie); 1901 } 1902 1903 1904 static status_t 1905 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) 1906 { 1907 TRACE("close\n"); 1908 return ((OverlayInode *)vnode->private_node)->Close(cookie); 1909 } 1910 1911 1912 static status_t 1913 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1914 { 1915 TRACE("free_cookie\n"); 1916 return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie); 1917 } 1918 1919 1920 static status_t 1921 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1922 void *buffer, size_t *length) 1923 { 1924 TRACE("read\n"); 1925 return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer, 1926 length, false, NULL); 1927 } 1928 1929 1930 static status_t 1931 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1932 const void *buffer, size_t *length) 1933 { 1934 TRACE("write\n"); 1935 return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer, 1936 *length, NULL); 1937 } 1938 1939 1940 static status_t 1941 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, 1942 int perms) 1943 { 1944 TRACE("create_dir: \"%s\"\n", name); 1945 return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms); 1946 } 1947 1948 1949 static status_t 1950 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) 1951 { 1952 TRACE("remove_dir: \"%s\"\n", name); 1953 return ((OverlayInode *)vnode->private_node)->RemoveDir(name); 1954 } 1955 1956 1957 static status_t 1958 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1959 { 1960 TRACE("open_dir\n"); 1961 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie); 1962 } 1963 1964 1965 static status_t 1966 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1967 { 1968 TRACE("close_dir\n"); 1969 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie); 1970 } 1971 1972 1973 static status_t 1974 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1975 { 1976 TRACE("free_dir_cookie\n"); 1977 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie); 1978 } 1979 1980 1981 static status_t 1982 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1983 struct dirent *buffer, size_t bufferSize, uint32 *num) 1984 { 1985 TRACE("read_dir\n"); 1986 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer, 1987 bufferSize, num); 1988 } 1989 1990 1991 static status_t 1992 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1993 { 1994 TRACE("rewind_dir\n"); 1995 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie); 1996 } 1997 1998 1999 static status_t 2000 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 2001 { 2002 TRACE("open_attr_dir\n"); 2003 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie, true); 2004 } 2005 2006 2007 static status_t 2008 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 2009 { 2010 TRACE("close_attr_dir\n"); 2011 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie); 2012 } 2013 2014 2015 static status_t 2016 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 2017 { 2018 TRACE("free_attr_dir_cookie\n"); 2019 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie); 2020 } 2021 2022 2023 static status_t 2024 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 2025 struct dirent *buffer, size_t bufferSize, uint32 *num) 2026 { 2027 TRACE("read_attr_dir\n"); 2028 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer, 2029 bufferSize, num, true); 2030 } 2031 2032 2033 static status_t 2034 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 2035 { 2036 TRACE("rewind_attr_dir\n"); 2037 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie); 2038 } 2039 2040 2041 static status_t 2042 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 2043 uint32 type, int openMode, void **cookie) 2044 { 2045 TRACE("create_attr\n"); 2046 return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 0, 2047 cookie, NULL, true, type); 2048 } 2049 2050 2051 static status_t 2052 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 2053 int openMode, void **cookie) 2054 { 2055 TRACE("open_attr\n"); 2056 OverlayInode *node = NULL; 2057 OverlayInode *parentNode = (OverlayInode *)vnode->private_node; 2058 status_t result = parentNode->LookupAttribute(name, &node); 2059 if (result != B_OK) 2060 return result; 2061 if (node == NULL) 2062 return B_ERROR; 2063 2064 return node->Open(openMode, cookie); 2065 } 2066 2067 2068 static status_t 2069 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie) 2070 { 2071 TRACE("close_attr\n"); 2072 open_cookie *cookie = (open_cookie *)_cookie; 2073 return cookie->node->Close(cookie); 2074 } 2075 2076 2077 static status_t 2078 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie) 2079 { 2080 TRACE("free_attr_cookie\n"); 2081 open_cookie *cookie = (open_cookie *)_cookie; 2082 return cookie->node->FreeCookie(cookie); 2083 } 2084 2085 2086 static status_t 2087 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos, 2088 void *buffer, size_t *length) 2089 { 2090 TRACE("read_attr\n"); 2091 open_cookie *cookie = (open_cookie *)_cookie; 2092 return cookie->node->Read(cookie, pos, buffer, length, false, NULL); 2093 } 2094 2095 2096 static status_t 2097 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos, 2098 const void *buffer, size_t *length) 2099 { 2100 TRACE("write_attr\n"); 2101 open_cookie *cookie = (open_cookie *)_cookie; 2102 return cookie->node->Write(cookie, pos, buffer, *length, NULL); 2103 } 2104 2105 2106 static status_t 2107 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie, 2108 struct stat *stat) 2109 { 2110 TRACE("read_attr_stat\n"); 2111 open_cookie *cookie = (open_cookie *)_cookie; 2112 return cookie->node->ReadStat(stat); 2113 } 2114 2115 2116 static status_t 2117 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie, 2118 const struct stat *stat, int statMask) 2119 { 2120 TRACE("write_attr_stat\n"); 2121 open_cookie *cookie = (open_cookie *)_cookie; 2122 return cookie->node->WriteStat(stat, statMask); 2123 } 2124 2125 2126 static status_t 2127 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, 2128 const char *fromName, fs_vnode *toVnode, const char *toName) 2129 { 2130 TRACE("rename attr: \"%s\" -> \"%s\"\n", fromName, toName); 2131 OverlayInode *fromNode = (OverlayInode *)vnode->private_node; 2132 OverlayInode *toNode = (OverlayInode *)toVnode->private_node; 2133 overlay_dirent *entry = NULL; 2134 2135 status_t result = fromNode->RemoveEntry(fromName, &entry, true); 2136 if (result != B_OK) 2137 return result; 2138 2139 char *oldName = entry->name; 2140 entry->name = strdup(toName); 2141 if (entry->name == NULL) { 2142 entry->name = oldName; 2143 if (fromNode->AddEntry(entry, true) != B_OK) 2144 entry->dispose_attribute(volume, fromNode->InodeNumber()); 2145 2146 return B_NO_MEMORY; 2147 } 2148 2149 result = toNode->AddEntry(entry, true); 2150 if (result != B_OK) { 2151 free(entry->name); 2152 entry->name = oldName; 2153 if (fromNode->AddEntry(entry, true) != B_OK) 2154 entry->dispose_attribute(volume, fromNode->InodeNumber()); 2155 2156 return result; 2157 } 2158 2159 OverlayInode *node = entry->node; 2160 if (node == NULL) 2161 return B_ERROR; 2162 2163 node->SetName(entry->name); 2164 node->SetSuperVnode(toNode->SuperVnode()); 2165 node->SetInodeNumber(toNode->InodeNumber()); 2166 2167 notify_attribute_changed(volume->id, -1, fromNode->InodeNumber(), fromName, 2168 B_ATTR_REMOVED); 2169 notify_attribute_changed(volume->id, -1, toNode->InodeNumber(), toName, 2170 B_ATTR_CREATED); 2171 2172 free(oldName); 2173 return B_OK; 2174 } 2175 2176 2177 static status_t 2178 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) 2179 { 2180 TRACE("remove_attr\n"); 2181 OverlayInode *node = (OverlayInode *)vnode->private_node; 2182 status_t result = node->RemoveEntry(name, NULL, true); 2183 if (result != B_OK) 2184 return result; 2185 2186 notify_attribute_changed(volume->id, -1, node->InodeNumber(), name, 2187 B_ATTR_REMOVED); 2188 return result; 2189 } 2190 2191 2192 static status_t 2193 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, 2194 const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, 2195 fs_vnode *_superVnode, ino_t *nodeID) 2196 { 2197 OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID) 2198 } 2199 2200 2201 static fs_vnode_ops sOverlayVnodeOps = { 2202 &overlay_lookup, 2203 &overlay_get_vnode_name, 2204 2205 &overlay_put_vnode, 2206 &overlay_remove_vnode, 2207 2208 &overlay_can_page, 2209 &overlay_read_pages, 2210 &overlay_write_pages, 2211 2212 &overlay_io, 2213 &overlay_cancel_io, 2214 2215 &overlay_get_file_map, 2216 2217 /* common */ 2218 &overlay_ioctl, 2219 &overlay_set_flags, 2220 &overlay_select, 2221 &overlay_deselect, 2222 &overlay_fsync, 2223 2224 &overlay_read_symlink, 2225 &overlay_create_symlink, 2226 &overlay_link, 2227 &overlay_unlink, 2228 &overlay_rename, 2229 2230 &overlay_access, 2231 &overlay_read_stat, 2232 &overlay_write_stat, 2233 NULL, // fs_preallocate 2234 2235 /* file */ 2236 &overlay_create, 2237 &overlay_open, 2238 &overlay_close, 2239 &overlay_free_cookie, 2240 &overlay_read, 2241 &overlay_write, 2242 2243 /* directory */ 2244 &overlay_create_dir, 2245 &overlay_remove_dir, 2246 &overlay_open_dir, 2247 &overlay_close_dir, 2248 &overlay_free_dir_cookie, 2249 &overlay_read_dir, 2250 &overlay_rewind_dir, 2251 2252 /* attribute directory operations */ 2253 &overlay_open_attr_dir, 2254 &overlay_close_attr_dir, 2255 &overlay_free_attr_dir_cookie, 2256 &overlay_read_attr_dir, 2257 &overlay_rewind_attr_dir, 2258 2259 /* attribute operations */ 2260 &overlay_create_attr, 2261 &overlay_open_attr, 2262 &overlay_close_attr, 2263 &overlay_free_attr_cookie, 2264 &overlay_read_attr, 2265 &overlay_write_attr, 2266 2267 &overlay_read_attr_stat, 2268 &overlay_write_attr_stat, 2269 &overlay_rename_attr, 2270 &overlay_remove_attr, 2271 2272 /* support for node and FS layers */ 2273 &overlay_create_special_node, 2274 &overlay_get_super_vnode 2275 }; 2276 2277 2278 // #pragma mark - volume ops 2279 2280 2281 #define OVERLAY_VOLUME_CALL(op, params...) \ 2282 TRACE_VOLUME("relaying volume op: " #op "\n"); \ 2283 if (volume->super_volume->ops->op != NULL) \ 2284 return volume->super_volume->ops->op(volume->super_volume, params); 2285 2286 2287 static status_t 2288 overlay_unmount(fs_volume *volume) 2289 { 2290 TRACE_VOLUME("relaying volume op: unmount\n"); 2291 if (volume->super_volume != NULL 2292 && volume->super_volume->ops != NULL 2293 && volume->super_volume->ops->unmount != NULL) 2294 volume->super_volume->ops->unmount(volume->super_volume); 2295 2296 delete (OverlayVolume *)volume->private_volume; 2297 return B_OK; 2298 } 2299 2300 2301 static status_t 2302 overlay_read_fs_info(fs_volume *volume, struct fs_info *info) 2303 { 2304 TRACE_VOLUME("relaying volume op: read_fs_info\n"); 2305 status_t result = B_UNSUPPORTED; 2306 if (volume->super_volume->ops->read_fs_info != NULL) { 2307 result = volume->super_volume->ops->read_fs_info(volume->super_volume, 2308 info); 2309 if (result != B_OK) 2310 return result; 2311 2312 info->flags &= ~B_FS_IS_READONLY; 2313 2314 // TODO: maybe calculate based on available ram 2315 off_t available = 1024 * 1024 * 100 / info->block_size; 2316 info->total_blocks += available; 2317 info->free_blocks += available; 2318 return B_OK; 2319 } 2320 2321 return B_UNSUPPORTED; 2322 } 2323 2324 2325 static status_t 2326 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info, 2327 uint32 mask) 2328 { 2329 OVERLAY_VOLUME_CALL(write_fs_info, info, mask) 2330 return B_UNSUPPORTED; 2331 } 2332 2333 2334 static status_t 2335 overlay_sync(fs_volume *volume) 2336 { 2337 TRACE_VOLUME("relaying volume op: sync\n"); 2338 if (volume->super_volume->ops->sync != NULL) 2339 return volume->super_volume->ops->sync(volume->super_volume); 2340 return B_UNSUPPORTED; 2341 } 2342 2343 2344 static status_t 2345 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type, 2346 uint32 *_flags, bool reenter) 2347 { 2348 TRACE_VOLUME("relaying volume op: get_vnode\n"); 2349 if (volume->super_volume->ops->get_vnode != NULL) { 2350 status_t status = volume->super_volume->ops->get_vnode( 2351 volume->super_volume, id, vnode, _type, _flags, reenter); 2352 if (status != B_OK) 2353 return status; 2354 2355 OverlayInode *node = new(std::nothrow) OverlayInode( 2356 (OverlayVolume *)volume->private_volume, vnode, id); 2357 if (node == NULL) { 2358 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 2359 return B_NO_MEMORY; 2360 } 2361 2362 status = node->InitCheck(); 2363 if (status != B_OK) { 2364 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 2365 delete node; 2366 return status; 2367 } 2368 2369 vnode->private_node = node; 2370 vnode->ops = &sOverlayVnodeOps; 2371 return B_OK; 2372 } 2373 2374 return B_UNSUPPORTED; 2375 } 2376 2377 2378 static status_t 2379 overlay_open_index_dir(fs_volume *volume, void **cookie) 2380 { 2381 OVERLAY_VOLUME_CALL(open_index_dir, cookie) 2382 return B_UNSUPPORTED; 2383 } 2384 2385 2386 static status_t 2387 overlay_close_index_dir(fs_volume *volume, void *cookie) 2388 { 2389 OVERLAY_VOLUME_CALL(close_index_dir, cookie) 2390 return B_UNSUPPORTED; 2391 } 2392 2393 2394 static status_t 2395 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie) 2396 { 2397 OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie) 2398 return B_UNSUPPORTED; 2399 } 2400 2401 2402 static status_t 2403 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer, 2404 size_t bufferSize, uint32 *_num) 2405 { 2406 OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num) 2407 return B_UNSUPPORTED; 2408 } 2409 2410 2411 static status_t 2412 overlay_rewind_index_dir(fs_volume *volume, void *cookie) 2413 { 2414 OVERLAY_VOLUME_CALL(rewind_index_dir, cookie) 2415 return B_UNSUPPORTED; 2416 } 2417 2418 2419 static status_t 2420 overlay_create_index(fs_volume *volume, const char *name, uint32 type, 2421 uint32 flags) 2422 { 2423 OVERLAY_VOLUME_CALL(create_index, name, type, flags) 2424 return B_UNSUPPORTED; 2425 } 2426 2427 2428 static status_t 2429 overlay_remove_index(fs_volume *volume, const char *name) 2430 { 2431 OVERLAY_VOLUME_CALL(remove_index, name) 2432 return B_UNSUPPORTED; 2433 } 2434 2435 2436 static status_t 2437 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat) 2438 { 2439 OVERLAY_VOLUME_CALL(read_index_stat, name, stat) 2440 return B_UNSUPPORTED; 2441 } 2442 2443 2444 static status_t 2445 overlay_open_query(fs_volume *volume, const char *query, uint32 flags, 2446 port_id port, uint32 token, void **_cookie) 2447 { 2448 OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie) 2449 return B_UNSUPPORTED; 2450 } 2451 2452 2453 static status_t 2454 overlay_close_query(fs_volume *volume, void *cookie) 2455 { 2456 OVERLAY_VOLUME_CALL(close_query, cookie) 2457 return B_UNSUPPORTED; 2458 } 2459 2460 2461 static status_t 2462 overlay_free_query_cookie(fs_volume *volume, void *cookie) 2463 { 2464 OVERLAY_VOLUME_CALL(free_query_cookie, cookie) 2465 return B_UNSUPPORTED; 2466 } 2467 2468 2469 static status_t 2470 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer, 2471 size_t bufferSize, uint32 *_num) 2472 { 2473 OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num) 2474 return B_UNSUPPORTED; 2475 } 2476 2477 2478 static status_t 2479 overlay_rewind_query(fs_volume *volume, void *cookie) 2480 { 2481 OVERLAY_VOLUME_CALL(rewind_query, cookie) 2482 return B_UNSUPPORTED; 2483 } 2484 2485 2486 static status_t 2487 overlay_all_layers_mounted(fs_volume *volume) 2488 { 2489 return B_OK; 2490 } 2491 2492 2493 static status_t 2494 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode) 2495 { 2496 OverlayInode *node = new(std::nothrow) OverlayInode( 2497 (OverlayVolume *)volume->private_volume, vnode, id); 2498 if (node == NULL) 2499 return B_NO_MEMORY; 2500 2501 status_t status = node->InitCheck(); 2502 if (status != B_OK) { 2503 delete node; 2504 return status; 2505 } 2506 2507 vnode->private_node = node; 2508 vnode->ops = &sOverlayVnodeOps; 2509 return B_OK; 2510 } 2511 2512 2513 static status_t 2514 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode) 2515 { 2516 delete (OverlayInode *)vnode->private_node; 2517 return B_OK; 2518 } 2519 2520 2521 static fs_volume_ops sOverlayVolumeOps = { 2522 &overlay_unmount, 2523 2524 &overlay_read_fs_info, 2525 &overlay_write_fs_info, 2526 &overlay_sync, 2527 2528 &overlay_get_vnode, 2529 &overlay_open_index_dir, 2530 &overlay_close_index_dir, 2531 &overlay_free_index_dir_cookie, 2532 &overlay_read_index_dir, 2533 &overlay_rewind_index_dir, 2534 2535 &overlay_create_index, 2536 &overlay_remove_index, 2537 &overlay_read_index_stat, 2538 2539 &overlay_open_query, 2540 &overlay_close_query, 2541 &overlay_free_query_cookie, 2542 &overlay_read_query, 2543 &overlay_rewind_query, 2544 2545 &overlay_all_layers_mounted, 2546 &overlay_create_sub_vnode, 2547 &overlay_delete_sub_vnode 2548 }; 2549 2550 2551 // #pragma mark - filesystem module 2552 2553 2554 static status_t 2555 overlay_mount(fs_volume *volume, const char *device, uint32 flags, 2556 const char *args, ino_t *rootID) 2557 { 2558 TRACE_VOLUME("mounting write overlay\n"); 2559 volume->private_volume = new(std::nothrow) OverlayVolume(volume); 2560 if (volume->private_volume == NULL) 2561 return B_NO_MEMORY; 2562 2563 volume->ops = &sOverlayVolumeOps; 2564 return B_OK; 2565 } 2566 2567 2568 static status_t 2569 overlay_std_ops(int32 op, ...) 2570 { 2571 switch (op) { 2572 case B_MODULE_INIT: 2573 case B_MODULE_UNINIT: 2574 return B_OK; 2575 default: 2576 return B_ERROR; 2577 } 2578 } 2579 2580 2581 static file_system_module_info sOverlayFileSystem = { 2582 { 2583 "file_systems/write_overlay" B_CURRENT_FS_API_VERSION, 2584 0, 2585 overlay_std_ops, 2586 }, 2587 2588 "write_overlay", // short_name 2589 "Write Overlay File System", // pretty_name 2590 0, // DDM flags 2591 2592 // scanning 2593 NULL, // identify_partition 2594 NULL, // scan_partition 2595 NULL, // free_identify_partition_cookie 2596 NULL, // free_partition_content_cookie 2597 2598 // general operations 2599 &overlay_mount, 2600 2601 // capability querying 2602 NULL, // get_supported_operations 2603 2604 NULL, // validate_resize 2605 NULL, // validate_move 2606 NULL, // validate_set_content_name 2607 NULL, // validate_set_content_parameters 2608 NULL, // validate_initialize 2609 2610 // shadow partition modification 2611 NULL, // shadow_changed 2612 2613 // writing 2614 NULL, // defragment 2615 NULL, // repair 2616 NULL, // resize 2617 NULL, // move 2618 NULL, // set_content_name 2619 NULL, // set_content_parameters 2620 NULL // initialize 2621 }; 2622 2623 2624 status_t 2625 publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode, 2626 int type) 2627 { 2628 return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps, 2629 type, 0); 2630 } 2631 2632 } // namespace write_overlay 2633 2634 using namespace write_overlay; 2635 2636 module_info *modules[] = { 2637 (module_info *)&sOverlayFileSystem, 2638 NULL, 2639 }; 2640