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