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 10 #include <new> 11 #include <stdlib.h> 12 #include <string.h> 13 14 #include <dirent.h> 15 16 #include <util/kernel_cpp.h> 17 18 #include <fs_info.h> 19 #include <fs_interface.h> 20 21 #include <debug.h> 22 #include <KernelExport.h> 23 #include <NodeMonitor.h> 24 25 26 //#define TRACE_OVERLAY 27 #ifdef TRACE_OVERLAY 28 # define TRACE(x...) dprintf("attribute_overlay: " x) 29 # define TRACE_VOLUME(x...) dprintf("attribute_overlay: " x) 30 # define TRACE_ALWAYS(x...) dprintf("attribute_overlay: " x) 31 #else 32 # define TRACE(x...) /* nothing */ 33 # define TRACE_VOLUME(x...) /* nothing */ 34 # define TRACE_ALWAYS(x...) dprintf("attribute_overlay: " x) 35 #endif 36 37 38 #define ATTRIBUTE_OVERLAY_FILE_MAGIC 'attr' 39 #define ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME "_HAIKU" 40 41 42 #define OVERLAY_CALL(op, params...) \ 43 TRACE("relaying op: " #op "\n"); \ 44 OverlayInode *node = (OverlayInode *)vnode->private_node; \ 45 fs_vnode *superVnode = node->SuperVnode(); \ 46 if (superVnode->ops->op != NULL) \ 47 return superVnode->ops->op(volume->super_volume, superVnode, params); \ 48 return B_UNSUPPORTED; 49 50 51 #define OVERLAY_VOLUME_CALL(op, params...) \ 52 TRACE_VOLUME("relaying volume op: " #op "\n"); \ 53 if (volume->super_volume->ops->op != NULL) \ 54 return volume->super_volume->ops->op(volume->super_volume, params); 55 56 57 namespace attribute_overlay { 58 59 class AttributeFile; 60 class AttributeEntry; 61 62 63 struct attribute_dir_cookie { 64 AttributeFile * file; 65 uint32 index; 66 }; 67 68 69 class OverlayVolume { 70 public: 71 OverlayVolume(fs_volume *volume); 72 ~OverlayVolume(); 73 74 fs_volume * Volume() { return fVolume; } 75 fs_volume * SuperVolume() { return fVolume->super_volume; } 76 77 private: 78 fs_volume * fVolume; 79 }; 80 81 82 class OverlayInode { 83 public: 84 OverlayInode(OverlayVolume *volume, 85 fs_vnode *superVnode, ino_t inodeNumber); 86 ~OverlayInode(); 87 88 status_t InitCheck(); 89 90 fs_volume * Volume() { return fVolume->Volume(); } 91 fs_volume * SuperVolume() { return fVolume->SuperVolume(); } 92 fs_vnode * SuperVnode() { return &fSuperVnode; } 93 ino_t InodeNumber() { return fInodeNumber; } 94 95 status_t GetAttributeFile(AttributeFile **attributeFile); 96 status_t WriteAttributeFile(); 97 status_t RemoveAttributeFile(); 98 99 private: 100 OverlayVolume * fVolume; 101 fs_vnode fSuperVnode; 102 ino_t fInodeNumber; 103 AttributeFile * fAttributeFile; 104 }; 105 106 107 class AttributeFile { 108 public: 109 AttributeFile(fs_volume *overlay, 110 fs_volume *volume, fs_vnode *vnode); 111 ~AttributeFile(); 112 113 status_t InitCheck() { return fStatus; } 114 115 dev_t VolumeID() { return fVolumeID; } 116 ino_t FileInode() { return fFileInode; } 117 118 status_t CreateEmpty(); 119 status_t WriteAttributeFile(fs_volume *overlay, 120 fs_volume *volume, fs_vnode *vnode); 121 status_t RemoveAttributeFile(fs_volume *overlay, 122 fs_volume *volume, fs_vnode *vnode); 123 124 status_t ReadAttributeDir(struct dirent *dirent, 125 size_t bufferSize, uint32 *numEntries, 126 uint32 *index); 127 128 uint32 CountAttributes(); 129 AttributeEntry * FindAttribute(const char *name, 130 uint32 *index = NULL); 131 132 status_t CreateAttribute(const char *name, type_code type, 133 int openMode, AttributeEntry **entry); 134 status_t OpenAttribute(const char *name, int openMode, 135 AttributeEntry **entry); 136 status_t RemoveAttribute(const char *name, 137 AttributeEntry **entry); 138 status_t AddAttribute(AttributeEntry *entry); 139 140 private: 141 struct attribute_file { 142 uint32 magic; 143 // ATTRIBUTE_OVERLAY_FILE_MAGIC 144 uint32 entry_count; 145 uint8 entries[1]; 146 } _PACKED; 147 148 status_t fStatus; 149 dev_t fVolumeID; 150 ino_t fFileInode; 151 ino_t fDirectoryInode; 152 ino_t fAttributeDirInode; 153 ino_t fAttributeFileInode; 154 attribute_file * fFile; 155 uint32 fAttributeDirIndex; 156 AttributeEntry ** fEntries; 157 }; 158 159 160 class AttributeEntry { 161 public: 162 AttributeEntry(AttributeFile *parent, 163 uint8 *buffer); 164 AttributeEntry(AttributeFile *parent, 165 const char *name, type_code type); 166 ~AttributeEntry(); 167 168 status_t InitCheck() { return fStatus; } 169 170 uint8 * Entry() { return (uint8 *)fEntry; } 171 size_t EntrySize(); 172 uint8 * Data() { return fData; } 173 size_t DataSize() { return fEntry->size; } 174 175 status_t SetType(type_code type); 176 type_code Type() { return fEntry->type; } 177 178 status_t SetSize(size_t size); 179 uint32 Size() { return fEntry->size; } 180 181 status_t SetName(const char *name); 182 const char * Name() { return fEntry->name; } 183 uint8 NameLength() { return fEntry->name_length; } 184 185 status_t FillDirent(struct dirent *dirent, 186 size_t bufferSize, uint32 *numEntries); 187 188 status_t Read(off_t position, void *buffer, 189 size_t *length); 190 status_t Write(off_t position, const void *buffer, 191 size_t *length); 192 193 status_t ReadStat(struct stat *stat); 194 status_t WriteStat(const struct stat *stat, 195 uint32 statMask); 196 197 private: 198 struct attribute_entry { 199 type_code type; 200 uint32 size; 201 uint8 name_length; // including 0 byte 202 char name[1]; // 0 terminated, followed by data 203 } _PACKED; 204 205 AttributeFile * fParent; 206 attribute_entry * fEntry; 207 uint8 * fData; 208 status_t fStatus; 209 bool fAllocatedEntry; 210 bool fAllocatedData; 211 }; 212 213 214 // #pragma mark OverlayVolume 215 216 217 OverlayVolume::OverlayVolume(fs_volume *volume) 218 : 219 fVolume(volume) 220 { 221 } 222 223 224 OverlayVolume::~OverlayVolume() 225 { 226 } 227 228 229 // #pragma mark OverlayInode 230 231 232 OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode, 233 ino_t inodeNumber) 234 : 235 fVolume(volume), 236 fSuperVnode(*superVnode), 237 fInodeNumber(inodeNumber), 238 fAttributeFile(NULL) 239 { 240 TRACE("inode created\n"); 241 } 242 243 244 OverlayInode::~OverlayInode() 245 { 246 TRACE("inode destroyed\n"); 247 delete fAttributeFile; 248 } 249 250 251 status_t 252 OverlayInode::InitCheck() 253 { 254 return B_OK; 255 } 256 257 258 status_t 259 OverlayInode::GetAttributeFile(AttributeFile **attributeFile) 260 { 261 if (fAttributeFile == NULL) { 262 fAttributeFile = new(std::nothrow) AttributeFile(Volume(), 263 SuperVolume(), &fSuperVnode); 264 if (fAttributeFile == NULL) { 265 TRACE_ALWAYS("no memory to allocate attribute file\n"); 266 return B_NO_MEMORY; 267 } 268 } 269 270 status_t result = fAttributeFile->InitCheck(); 271 if (result != B_OK) { 272 if (result == B_ENTRY_NOT_FOUND) { 273 // TODO: need to check if we're able to create the file 274 // but at least allow virtual attributes for now 275 } 276 277 result = fAttributeFile->CreateEmpty(); 278 if (result != B_OK) 279 return result; 280 } 281 282 *attributeFile = fAttributeFile; 283 return B_OK; 284 } 285 286 287 status_t 288 OverlayInode::WriteAttributeFile() 289 { 290 if (fAttributeFile == NULL) 291 return B_NO_INIT; 292 293 status_t result = fAttributeFile->InitCheck(); 294 if (result != B_OK) 295 return result; 296 297 return fAttributeFile->WriteAttributeFile(Volume(), SuperVolume(), 298 &fSuperVnode); 299 } 300 301 302 status_t 303 OverlayInode::RemoveAttributeFile() 304 { 305 if (fAttributeFile == NULL) 306 return B_NO_INIT; 307 308 status_t result = fAttributeFile->InitCheck(); 309 if (result != B_OK) 310 return result; 311 312 return fAttributeFile->RemoveAttributeFile(Volume(), SuperVolume(), 313 &fSuperVnode); 314 } 315 316 317 // #pragma mark AttributeFile 318 319 320 AttributeFile::AttributeFile(fs_volume *overlay, fs_volume *volume, 321 fs_vnode *vnode) 322 : 323 fStatus(B_NO_INIT), 324 fVolumeID(volume->id), 325 fFileInode(0), 326 fDirectoryInode(0), 327 fAttributeDirInode(0), 328 fAttributeFileInode(0), 329 fFile(NULL), 330 fAttributeDirIndex(0), 331 fEntries(NULL) 332 { 333 if (vnode->ops->get_vnode_name == NULL) { 334 TRACE_ALWAYS("cannot get vnode name, hook missing\n"); 335 fStatus = B_UNSUPPORTED; 336 return; 337 } 338 339 char nameBuffer[B_FILE_NAME_LENGTH]; 340 nameBuffer[sizeof(nameBuffer) - 1] = 0; 341 fStatus = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, 342 sizeof(nameBuffer) - 1); 343 if (fStatus != B_OK) { 344 TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(fStatus)); 345 return; 346 } 347 348 if (strcmp(nameBuffer, ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { 349 // we don't want attribute overlays on the attribute dir itself 350 fStatus = B_UNSUPPORTED; 351 return; 352 } 353 354 struct stat stat; 355 if (vnode->ops->read_stat != NULL 356 && vnode->ops->read_stat(volume, vnode, &stat) == B_OK) { 357 fFileInode = stat.st_ino; 358 } 359 360 // TODO: the ".." lookup is not actually valid for non-directory vnodes. 361 // we make use of the fact that a filesystem probably still provides the 362 // lookup hook and has hardcoded ".." to resolve to the parent entry. if we 363 // wanted to do this correctly we need some other way to relate this vnode 364 // to its parent directory vnode. 365 const char *lookup[] 366 = { "..", ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, nameBuffer }; 367 int32 lookupCount = sizeof(lookup) / sizeof(lookup[0]); 368 fs_vnode currentVnode = *vnode; 369 ino_t lastInodeNumber = 0; 370 371 for (int32 i = 0; i < lookupCount; i++) { 372 if (currentVnode.ops->lookup == NULL) { 373 TRACE_ALWAYS("lookup not possible, lookup hook missing\n"); 374 fStatus = B_UNSUPPORTED; 375 if (i > 0) 376 put_vnode(volume, lastInodeNumber); 377 return; 378 } 379 380 ino_t inodeNumber; 381 fStatus = currentVnode.ops->lookup(volume, ¤tVnode, lookup[i], 382 &inodeNumber); 383 384 if (i > 0) 385 put_vnode(volume, lastInodeNumber); 386 387 if (fStatus != B_OK) { 388 if (fStatus != B_ENTRY_NOT_FOUND) { 389 TRACE_ALWAYS("lookup of \"%s\" failed: %s\n", lookup[i], 390 strerror(fStatus)); 391 } 392 return; 393 } 394 395 if (i == 0) 396 fDirectoryInode = inodeNumber; 397 else if (i == 1) 398 fAttributeDirInode = inodeNumber; 399 else if (i == 2) 400 fAttributeFileInode = inodeNumber; 401 402 OverlayInode *overlayInode = NULL; 403 fStatus = get_vnode(overlay, inodeNumber, (void **)&overlayInode); 404 if (fStatus != B_OK) { 405 TRACE_ALWAYS("getting vnode failed: %s\n", strerror(fStatus)); 406 return; 407 } 408 409 currentVnode = *overlayInode->SuperVnode(); 410 lastInodeNumber = inodeNumber; 411 } 412 413 if (currentVnode.ops->read_stat == NULL || currentVnode.ops->open == NULL 414 || currentVnode.ops->read == NULL) { 415 TRACE_ALWAYS("can't use attribute file, hooks missing\n"); 416 put_vnode(volume, lastInodeNumber); 417 fStatus = B_UNSUPPORTED; 418 return; 419 } 420 421 fStatus = currentVnode.ops->read_stat(volume, ¤tVnode, &stat); 422 if (fStatus != B_OK) { 423 TRACE_ALWAYS("failed to stat attribute file: %s\n", strerror(fStatus)); 424 put_vnode(volume, lastInodeNumber); 425 return; 426 } 427 428 void *attrFileCookie = NULL; 429 fStatus = currentVnode.ops->open(volume, ¤tVnode, O_RDONLY, 430 &attrFileCookie); 431 if (fStatus != B_OK) { 432 TRACE_ALWAYS("failed to open attribute file: %s\n", strerror(fStatus)); 433 put_vnode(volume, lastInodeNumber); 434 return; 435 } 436 437 size_t readLength = stat.st_size; 438 uint8 *buffer = (uint8 *)malloc(readLength); 439 if (buffer == NULL) { 440 TRACE_ALWAYS("cannot allocate memory for read buffer\n"); 441 put_vnode(volume, lastInodeNumber); 442 fStatus = B_NO_MEMORY; 443 return; 444 } 445 446 fStatus = currentVnode.ops->read(volume, ¤tVnode, attrFileCookie, 0, 447 buffer, &readLength); 448 if (fStatus != B_OK) { 449 TRACE_ALWAYS("failed to read from file: %s\n", strerror(fStatus)); 450 put_vnode(volume, lastInodeNumber); 451 return; 452 } 453 454 if (currentVnode.ops->close != NULL) 455 currentVnode.ops->close(volume, ¤tVnode, attrFileCookie); 456 if (currentVnode.ops->free_cookie != NULL) 457 currentVnode.ops->free_cookie(volume, ¤tVnode, attrFileCookie); 458 459 put_vnode(volume, lastInodeNumber); 460 461 fFile = (attribute_file *)buffer; 462 if (fFile->magic != ATTRIBUTE_OVERLAY_FILE_MAGIC) { 463 TRACE_ALWAYS("attribute file has bad magic\n"); 464 fStatus = B_BAD_VALUE; 465 return; 466 } 467 468 fEntries = (AttributeEntry **)malloc(fFile->entry_count 469 * sizeof(AttributeEntry *)); 470 if (fEntries == NULL) { 471 TRACE_ALWAYS("no memory to allocate entry pointers\n"); 472 fStatus = B_NO_MEMORY; 473 return; 474 } 475 476 for (uint32 i = 0; i < fFile->entry_count; i++) 477 fEntries[i] = NULL; 478 479 size_t totalSize = 0; 480 readLength -= sizeof(attribute_file) - 1; 481 for (uint32 i = 0; i < fFile->entry_count; i++) { 482 fEntries[i] = new(std::nothrow) AttributeEntry(this, 483 fFile->entries + totalSize); 484 if (fEntries[i] == NULL) { 485 TRACE_ALWAYS("no memory to allocate attribute entry\n"); 486 fStatus = B_NO_MEMORY; 487 return; 488 } 489 490 totalSize += fEntries[i]->EntrySize() + fEntries[i]->DataSize(); 491 if (totalSize > readLength) { 492 TRACE_ALWAYS("attribute entries are too large for buffer\n"); 493 fStatus = B_BAD_VALUE; 494 return; 495 } 496 } 497 } 498 499 500 AttributeFile::~AttributeFile() 501 { 502 if (fFile == NULL) 503 return; 504 505 if (fEntries != NULL) { 506 for (uint32 i = 0; i < fFile->entry_count; i++) 507 delete fEntries[i]; 508 509 free(fEntries); 510 } 511 512 free(fFile); 513 } 514 515 516 status_t 517 AttributeFile::CreateEmpty() 518 { 519 if (fFile == NULL) { 520 fFile = (attribute_file *)malloc(sizeof(attribute_file) - 1); 521 if (fFile == NULL) { 522 TRACE_ALWAYS("failed to allocate file buffer\n"); 523 fStatus = B_NO_MEMORY; 524 return fStatus; 525 } 526 527 fFile->entry_count = 0; 528 fFile->magic = ATTRIBUTE_OVERLAY_FILE_MAGIC; 529 } 530 531 fStatus = B_OK; 532 return B_OK; 533 } 534 535 536 status_t 537 AttributeFile::WriteAttributeFile(fs_volume *overlay, fs_volume *volume, 538 fs_vnode *vnode) 539 { 540 if (fFile == NULL) 541 return B_NO_INIT; 542 543 char nameBuffer[B_FILE_NAME_LENGTH]; 544 nameBuffer[sizeof(nameBuffer) - 1] = 0; 545 status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, 546 sizeof(nameBuffer) - 1); 547 if (result != B_OK) { 548 TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result)); 549 return result; 550 } 551 552 fs_vnode currentVnode = *vnode; 553 if (fDirectoryInode == 0) { 554 if (currentVnode.ops->lookup == NULL) { 555 TRACE_ALWAYS("lookup not possible, lookup hook missing\n"); 556 return B_UNSUPPORTED; 557 } 558 559 // see TODO above 560 result = currentVnode.ops->lookup(volume, ¤tVnode, "..", 561 &fDirectoryInode); 562 if (result != B_OK) { 563 TRACE_ALWAYS("lookup of parent directory failed: %s\n", 564 strerror(result)); 565 return B_UNSUPPORTED; 566 } 567 568 put_vnode(volume, fDirectoryInode); 569 } 570 571 OverlayInode *overlayInode = NULL; 572 if (fAttributeDirInode == 0) { 573 result = get_vnode(overlay, fDirectoryInode, (void **)&overlayInode); 574 if (result != B_OK) { 575 TRACE_ALWAYS("failed to get directory vnode: %s\n", 576 strerror(result)); 577 return result; 578 } 579 580 currentVnode = *overlayInode->SuperVnode(); 581 582 // create the attribute directory 583 result = currentVnode.ops->create_dir(volume, ¤tVnode, 584 ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, S_IRWXU | S_IRWXG | S_IRWXO); 585 586 if (result == B_OK) { 587 result = currentVnode.ops->lookup(volume, ¤tVnode, 588 ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME, &fAttributeDirInode); 589 590 // lookup() got us a reference we don't need -- put it 591 if (result == B_OK) 592 put_vnode(volume, fAttributeDirInode); 593 } 594 595 put_vnode(volume, fDirectoryInode); 596 597 if (result != B_OK) { 598 TRACE_ALWAYS("failed to create attribute directory: %s\n", 599 strerror(result)); 600 fAttributeDirInode = 0; 601 return result; 602 } 603 } 604 605 void *attrFileCookie = NULL; 606 if (fAttributeFileInode == 0) { 607 result = get_vnode(overlay, fAttributeDirInode, (void **)&overlayInode); 608 if (result != B_OK) { 609 TRACE_ALWAYS("failed to get attribute directory vnode: %s\n", 610 strerror(result)); 611 return result; 612 } 613 614 currentVnode = *overlayInode->SuperVnode(); 615 616 // create the attribute file 617 result = currentVnode.ops->create(volume, ¤tVnode, 618 nameBuffer, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP 619 | S_IWGRP | S_IROTH | S_IWOTH, &attrFileCookie, 620 &fAttributeFileInode); 621 622 put_vnode(volume, fAttributeDirInode); 623 624 if (result != B_OK) { 625 TRACE_ALWAYS("failed to create attribute file: %s\n", 626 strerror(result)); 627 return result; 628 } 629 630 result = get_vnode(overlay, fAttributeFileInode, 631 (void **)&overlayInode); 632 if (result != B_OK) { 633 TRACE_ALWAYS("getting attribute file vnode after create failed: " 634 "%s\n", strerror(result)); 635 return result; 636 } 637 638 currentVnode = *overlayInode->SuperVnode(); 639 } else { 640 result = get_vnode(overlay, fAttributeFileInode, 641 (void **)&overlayInode); 642 if (result != B_OK) { 643 TRACE_ALWAYS("getting attribute file vnode failed: %s\n", 644 strerror(result)); 645 return result; 646 } 647 648 currentVnode = *overlayInode->SuperVnode(); 649 650 // open the attribute file 651 result = currentVnode.ops->open(volume, ¤tVnode, O_RDWR | O_TRUNC, 652 &attrFileCookie); 653 if (result != B_OK) { 654 TRACE_ALWAYS("failed to open attribute file for writing: %s\n", 655 strerror(result)); 656 put_vnode(volume, fAttributeFileInode); 657 return result; 658 } 659 } 660 661 off_t position = 0; 662 size_t writeLength = sizeof(attribute_file) - 1; 663 result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, 664 position, fFile, &writeLength); 665 if (result != B_OK) { 666 TRACE_ALWAYS("failed to write to attribute file: %s\n", 667 strerror(result)); 668 goto close_and_put; 669 } 670 671 for (uint32 i = 0; i < fFile->entry_count; i++) { 672 writeLength = fEntries[i]->EntrySize(); 673 result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, 674 position, fEntries[i]->Entry(), &writeLength); 675 if (result != B_OK) { 676 TRACE_ALWAYS("failed to write to attribute file: %s\n", 677 strerror(result)); 678 goto close_and_put; 679 } 680 681 writeLength = fEntries[i]->DataSize(); 682 result = currentVnode.ops->write(volume, ¤tVnode, attrFileCookie, 683 position, fEntries[i]->Data(), &writeLength); 684 if (result != B_OK) { 685 TRACE_ALWAYS("failed to write to attribute file: %s\n", 686 strerror(result)); 687 goto close_and_put; 688 } 689 } 690 691 close_and_put: 692 if (currentVnode.ops->close != NULL) 693 currentVnode.ops->close(volume, ¤tVnode, attrFileCookie); 694 if (currentVnode.ops->free_cookie != NULL) 695 currentVnode.ops->free_cookie(volume, ¤tVnode, attrFileCookie); 696 697 put_vnode(volume, fAttributeFileInode); 698 return B_OK; 699 } 700 701 702 status_t 703 AttributeFile::RemoveAttributeFile(fs_volume *overlay, fs_volume *volume, 704 fs_vnode *vnode) 705 { 706 bool hasAttributeFile = fAttributeFileInode != 0; 707 ino_t attributeDirInode = fAttributeDirInode; 708 709 // invalidate all of our cached inode numbers 710 fDirectoryInode = 0; 711 fAttributeDirInode = 0; 712 fAttributeFileInode = 0; 713 714 if (!hasAttributeFile) { 715 // there is no backing file at all yet 716 return B_OK; 717 } 718 719 char nameBuffer[B_FILE_NAME_LENGTH]; 720 nameBuffer[sizeof(nameBuffer) - 1] = 0; 721 status_t result = vnode->ops->get_vnode_name(volume, vnode, nameBuffer, 722 sizeof(nameBuffer) - 1); 723 if (result != B_OK) { 724 TRACE_ALWAYS("failed to get vnode name: %s\n", strerror(result)); 725 return result; 726 } 727 728 OverlayInode *overlayInode = NULL; 729 result = get_vnode(overlay, attributeDirInode, (void **)&overlayInode); 730 if (result != B_OK) { 731 TRACE_ALWAYS("getting attribute directory vnode failed: %s\n", 732 strerror(result)); 733 return result; 734 } 735 736 fs_vnode attributeDir = *overlayInode->SuperVnode(); 737 if (attributeDir.ops->unlink == NULL) { 738 TRACE_ALWAYS("cannot remove attribute file, unlink hook missing\n"); 739 put_vnode(volume, attributeDirInode); 740 return B_UNSUPPORTED; 741 } 742 743 result = attributeDir.ops->unlink(volume, &attributeDir, nameBuffer); 744 if (result != B_OK) { 745 TRACE_ALWAYS("failed to unlink attribute file: %s\n", strerror(result)); 746 put_vnode(volume, attributeDirInode); 747 return result; 748 } 749 750 put_vnode(volume, attributeDirInode); 751 return B_OK; 752 } 753 754 755 uint32 756 AttributeFile::CountAttributes() 757 { 758 if (fFile == NULL) 759 return 0; 760 761 return fFile->entry_count; 762 } 763 764 765 AttributeEntry * 766 AttributeFile::FindAttribute(const char *name, uint32 *index) 767 { 768 for (uint32 i = 0; i < fFile->entry_count; i++) { 769 if (strcmp(fEntries[i]->Name(), name) == 0) { 770 if (index) 771 *index = i; 772 773 return fEntries[i]; 774 } 775 } 776 777 return NULL; 778 } 779 780 781 status_t 782 AttributeFile::CreateAttribute(const char *name, type_code type, int openMode, 783 AttributeEntry **_entry) 784 { 785 AttributeEntry *existing = FindAttribute(name); 786 if (existing != NULL) { 787 if ((openMode & O_TRUNC) != 0) 788 existing->SetSize(0); 789 790 // attribute already exists, only allow if the attribute type is 791 // compatible or the attribute size is 0 792 if (existing->Type() != type) { 793 if (existing->Size() != 0) 794 return B_FILE_EXISTS; 795 existing->SetType(type); 796 } 797 798 if (existing->InitCheck() == B_OK) { 799 *_entry = existing; 800 return B_OK; 801 } 802 803 // we tried to change the existing item but failed, try to just 804 // remove it instead and creating a new one 805 RemoveAttribute(name, NULL); 806 } 807 808 AttributeEntry *entry = new(std::nothrow) AttributeEntry(this, name, type); 809 if (entry == NULL) 810 return B_NO_MEMORY; 811 812 status_t result = AddAttribute(entry); 813 if (result != B_OK) { 814 delete entry; 815 return result; 816 } 817 818 *_entry = entry; 819 return B_OK; 820 } 821 822 823 status_t 824 AttributeFile::OpenAttribute(const char *name, int openMode, 825 AttributeEntry **_entry) 826 { 827 AttributeEntry *entry = FindAttribute(name); 828 if (entry == NULL) 829 return B_ENTRY_NOT_FOUND; 830 831 if (openMode & O_TRUNC) 832 entry->SetSize(0); 833 834 *_entry = entry; 835 return B_OK; 836 } 837 838 839 status_t 840 AttributeFile::RemoveAttribute(const char *name, AttributeEntry **_entry) 841 { 842 uint32 index = 0; 843 AttributeEntry *entry = FindAttribute(name, &index); 844 if (entry == NULL) 845 return B_ENTRY_NOT_FOUND; 846 847 for (uint32 i = index + 1; i < fFile->entry_count; i++) 848 fEntries[i - 1] = fEntries[i]; 849 fFile->entry_count--; 850 851 if (_entry) 852 *_entry = entry; 853 else 854 delete entry; 855 856 notify_attribute_changed(fVolumeID, -1, fFileInode, name, B_ATTR_REMOVED); 857 return B_OK; 858 } 859 860 861 status_t 862 AttributeFile::AddAttribute(AttributeEntry *entry) 863 { 864 status_t result = entry->InitCheck(); 865 if (result != B_OK) 866 return result; 867 868 if (FindAttribute(entry->Name()) != NULL) 869 return B_FILE_EXISTS; 870 871 AttributeEntry **newEntries = (AttributeEntry **)realloc(fEntries, 872 (fFile->entry_count + 1) * sizeof(AttributeEntry *)); 873 if (newEntries == NULL) 874 return B_NO_MEMORY; 875 876 fEntries = newEntries; 877 fEntries[fFile->entry_count++] = entry; 878 879 notify_attribute_changed(fVolumeID, -1, fFileInode, entry->Name(), 880 B_ATTR_CREATED); 881 882 return B_OK; 883 } 884 885 886 status_t 887 AttributeFile::ReadAttributeDir(struct dirent *dirent, size_t bufferSize, 888 uint32 *numEntries, uint32 *index) 889 { 890 if (fFile == NULL || *index >= fFile->entry_count) { 891 *numEntries = 0; 892 return B_OK; 893 } 894 895 return fEntries[(*index)++]->FillDirent(dirent, bufferSize, numEntries); 896 } 897 898 899 // #pragma mark AttributeEntry 900 901 902 AttributeEntry::AttributeEntry(AttributeFile *parent, uint8 *buffer) 903 : 904 fParent(parent), 905 fEntry(NULL), 906 fData(NULL), 907 fStatus(B_NO_INIT), 908 fAllocatedEntry(false), 909 fAllocatedData(false) 910 { 911 if (buffer == NULL) 912 return; 913 914 fEntry = (attribute_entry *)buffer; 915 fData = (uint8 *)fEntry->name + fEntry->name_length; 916 fStatus = B_OK; 917 } 918 919 920 AttributeEntry::AttributeEntry(AttributeFile *parent, const char *name, 921 type_code type) 922 : 923 fParent(parent), 924 fEntry(NULL), 925 fData(NULL), 926 fStatus(B_NO_INIT), 927 fAllocatedEntry(false), 928 fAllocatedData(false) 929 { 930 fStatus = SetName(name); 931 if (fStatus != B_OK) 932 return; 933 934 fEntry->type = type; 935 fEntry->size = 0; 936 } 937 938 939 AttributeEntry::~AttributeEntry() 940 { 941 if (fAllocatedEntry) 942 free(fEntry); 943 if (fAllocatedData) 944 free(fData); 945 } 946 947 948 size_t 949 AttributeEntry::EntrySize() 950 { 951 return sizeof(attribute_entry) - 1 + fEntry->name_length; 952 } 953 954 955 status_t 956 AttributeEntry::SetType(type_code type) 957 { 958 fEntry->type = type; 959 return B_OK; 960 } 961 962 963 status_t 964 AttributeEntry::SetSize(size_t size) 965 { 966 if (size <= fEntry->size) { 967 fEntry->size = size; 968 return B_OK; 969 } 970 971 if (fAllocatedData) { 972 uint8 *newData = (uint8 *)realloc(fData, size); 973 if (newData == NULL) { 974 fStatus = B_NO_MEMORY; 975 return fStatus; 976 } 977 978 fData = newData; 979 fEntry->size = size; 980 return B_OK; 981 } 982 983 uint8 *newData = (uint8 *)malloc(size); 984 if (newData == NULL) { 985 fStatus = B_NO_MEMORY; 986 return fStatus; 987 } 988 989 memcpy(newData, fData, min_c(fEntry->size, size)); 990 fEntry->size = size; 991 fAllocatedData = true; 992 fData = newData; 993 return B_OK; 994 } 995 996 997 status_t 998 AttributeEntry::SetName(const char *name) 999 { 1000 size_t nameLength = strlen(name) + 1; 1001 if (nameLength > 255) { 1002 fStatus = B_NAME_TOO_LONG; 1003 return fStatus; 1004 } 1005 1006 if (!fAllocatedEntry || fEntry->name_length < nameLength) { 1007 attribute_entry *newEntry = (attribute_entry *)malloc( 1008 sizeof(attribute_entry) - 1 + nameLength); 1009 if (newEntry == NULL) { 1010 fStatus = B_NO_MEMORY; 1011 return fStatus; 1012 } 1013 1014 if (fEntry != NULL) 1015 memcpy(newEntry, fEntry, sizeof(attribute_entry) - 1); 1016 if (fAllocatedEntry) 1017 free(fEntry); 1018 1019 fAllocatedEntry = true; 1020 fEntry = newEntry; 1021 } 1022 1023 fEntry->name_length = nameLength; 1024 strlcpy(fEntry->name, name, nameLength); 1025 return B_OK; 1026 } 1027 1028 1029 status_t 1030 AttributeEntry::FillDirent(struct dirent *dirent, size_t bufferSize, 1031 uint32 *numEntries) 1032 { 1033 dirent->d_dev = dirent->d_pdev = fParent->VolumeID(); 1034 dirent->d_ino = (ino_t)this; 1035 dirent->d_pino = fParent->FileInode(); 1036 dirent->d_reclen = sizeof(struct dirent) + fEntry->name_length; 1037 if (bufferSize < dirent->d_reclen) { 1038 *numEntries = 0; 1039 return B_BAD_VALUE; 1040 } 1041 1042 strncpy(dirent->d_name, fEntry->name, fEntry->name_length); 1043 dirent->d_name[fEntry->name_length - 1] = 0; 1044 *numEntries = 1; 1045 return B_OK; 1046 } 1047 1048 1049 status_t 1050 AttributeEntry::Read(off_t position, void *buffer, size_t *length) 1051 { 1052 *length = (size_t)min_c((off_t)*length, fEntry->size - position); 1053 memcpy(buffer, fData + position, *length); 1054 return B_OK; 1055 } 1056 1057 1058 status_t 1059 AttributeEntry::Write(off_t position, const void *buffer, size_t *length) 1060 { 1061 size_t neededSize = position + *length; 1062 if (neededSize > fEntry->size) { 1063 status_t result = SetSize(neededSize); 1064 if (result != B_OK) { 1065 *length = 0; 1066 return result; 1067 } 1068 } 1069 1070 memcpy(fData + position, buffer, *length); 1071 notify_attribute_changed(fParent->VolumeID(), -1, fParent->FileInode(), 1072 fEntry->name, B_ATTR_CHANGED); 1073 return B_OK; 1074 } 1075 1076 1077 status_t 1078 AttributeEntry::ReadStat(struct stat *stat) 1079 { 1080 stat->st_dev = fParent->VolumeID(); 1081 stat->st_ino = (ino_t)this; 1082 stat->st_nlink = 1; 1083 stat->st_blksize = 512; 1084 stat->st_uid = 1; 1085 stat->st_gid = 1; 1086 stat->st_size = fEntry->size; 1087 stat->st_mode = S_ATTR | 0x0777; 1088 stat->st_type = fEntry->type; 1089 stat->st_atime = stat->st_mtime = stat->st_crtime = time(NULL); 1090 stat->st_blocks = (fEntry->size + stat->st_blksize - 1) / stat->st_blksize; 1091 return B_OK; 1092 } 1093 1094 1095 status_t 1096 AttributeEntry::WriteStat(const struct stat *stat, uint32 statMask) 1097 { 1098 return B_UNSUPPORTED; 1099 } 1100 1101 1102 // #pragma mark - vnode ops 1103 1104 1105 static status_t 1106 overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 1107 { 1108 OverlayInode *node = (OverlayInode *)vnode->private_node; 1109 fs_vnode *superVnode = node->SuperVnode(); 1110 1111 status_t result = B_OK; 1112 if (superVnode->ops->put_vnode != NULL) { 1113 result = superVnode->ops->put_vnode(volume->super_volume, superVnode, 1114 reenter); 1115 } 1116 1117 delete node; 1118 return result; 1119 } 1120 1121 1122 static status_t 1123 overlay_remove_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) 1124 { 1125 OverlayInode *node = (OverlayInode *)vnode->private_node; 1126 fs_vnode *superVnode = node->SuperVnode(); 1127 1128 status_t result = B_OK; 1129 if (superVnode->ops->remove_vnode != NULL) { 1130 result = superVnode->ops->remove_vnode(volume->super_volume, superVnode, 1131 reenter); 1132 } 1133 1134 delete node; 1135 return result; 1136 } 1137 1138 1139 static status_t 1140 overlay_get_super_vnode(fs_volume *volume, fs_vnode *vnode, 1141 fs_volume *superVolume, fs_vnode *_superVnode) 1142 { 1143 if (volume == superVolume) { 1144 *_superVnode = *vnode; 1145 return B_OK; 1146 } 1147 1148 OverlayInode *node = (OverlayInode *)vnode->private_node; 1149 fs_vnode *superVnode = node->SuperVnode(); 1150 1151 if (superVnode->ops->get_super_vnode != NULL) { 1152 return superVnode->ops->get_super_vnode(volume->super_volume, 1153 superVnode, superVolume, _superVnode); 1154 } 1155 1156 *_superVnode = *superVnode; 1157 return B_OK; 1158 } 1159 1160 1161 static status_t 1162 overlay_lookup(fs_volume *volume, fs_vnode *vnode, const char *name, ino_t *id) 1163 { 1164 OVERLAY_CALL(lookup, name, id) 1165 } 1166 1167 1168 static status_t 1169 overlay_get_vnode_name(fs_volume *volume, fs_vnode *vnode, char *buffer, 1170 size_t bufferSize) 1171 { 1172 OVERLAY_CALL(get_vnode_name, buffer, bufferSize) 1173 } 1174 1175 1176 static bool 1177 overlay_can_page(fs_volume *volume, fs_vnode *vnode, void *cookie) 1178 { 1179 TRACE("relaying op: can_page\n"); 1180 OverlayInode *node = (OverlayInode *)vnode->private_node; 1181 fs_vnode *superVnode = node->SuperVnode(); 1182 1183 if (superVnode->ops->can_page != NULL) { 1184 return superVnode->ops->can_page(volume->super_volume, superVnode, 1185 cookie); 1186 } 1187 1188 return false; 1189 } 1190 1191 1192 static status_t 1193 overlay_read_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1194 const iovec *vecs, size_t count, size_t *numBytes) 1195 { 1196 OVERLAY_CALL(read_pages, cookie, pos, vecs, count, numBytes) 1197 } 1198 1199 1200 static status_t 1201 overlay_write_pages(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1202 const iovec *vecs, size_t count, size_t *numBytes) 1203 { 1204 OVERLAY_CALL(write_pages, cookie, pos, vecs, count, numBytes) 1205 } 1206 1207 1208 static status_t 1209 overlay_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1210 io_request *request) 1211 { 1212 OVERLAY_CALL(io, cookie, request) 1213 } 1214 1215 1216 static status_t 1217 overlay_cancel_io(fs_volume *volume, fs_vnode *vnode, void *cookie, 1218 io_request *request) 1219 { 1220 OVERLAY_CALL(cancel_io, cookie, request) 1221 } 1222 1223 1224 static status_t 1225 overlay_get_file_map(fs_volume *volume, fs_vnode *vnode, off_t offset, 1226 size_t size, struct file_io_vec *vecs, size_t *count) 1227 { 1228 OVERLAY_CALL(get_file_map, offset, size, vecs, count) 1229 } 1230 1231 1232 static status_t 1233 overlay_ioctl(fs_volume *volume, fs_vnode *vnode, void *cookie, uint32 op, 1234 void *buffer, size_t length) 1235 { 1236 OVERLAY_CALL(ioctl, cookie, op, buffer, length) 1237 } 1238 1239 1240 static status_t 1241 overlay_set_flags(fs_volume *volume, fs_vnode *vnode, void *cookie, 1242 int flags) 1243 { 1244 OVERLAY_CALL(set_flags, cookie, flags) 1245 } 1246 1247 1248 static status_t 1249 overlay_select(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1250 selectsync *sync) 1251 { 1252 OVERLAY_CALL(select, cookie, event, sync) 1253 } 1254 1255 1256 static status_t 1257 overlay_deselect(fs_volume *volume, fs_vnode *vnode, void *cookie, uint8 event, 1258 selectsync *sync) 1259 { 1260 OVERLAY_CALL(deselect, cookie, event, sync) 1261 } 1262 1263 1264 static status_t 1265 overlay_fsync(fs_volume *volume, fs_vnode *vnode) 1266 { 1267 OverlayInode *node = (OverlayInode *)vnode->private_node; 1268 fs_vnode *superVnode = node->SuperVnode(); 1269 1270 if (superVnode->ops->fsync != NULL) 1271 return superVnode->ops->fsync(volume->super_volume, superVnode); 1272 1273 return B_OK; 1274 } 1275 1276 1277 static status_t 1278 overlay_read_symlink(fs_volume *volume, fs_vnode *vnode, char *buffer, 1279 size_t *bufferSize) 1280 { 1281 OVERLAY_CALL(read_symlink, buffer, bufferSize) 1282 } 1283 1284 1285 static status_t 1286 overlay_create_symlink(fs_volume *volume, fs_vnode *vnode, const char *name, 1287 const char *path, int mode) 1288 { 1289 OVERLAY_CALL(create_symlink, name, path, mode) 1290 } 1291 1292 1293 static status_t 1294 overlay_link(fs_volume *volume, fs_vnode *vnode, const char *name, 1295 fs_vnode *target) 1296 { 1297 OverlayInode *targetNode = (OverlayInode *)target->private_node; 1298 OVERLAY_CALL(link, name, targetNode->SuperVnode()) 1299 } 1300 1301 1302 static status_t 1303 overlay_unlink(fs_volume *volume, fs_vnode *vnode, const char *name) 1304 { 1305 OVERLAY_CALL(unlink, name) 1306 } 1307 1308 1309 static status_t 1310 overlay_rename(fs_volume *volume, fs_vnode *vnode, 1311 const char *fromName, fs_vnode *toDir, const char *toName) 1312 { 1313 OverlayInode *toDirNode = (OverlayInode *)toDir->private_node; 1314 OVERLAY_CALL(rename, fromName, toDirNode->SuperVnode(), toName) 1315 } 1316 1317 1318 static status_t 1319 overlay_access(fs_volume *volume, fs_vnode *vnode, int mode) 1320 { 1321 OVERLAY_CALL(access, mode) 1322 } 1323 1324 1325 static status_t 1326 overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat) 1327 { 1328 OVERLAY_CALL(read_stat, stat) 1329 } 1330 1331 1332 static status_t 1333 overlay_write_stat(fs_volume *volume, fs_vnode *vnode, const struct stat *stat, 1334 uint32 statMask) 1335 { 1336 OVERLAY_CALL(write_stat, stat, statMask) 1337 } 1338 1339 1340 static status_t 1341 overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name, 1342 int openMode, int perms, void **cookie, ino_t *newVnodeID) 1343 { 1344 OVERLAY_CALL(create, name, openMode, perms, cookie, newVnodeID) 1345 } 1346 1347 1348 static status_t 1349 overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie) 1350 { 1351 OVERLAY_CALL(open, openMode, cookie) 1352 } 1353 1354 1355 static status_t 1356 overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie) 1357 { 1358 OVERLAY_CALL(close, cookie) 1359 } 1360 1361 1362 static status_t 1363 overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1364 { 1365 OVERLAY_CALL(free_cookie, cookie) 1366 } 1367 1368 1369 static status_t 1370 overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1371 void *buffer, size_t *length) 1372 { 1373 OVERLAY_CALL(read, cookie, pos, buffer, length) 1374 } 1375 1376 1377 static status_t 1378 overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1379 const void *buffer, size_t *length) 1380 { 1381 OVERLAY_CALL(write, cookie, pos, buffer, length) 1382 } 1383 1384 1385 static status_t 1386 overlay_create_dir(fs_volume *volume, fs_vnode *vnode, const char *name, 1387 int perms) 1388 { 1389 OVERLAY_CALL(create_dir, name, perms) 1390 } 1391 1392 1393 static status_t 1394 overlay_remove_dir(fs_volume *volume, fs_vnode *vnode, const char *name) 1395 { 1396 OVERLAY_CALL(remove_dir, name) 1397 } 1398 1399 1400 static status_t 1401 overlay_open_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1402 { 1403 OVERLAY_CALL(open_dir, cookie) 1404 } 1405 1406 1407 static status_t 1408 overlay_close_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1409 { 1410 OVERLAY_CALL(close_dir, cookie) 1411 } 1412 1413 1414 static status_t 1415 overlay_free_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1416 { 1417 OVERLAY_CALL(free_dir_cookie, cookie) 1418 } 1419 1420 1421 static status_t 1422 overlay_read_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1423 struct dirent *buffer, size_t bufferSize, uint32 *num) 1424 { 1425 TRACE("relaying op: read_dir\n"); 1426 OverlayInode *node = (OverlayInode *)vnode->private_node; 1427 fs_vnode *superVnode = node->SuperVnode(); 1428 if (superVnode->ops->read_dir != NULL) { 1429 status_t result = superVnode->ops->read_dir(volume->super_volume, 1430 superVnode, cookie, buffer, bufferSize, num); 1431 1432 // TODO: handle multiple records 1433 if (result == B_OK && *num == 1 && strcmp(buffer->d_name, 1434 ATTRIBUTE_OVERLAY_ATTRIBUTE_DIR_NAME) == 0) { 1435 // skip over the attribute directory 1436 return superVnode->ops->read_dir(volume->super_volume, superVnode, 1437 cookie, buffer, bufferSize, num); 1438 } 1439 1440 return result; 1441 } 1442 1443 return B_UNSUPPORTED; 1444 } 1445 1446 1447 static status_t 1448 overlay_rewind_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1449 { 1450 OVERLAY_CALL(rewind_dir, cookie) 1451 } 1452 1453 1454 static status_t 1455 overlay_open_attr_dir(fs_volume *volume, fs_vnode *vnode, void **cookie) 1456 { 1457 OverlayInode *node = (OverlayInode *)vnode->private_node; 1458 AttributeFile *attributeFile = NULL; 1459 status_t result = node->GetAttributeFile(&attributeFile); 1460 if (result != B_OK) 1461 return result; 1462 1463 attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)malloc( 1464 sizeof(attribute_dir_cookie)); 1465 if (dirCookie == NULL) 1466 return B_NO_MEMORY; 1467 1468 dirCookie->file = attributeFile; 1469 dirCookie->index = 0; 1470 *cookie = dirCookie; 1471 return B_OK; 1472 } 1473 1474 1475 static status_t 1476 overlay_close_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1477 { 1478 return B_OK; 1479 } 1480 1481 1482 static status_t 1483 overlay_free_attr_dir_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1484 { 1485 free(cookie); 1486 return B_OK; 1487 } 1488 1489 1490 static status_t 1491 overlay_read_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie, 1492 struct dirent *buffer, size_t bufferSize, uint32 *num) 1493 { 1494 attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; 1495 return dirCookie->file->ReadAttributeDir(buffer, bufferSize, num, 1496 &dirCookie->index); 1497 } 1498 1499 1500 static status_t 1501 overlay_rewind_attr_dir(fs_volume *volume, fs_vnode *vnode, void *cookie) 1502 { 1503 attribute_dir_cookie *dirCookie = (attribute_dir_cookie *)cookie; 1504 dirCookie->index = 0; 1505 return B_OK; 1506 } 1507 1508 1509 static status_t 1510 overlay_create_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 1511 uint32 type, int openMode, void **cookie) 1512 { 1513 OverlayInode *node = (OverlayInode *)vnode->private_node; 1514 AttributeFile *attributeFile = NULL; 1515 status_t result = node->GetAttributeFile(&attributeFile); 1516 if (result != B_OK) 1517 return result; 1518 1519 return attributeFile->CreateAttribute(name, type, openMode, 1520 (AttributeEntry **)cookie); 1521 } 1522 1523 1524 static status_t 1525 overlay_open_attr(fs_volume *volume, fs_vnode *vnode, const char *name, 1526 int openMode, void **cookie) 1527 { 1528 OverlayInode *node = (OverlayInode *)vnode->private_node; 1529 AttributeFile *attributeFile = NULL; 1530 status_t result = node->GetAttributeFile(&attributeFile); 1531 if (result != B_OK) 1532 return result; 1533 1534 return attributeFile->OpenAttribute(name, openMode, 1535 (AttributeEntry **)cookie); 1536 } 1537 1538 1539 static status_t 1540 overlay_close_attr(fs_volume *volume, fs_vnode *vnode, void *cookie) 1541 { 1542 return B_OK; 1543 } 1544 1545 1546 static status_t 1547 overlay_free_attr_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie) 1548 { 1549 return B_OK; 1550 } 1551 1552 1553 static status_t 1554 overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1555 void *buffer, size_t *length) 1556 { 1557 return ((AttributeEntry *)cookie)->Read(pos, buffer, length); 1558 } 1559 1560 1561 static status_t 1562 overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos, 1563 const void *buffer, size_t *length) 1564 { 1565 return ((AttributeEntry *)cookie)->Write(pos, buffer, length); 1566 } 1567 1568 1569 static status_t 1570 overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, 1571 struct stat *stat) 1572 { 1573 return ((AttributeEntry *)cookie)->ReadStat(stat); 1574 } 1575 1576 1577 static status_t 1578 overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie, 1579 const struct stat *stat, int statMask) 1580 { 1581 return ((AttributeEntry *)cookie)->WriteStat(stat, statMask); 1582 } 1583 1584 1585 static status_t 1586 overlay_rename_attr(fs_volume *volume, fs_vnode *vnode, 1587 const char *fromName, fs_vnode *toVnode, const char *toName) 1588 { 1589 OverlayInode *node = (OverlayInode *)vnode->private_node; 1590 AttributeFile *attributeFile = NULL; 1591 status_t result = node->GetAttributeFile(&attributeFile); 1592 if (result != B_OK) 1593 return B_OK; 1594 1595 AttributeFile *toAttributeFile = attributeFile; 1596 if (vnode->private_node != toVnode->private_node) { 1597 OverlayInode *toNode = (OverlayInode *)toVnode->private_node; 1598 result = toNode->GetAttributeFile(&toAttributeFile); 1599 if (result != B_OK) 1600 return result; 1601 } 1602 1603 AttributeEntry *entry = NULL; 1604 result = attributeFile->RemoveAttribute(fromName, &entry); 1605 if (result != B_OK) 1606 return result; 1607 1608 result = entry->SetName(toName); 1609 if (result != B_OK) { 1610 if (attributeFile->AddAttribute(entry) != B_OK) 1611 delete entry; 1612 return result; 1613 } 1614 1615 result = toAttributeFile->AddAttribute(entry); 1616 if (result != B_OK) { 1617 if (entry->SetName(fromName) != B_OK 1618 || attributeFile->AddAttribute(entry) != B_OK) 1619 delete entry; 1620 return result; 1621 } 1622 1623 return B_OK; 1624 } 1625 1626 1627 static status_t 1628 overlay_remove_attr(fs_volume *volume, fs_vnode *vnode, const char *name) 1629 { 1630 OverlayInode *node = (OverlayInode *)vnode->private_node; 1631 AttributeFile *attributeFile = NULL; 1632 status_t result = node->GetAttributeFile(&attributeFile); 1633 if (result != B_OK) 1634 return result; 1635 1636 return attributeFile->RemoveAttribute(name, NULL); 1637 } 1638 1639 1640 static status_t 1641 overlay_create_special_node(fs_volume *volume, fs_vnode *vnode, 1642 const char *name, fs_vnode *subVnode, mode_t mode, uint32 flags, 1643 fs_vnode *_superVnode, ino_t *nodeID) 1644 { 1645 OVERLAY_CALL(create_special_node, name, subVnode, mode, flags, _superVnode, 1646 nodeID) 1647 } 1648 1649 1650 static fs_vnode_ops sOverlayVnodeOps = { 1651 &overlay_lookup, 1652 &overlay_get_vnode_name, 1653 1654 &overlay_put_vnode, 1655 &overlay_remove_vnode, 1656 1657 &overlay_can_page, 1658 &overlay_read_pages, 1659 &overlay_write_pages, 1660 1661 &overlay_io, 1662 &overlay_cancel_io, 1663 1664 &overlay_get_file_map, 1665 1666 /* common */ 1667 &overlay_ioctl, 1668 &overlay_set_flags, 1669 &overlay_select, 1670 &overlay_deselect, 1671 &overlay_fsync, 1672 1673 &overlay_read_symlink, 1674 &overlay_create_symlink, 1675 &overlay_link, 1676 &overlay_unlink, 1677 &overlay_rename, 1678 1679 &overlay_access, 1680 &overlay_read_stat, 1681 &overlay_write_stat, 1682 NULL, // fs_preallocate 1683 1684 /* file */ 1685 &overlay_create, 1686 &overlay_open, 1687 &overlay_close, 1688 &overlay_free_cookie, 1689 &overlay_read, 1690 &overlay_write, 1691 1692 /* directory */ 1693 &overlay_create_dir, 1694 &overlay_remove_dir, 1695 &overlay_open_dir, 1696 &overlay_close_dir, 1697 &overlay_free_dir_cookie, 1698 &overlay_read_dir, 1699 &overlay_rewind_dir, 1700 1701 /* attribute directory operations */ 1702 &overlay_open_attr_dir, 1703 &overlay_close_attr_dir, 1704 &overlay_free_attr_dir_cookie, 1705 &overlay_read_attr_dir, 1706 &overlay_rewind_attr_dir, 1707 1708 /* attribute operations */ 1709 &overlay_create_attr, 1710 &overlay_open_attr, 1711 &overlay_close_attr, 1712 &overlay_free_attr_cookie, 1713 &overlay_read_attr, 1714 &overlay_write_attr, 1715 1716 &overlay_read_attr_stat, 1717 &overlay_write_attr_stat, 1718 &overlay_rename_attr, 1719 &overlay_remove_attr, 1720 1721 /* support for node and FS layers */ 1722 &overlay_create_special_node, 1723 &overlay_get_super_vnode 1724 }; 1725 1726 1727 // #pragma mark - volume ops 1728 1729 1730 static status_t 1731 overlay_unmount(fs_volume *volume) 1732 { 1733 TRACE_VOLUME("relaying volume op: unmount\n"); 1734 if (volume->super_volume != NULL 1735 && volume->super_volume->ops != NULL 1736 && volume->super_volume->ops->unmount != NULL) 1737 volume->super_volume->ops->unmount(volume->super_volume); 1738 1739 delete (OverlayVolume *)volume->private_volume; 1740 return B_OK; 1741 } 1742 1743 1744 static status_t 1745 overlay_read_fs_info(fs_volume *volume, struct fs_info *info) 1746 { 1747 TRACE_VOLUME("relaying volume op: read_fs_info\n"); 1748 status_t result = B_UNSUPPORTED; 1749 if (volume->super_volume->ops->read_fs_info != NULL) { 1750 result = volume->super_volume->ops->read_fs_info(volume->super_volume, 1751 info); 1752 if (result != B_OK) 1753 return result; 1754 1755 info->flags &= B_FS_SUPPORTS_MONITOR_CHILDREN; 1756 info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/; 1757 return B_OK; 1758 } 1759 1760 return B_UNSUPPORTED; 1761 } 1762 1763 1764 static status_t 1765 overlay_write_fs_info(fs_volume *volume, const struct fs_info *info, 1766 uint32 mask) 1767 { 1768 OVERLAY_VOLUME_CALL(write_fs_info, info, mask) 1769 return B_UNSUPPORTED; 1770 } 1771 1772 1773 static status_t 1774 overlay_sync(fs_volume *volume) 1775 { 1776 TRACE_VOLUME("relaying volume op: sync\n"); 1777 if (volume->super_volume->ops->sync != NULL) 1778 return volume->super_volume->ops->sync(volume->super_volume); 1779 return B_UNSUPPORTED; 1780 } 1781 1782 1783 static status_t 1784 overlay_get_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode, int *_type, 1785 uint32 *_flags, bool reenter) 1786 { 1787 TRACE_VOLUME("relaying volume op: get_vnode\n"); 1788 if (volume->super_volume->ops->get_vnode != NULL) { 1789 status_t status = volume->super_volume->ops->get_vnode( 1790 volume->super_volume, id, vnode, _type, _flags, reenter); 1791 if (status != B_OK) 1792 return status; 1793 1794 OverlayInode *node = new(std::nothrow) OverlayInode( 1795 (OverlayVolume *)volume->private_volume, vnode, id); 1796 if (node == NULL) { 1797 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 1798 return B_NO_MEMORY; 1799 } 1800 1801 status = node->InitCheck(); 1802 if (status != B_OK) { 1803 vnode->ops->put_vnode(volume->super_volume, vnode, reenter); 1804 delete node; 1805 return status; 1806 } 1807 1808 vnode->private_node = node; 1809 vnode->ops = &sOverlayVnodeOps; 1810 return B_OK; 1811 } 1812 1813 return B_UNSUPPORTED; 1814 } 1815 1816 1817 static status_t 1818 overlay_open_index_dir(fs_volume *volume, void **cookie) 1819 { 1820 OVERLAY_VOLUME_CALL(open_index_dir, cookie) 1821 return B_UNSUPPORTED; 1822 } 1823 1824 1825 static status_t 1826 overlay_close_index_dir(fs_volume *volume, void *cookie) 1827 { 1828 OVERLAY_VOLUME_CALL(close_index_dir, cookie) 1829 return B_UNSUPPORTED; 1830 } 1831 1832 1833 static status_t 1834 overlay_free_index_dir_cookie(fs_volume *volume, void *cookie) 1835 { 1836 OVERLAY_VOLUME_CALL(free_index_dir_cookie, cookie) 1837 return B_UNSUPPORTED; 1838 } 1839 1840 1841 static status_t 1842 overlay_read_index_dir(fs_volume *volume, void *cookie, struct dirent *buffer, 1843 size_t bufferSize, uint32 *_num) 1844 { 1845 OVERLAY_VOLUME_CALL(read_index_dir, cookie, buffer, bufferSize, _num) 1846 return B_UNSUPPORTED; 1847 } 1848 1849 1850 static status_t 1851 overlay_rewind_index_dir(fs_volume *volume, void *cookie) 1852 { 1853 OVERLAY_VOLUME_CALL(rewind_index_dir, cookie) 1854 return B_UNSUPPORTED; 1855 } 1856 1857 1858 static status_t 1859 overlay_create_index(fs_volume *volume, const char *name, uint32 type, 1860 uint32 flags) 1861 { 1862 OVERLAY_VOLUME_CALL(create_index, name, type, flags) 1863 return B_UNSUPPORTED; 1864 } 1865 1866 1867 static status_t 1868 overlay_remove_index(fs_volume *volume, const char *name) 1869 { 1870 OVERLAY_VOLUME_CALL(remove_index, name) 1871 return B_UNSUPPORTED; 1872 } 1873 1874 1875 static status_t 1876 overlay_read_index_stat(fs_volume *volume, const char *name, struct stat *stat) 1877 { 1878 OVERLAY_VOLUME_CALL(read_index_stat, name, stat) 1879 return B_UNSUPPORTED; 1880 } 1881 1882 1883 static status_t 1884 overlay_open_query(fs_volume *volume, const char *query, uint32 flags, 1885 port_id port, uint32 token, void **_cookie) 1886 { 1887 OVERLAY_VOLUME_CALL(open_query, query, flags, port, token, _cookie) 1888 return B_UNSUPPORTED; 1889 } 1890 1891 1892 static status_t 1893 overlay_close_query(fs_volume *volume, void *cookie) 1894 { 1895 OVERLAY_VOLUME_CALL(close_query, cookie) 1896 return B_UNSUPPORTED; 1897 } 1898 1899 1900 static status_t 1901 overlay_free_query_cookie(fs_volume *volume, void *cookie) 1902 { 1903 OVERLAY_VOLUME_CALL(free_query_cookie, cookie) 1904 return B_UNSUPPORTED; 1905 } 1906 1907 1908 static status_t 1909 overlay_read_query(fs_volume *volume, void *cookie, struct dirent *buffer, 1910 size_t bufferSize, uint32 *_num) 1911 { 1912 OVERLAY_VOLUME_CALL(read_query, cookie, buffer, bufferSize, _num) 1913 return B_UNSUPPORTED; 1914 } 1915 1916 1917 static status_t 1918 overlay_rewind_query(fs_volume *volume, void *cookie) 1919 { 1920 OVERLAY_VOLUME_CALL(rewind_query, cookie) 1921 return B_UNSUPPORTED; 1922 } 1923 1924 1925 static status_t 1926 overlay_all_layers_mounted(fs_volume *volume) 1927 { 1928 return B_OK; 1929 } 1930 1931 1932 static status_t 1933 overlay_create_sub_vnode(fs_volume *volume, ino_t id, fs_vnode *vnode) 1934 { 1935 OverlayInode *node = new(std::nothrow) OverlayInode( 1936 (OverlayVolume *)volume->private_volume, vnode, id); 1937 if (node == NULL) 1938 return B_NO_MEMORY; 1939 1940 status_t status = node->InitCheck(); 1941 if (status != B_OK) { 1942 delete node; 1943 return status; 1944 } 1945 1946 vnode->private_node = node; 1947 vnode->ops = &sOverlayVnodeOps; 1948 return B_OK; 1949 } 1950 1951 1952 static status_t 1953 overlay_delete_sub_vnode(fs_volume *volume, fs_vnode *vnode) 1954 { 1955 delete (OverlayInode *)vnode->private_node; 1956 return B_OK; 1957 } 1958 1959 1960 static fs_volume_ops sOverlayVolumeOps = { 1961 &overlay_unmount, 1962 1963 &overlay_read_fs_info, 1964 &overlay_write_fs_info, 1965 &overlay_sync, 1966 1967 &overlay_get_vnode, 1968 &overlay_open_index_dir, 1969 &overlay_close_index_dir, 1970 &overlay_free_index_dir_cookie, 1971 &overlay_read_index_dir, 1972 &overlay_rewind_index_dir, 1973 1974 &overlay_create_index, 1975 &overlay_remove_index, 1976 &overlay_read_index_stat, 1977 1978 &overlay_open_query, 1979 &overlay_close_query, 1980 &overlay_free_query_cookie, 1981 &overlay_read_query, 1982 &overlay_rewind_query, 1983 1984 &overlay_all_layers_mounted, 1985 &overlay_create_sub_vnode, 1986 &overlay_delete_sub_vnode 1987 }; 1988 1989 1990 // #pragma mark - filesystem module 1991 1992 1993 static status_t 1994 overlay_mount(fs_volume *volume, const char *device, uint32 flags, 1995 const char *args, ino_t *rootID) 1996 { 1997 TRACE_VOLUME("mounting attribute overlay\n"); 1998 volume->private_volume = new(std::nothrow) OverlayVolume(volume); 1999 if (volume->private_volume == NULL) 2000 return B_NO_MEMORY; 2001 2002 volume->ops = &sOverlayVolumeOps; 2003 return B_OK; 2004 } 2005 2006 2007 static status_t 2008 overlay_std_ops(int32 op, ...) 2009 { 2010 switch (op) { 2011 case B_MODULE_INIT: 2012 case B_MODULE_UNINIT: 2013 return B_OK; 2014 default: 2015 return B_ERROR; 2016 } 2017 } 2018 2019 2020 static file_system_module_info sOverlayFileSystem = { 2021 { 2022 "file_systems/attribute_overlay" B_CURRENT_FS_API_VERSION, 2023 0, 2024 overlay_std_ops, 2025 }, 2026 2027 "attribute_overlay", // short_name 2028 "Attribute Overlay File System", // pretty_name 2029 0, // DDM flags 2030 2031 // scanning 2032 NULL, // identify_partition 2033 NULL, // scan_partition 2034 NULL, // free_identify_partition_cookie 2035 NULL, // free_partition_content_cookie 2036 2037 // general operations 2038 &overlay_mount, 2039 2040 // capability querying 2041 NULL, // get_supported_operations 2042 2043 NULL, // validate_resize 2044 NULL, // validate_move 2045 NULL, // validate_set_content_name 2046 NULL, // validate_set_content_parameters 2047 NULL, // validate_initialize 2048 2049 // shadow partition modification 2050 NULL, // shadow_changed 2051 2052 // writing 2053 NULL, // defragment 2054 NULL, // repair 2055 NULL, // resize 2056 NULL, // move 2057 NULL, // set_content_name 2058 NULL, // set_content_parameters 2059 NULL // initialize 2060 }; 2061 2062 } // namespace attribute_overlay 2063 2064 using namespace attribute_overlay; 2065 2066 module_info *modules[] = { 2067 (module_info *)&sOverlayFileSystem, 2068 NULL, 2069 }; 2070