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