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