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 #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, fileInode, name, 78 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, 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 = MIN(fStat.st_size - position, *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 = MIN(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 = MIN(fOriginalNodeLength - position, gapSize); 708 status_t result = B_ERROR; 709 if (readPages) { 710 iovec vector; 711 vector.iov_base = pointer; 712 vector.iov_len = readLength; 713 714 result = fSuperVnode.ops->read_pages(SuperVolume(), 715 &fSuperVnode, superCookie, position, &vector, 1, 716 &readLength); 717 } else if (ioRequest != NULL) { 718 IORequest *subRequest; 719 result = ioRequest->CreateSubRequest(position, position, 720 readLength, subRequest); 721 if (result != B_OK) 722 return result; 723 724 bool wereSuppressed = ioRequest->SuppressChildNotifications(); 725 ioRequest->SetSuppressChildNotifications(true); 726 result = fSuperVnode.ops->io(SuperVolume(), &fSuperVnode, 727 superCookie, subRequest); 728 if (result != B_OK) 729 return result; 730 731 result = subRequest->Wait(0, 0); 732 readLength = subRequest->TransferredBytes(); 733 ioRequest->SetSuppressChildNotifications(wereSuppressed); 734 } else if (fIsAttribute) { 735 result = fSuperVnode.ops->read_attr(SuperVolume(), &fSuperVnode, 736 superCookie, position, pointer, &readLength); 737 } else { 738 result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode, 739 superCookie, position, pointer, &readLength); 740 } 741 742 if (result != B_OK) 743 return result; 744 745 pointer += readLength; 746 position += readLength; 747 bytesLeft -= readLength; 748 gapSize -= readLength; 749 } 750 751 if (gapSize > 0) { 752 // there's a gap before our next position which we cannot 753 // fill with original file content, zero it out 754 if (ioRequest != NULL) 755 ;// TODO: handle this case 756 else 757 memset(pointer, 0, gapSize); 758 759 bytesLeft -= gapSize; 760 position += gapSize; 761 pointer += gapSize; 762 } 763 764 // we've reached the end 765 if (bytesLeft == 0 || element == NULL) 766 break; 767 768 off_t elementEnd = element->position + element->length; 769 if (elementEnd > position) { 770 size_t copyLength = MIN(elementEnd - position, bytesLeft); 771 772 const void *source = element->buffer + (position 773 - element->position); 774 if (ioRequest != NULL) { 775 ioRequest->CopyData(source, ioRequest->Offset() 776 + ((addr_t)pointer - (addr_t)buffer), copyLength); 777 } else 778 memcpy(pointer, source, copyLength); 779 780 bytesLeft -= copyLength; 781 position += copyLength; 782 pointer += copyLength; 783 } 784 785 element = element->next; 786 } 787 788 return B_OK; 789 } 790 791 792 status_t 793 OverlayInode::Write(void *_cookie, off_t position, const void *buffer, 794 size_t length, IORequest *ioRequest) 795 { 796 RecursiveLocker locker(fLock); 797 if (_cookie != NULL) { 798 open_cookie *cookie = (open_cookie *)_cookie; 799 if (cookie->open_mode & O_APPEND) 800 position = fStat.st_size; 801 } 802 803 if (!fIsDataModified) 804 SetDataModified(); 805 806 // find insertion point 807 write_buffer **link = &fWriteBuffers; 808 write_buffer *other = fWriteBuffers; 809 write_buffer *swallow = NULL; 810 off_t newPosition = position; 811 size_t newLength = length; 812 uint32 swallowCount = 0; 813 814 while (other) { 815 off_t newEnd = newPosition + newLength; 816 off_t otherEnd = other->position + other->length; 817 if (otherEnd < newPosition) { 818 // other is completely before us 819 link = &other->next; 820 other = other->next; 821 continue; 822 } 823 824 if (other->position > newEnd) { 825 // other is completely past us 826 break; 827 } 828 829 swallowCount++; 830 if (swallow == NULL) 831 swallow = other; 832 833 if (other->position <= newPosition) { 834 if (swallowCount == 1 && otherEnd >= newEnd) { 835 // other chunk completely covers us, just copy 836 void *target = other->buffer + (newPosition - other->position); 837 if (ioRequest != NULL) 838 ioRequest->CopyData(ioRequest->Offset(), target, length); 839 else 840 memcpy(target, buffer, length); 841 842 fStat.st_mtime = time(NULL); 843 if (fIsAttribute) { 844 notify_attribute_changed(SuperVolume()->id, fInodeNumber, 845 fName, B_ATTR_CHANGED); 846 } else { 847 notify_stat_changed(SuperVolume()->id, fInodeNumber, 848 B_STAT_MODIFICATION_TIME); 849 } 850 return B_OK; 851 } 852 853 newLength += newPosition - other->position; 854 newPosition = other->position; 855 } 856 857 if (otherEnd > newEnd) 858 newLength += otherEnd - newEnd; 859 860 other = other->next; 861 } 862 863 write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1 864 + newLength); 865 if (element == NULL) 866 return B_NO_MEMORY; 867 868 element->next = *link; 869 element->position = newPosition; 870 element->length = newLength; 871 *link = element; 872 873 bool sizeChanged = false; 874 off_t newEnd = newPosition + newLength; 875 if (newEnd > fStat.st_size) { 876 fStat.st_size = newEnd; 877 sizeChanged = true; 878 879 if (fFileCache) 880 file_cache_set_size(fFileCache, newEnd); 881 } 882 883 // populate the buffer with the existing chunks 884 if (swallowCount > 0) { 885 while (swallowCount-- > 0) { 886 memcpy(element->buffer + (swallow->position - newPosition), 887 swallow->buffer, swallow->length); 888 889 element->next = swallow->next; 890 free(swallow); 891 swallow = element->next; 892 } 893 } 894 895 void *target = element->buffer + (position - newPosition); 896 if (ioRequest != NULL) 897 ioRequest->CopyData(0, target, length); 898 else 899 memcpy(target, buffer, length); 900 901 fStat.st_mtime = time(NULL); 902 903 if (fIsAttribute) { 904 notify_attribute_changed(SuperVolume()->id, fInodeNumber, fName, 905 B_ATTR_CHANGED); 906 } else { 907 notify_stat_changed(SuperVolume()->id, fInodeNumber, 908 B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0)); 909 } 910 911 return B_OK; 912 } 913 914 915 status_t 916 OverlayInode::SynchronousIO(void *cookie, IORequest *request) 917 { 918 status_t result; 919 size_t length = request->Length(); 920 if (request->IsWrite()) 921 result = Write(cookie, request->Offset(), NULL, length, request); 922 else 923 result = Read(cookie, request->Offset(), NULL, &length, false, request); 924 925 if (result == B_OK) 926 request->SetTransferredBytes(false, length); 927 928 request->SetStatusAndNotify(result); 929 return result; 930 } 931 932 933 status_t 934 OverlayInode::SetFlags(void *_cookie, int flags) 935 { 936 // we can only handle O_APPEND, O_NONBLOCK is ignored. 937 open_cookie *cookie = (open_cookie *)_cookie; 938 cookie->open_mode = (cookie->open_mode & ~O_APPEND) | (flags & ~O_APPEND); 939 return B_OK; 940 } 941 942 943 status_t 944 OverlayInode::CreateDir(const char *name, int perms) 945 { 946 return _CreateCommon(name, S_IFDIR, perms, NULL, NULL, false, 0); 947 } 948 949 950 status_t 951 OverlayInode::RemoveDir(const char *name) 952 { 953 return RemoveEntry(name, NULL); 954 } 955 956 957 status_t 958 OverlayInode::OpenDir(void **cookie, bool attribute) 959 { 960 RecursiveLocker locker(fLock); 961 if (!attribute) { 962 if (!fHasStat) 963 _PopulateStat(); 964 965 if (!S_ISDIR(fStat.st_mode)) 966 return B_NOT_A_DIRECTORY; 967 } 968 969 if (!attribute && !fHasDirents) 970 _PopulateDirents(); 971 else if (attribute && !fHasAttributeDirents) 972 _PopulateAttributeDirents(); 973 974 open_dir_cookie *dirCookie = (open_dir_cookie *)malloc( 975 sizeof(open_dir_cookie)); 976 if (dirCookie == NULL) 977 return B_NO_MEMORY; 978 979 dirCookie->index = 0; 980 *cookie = dirCookie; 981 return B_OK; 982 } 983 984 985 status_t 986 OverlayInode::CloseDir(void *cookie) 987 { 988 return B_OK; 989 } 990 991 992 status_t 993 OverlayInode::FreeDirCookie(void *cookie) 994 { 995 free(cookie); 996 return B_OK; 997 } 998 999 1000 status_t 1001 OverlayInode::ReadDir(void *cookie, struct dirent *buffer, size_t bufferSize, 1002 uint32 *num, bool attribute) 1003 { 1004 RecursiveLocker locker(fLock); 1005 uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount; 1006 overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents; 1007 1008 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie; 1009 if (dirCookie->index >= direntCount) { 1010 *num = 0; 1011 return B_OK; 1012 } 1013 1014 overlay_dirent *dirent = dirents[dirCookie->index++]; 1015 size_t nameLength = MIN(strlen(dirent->name), 1016 bufferSize - sizeof(struct dirent)) + 1; 1017 1018 buffer->d_dev = SuperVolume()->id; 1019 buffer->d_pdev = 0; 1020 buffer->d_ino = dirent->inode_number; 1021 buffer->d_pino = 0; 1022 buffer->d_reclen = sizeof(struct dirent) + nameLength; 1023 strlcpy(buffer->d_name, dirent->name, nameLength); 1024 1025 *num = 1; 1026 return B_OK; 1027 } 1028 1029 1030 status_t 1031 OverlayInode::RewindDir(void *cookie) 1032 { 1033 open_dir_cookie *dirCookie = (open_dir_cookie *)cookie; 1034 dirCookie->index = 0; 1035 return B_OK; 1036 } 1037 1038 1039 status_t 1040 OverlayInode::CreateSymlink(const char *name, const char *path, int mode) 1041 { 1042 OverlayInode *newNode = NULL; 1043 // TODO: find out why mode is ignored 1044 status_t result = _CreateCommon(name, S_IFLNK, 0777, NULL, &newNode, 1045 false, 0); 1046 if (result != B_OK) 1047 return result; 1048 1049 return newNode->Write(NULL, 0, path, strlen(path), NULL); 1050 } 1051 1052 1053 status_t 1054 OverlayInode::ReadSymlink(char *buffer, size_t *bufferSize) 1055 { 1056 if (fIsVirtual) { 1057 if (!S_ISLNK(fStat.st_mode)) 1058 return B_BAD_VALUE; 1059 1060 return Read(NULL, 0, buffer, bufferSize, false, NULL); 1061 } 1062 1063 if (fSuperVnode.ops->read_symlink == NULL) 1064 return B_UNSUPPORTED; 1065 1066 return fSuperVnode.ops->read_symlink(SuperVolume(), &fSuperVnode, buffer, 1067 bufferSize); 1068 } 1069 1070 1071 status_t 1072 OverlayInode::AddEntry(overlay_dirent *entry, bool attribute) 1073 { 1074 RecursiveLocker locker(fLock); 1075 if (!attribute && !fHasDirents) 1076 _PopulateDirents(); 1077 else if (attribute && !fHasAttributeDirents) 1078 _PopulateAttributeDirents(); 1079 1080 status_t result = RemoveEntry(entry->name, NULL, attribute); 1081 if (result != B_OK && result != B_ENTRY_NOT_FOUND) 1082 return B_FILE_EXISTS; 1083 1084 overlay_dirent **newDirents = (overlay_dirent **)realloc( 1085 attribute ? fAttributeDirents : fDirents, 1086 sizeof(overlay_dirent *) 1087 * ((attribute ? fAttributeDirentCount : fDirentCount) + 1)); 1088 if (newDirents == NULL) 1089 return B_NO_MEMORY; 1090 1091 if (attribute) { 1092 fAttributeDirents = newDirents; 1093 fAttributeDirents[fAttributeDirentCount++] = entry; 1094 } else { 1095 fDirents = newDirents; 1096 fDirents[fDirentCount++] = entry; 1097 } 1098 1099 if (!fIsModified) 1100 SetModified(); 1101 1102 return B_OK; 1103 } 1104 1105 1106 status_t 1107 OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry, 1108 bool attribute) 1109 { 1110 RecursiveLocker locker(fLock); 1111 if (!attribute && !fHasDirents) 1112 _PopulateDirents(); 1113 else if (attribute && !fHasAttributeDirents) 1114 _PopulateAttributeDirents(); 1115 1116 uint32 direntCount = attribute ? fAttributeDirentCount : fDirentCount; 1117 overlay_dirent **dirents = attribute ? fAttributeDirents : fDirents; 1118 for (uint32 i = 0; i < direntCount; i++) { 1119 overlay_dirent *entry = dirents[i]; 1120 if (strcmp(entry->name, name) == 0) { 1121 if (_entry == NULL && !attribute) { 1122 // check for non-empty directories when trying 1123 // to dispose the entry 1124 OverlayInode *node = NULL; 1125 status_t result = get_vnode(Volume(), entry->inode_number, 1126 (void **)&node); 1127 if (result != B_OK) 1128 return result; 1129 1130 if (node->IsNonEmptyDirectory()) 1131 result = B_DIRECTORY_NOT_EMPTY; 1132 1133 put_vnode(Volume(), entry->inode_number); 1134 if (result != B_OK) 1135 return result; 1136 } 1137 1138 for (uint32 j = i + 1; j < direntCount; j++) 1139 dirents[j - 1] = dirents[j]; 1140 1141 if (attribute) 1142 fAttributeDirentCount--; 1143 else 1144 fDirentCount--; 1145 1146 if (_entry != NULL) 1147 *_entry = entry; 1148 else if (attribute) 1149 entry->dispose_attribute(Volume(), fInodeNumber); 1150 else 1151 entry->remove_and_dispose(Volume(), fInodeNumber); 1152 1153 if (!fIsModified) 1154 SetModified(); 1155 1156 return B_OK; 1157 } 1158 } 1159 1160 return B_ENTRY_NOT_FOUND; 1161 } 1162 1163 1164 void 1165 OverlayInode::_TrimBuffers() 1166 { 1167 // the file size has been changed and we want to trim 1168 // off everything that goes beyond the new size 1169 write_buffer **link = &fWriteBuffers; 1170 write_buffer *buffer = fWriteBuffers; 1171 1172 while (buffer != NULL) { 1173 off_t bufferEnd = buffer->position + buffer->length; 1174 if (bufferEnd > fStat.st_size) 1175 break; 1176 1177 link = &buffer->next; 1178 buffer = buffer->next; 1179 } 1180 1181 if (buffer == NULL) { 1182 // didn't find anything crossing or past the end 1183 return; 1184 } 1185 1186 if (buffer->position < fStat.st_size) { 1187 // got a crossing buffer to resize 1188 size_t newLength = fStat.st_size - buffer->position; 1189 write_buffer *newBuffer = (write_buffer *)realloc(buffer, 1190 sizeof(write_buffer) - 1 + newLength); 1191 1192 if (newBuffer != NULL) { 1193 buffer = newBuffer; 1194 *link = newBuffer; 1195 } else { 1196 // we don't really care if it worked, if it didn't we simply 1197 // keep the old buffer and reset it's size 1198 } 1199 1200 buffer->length = newLength; 1201 link = &buffer->next; 1202 buffer = buffer->next; 1203 } 1204 1205 // everything else we can throw away 1206 *link = NULL; 1207 while (buffer != NULL) { 1208 write_buffer *next = buffer->next; 1209 free(buffer); 1210 buffer = next; 1211 } 1212 } 1213 1214 1215 status_t 1216 OverlayInode::_PopulateStat() 1217 { 1218 if (fHasStat) 1219 return B_OK; 1220 1221 fHasStat = true; 1222 if (fIsAttribute) { 1223 if (fName == NULL || fSuperVnode.ops->open_attr == NULL 1224 || fSuperVnode.ops->read_attr_stat == NULL) 1225 return B_UNSUPPORTED; 1226 1227 void *cookie = NULL; 1228 status_t result = fSuperVnode.ops->open_attr(SuperVolume(), 1229 &fSuperVnode, fName, O_RDONLY, &cookie); 1230 if (result != B_OK) 1231 return result; 1232 1233 result = fSuperVnode.ops->read_attr_stat(SuperVolume(), &fSuperVnode, 1234 cookie, &fStat); 1235 1236 if (fSuperVnode.ops->close_attr != NULL) 1237 fSuperVnode.ops->close_attr(SuperVolume(), &fSuperVnode, cookie); 1238 1239 if (fSuperVnode.ops->free_attr_cookie != NULL) { 1240 fSuperVnode.ops->free_attr_cookie(SuperVolume(), &fSuperVnode, 1241 cookie); 1242 } 1243 1244 return B_OK; 1245 } 1246 1247 if (fSuperVnode.ops->read_stat == NULL) 1248 return B_UNSUPPORTED; 1249 1250 return fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode, &fStat); 1251 } 1252 1253 1254 status_t 1255 OverlayInode::_PopulateDirents() 1256 { 1257 if (fHasDirents) 1258 return B_OK; 1259 1260 fDirents = (overlay_dirent **)malloc(sizeof(overlay_dirent *) * 2); 1261 if (fDirents == NULL) 1262 return B_NO_MEMORY; 1263 1264 const char *names[] = { ".", ".." }; 1265 ino_t inodes[] = { fInodeNumber, 1266 fParentDir != NULL ? fParentDir->InodeNumber() : 0 }; 1267 for (uint32 i = 0; i < 2; i++) { 1268 fDirents[i] = (overlay_dirent *)malloc(sizeof(overlay_dirent)); 1269 if (fDirents[i] == NULL) 1270 return B_NO_MEMORY; 1271 1272 fDirents[i]->inode_number = inodes[i]; 1273 fDirents[i]->name = strdup(names[i]); 1274 if (fDirents[i]->name == NULL) { 1275 free(fDirents[i]); 1276 return B_NO_MEMORY; 1277 } 1278 1279 fDirentCount++; 1280 } 1281 1282 fHasDirents = true; 1283 if (fIsVirtual || fSuperVnode.ops->open_dir == NULL 1284 || fSuperVnode.ops->read_dir == NULL) 1285 return B_OK; 1286 1287 // we don't really care about errors from here on 1288 void *superCookie = NULL; 1289 status_t result = fSuperVnode.ops->open_dir(SuperVolume(), 1290 &fSuperVnode, &superCookie); 1291 if (result != B_OK) 1292 return B_OK; 1293 1294 size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH; 1295 struct dirent *buffer = (struct dirent *)malloc(bufferSize); 1296 if (buffer == NULL) 1297 goto close_dir; 1298 1299 while (true) { 1300 uint32 num = 1; 1301 result = fSuperVnode.ops->read_dir(SuperVolume(), 1302 &fSuperVnode, superCookie, buffer, bufferSize, &num); 1303 if (result != B_OK || num == 0) 1304 break; 1305 1306 overlay_dirent **newDirents = (overlay_dirent **)realloc(fDirents, 1307 sizeof(overlay_dirent *) * (fDirentCount + num)); 1308 if (newDirents == NULL) { 1309 TRACE_ALWAYS("failed to allocate storage for dirents\n"); 1310 break; 1311 } 1312 1313 fDirents = newDirents; 1314 struct dirent *dirent = buffer; 1315 for (uint32 i = 0; i < num; i++) { 1316 if (strcmp(dirent->d_name, ".") != 0 1317 && strcmp(dirent->d_name, "..") != 0) { 1318 overlay_dirent *entry = (overlay_dirent *)malloc( 1319 sizeof(overlay_dirent)); 1320 if (entry == NULL) { 1321 TRACE_ALWAYS("failed to allocate storage for dirent\n"); 1322 break; 1323 } 1324 1325 entry->inode_number = dirent->d_ino; 1326 entry->name = strdup(dirent->d_name); 1327 if (entry->name == NULL) { 1328 TRACE_ALWAYS("failed to duplicate dirent entry name\n"); 1329 free(entry); 1330 break; 1331 } 1332 1333 fDirents[fDirentCount++] = entry; 1334 } 1335 1336 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen); 1337 } 1338 } 1339 1340 free(buffer); 1341 1342 close_dir: 1343 if (fSuperVnode.ops->close_dir != NULL) 1344 fSuperVnode.ops->close_dir(SuperVolume(), &fSuperVnode, superCookie); 1345 1346 if (fSuperVnode.ops->free_dir_cookie != NULL) { 1347 fSuperVnode.ops->free_dir_cookie(SuperVolume(), &fSuperVnode, 1348 superCookie); 1349 } 1350 1351 return B_OK; 1352 } 1353 1354 1355 status_t 1356 OverlayInode::_PopulateAttributeDirents() 1357 { 1358 if (fHasAttributeDirents) 1359 return B_OK; 1360 1361 fHasAttributeDirents = true; 1362 if (fIsVirtual || fSuperVnode.ops->open_attr_dir == NULL 1363 || fSuperVnode.ops->read_attr_dir == NULL) 1364 return B_OK; 1365 1366 // we don't really care about errors from here on 1367 void *superCookie = NULL; 1368 status_t result = fSuperVnode.ops->open_attr_dir(SuperVolume(), 1369 &fSuperVnode, &superCookie); 1370 if (result != B_OK) 1371 return B_OK; 1372 1373 size_t bufferSize = sizeof(struct dirent) + B_FILE_NAME_LENGTH; 1374 struct dirent *buffer = (struct dirent *)malloc(bufferSize); 1375 if (buffer == NULL) 1376 goto close_attr_dir; 1377 1378 while (true) { 1379 uint32 num = 1; 1380 result = fSuperVnode.ops->read_attr_dir(SuperVolume(), 1381 &fSuperVnode, superCookie, buffer, bufferSize, &num); 1382 if (result != B_OK || num == 0) 1383 break; 1384 1385 overlay_dirent **newDirents = (overlay_dirent **)realloc( 1386 fAttributeDirents, sizeof(overlay_dirent *) 1387 * (fAttributeDirentCount + num)); 1388 if (newDirents == NULL) { 1389 TRACE_ALWAYS("failed to allocate storage for attribute dirents\n"); 1390 break; 1391 } 1392 1393 fAttributeDirents = newDirents; 1394 struct dirent *dirent = buffer; 1395 for (uint32 i = 0; i < num; i++) { 1396 overlay_dirent *entry = (overlay_dirent *)malloc( 1397 sizeof(overlay_dirent)); 1398 if (entry == NULL) { 1399 TRACE_ALWAYS("failed to allocate storage for attr dirent\n"); 1400 break; 1401 } 1402 1403 entry->node = NULL; 1404 entry->inode_number = fInodeNumber; 1405 entry->name = strdup(dirent->d_name); 1406 if (entry->name == NULL) { 1407 TRACE_ALWAYS("failed to duplicate dirent entry name\n"); 1408 free(entry); 1409 break; 1410 } 1411 1412 fAttributeDirents[fAttributeDirentCount++] = entry; 1413 dirent = (struct dirent *)((uint8 *)dirent + dirent->d_reclen); 1414 } 1415 } 1416 1417 free(buffer); 1418 1419 close_attr_dir: 1420 if (fSuperVnode.ops->close_attr_dir != NULL) { 1421 fSuperVnode.ops->close_attr_dir(SuperVolume(), &fSuperVnode, 1422 superCookie); 1423 } 1424 1425 if (fSuperVnode.ops->free_attr_dir_cookie != NULL) { 1426 fSuperVnode.ops->free_attr_dir_cookie(SuperVolume(), &fSuperVnode, 1427 superCookie); 1428 } 1429 1430 return B_OK; 1431 } 1432 1433 1434 status_t 1435 OverlayInode::_CreateCommon(const char *name, int type, int perms, 1436 ino_t *newInodeNumber, OverlayInode **_node, bool attribute, 1437 type_code attributeType) 1438 { 1439 RecursiveLocker locker(fLock); 1440 if (!fHasStat) 1441 _PopulateStat(); 1442 1443 if (!attribute && !S_ISDIR(fStat.st_mode)) 1444 return B_NOT_A_DIRECTORY; 1445 1446 locker.Unlock(); 1447 1448 overlay_dirent *entry = (overlay_dirent *)malloc(sizeof(overlay_dirent)); 1449 if (entry == NULL) 1450 return B_NO_MEMORY; 1451 1452 entry->node = NULL; 1453 entry->name = strdup(name); 1454 if (entry->name == NULL) { 1455 free(entry); 1456 return B_NO_MEMORY; 1457 } 1458 1459 if (attribute) 1460 entry->inode_number = fInodeNumber; 1461 else 1462 entry->inode_number = fVolume->BuildInodeNumber(); 1463 1464 OverlayInode *node = new(std::nothrow) OverlayInode(fVolume, NULL, 1465 entry->inode_number, this, entry->name, (perms & S_IUMSK) | type 1466 | (attribute ? S_ATTR : 0), attribute, attributeType); 1467 if (node == NULL) { 1468 free(entry->name); 1469 free(entry); 1470 return B_NO_MEMORY; 1471 } 1472 1473 status_t result = AddEntry(entry, attribute); 1474 if (result != B_OK) { 1475 free(entry->name); 1476 free(entry); 1477 delete node; 1478 return result; 1479 } 1480 1481 if (!attribute) { 1482 result = publish_overlay_vnode(fVolume->Volume(), entry->inode_number, 1483 node, type); 1484 if (result != B_OK) { 1485 RemoveEntry(entry->name, NULL); 1486 delete node; 1487 return result; 1488 } 1489 } else 1490 entry->node = node; 1491 1492 node->Lock(); 1493 node->SetDataModified(); 1494 if (!attribute) 1495 node->CreateCache(); 1496 node->Unlock(); 1497 1498 if (newInodeNumber != NULL) 1499 *newInodeNumber = entry->inode_number; 1500 if (_node != NULL) 1501 *_node = node; 1502 1503 if (attribute) { 1504 notify_attribute_changed(SuperVolume()->id, fInodeNumber, entry->name, 1505 B_ATTR_CREATED); 1506 } else { 1507 notify_entry_created(SuperVolume()->id, fInodeNumber, entry->name, 1508 entry->inode_number); 1509 } 1510 1511 return B_OK; 1512 } 1513 1514 1515 // #pragma mark - vnode ops 1516 1517 1518 #define OVERLAY_CALL(op, params...) \ 1519 TRACE("relaying op: " #op "\n"); \ 1520 OverlayInode *node = (OverlayInode *)vnode->private_node; \ 1521 if (node->IsVirtual()) \ 1522 return B_UNSUPPORTED; \ 1523 fs_vnode *superVnode = node->SuperVnode(); \ 1524 if (superVnode->ops->op != NULL) \ 1525 return superVnode->ops->op(volume->super_volume, superVnode, params); \ 1526 return B_UNSUPPORTED; 1527 1528 1529 static status_t 1530 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 1531 { 1532 TRACE("put_vnode\n"); 1533 OverlayInode *node = (OverlayInode *)vnode->private_node; 1534 if (node->IsVirtual() || node->IsModified()) { 1535 panic("loosing virtual/modified node\n"); 1536 delete node; 1537 return B_OK; 1538 } 1539 1540 status_t result = B_OK; 1541 fs_vnode *superVnode = node->SuperVnode(); 1542 if (superVnode->ops->put_vnode != NULL) { 1543 result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 1544 reenter); 1545 } 1546 1547 delete node; 1548 return result; 1549 } 1550 1551 1552 static status_t 1553 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 1554 { 1555 TRACE("remove_vnode\n"); 1556 OverlayInode *node = (OverlayInode *)vnode->private_node; 1557 if (node->IsVirtual()) { 1558 delete node; 1559 return B_OK; 1560 } 1561 1562 status_t result = B_OK; 1563 fs_vnode *superVnode = node->SuperVnode(); 1564 if (superVnode->ops->put_vnode != NULL) { 1565 result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 1566 reenter); 1567 } 1568 1569 delete node; 1570 return result; 1571 } 1572 1573 1574 static status_t 1575 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, 1576 fs_volume *superVolume, fs_vnode *_superVnode) 1577 { 1578 if (volume == superVolume) { 1579 *_superVnode = *vnode; 1580 return B_OK; 1581 } 1582 1583 OverlayInode *node = (OverlayInode *)vnode->private_node; 1584 if (node->IsVirtual()) { 1585 *_superVnode = *vnode; 1586 return B_OK; 1587 } 1588 1589 fs_vnode *superVnode = node->SuperVnode(); 1590 if (superVnode->ops->get_super_vnode != NULL) { 1591 return superVnode->ops->get_super_vnode(volume->super_volume, 1592 superVnode, superVolume, _superVnode); 1593 } 1594 1595 *_superVnode = *superVnode; 1596 return B_OK; 1597 } 1598 1599 1600 static status_t 1601 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) 1602 { 1603 TRACE("lookup: \"%s\"\n", name); 1604 return ((OverlayInode *)vnode->private_node)->Lookup(name, id); 1605 } 1606 1607 1608 static status_t 1609 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, 1610 size_t bufferSize) 1611 { 1612 return ((OverlayInode *)vnode->private_node)->GetName(buffer, bufferSize); 1613 } 1614 1615 1616 static bool 1617 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) 1618 { 1619 TRACE("relaying op: can_page\n"); 1620 OverlayInode *node = (OverlayInode *)vnode->private_node; 1621 if (node->IsVirtual()) 1622 return false; 1623 1624 fs_vnode *superVnode = node->SuperVnode(); 1625 if (superVnode->ops->can_page != NULL) { 1626 return superVnode->ops->can_page(volume->super_volume, superVnode, 1627 cookie); 1628 } 1629 1630 return false; 1631 } 1632 1633 1634 static status_t 1635 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1636 const iovec *vecs, size_t count, size_t *numBytes) 1637 { 1638 OverlayInode *node = (OverlayInode *)vnode->private_node; 1639 size_t bytesLeft = *numBytes; 1640 1641 for (size_t i = 0; i < count; i++) { 1642 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft); 1643 status_t result = node->Read(cookie, pos, vecs[i].iov_base, 1644 &transferBytes, true, NULL); 1645 if (result != B_OK) { 1646 *numBytes -= bytesLeft; 1647 return result; 1648 } 1649 1650 bytesLeft -= transferBytes; 1651 if (bytesLeft == 0) 1652 return B_OK; 1653 1654 if (transferBytes < vecs[i].iov_len) { 1655 *numBytes -= bytesLeft; 1656 return B_OK; 1657 } 1658 1659 pos += transferBytes; 1660 } 1661 1662 *numBytes = 0; 1663 return B_OK; 1664 } 1665 1666 1667 static status_t 1668 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1669 const iovec *vecs, size_t count, size_t *numBytes) 1670 { 1671 OverlayInode *node = (OverlayInode *)vnode->private_node; 1672 size_t bytesLeft = *numBytes; 1673 1674 for (size_t i = 0; i < count; i++) { 1675 size_t transferBytes = MIN(vecs[i].iov_len, bytesLeft); 1676 status_t result = node->Write(cookie, pos, vecs[i].iov_base, 1677 transferBytes, NULL); 1678 if (result != B_OK) { 1679 *numBytes -= bytesLeft; 1680 return result; 1681 } 1682 1683 bytesLeft -= transferBytes; 1684 if (bytesLeft == 0) 1685 return B_OK; 1686 1687 if (transferBytes < vecs[i].iov_len) { 1688 *numBytes -= bytesLeft; 1689 return B_OK; 1690 } 1691 1692 pos += transferBytes; 1693 } 1694 1695 *numBytes = 0; 1696 return B_OK; 1697 } 1698 1699 1700 static status_t 1701 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1702 io_request *request) 1703 { 1704 OverlayInode *node = (OverlayInode *)vnode->private_node; 1705 if (io_request_is_write(request) || node->IsModified()) 1706 return node->SynchronousIO(cookie, (IORequest *)request); 1707 1708 TRACE("relaying op: io\n"); 1709 fs_vnode *superVnode = node->SuperVnode(); 1710 if (superVnode->ops->io != NULL) { 1711 return superVnode->ops->io(volume->super_volume, superVnode, 1712 cookie != NULL ? ((open_cookie *)cookie)->super_cookie : NULL, 1713 request); 1714 } 1715 1716 return B_UNSUPPORTED; 1717 } 1718 1719 1720 static status_t 1721 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1722 io_request *request) 1723 { 1724 OVERLAY_CALL(cancel_io, cookie, request) 1725 } 1726 1727 1728 static status_t 1729 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, 1730 size_t size, struct file_io_vec *vecs, size_t *count) 1731 { 1732 OVERLAY_CALL(get_file_map, offset, size, vecs, count) 1733 } 1734 1735 1736 static status_t 1737 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op, 1738 void *buffer, size_t length) 1739 { 1740 OVERLAY_CALL(ioctl, cookie, op, buffer, length) 1741 } 1742 1743 1744 static status_t 1745 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, 1746 int flags) 1747 { 1748 return ((OverlayInode *)vnode->private_node)->SetFlags(cookie, flags); 1749 } 1750 1751 1752 static status_t 1753 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1754 selectsync *sync) 1755 { 1756 OVERLAY_CALL(select, cookie, event, sync) 1757 } 1758 1759 1760 static status_t 1761 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1762 selectsync *sync) 1763 { 1764 OVERLAY_CALL(deselect, cookie, event, sync) 1765 } 1766 1767 1768 static status_t 1769 overlay_fsync(fs_volume *volume, fs_vnode *vnode) 1770 { 1771 return B_OK; 1772 } 1773 1774 1775 static status_t 1776 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, 1777 size_t *bufferSize) 1778 { 1779 TRACE("read_symlink\n"); 1780 return ((OverlayInode *)vnode->private_node)->ReadSymlink(buffer, 1781 bufferSize); 1782 } 1783 1784 1785 static status_t 1786 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, 1787 const char *path, int mode) 1788 { 1789 TRACE("create_symlink: \"%s\" -> \"%s\"\n", name, path); 1790 return ((OverlayInode *)vnode->private_node)->CreateSymlink(name, path, 1791 mode); 1792 } 1793 1794 1795 static status_t 1796 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, 1797 fs_vnode *target) 1798 { 1799 return B_UNSUPPORTED; 1800 } 1801 1802 1803 static status_t 1804 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) 1805 { 1806 TRACE("unlink: \"%s\"\n", name); 1807 return ((OverlayInode *)vnode->private_node)->RemoveEntry(name, NULL); 1808 } 1809 1810 1811 static status_t 1812 overlay_rename(fs_volume *volume, fs_vnode *vnode, 1813 const char *fromName, fs_vnode *toVnode, const char *toName) 1814 { 1815 TRACE("rename: \"%s\" -> \"%s\"\n", fromName, toName); 1816 OverlayInode *fromNode = (OverlayInode *)vnode->private_node; 1817 OverlayInode *toNode = (OverlayInode *)toVnode->private_node; 1818 overlay_dirent *entry = NULL; 1819 1820 status_t result = fromNode->RemoveEntry(fromName, &entry); 1821 if (result != B_OK) 1822 return result; 1823 1824 char *oldName = entry->name; 1825 entry->name = strdup(toName); 1826 if (entry->name == NULL) { 1827 entry->name = oldName; 1828 if (fromNode->AddEntry(entry) != B_OK) 1829 entry->remove_and_dispose(volume, fromNode->InodeNumber()); 1830 1831 return B_NO_MEMORY; 1832 } 1833 1834 result = toNode->AddEntry(entry); 1835 if (result != B_OK) { 1836 free(entry->name); 1837 entry->name = oldName; 1838 if (fromNode->AddEntry(entry) != B_OK) 1839 entry->remove_and_dispose(volume, fromNode->InodeNumber()); 1840 1841 return result; 1842 } 1843 1844 OverlayInode *node = NULL; 1845 result = get_vnode(volume, entry->inode_number, (void **)&node); 1846 if (result == B_OK && node != NULL) { 1847 node->SetName(entry->name); 1848 node->SetParentDir(toNode); 1849 put_vnode(volume, entry->inode_number); 1850 } 1851 1852 free(oldName); 1853 notify_entry_moved(volume->id, fromNode->InodeNumber(), fromName, 1854 toNode->InodeNumber(), toName, entry->inode_number); 1855 return B_OK; 1856 } 1857 1858 1859 static status_t 1860 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode) 1861 { 1862 // TODO: implement 1863 return B_OK; 1864 } 1865 1866 1867 static status_t 1868 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) 1869 { 1870 TRACE("read_stat\n"); 1871 return ((OverlayInode *)vnode->private_node)->ReadStat(stat); 1872 } 1873 1874 1875 static status_t 1876 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, 1877 uint32 statMask) 1878 { 1879 TRACE("write_stat\n"); 1880 return ((OverlayInode *)vnode->private_node)->WriteStat(stat, statMask); 1881 } 1882 1883 1884 static status_t 1885 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, 1886 int openMode, int perms, void **cookie, ino_t *newVnodeID) 1887 { 1888 TRACE("create: \"%s\"\n", name); 1889 return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 1890 perms, cookie, newVnodeID); 1891 } 1892 1893 1894 static status_t 1895 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) 1896 { 1897 TRACE("open\n"); 1898 return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie); 1899 } 1900 1901 1902 static status_t 1903 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) 1904 { 1905 TRACE("close\n"); 1906 return ((OverlayInode *)vnode->private_node)->Close(cookie); 1907 } 1908 1909 1910 static status_t 1911 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1912 { 1913 TRACE("free_cookie\n"); 1914 return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie); 1915 } 1916 1917 1918 static status_t 1919 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1920 void *buffer, size_t *length) 1921 { 1922 TRACE("read\n"); 1923 return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer, 1924 length, false, NULL); 1925 } 1926 1927 1928 static status_t 1929 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1930 const void *buffer, size_t *length) 1931 { 1932 TRACE("write\n"); 1933 return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer, 1934 *length, NULL); 1935 } 1936 1937 1938 static status_t 1939 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, 1940 int perms) 1941 { 1942 TRACE("create_dir: \"%s\"\n", name); 1943 return ((OverlayInode *)vnode->private_node)->CreateDir(name, perms); 1944 } 1945 1946 1947 static status_t 1948 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) 1949 { 1950 TRACE("remove_dir: \"%s\"\n", name); 1951 return ((OverlayInode *)vnode->private_node)->RemoveDir(name); 1952 } 1953 1954 1955 static status_t 1956 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1957 { 1958 TRACE("open_dir\n"); 1959 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie); 1960 } 1961 1962 1963 static status_t 1964 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1965 { 1966 TRACE("close_dir\n"); 1967 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie); 1968 } 1969 1970 1971 static status_t 1972 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1973 { 1974 TRACE("free_dir_cookie\n"); 1975 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie); 1976 } 1977 1978 1979 static status_t 1980 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1981 struct dirent *buffer, size_t bufferSize, uint32 *num) 1982 { 1983 TRACE("read_dir\n"); 1984 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer, 1985 bufferSize, num); 1986 } 1987 1988 1989 static status_t 1990 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1991 { 1992 TRACE("rewind_dir\n"); 1993 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie); 1994 } 1995 1996 1997 static status_t 1998 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1999 { 2000 TRACE("open_attr_dir\n"); 2001 return ((OverlayInode *)vnode->private_node)->OpenDir(cookie, true); 2002 } 2003 2004 2005 static status_t 2006 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 2007 { 2008 TRACE("close_attr_dir\n"); 2009 return ((OverlayInode *)vnode->private_node)->CloseDir(cookie); 2010 } 2011 2012 2013 static status_t 2014 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 2015 { 2016 TRACE("free_attr_dir_cookie\n"); 2017 return ((OverlayInode *)vnode->private_node)->FreeDirCookie(cookie); 2018 } 2019 2020 2021 static status_t 2022 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 2023 struct dirent *buffer, size_t bufferSize, uint32 *num) 2024 { 2025 TRACE("read_attr_dir\n"); 2026 return ((OverlayInode *)vnode->private_node)->ReadDir(cookie, buffer, 2027 bufferSize, num, true); 2028 } 2029 2030 2031 static status_t 2032 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 2033 { 2034 TRACE("rewind_attr_dir\n"); 2035 return ((OverlayInode *)vnode->private_node)->RewindDir(cookie); 2036 } 2037 2038 2039 static status_t 2040 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 2041 uint32 type, int openMode, void **cookie) 2042 { 2043 TRACE("create_attr\n"); 2044 return ((OverlayInode *)vnode->private_node)->Create(name, openMode, 0, 2045 cookie, NULL, true, type); 2046 } 2047 2048 2049 static status_t 2050 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 2051 int openMode, void **cookie) 2052 { 2053 TRACE("open_attr\n"); 2054 OverlayInode *node = NULL; 2055 OverlayInode *parentNode = (OverlayInode *)vnode->private_node; 2056 status_t result = parentNode->LookupAttribute(name, &node); 2057 if (result != B_OK) 2058 return result; 2059 if (node == NULL) 2060 return B_ERROR; 2061 2062 return node->Open(openMode, cookie); 2063 } 2064 2065 2066 static status_t 2067 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie) 2068 { 2069 TRACE("close_attr\n"); 2070 open_cookie *cookie = (open_cookie *)_cookie; 2071 return cookie->node->Close(cookie); 2072 } 2073 2074 2075 static status_t 2076 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *_cookie) 2077 { 2078 TRACE("free_attr_cookie\n"); 2079 open_cookie *cookie = (open_cookie *)_cookie; 2080 return cookie->node->FreeCookie(cookie); 2081 } 2082 2083 2084 static status_t 2085 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos, 2086 void *buffer, size_t *length) 2087 { 2088 TRACE("read_attr\n"); 2089 open_cookie *cookie = (open_cookie *)_cookie; 2090 return cookie->node->Read(cookie, pos, buffer, length, false, NULL); 2091 } 2092 2093 2094 static status_t 2095 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *_cookie, off_t pos, 2096 const void *buffer, size_t *length) 2097 { 2098 TRACE("write_attr\n"); 2099 open_cookie *cookie = (open_cookie *)_cookie; 2100 return cookie->node->Write(cookie, pos, buffer, *length, NULL); 2101 } 2102 2103 2104 static status_t 2105 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie, 2106 struct stat *stat) 2107 { 2108 TRACE("read_attr_stat\n"); 2109 open_cookie *cookie = (open_cookie *)_cookie; 2110 return cookie->node->ReadStat(stat); 2111 } 2112 2113 2114 static status_t 2115 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *_cookie, 2116 const struct stat *stat, int statMask) 2117 { 2118 TRACE("write_attr_stat\n"); 2119 open_cookie *cookie = (open_cookie *)_cookie; 2120 return cookie->node->WriteStat(stat, statMask); 2121 } 2122 2123 2124 static status_t 2125 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, 2126 const char *fromName, fs_vnode *toVnode, const char *toName) 2127 { 2128 TRACE("rename attr: \"%s\" -> \"%s\"\n", fromName, toName); 2129 OverlayInode *fromNode = (OverlayInode *)vnode->private_node; 2130 OverlayInode *toNode = (OverlayInode *)toVnode->private_node; 2131 overlay_dirent *entry = NULL; 2132 2133 status_t result = fromNode->RemoveEntry(fromName, &entry, true); 2134 if (result != B_OK) 2135 return result; 2136 2137 char *oldName = entry->name; 2138 entry->name = strdup(toName); 2139 if (entry->name == NULL) { 2140 entry->name = oldName; 2141 if (fromNode->AddEntry(entry, true) != B_OK) 2142 entry->dispose_attribute(volume, fromNode->InodeNumber()); 2143 2144 return B_NO_MEMORY; 2145 } 2146 2147 result = toNode->AddEntry(entry, true); 2148 if (result != B_OK) { 2149 free(entry->name); 2150 entry->name = oldName; 2151 if (fromNode->AddEntry(entry, true) != B_OK) 2152 entry->dispose_attribute(volume, fromNode->InodeNumber()); 2153 2154 return result; 2155 } 2156 2157 OverlayInode *node = entry->node; 2158 if (node == NULL) 2159 return B_ERROR; 2160 2161 node->SetName(entry->name); 2162 node->SetSuperVnode(toNode->SuperVnode()); 2163 node->SetInodeNumber(toNode->InodeNumber()); 2164 2165 notify_attribute_changed(volume->id, fromNode->InodeNumber(), fromName, 2166 B_ATTR_REMOVED); 2167 notify_attribute_changed(volume->id, toNode->InodeNumber(), toName, 2168 B_ATTR_CREATED); 2169 2170 free(oldName); 2171 return B_OK; 2172 } 2173 2174 2175 static status_t 2176 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) 2177 { 2178 TRACE("remove_attr\n"); 2179 OverlayInode *node = (OverlayInode *)vnode->private_node; 2180 status_t result = node->RemoveEntry(name, NULL, true); 2181 if (result != B_OK) 2182 return result; 2183 2184 notify_attribute_changed(volume->id, node->InodeNumber(), name, 2185 B_ATTR_REMOVED); 2186 return result; 2187 } 2188 2189 2190 static status_t 2191 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, 2192 const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, 2193 fs_vnode *_superVnode, ino_t *nodeID) 2194 { 2195 OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, nodeID) 2196 } 2197 2198 2199 static fs_vnode_ops sOverlayVnodeOps = { 2200 &overlay_lookup, 2201 &overlay_get_vnode_name, 2202 2203 &overlay_put_vnode, 2204 &overlay_remove_vnode, 2205 2206 &overlay_can_page, 2207 &overlay_read_pages, 2208 &overlay_write_pages, 2209 2210 &overlay_io, 2211 &overlay_cancel_io, 2212 2213 &overlay_get_file_map, 2214 2215 /* common */ 2216 &overlay_ioctl, 2217 &overlay_set_flags, 2218 &overlay_select, 2219 &overlay_deselect, 2220 &overlay_fsync, 2221 2222 &overlay_read_symlink, 2223 &overlay_create_symlink, 2224 &overlay_link, 2225 &overlay_unlink, 2226 &overlay_rename, 2227 2228 &overlay_access, 2229 &overlay_read_stat, 2230 &overlay_write_stat, 2231 NULL, // fs_preallocate 2232 2233 /* file */ 2234 &overlay_create, 2235 &overlay_open, 2236 &overlay_close, 2237 &overlay_free_cookie, 2238 &overlay_read, 2239 &overlay_write, 2240 2241 /* directory */ 2242 &overlay_create_dir, 2243 &overlay_remove_dir, 2244 &overlay_open_dir, 2245 &overlay_close_dir, 2246 &overlay_free_dir_cookie, 2247 &overlay_read_dir, 2248 &overlay_rewind_dir, 2249 2250 /* attribute directory operations */ 2251 &overlay_open_attr_dir, 2252 &overlay_close_attr_dir, 2253 &overlay_free_attr_dir_cookie, 2254 &overlay_read_attr_dir, 2255 &overlay_rewind_attr_dir, 2256 2257 /* attribute operations */ 2258 &overlay_create_attr, 2259 &overlay_open_attr, 2260 &overlay_close_attr, 2261 &overlay_free_attr_cookie, 2262 &overlay_read_attr, 2263 &overlay_write_attr, 2264 2265 &overlay_read_attr_stat, 2266 &overlay_write_attr_stat, 2267 &overlay_rename_attr, 2268 &overlay_remove_attr, 2269 2270 /* support for node and FS layers */ 2271 &overlay_create_special_node, 2272 &overlay_get_super_vnode 2273 }; 2274 2275 2276 // #pragma mark - volume ops 2277 2278 2279 #define OVERLAY_VOLUME_CALL(op, params...) \ 2280 TRACE_VOLUME("relaying volume op: " #op "\n"); \ 2281 if (volume->super_volume->ops->op != NULL) \ 2282 return volume->super_volume->ops->op(volume->super_volume, params); 2283 2284 2285 static status_t 2286 overlay_unmount(fs_volume *volume) 2287 { 2288 TRACE_VOLUME("relaying volume op: unmount\n"); 2289 if (volume->super_volume != NULL 2290 && volume->super_volume->ops != NULL 2291 && volume->super_volume->ops->unmount != NULL) 2292 volume->super_volume->ops->unmount(volume->super_volume); 2293 2294 delete (OverlayVolume *)volume->private_volume; 2295 return B_OK; 2296 } 2297 2298 2299 static status_t 2300 overlay_read_fs_info(fs_volume *volume, struct fs_info *info) 2301 { 2302 TRACE_VOLUME("relaying volume op: read_fs_info\n"); 2303 status_t result = B_UNSUPPORTED; 2304 if (volume->super_volume->ops->read_fs_info != NULL) { 2305 result = volume->super_volume->ops->read_fs_info(volume->super_volume, 2306 info); 2307 if (result != B_OK) 2308 return result; 2309 2310 info->flags &= ~B_FS_IS_READONLY; 2311 2312 // TODO: maybe calculate based on available ram 2313 off_t available = 1024 * 1024 * 100 / info->block_size; 2314 info->total_blocks += available; 2315 info->free_blocks += available; 2316 return B_OK; 2317 } 2318 2319 return B_UNSUPPORTED; 2320 } 2321 2322 2323 static status_t 2324 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info, 2325 uint32 mask) 2326 { 2327 OVERLAY_VOLUME_CALL(write_fs_info, info, mask) 2328 return B_UNSUPPORTED; 2329 } 2330 2331 2332 static status_t 2333 overlay_sync(fs_volume *volume) 2334 { 2335 TRACE_VOLUME("relaying volume op: sync\n"); 2336 if (volume->super_volume->ops->sync != NULL) 2337 return volume->super_volume->ops->sync(volume->super_volume); 2338 return B_UNSUPPORTED; 2339 } 2340 2341 2342 static status_t 2343 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type, 2344 uint32 *_flags, bool reenter) 2345 { 2346 TRACE_VOLUME("relaying volume op: get_vnode\n"); 2347 if (volume->super_volume->ops->get_vnode != NULL) { 2348 status_t status = volume->super_volume->ops->get_vnode( 2349 volume->super_volume, id, vnode, _type, _flags, reenter); 2350 if (status != B_OK) 2351 return status; 2352 2353 OverlayInode *node = new(std::nothrow) OverlayInode( 2354 (OverlayVolume *)volume->private_volume, vnode, id); 2355 if (node == NULL) { 2356 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 2357 return B_NO_MEMORY; 2358 } 2359 2360 status = node->InitCheck(); 2361 if (status != B_OK) { 2362 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 2363 delete node; 2364 return status; 2365 } 2366 2367 vnode->private_node = node; 2368 vnode->ops = &sOverlayVnodeOps; 2369 return B_OK; 2370 } 2371 2372 return B_UNSUPPORTED; 2373 } 2374 2375 2376 static status_t 2377 overlay_open_index_dir(fs_volume *volume, void **cookie) 2378 { 2379 OVERLAY_VOLUME_CALL(open_index_dir, cookie) 2380 return B_UNSUPPORTED; 2381 } 2382 2383 2384 static status_t 2385 overlay_close_index_dir(fs_volume *volume, void *cookie) 2386 { 2387 OVERLAY_VOLUME_CALL(close_index_dir, cookie) 2388 return B_UNSUPPORTED; 2389 } 2390 2391 2392 static status_t 2393 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie) 2394 { 2395 OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie) 2396 return B_UNSUPPORTED; 2397 } 2398 2399 2400 static status_t 2401 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer, 2402 size_t bufferSize, uint32 *_num) 2403 { 2404 OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num) 2405 return B_UNSUPPORTED; 2406 } 2407 2408 2409 static status_t 2410 overlay_rewind_index_dir(fs_volume *volume, void *cookie) 2411 { 2412 OVERLAY_VOLUME_CALL(rewind_index_dir, cookie) 2413 return B_UNSUPPORTED; 2414 } 2415 2416 2417 static status_t 2418 overlay_create_index(fs_volume *volume, const char *name, uint32 type, 2419 uint32 flags) 2420 { 2421 OVERLAY_VOLUME_CALL(create_index, name, type, flags) 2422 return B_UNSUPPORTED; 2423 } 2424 2425 2426 static status_t 2427 overlay_remove_index(fs_volume *volume, const char *name) 2428 { 2429 OVERLAY_VOLUME_CALL(remove_index, name) 2430 return B_UNSUPPORTED; 2431 } 2432 2433 2434 static status_t 2435 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat) 2436 { 2437 OVERLAY_VOLUME_CALL(read_index_stat, name, stat) 2438 return B_UNSUPPORTED; 2439 } 2440 2441 2442 static status_t 2443 overlay_open_query(fs_volume *volume, const char *query, uint32 flags, 2444 port_id port, uint32 token, void **_cookie) 2445 { 2446 OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie) 2447 return B_UNSUPPORTED; 2448 } 2449 2450 2451 static status_t 2452 overlay_close_query(fs_volume *volume, void *cookie) 2453 { 2454 OVERLAY_VOLUME_CALL(close_query, cookie) 2455 return B_UNSUPPORTED; 2456 } 2457 2458 2459 static status_t 2460 overlay_free_query_cookie(fs_volume *volume, void *cookie) 2461 { 2462 OVERLAY_VOLUME_CALL(free_query_cookie, cookie) 2463 return B_UNSUPPORTED; 2464 } 2465 2466 2467 static status_t 2468 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer, 2469 size_t bufferSize, uint32 *_num) 2470 { 2471 OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num) 2472 return B_UNSUPPORTED; 2473 } 2474 2475 2476 static status_t 2477 overlay_rewind_query(fs_volume *volume, void *cookie) 2478 { 2479 OVERLAY_VOLUME_CALL(rewind_query, cookie) 2480 return B_UNSUPPORTED; 2481 } 2482 2483 2484 static status_t 2485 overlay_all_layers_mounted(fs_volume *volume) 2486 { 2487 return B_OK; 2488 } 2489 2490 2491 static status_t 2492 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode) 2493 { 2494 OverlayInode *node = new(std::nothrow) OverlayInode( 2495 (OverlayVolume *)volume->private_volume, vnode, id); 2496 if (node == NULL) 2497 return B_NO_MEMORY; 2498 2499 status_t status = node->InitCheck(); 2500 if (status != B_OK) { 2501 delete node; 2502 return status; 2503 } 2504 2505 vnode->private_node = node; 2506 vnode->ops = &sOverlayVnodeOps; 2507 return B_OK; 2508 } 2509 2510 2511 static status_t 2512 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode) 2513 { 2514 delete (OverlayInode *)vnode->private_node; 2515 return B_OK; 2516 } 2517 2518 2519 static fs_volume_ops sOverlayVolumeOps = { 2520 &overlay_unmount, 2521 2522 &overlay_read_fs_info, 2523 &overlay_write_fs_info, 2524 &overlay_sync, 2525 2526 &overlay_get_vnode, 2527 &overlay_open_index_dir, 2528 &overlay_close_index_dir, 2529 &overlay_free_index_dir_cookie, 2530 &overlay_read_index_dir, 2531 &overlay_rewind_index_dir, 2532 2533 &overlay_create_index, 2534 &overlay_remove_index, 2535 &overlay_read_index_stat, 2536 2537 &overlay_open_query, 2538 &overlay_close_query, 2539 &overlay_free_query_cookie, 2540 &overlay_read_query, 2541 &overlay_rewind_query, 2542 2543 &overlay_all_layers_mounted, 2544 &overlay_create_sub_vnode, 2545 &overlay_delete_sub_vnode 2546 }; 2547 2548 2549 // #pragma mark - filesystem module 2550 2551 2552 static status_t 2553 overlay_mount(fs_volume *volume, const char *device, uint32 flags, 2554 const char *args, ino_t *rootID) 2555 { 2556 TRACE_VOLUME("mounting write overlay\n"); 2557 volume->private_volume = new(std::nothrow) OverlayVolume(volume); 2558 if (volume->private_volume == NULL) 2559 return B_NO_MEMORY; 2560 2561 volume->ops = &sOverlayVolumeOps; 2562 return B_OK; 2563 } 2564 2565 2566 static status_t 2567 overlay_std_ops(int32 op, ...) 2568 { 2569 switch (op) { 2570 case B_MODULE_INIT: 2571 case B_MODULE_UNINIT: 2572 return B_OK; 2573 default: 2574 return B_ERROR; 2575 } 2576 } 2577 2578 2579 static file_system_module_info sOverlayFileSystem = { 2580 { 2581 "file_systems/write_overlay"B_CURRENT_FS_API_VERSION, 2582 0, 2583 overlay_std_ops, 2584 }, 2585 2586 "write_overlay", // short_name 2587 "Write Overlay File System", // pretty_name 2588 0, // DDM flags 2589 2590 // scanning 2591 NULL, // identify_partition 2592 NULL, // scan_partition 2593 NULL, // free_identify_partition_cookie 2594 NULL, // free_partition_content_cookie 2595 2596 // general operations 2597 &overlay_mount, 2598 2599 // capability querying 2600 NULL, // get_supported_operations 2601 2602 NULL, // validate_resize 2603 NULL, // validate_move 2604 NULL, // validate_set_content_name 2605 NULL, // validate_set_content_parameters 2606 NULL, // validate_initialize 2607 2608 // shadow partition modification 2609 NULL, // shadow_changed 2610 2611 // writing 2612 NULL, // defragment 2613 NULL, // repair 2614 NULL, // resize 2615 NULL, // move 2616 NULL, // set_content_name 2617 NULL, // set_content_parameters 2618 NULL // initialize 2619 }; 2620 2621 2622 status_t 2623 publish_overlay_vnode(fs_volume *volume, ino_t inodeNumber, void *privateNode, 2624 int type) 2625 { 2626 return publish_vnode(volume, inodeNumber, privateNode, &sOverlayVnodeOps, 2627 type, 0); 2628 } 2629 2630 } // namespace write_overlay 2631 2632 using namespace write_overlay; 2633 2634 module_info *modules[] = { 2635 (module_info *)&sOverlayFileSystem, 2636 NULL, 2637 }; 2638