1 /* 2 * Copyright 2017, Chế Vũ Gia Hy, cvghy116@gmail.com. 3 * Copyright 2011, Jérôme Duval, korli@users.berlios.de. 4 * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. 5 * This file may be used under the terms of the MIT License. 6 */ 7 8 9 #include "Attribute.h" 10 #include "AttributeIterator.h" 11 #include "btrfs.h" 12 #include "DirectoryIterator.h" 13 #include "Inode.h" 14 #include "Utility.h" 15 16 17 //#define TRACE_BTRFS 18 #ifdef TRACE_BTRFS 19 # define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x) 20 #else 21 # define TRACE(x...) ; 22 #endif 23 #define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x) 24 25 26 #define BTRFS_IO_SIZE 65536 27 28 29 struct identify_cookie { 30 btrfs_super_block super_block; 31 }; 32 33 34 //! btrfs_io() callback hook 35 static status_t 36 iterative_io_get_vecs_hook(void* cookie, io_request* request, off_t offset, 37 size_t size, struct file_io_vec* vecs, size_t* _count) 38 { 39 Inode* inode = (Inode*)cookie; 40 41 return file_map_translate(inode->Map(), offset, size, vecs, _count, 42 inode->GetVolume()->BlockSize()); 43 } 44 45 46 //! btrfs_io() callback hook 47 static status_t 48 iterative_io_finished_hook(void* cookie, io_request* request, status_t status, 49 bool partialTransfer, size_t bytesTransferred) 50 { 51 Inode* inode = (Inode*)cookie; 52 rw_lock_read_unlock(inode->Lock()); 53 return B_OK; 54 } 55 56 57 // #pragma mark - Scanning 58 59 60 static float 61 btrfs_identify_partition(int fd, partition_data* partition, void** _cookie) 62 { 63 btrfs_super_block superBlock; 64 status_t status = Volume::Identify(fd, &superBlock); 65 if (status != B_OK) 66 return -1; 67 68 identify_cookie* cookie = new identify_cookie; 69 memcpy(&cookie->super_block, &superBlock, sizeof(btrfs_super_block)); 70 71 *_cookie = cookie; 72 return 0.8f; 73 } 74 75 76 static status_t 77 btrfs_scan_partition(int fd, partition_data* partition, void* _cookie) 78 { 79 identify_cookie* cookie = (identify_cookie*)_cookie; 80 81 partition->status = B_PARTITION_VALID; 82 partition->flags |= B_PARTITION_FILE_SYSTEM; 83 partition->content_size = cookie->super_block.TotalSize(); 84 partition->block_size = cookie->super_block.BlockSize(); 85 partition->content_name = strdup(cookie->super_block.label); 86 if (partition->content_name == NULL) 87 return B_NO_MEMORY; 88 89 return B_OK; 90 } 91 92 93 static void 94 btrfs_free_identify_partition_cookie(partition_data* partition, void* _cookie) 95 { 96 delete (identify_cookie*)_cookie; 97 } 98 99 100 // #pragma mark - 101 102 103 static status_t 104 btrfs_mount(fs_volume* _volume, const char* device, uint32 flags, 105 const char* args, ino_t* _rootID) 106 { 107 Volume* volume = new(std::nothrow) Volume(_volume); 108 if (volume == NULL) 109 return B_NO_MEMORY; 110 111 // TODO: this is a bit hacky: we can't use publish_vnode() to publish 112 // the root node, or else its file cache cannot be created (we could 113 // create it later, though). Therefore we're using get_vnode() in Mount(), 114 // but that requires us to export our volume data before calling it. 115 _volume->private_volume = volume; 116 _volume->ops = &gBtrfsVolumeOps; 117 118 status_t status = volume->Mount(device, flags); 119 if (status != B_OK) { 120 ERROR("Failed mounting the volume. Error: %s\n", strerror(status)); 121 delete volume; 122 return status; 123 } 124 125 *_rootID = volume->RootNode()->ID(); 126 return B_OK; 127 } 128 129 130 static status_t 131 btrfs_unmount(fs_volume* _volume) 132 { 133 Volume* volume = (Volume*)_volume->private_volume; 134 135 status_t status = volume->Unmount(); 136 delete volume; 137 138 return status; 139 } 140 141 142 static status_t 143 btrfs_read_fs_info(fs_volume* _volume, struct fs_info* info) 144 { 145 Volume* volume = (Volume*)_volume->private_volume; 146 147 // File system flags 148 info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_ATTR 149 | (volume->IsReadOnly() ? B_FS_IS_READONLY : 0); 150 info->io_size = BTRFS_IO_SIZE; 151 info->block_size = volume->BlockSize(); 152 info->total_blocks = volume->SuperBlock().TotalSize() / volume->BlockSize(); 153 info->free_blocks = 0; //volume->NumFreeBlocks(); 154 155 // Volume name 156 strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name)); 157 158 // File system name 159 strlcpy(info->fsh_name, "btrfs", sizeof(info->fsh_name)); 160 161 return B_OK; 162 } 163 164 165 // #pragma mark - 166 167 168 static status_t 169 btrfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type, 170 uint32* _flags, bool reenter) 171 { 172 Volume* volume = (Volume*)_volume->private_volume; 173 174 Inode* inode = new(std::nothrow) Inode(volume, id); 175 if (inode == NULL) 176 return B_NO_MEMORY; 177 178 status_t status = inode->InitCheck(); 179 if (status != B_OK) { 180 delete inode; 181 ERROR("get_vnode: InitCheck() failed. Error: %s\n", strerror(status)); 182 return status; 183 } 184 185 _node->private_node = inode; 186 _node->ops = &gBtrfsVnodeOps; 187 *_type = inode->Mode(); 188 *_flags = 0; 189 190 return B_OK; 191 } 192 193 194 static status_t 195 btrfs_put_vnode(fs_volume* _volume, fs_vnode* _node, bool reenter) 196 { 197 delete (Inode*)_node->private_node; 198 return B_OK; 199 } 200 201 202 static bool 203 btrfs_can_page(fs_volume* _volume, fs_vnode* _node, void* _cookie) 204 { 205 return true; 206 } 207 208 209 static status_t 210 btrfs_read_pages(fs_volume* _volume, fs_vnode* _node, void* _cookie, 211 off_t pos, const iovec* vecs, size_t count, size_t* _numBytes) 212 { 213 Volume* volume = (Volume*)_volume->private_volume; 214 Inode* inode = (Inode*)_node->private_node; 215 216 if (inode->FileCache() == NULL) 217 return B_BAD_VALUE; 218 219 rw_lock_read_lock(inode->Lock()); 220 221 uint32 vecIndex = 0; 222 size_t vecOffset = 0; 223 size_t bytesLeft = *_numBytes; 224 status_t status; 225 226 while (true) { 227 file_io_vec fileVecs[8]; 228 size_t fileVecCount = 8; 229 230 status = file_map_translate(inode->Map(), pos, bytesLeft, fileVecs, 231 &fileVecCount, 0); 232 if (status != B_OK && status != B_BUFFER_OVERFLOW) 233 break; 234 235 bool bufferOverflow = status == B_BUFFER_OVERFLOW; 236 237 size_t bytes = bytesLeft; 238 status = read_file_io_vec_pages(volume->Device(), fileVecs, 239 fileVecCount, vecs, count, &vecIndex, &vecOffset, &bytes); 240 if (status != B_OK || !bufferOverflow) 241 break; 242 243 pos += bytes; 244 bytesLeft -= bytes; 245 } 246 247 rw_lock_read_unlock(inode->Lock()); 248 249 return status; 250 } 251 252 253 static status_t 254 btrfs_io(fs_volume* _volume, fs_vnode* _node, void* _cookie, io_request* request) 255 { 256 Volume* volume = (Volume*)_volume->private_volume; 257 Inode* inode = (Inode*)_node->private_node; 258 259 #ifndef FS_SHELL 260 if (io_request_is_write(request) && volume->IsReadOnly()) { 261 notify_io_request(request, B_READ_ONLY_DEVICE); 262 return B_READ_ONLY_DEVICE; 263 } 264 #endif 265 266 if (inode->FileCache() == NULL) { 267 #ifndef FS_SHELL 268 notify_io_request(request, B_BAD_VALUE); 269 #endif 270 return B_BAD_VALUE; 271 } 272 273 // We lock the node here and will unlock it in the "finished" hook. 274 rw_lock_read_lock(inode->Lock()); 275 276 return do_iterative_fd_io(volume->Device(), request, 277 iterative_io_get_vecs_hook, iterative_io_finished_hook, inode); 278 } 279 280 281 static status_t 282 btrfs_get_file_map(fs_volume* _volume, fs_vnode* _node, off_t offset, 283 size_t size, struct file_io_vec* vecs, size_t* _count) 284 { 285 TRACE("btrfs_get_file_map()\n"); 286 Inode* inode = (Inode*)_node->private_node; 287 size_t index = 0, max = *_count; 288 289 while (true) { 290 off_t blockOffset; 291 off_t blockLength; 292 status_t status = inode->FindBlock(offset, blockOffset, &blockLength); 293 if (status != B_OK) 294 return status; 295 296 if (index > 0 && (vecs[index - 1].offset 297 == blockOffset - vecs[index - 1].length)) { 298 vecs[index - 1].length += blockLength; 299 } else { 300 if (index >= max) { 301 // we're out of file_io_vecs; let's bail out 302 *_count = index; 303 return B_BUFFER_OVERFLOW; 304 } 305 306 vecs[index].offset = blockOffset; 307 vecs[index].length = blockLength; 308 index++; 309 } 310 311 offset += blockLength; 312 size -= blockLength; 313 314 if ((off_t)size <= vecs[index - 1].length || offset >= inode->Size()) { 315 // We're done! 316 *_count = index; 317 TRACE("btrfs_get_file_map for inode %" B_PRIdINO "\n", inode->ID()); 318 return B_OK; 319 } 320 } 321 322 // can never get here 323 return B_ERROR; 324 } 325 326 327 // #pragma mark - 328 329 330 static status_t 331 btrfs_lookup(fs_volume* _volume, fs_vnode* _directory, const char* name, 332 ino_t* _vnodeID) 333 { 334 TRACE("btrfs_lookup: name address: %p (%s)\n", name, name); 335 Volume* volume = (Volume*)_volume->private_volume; 336 Inode* directory = (Inode*)_directory->private_node; 337 338 // check access permissions 339 status_t status = directory->CheckPermissions(X_OK); 340 if (status < B_OK) 341 return status; 342 343 status = DirectoryIterator(directory).Lookup(name, strlen(name), _vnodeID); 344 if (status != B_OK) 345 return status; 346 347 return get_vnode(volume->FSVolume(), *_vnodeID, NULL); 348 } 349 350 351 static status_t 352 btrfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd, 353 void* buffer, size_t bufferLength) 354 { 355 TRACE("ioctl: %" B_PRIu32 "\n", cmd); 356 357 /*Volume* volume = (Volume*)_volume->private_volume;*/ 358 return B_DEV_INVALID_IOCTL; 359 } 360 361 362 static status_t 363 btrfs_read_stat(fs_volume* _volume, fs_vnode* _node, struct stat* stat) 364 { 365 Inode* inode = (Inode*)_node->private_node; 366 367 stat->st_dev = inode->GetVolume()->ID(); 368 stat->st_ino = inode->ID(); 369 stat->st_nlink = 1; 370 stat->st_blksize = BTRFS_IO_SIZE; 371 372 stat->st_uid = inode->UserID(); 373 stat->st_gid = inode->GroupID(); 374 stat->st_mode = inode->Mode(); 375 stat->st_type = 0; 376 377 inode->GetAccessTime(stat->st_atim); 378 inode->GetModificationTime(stat->st_mtim); 379 inode->GetChangeTime(stat->st_ctim); 380 inode->GetCreationTime(stat->st_crtim); 381 382 stat->st_size = inode->Size(); 383 stat->st_blocks = (inode->Size() + 511) / 512; 384 385 return B_OK; 386 } 387 388 389 static status_t 390 btrfs_open(fs_volume* /*_volume*/, fs_vnode* _node, int openMode, 391 void** _cookie) 392 { 393 Inode* inode = (Inode*)_node->private_node; 394 395 // opening a directory read-only is allowed, although you can't read 396 // any data from it. 397 if (inode->IsDirectory() && (openMode & O_RWMASK) != 0) 398 return B_IS_A_DIRECTORY; 399 400 status_t status = inode->CheckPermissions(open_mode_to_access(openMode) 401 | (openMode & O_TRUNC ? W_OK : 0)); 402 if (status != B_OK) 403 return status; 404 405 // Prepare the cookie 406 file_cookie* cookie = new(std::nothrow) file_cookie; 407 if (cookie == NULL) 408 return B_NO_MEMORY; 409 ObjectDeleter<file_cookie> cookieDeleter(cookie); 410 411 cookie->open_mode = openMode & BTRFS_OPEN_MODE_USER_MASK; 412 cookie->last_size = inode->Size(); 413 cookie->last_notification = system_time(); 414 415 if ((openMode & O_NOCACHE) != 0 && inode->FileCache() != NULL) { 416 // Disable the file cache, if requested? 417 status = file_cache_disable(inode->FileCache()); 418 if (status != B_OK) 419 return status; 420 } 421 422 cookieDeleter.Detach(); 423 *_cookie = cookie; 424 425 return B_OK; 426 } 427 428 429 static status_t 430 btrfs_read(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos, 431 void* buffer, size_t* _length) 432 { 433 Inode* inode = (Inode*)_node->private_node; 434 435 if (!inode->IsFile()) { 436 *_length = 0; 437 return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE; 438 } 439 440 return inode->ReadAt(pos, (uint8*)buffer, _length); 441 } 442 443 444 static status_t 445 btrfs_close(fs_volume* _volume, fs_vnode* _node, void* _cookie) 446 { 447 return B_OK; 448 } 449 450 451 static status_t 452 btrfs_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) 453 { 454 file_cookie* cookie = (file_cookie*)_cookie; 455 Volume* volume = (Volume*)_volume->private_volume; 456 Inode* inode = (Inode*)_node->private_node; 457 458 if (inode->Size() != cookie->last_size) 459 notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE); 460 461 delete cookie; 462 return B_OK; 463 } 464 465 466 static status_t 467 btrfs_access(fs_volume* _volume, fs_vnode* _node, int accessMode) 468 { 469 Inode* inode = (Inode*)_node->private_node; 470 return inode->CheckPermissions(accessMode); 471 } 472 473 474 static status_t 475 btrfs_read_link(fs_volume* _volume, fs_vnode* _node, char* buffer, 476 size_t* _bufferSize) 477 { 478 Inode* inode = (Inode*)_node->private_node; 479 return inode->ReadAt(0, (uint8*)buffer, _bufferSize); 480 } 481 482 483 // #pragma mark - Directory functions 484 485 486 static status_t 487 btrfs_create_dir(fs_volume* _volume, fs_vnode* _directory, const char* name, 488 int mode) 489 { 490 Volume* volume = (Volume*)_volume->private_volume; 491 Inode* directory = (Inode*)_directory->private_node; 492 BTree::Path path(volume->FSTree()); 493 494 if (volume->IsReadOnly()) 495 return B_READ_ONLY_DEVICE; 496 497 if (!directory->IsDirectory()) 498 return B_NOT_A_DIRECTORY; 499 500 status_t status = directory->CheckPermissions(W_OK); 501 if (status < B_OK) 502 return status; 503 504 Transaction transaction(volume); 505 ino_t id = volume->GetNextInodeID(); 506 mode = S_DIRECTORY | (mode & S_IUMSK); 507 Inode* inode = Inode::Create(transaction, id, directory, mode); 508 if (inode == NULL) 509 return B_NO_MEMORY; 510 511 status = inode->Insert(transaction, &path); 512 if (status != B_OK) 513 return status; 514 515 status = inode->MakeReference(transaction, &path, directory, name, mode); 516 if (status != B_OK) 517 return status; 518 519 put_vnode(volume->FSVolume(), inode->ID()); 520 entry_cache_add(volume->ID(), directory->ID(), name, inode->ID()); 521 522 status = transaction.Done(); 523 if (status == B_OK) 524 notify_entry_created(volume->ID(), directory->ID(), name, inode->ID()); 525 else 526 entry_cache_remove(volume->ID(), directory->ID(), name); 527 528 return status; 529 } 530 531 532 static status_t 533 btrfs_remove_dir(fs_volume* _volume, fs_vnode* _directory, const char* name) 534 { 535 Volume* volume = (Volume*)_volume->private_volume; 536 Inode* directory = (Inode*)_directory->private_node; 537 538 Transaction transaction(volume); 539 BTree::Path path(volume->FSTree()); 540 541 ino_t id; 542 status_t status = DirectoryIterator(directory).Lookup(name, strlen(name), 543 &id); 544 if (status != B_OK) 545 return status; 546 547 Inode inode(volume, id); 548 status = inode.InitCheck(); 549 if (status != B_OK) 550 return status; 551 552 status = inode.Remove(transaction, &path); 553 if (status != B_OK) 554 return status; 555 status = inode.Dereference(transaction, &path, directory->ID(), name); 556 if (status != B_OK) 557 return status; 558 559 entry_cache_remove(volume->ID(), directory->ID(), name); 560 entry_cache_remove(volume->ID(), id, ".."); 561 562 status = transaction.Done(); 563 if (status == B_OK) 564 notify_entry_removed(volume->ID(), directory->ID(), name, id); 565 else { 566 entry_cache_add(volume->ID(), directory->ID(), name, id); 567 entry_cache_add(volume->ID(), id, "..", id); 568 } 569 570 return status; 571 } 572 573 574 static status_t 575 btrfs_open_dir(fs_volume* /*_volume*/, fs_vnode* _node, void** _cookie) 576 { 577 Inode* inode = (Inode*)_node->private_node; 578 status_t status = inode->CheckPermissions(R_OK); 579 if (status < B_OK) 580 return status; 581 582 if (!inode->IsDirectory()) 583 return B_NOT_A_DIRECTORY; 584 585 DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode); 586 if (iterator == NULL || iterator->InitCheck() != B_OK) { 587 delete iterator; 588 return B_NO_MEMORY; 589 } 590 591 *_cookie = iterator; 592 return B_OK; 593 } 594 595 596 static status_t 597 btrfs_read_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie, 598 struct dirent* dirent, size_t bufferSize, uint32* _num) 599 { 600 DirectoryIterator* iterator = (DirectoryIterator*)_cookie; 601 Volume* volume = (Volume*)_volume->private_volume; 602 603 uint32 maxCount = *_num; 604 uint32 count = 0; 605 606 while (count < maxCount && bufferSize > sizeof(struct dirent)) { 607 ino_t id; 608 size_t length = bufferSize - sizeof(struct dirent) + 1; 609 610 status_t status = iterator->GetNext(dirent->d_name, &length, 611 &id); 612 613 if (status == B_ENTRY_NOT_FOUND) 614 break; 615 616 if (status == B_BUFFER_OVERFLOW) { 617 // the remaining name buffer length was too small 618 if (count == 0) 619 return B_BUFFER_OVERFLOW; 620 break; 621 } 622 623 if (status != B_OK) 624 return status; 625 626 dirent->d_dev = volume->ID(); 627 dirent->d_ino = id; 628 dirent->d_reclen = sizeof(struct dirent) + length; 629 630 bufferSize -= dirent->d_reclen; 631 dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen); 632 count++; 633 } 634 635 *_num = count; 636 return B_OK; 637 } 638 639 640 static status_t 641 btrfs_rewind_dir(fs_volume* /*_volume*/, fs_vnode* /*node*/, void* _cookie) 642 { 643 DirectoryIterator* iterator = (DirectoryIterator*)_cookie; 644 645 return iterator->Rewind(); 646 } 647 648 649 static status_t 650 btrfs_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void * /*_cookie*/) 651 { 652 return B_OK; 653 } 654 655 656 static status_t 657 btrfs_free_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) 658 { 659 delete (DirectoryIterator*)_cookie; 660 return B_OK; 661 } 662 663 664 static status_t 665 btrfs_open_attr_dir(fs_volume* _volume, fs_vnode* _node, void** _cookie) 666 { 667 Inode* inode = (Inode*)_node->private_node; 668 TRACE("%s()\n", __FUNCTION__); 669 670 // on directories too ? 671 if (!inode->IsFile()) 672 return EINVAL; 673 674 AttributeIterator* iterator = new(std::nothrow) AttributeIterator(inode); 675 if (iterator == NULL || iterator->InitCheck() != B_OK) { 676 delete iterator; 677 return B_NO_MEMORY; 678 } 679 680 *_cookie = iterator; 681 return B_OK; 682 } 683 684 685 static status_t 686 btrfs_close_attr_dir(fs_volume* _volume, fs_vnode* _node, void* cookie) 687 { 688 TRACE("%s()\n", __FUNCTION__); 689 return B_OK; 690 } 691 692 693 static status_t 694 btrfs_free_attr_dir_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie) 695 { 696 TRACE("%s()\n", __FUNCTION__); 697 delete (AttributeIterator*)_cookie; 698 return B_OK; 699 } 700 701 702 static status_t 703 btrfs_read_attr_dir(fs_volume* _volume, fs_vnode* _node, 704 void* _cookie, struct dirent* dirent, size_t bufferSize, 705 uint32* _num) 706 { 707 TRACE("%s()\n", __FUNCTION__); 708 AttributeIterator* iterator = (AttributeIterator*)_cookie; 709 710 size_t length = bufferSize; 711 status_t status = iterator->GetNext(dirent->d_name, &length); 712 if (status == B_ENTRY_NOT_FOUND) { 713 *_num = 0; 714 return B_OK; 715 } 716 717 if (status != B_OK) 718 return status; 719 720 Volume* volume = (Volume*)_volume->private_volume; 721 dirent->d_dev = volume->ID(); 722 dirent->d_reclen = sizeof(struct dirent) + length; 723 *_num = 1; 724 725 return B_OK; 726 } 727 728 729 static status_t 730 btrfs_rewind_attr_dir(fs_volume* _volume, fs_vnode* _node, void* _cookie) 731 { 732 AttributeIterator* iterator = (AttributeIterator*)_cookie; 733 return iterator->Rewind(); 734 } 735 736 737 /* attribute operations */ 738 static status_t 739 btrfs_create_attr(fs_volume* _volume, fs_vnode* _node, 740 const char* name, uint32 type, int openMode, void** _cookie) 741 { 742 return EROFS; 743 } 744 745 746 static status_t 747 btrfs_open_attr(fs_volume* _volume, fs_vnode* _node, const char* name, 748 int openMode, void** _cookie) 749 { 750 TRACE("%s()\n", __FUNCTION__); 751 752 Inode* inode = (Inode*)_node->private_node; 753 Attribute attribute(inode); 754 755 return attribute.Open(name, openMode, (attr_cookie**)_cookie); 756 } 757 758 759 static status_t 760 btrfs_close_attr(fs_volume* _volume, fs_vnode* _node, 761 void* cookie) 762 { 763 return B_OK; 764 } 765 766 767 static status_t 768 btrfs_free_attr_cookie(fs_volume* _volume, fs_vnode* _node, 769 void* cookie) 770 { 771 delete (attr_cookie*)cookie; 772 return B_OK; 773 } 774 775 776 static status_t 777 btrfs_read_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie, 778 off_t pos, void* buffer, size_t* _length) 779 { 780 TRACE("%s()\n", __FUNCTION__); 781 782 attr_cookie* cookie = (attr_cookie*)_cookie; 783 Inode* inode = (Inode*)_node->private_node; 784 785 Attribute attribute(inode, cookie); 786 787 return attribute.Read(cookie, pos, (uint8*)buffer, _length); 788 } 789 790 791 static status_t 792 btrfs_write_attr(fs_volume* _volume, fs_vnode* _node, void* cookie, 793 off_t pos, const void* buffer, size_t* length) 794 { 795 return EROFS; 796 } 797 798 799 static status_t 800 btrfs_read_attr_stat(fs_volume* _volume, fs_vnode* _node, 801 void* _cookie, struct stat* stat) 802 { 803 attr_cookie* cookie = (attr_cookie*)_cookie; 804 Inode* inode = (Inode*)_node->private_node; 805 806 Attribute attribute(inode, cookie); 807 808 return attribute.Stat(*stat); 809 } 810 811 812 static status_t 813 btrfs_write_attr_stat(fs_volume* _volume, fs_vnode* _node, 814 void* cookie, const struct stat* stat, int statMask) 815 { 816 return EROFS; 817 } 818 819 820 static status_t 821 btrfs_rename_attr(fs_volume* _volume, fs_vnode* fromVnode, 822 const char* fromName, fs_vnode* toVnode, const char* toName) 823 { 824 return EROFS; 825 } 826 827 828 static status_t 829 btrfs_remove_attr(fs_volume* _volume, fs_vnode* vnode, 830 const char* name) 831 { 832 return EROFS; 833 } 834 835 // #pragma mark - 836 837 838 static status_t 839 btrfs_std_ops(int32 op, ...) 840 { 841 switch (op) { 842 case B_MODULE_INIT: 843 return B_OK; 844 case B_MODULE_UNINIT: 845 return B_OK; 846 847 default: 848 return B_ERROR; 849 } 850 } 851 852 853 fs_volume_ops gBtrfsVolumeOps = { 854 &btrfs_unmount, 855 &btrfs_read_fs_info, 856 NULL, // write_fs_info() 857 NULL, // fs_sync, 858 &btrfs_get_vnode, 859 }; 860 861 862 fs_vnode_ops gBtrfsVnodeOps = { 863 /* vnode operations */ 864 &btrfs_lookup, 865 NULL, 866 &btrfs_put_vnode, 867 NULL, // btrfs_remove_vnode, 868 869 /* VM file access */ 870 &btrfs_can_page, 871 &btrfs_read_pages, 872 NULL, // btrfs_write_pages, 873 874 NULL, // io() 875 NULL, // cancel_io() 876 877 &btrfs_get_file_map, 878 879 &btrfs_ioctl, 880 NULL, 881 NULL, // fs_select 882 NULL, // fs_deselect 883 NULL, // fs_fsync, 884 885 &btrfs_read_link, 886 NULL, // fs_create_symlink, 887 888 NULL, // fs_link, 889 NULL, // fs_unlink, 890 NULL, // fs_rename, 891 892 &btrfs_access, 893 &btrfs_read_stat, 894 NULL, // fs_write_stat, 895 NULL, // fs_preallocate 896 897 /* file operations */ 898 NULL, // fs_create, 899 &btrfs_open, 900 &btrfs_close, 901 &btrfs_free_cookie, 902 &btrfs_read, 903 NULL, // fs_write, 904 905 /* directory operations */ 906 &btrfs_create_dir, 907 &btrfs_remove_dir, 908 &btrfs_open_dir, 909 &btrfs_close_dir, 910 &btrfs_free_dir_cookie, 911 &btrfs_read_dir, 912 &btrfs_rewind_dir, 913 914 /* attribute directory operations */ 915 &btrfs_open_attr_dir, 916 &btrfs_close_attr_dir, 917 &btrfs_free_attr_dir_cookie, 918 &btrfs_read_attr_dir, 919 &btrfs_rewind_attr_dir, 920 921 /* attribute operations */ 922 &btrfs_create_attr, 923 &btrfs_open_attr, 924 &btrfs_close_attr, 925 &btrfs_free_attr_cookie, 926 &btrfs_read_attr, 927 &btrfs_write_attr, 928 &btrfs_read_attr_stat, 929 &btrfs_write_attr_stat, 930 &btrfs_rename_attr, 931 &btrfs_remove_attr, 932 }; 933 934 935 static file_system_module_info sBtrfsFileSystem = { 936 { 937 "file_systems/btrfs" B_CURRENT_FS_API_VERSION, 938 0, 939 btrfs_std_ops, 940 }, 941 942 "btrfs", // short_name 943 "btrfs File System", // pretty_name 944 0, // DDM flags 945 946 // scanning 947 btrfs_identify_partition, 948 btrfs_scan_partition, 949 btrfs_free_identify_partition_cookie, 950 NULL, // free_partition_content_cookie() 951 952 &btrfs_mount, 953 954 955 /* capability querying operations */ 956 NULL, 957 958 NULL, // validate_resize 959 NULL, // validate_move 960 NULL, // validate_set_content_name 961 NULL, // validate_set_content_parameters 962 NULL, // validate_initialize, 963 964 /* shadow partition modification */ 965 NULL, // shadow_changed 966 967 /* writing */ 968 NULL, // defragment 969 NULL, // repair 970 NULL, // resize 971 NULL, // move 972 NULL, // set_content_name 973 NULL, // set_content_parameters 974 NULL, // initialize 975 NULL // unitialize 976 }; 977 978 979 module_info* modules[] = { 980 (module_info*)&sBtrfsFileSystem, 981 NULL, 982 }; 983