1 /* 2 * Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 8 #include "system_dependencies.h" 9 #include "Directory.h" 10 #include "Inode.h" 11 #include "Utility.h" 12 #include "Volume.h" 13 14 15 #define XFS_IO_SIZE 65536 16 17 struct identify_cookie 18 { 19 /* super_block_struct super_block; 20 * No structure yet implemented. 21 */ 22 int cookie; 23 }; 24 25 26 //! xfs_io() callback hook 27 static status_t 28 iterative_io_get_vecs_hook(void *cookie, io_request *request, off_t offset, 29 size_t size, struct file_io_vec *vecs, size_t *_count) 30 { 31 return B_NOT_SUPPORTED; 32 } 33 34 35 //! xfs_io() callback hook 36 static status_t 37 iterative_io_finished_hook(void *cookie, io_request *request, status_t status, 38 bool partialTransfer, size_t bytesTransferred) 39 { 40 return B_NOT_SUPPORTED; 41 } 42 43 44 // #pragma mark - Scanning 45 46 47 static float 48 xfs_identify_partition(int fd, partition_data *partition, void **_cookie) 49 { 50 return B_NOT_SUPPORTED; 51 } 52 53 54 static status_t 55 xfs_scan_partition(int fd, partition_data *partition, void *_cookie) 56 { 57 return B_NOT_SUPPORTED; 58 } 59 60 61 static void 62 xfs_free_identify_partition_cookie(partition_data *partition, void *_cookie) 63 { 64 dprintf("Unsupported in XFS currently.\n"); 65 return; 66 } 67 68 69 // #pragma mark - 70 71 72 static status_t 73 xfs_mount(fs_volume *_volume, const char *device, uint32 flags, 74 const char *args, ino_t *_rootID) 75 { 76 TRACE("xfs_mount(): Trying to mount\n"); 77 78 Volume *volume = new (std::nothrow) Volume(_volume); 79 if (volume == NULL) 80 return B_NO_MEMORY; 81 82 _volume->private_volume = volume; 83 _volume->ops = &gxfsVolumeOps; 84 85 status_t status = volume->Mount(device, flags); 86 if (status != B_OK) { 87 ERROR("Failed mounting the volume. Error: %s\n", strerror(status)); 88 delete volume; 89 _volume->private_volume = NULL; 90 return status; 91 } 92 93 *_rootID = volume->Root(); 94 return B_OK; 95 } 96 97 98 static status_t 99 xfs_unmount(fs_volume *_volume) 100 { 101 Volume* volume = (Volume*) _volume->private_volume; 102 103 status_t status = volume->Unmount(); 104 delete volume; 105 TRACE("xfs_unmount(): Deleted volume"); 106 return status; 107 } 108 109 110 static status_t 111 xfs_read_fs_info(fs_volume *_volume, struct fs_info *info) 112 { 113 TRACE("XFS_READ_FS_INFO:\n"); 114 Volume* volume = (Volume*)_volume->private_volume; 115 116 info->flags = B_FS_IS_READONLY 117 | B_FS_HAS_ATTR | B_FS_IS_PERSISTENT; 118 119 info->io_size = XFS_IO_SIZE; 120 info->block_size = volume->SuperBlock().BlockSize(); 121 info->total_blocks = volume->SuperBlock().TotalBlocks(); 122 info->free_blocks = volume->SuperBlock().FreeBlocks(); 123 124 strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name)); 125 strlcpy(info->fsh_name, "xfs", sizeof(info->fsh_name)); 126 127 return B_OK; 128 } 129 130 131 // #pragma mark - 132 133 134 static status_t 135 xfs_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type, 136 uint32 *_flags, bool reenter) 137 { 138 TRACE("XFS_GET_VNODE:\n"); 139 Volume* volume = (Volume*)_volume->private_volume; 140 141 Inode* inode = new(std::nothrow) Inode(volume, id); 142 if (inode == NULL) 143 return B_NO_MEMORY; 144 145 status_t status = inode->Init(); 146 if (status != B_OK) { 147 delete inode; 148 ERROR("get_vnode: InitCheck() failed. Error: %s\n", strerror(status)); 149 return B_NO_INIT; 150 } 151 152 _node->private_node = inode; 153 _node->ops = &gxfsVnodeOps; 154 *_type = inode->Mode(); 155 *_flags = 0; 156 TRACE("(%ld)\n", inode->ID()); 157 return B_OK; 158 } 159 160 161 static status_t 162 xfs_put_vnode(fs_volume *_volume, fs_vnode *_node, bool reenter) 163 { 164 TRACE("XFS_PUT_VNODE:\n"); 165 delete (Inode*)_node->private_node; 166 return B_OK; 167 } 168 169 170 static bool 171 xfs_can_page(fs_volume *_volume, fs_vnode *_node, void *_cookie) 172 { 173 return B_NOT_SUPPORTED; 174 } 175 176 177 static status_t 178 xfs_read_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie, 179 off_t pos, const iovec *vecs, size_t count, size_t *_numBytes) 180 { 181 return B_NOT_SUPPORTED; 182 } 183 184 185 static status_t 186 xfs_io(fs_volume *_volume, fs_vnode *_node, void *_cookie, 187 io_request *request) 188 { 189 return B_NOT_SUPPORTED; 190 } 191 192 193 static status_t 194 xfs_get_file_map(fs_volume *_volume, fs_vnode *_node, off_t offset, 195 size_t size, struct file_io_vec *vecs, size_t *_count) 196 { 197 return B_NOT_SUPPORTED; 198 } 199 200 201 // #pragma mark - 202 203 204 static status_t 205 xfs_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name, 206 ino_t *_vnodeID) 207 { 208 TRACE("XFS_LOOKUP: %p (%s)\n", name, name); 209 Volume* volume = (Volume*)_volume->private_volume; 210 Inode* directory = (Inode*)_directory->private_node; 211 212 if (!directory->IsDirectory()) 213 return B_NOT_A_DIRECTORY; 214 215 status_t status = directory->CheckPermissions(X_OK); 216 if (status < B_OK) 217 return status; 218 219 DirectoryIterator* iterator = 220 new(std::nothrow) DirectoryIterator(directory); 221 if (iterator == NULL) 222 return B_NO_MEMORY; 223 224 status = iterator->Init(); 225 if (status != B_OK) { 226 delete iterator; 227 return status; 228 } 229 230 status = iterator->Lookup(name, strlen(name), (xfs_ino_t*)_vnodeID); 231 if (status != B_OK) { 232 delete iterator; 233 return status; 234 } 235 236 TRACE("XFS_LOOKUP: ID: (%ld)\n", *_vnodeID); 237 status = get_vnode(volume->FSVolume(), *_vnodeID, NULL); 238 TRACE("get_vnode status: (%d)\n", status); 239 return status; 240 } 241 242 243 static status_t 244 xfs_ioctl(fs_volume *_volume, fs_vnode *_node, void *_cookie, uint32 cmd, 245 void *buffer, size_t bufferLength) 246 { 247 return B_NOT_SUPPORTED; 248 } 249 250 251 static status_t 252 xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) 253 { 254 Inode* inode = (Inode*)_node->private_node; 255 TRACE("XFS_READ_STAT: id: (%ld)\n", inode->ID()); 256 stat->st_dev = inode->GetVolume()->ID(); 257 stat->st_ino = inode->ID(); 258 stat->st_nlink = 1; 259 stat->st_blksize = XFS_IO_SIZE; 260 261 stat->st_uid = inode->UserId(); 262 stat->st_gid = inode->GroupId(); 263 stat->st_mode = inode->Mode(); 264 stat->st_type = 0; // TODO 265 266 stat->st_size = inode->Size(); 267 stat->st_blocks = inode->BlockCount(); 268 269 inode->GetAccessTime(stat->st_atim); 270 inode->GetModificationTime(stat->st_mtim); 271 inode->GetChangeTime(stat->st_ctim); 272 273 /* TODO: Can we obtain the Creation Time in v4 system? */ 274 inode->GetChangeTime(stat->st_crtim); 275 276 return B_OK; 277 278 } 279 280 281 static status_t 282 xfs_open(fs_volume * /*_volume*/, fs_vnode *_node, int openMode, 283 void **_cookie) 284 { 285 TRACE("XFS_OPEN:\n"); 286 Inode* inode = (Inode*)_node->private_node; 287 288 // opening a directory read-only is allowed, although you can't read 289 // any data from it. 290 if (inode->IsDirectory() && (openMode & O_RWMASK) != 0) 291 return B_IS_A_DIRECTORY; 292 293 status_t status = inode->CheckPermissions(open_mode_to_access(openMode) 294 | (openMode & O_TRUNC ? W_OK : 0)); 295 if (status != B_OK) 296 return status; 297 298 // Prepare the cookie 299 file_cookie* cookie = new(std::nothrow) file_cookie; 300 if (cookie == NULL) 301 return B_NO_MEMORY; 302 ObjectDeleter<file_cookie> cookieDeleter(cookie); 303 304 cookie->open_mode = openMode & XFS_OPEN_MODE_USER_MASK; 305 cookie->last_size = inode->Size(); 306 cookie->last_notification = system_time(); 307 308 cookieDeleter.Detach(); 309 *_cookie = cookie; 310 311 return B_OK; 312 } 313 314 315 static status_t 316 xfs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, 317 void *buffer, size_t *_length) 318 { 319 TRACE("Inode::ReadAt: pos:(%ld), *length:(%ld)\n", pos, *_length); 320 Inode* inode = (Inode*)_node->private_node; 321 322 if (!inode->IsFile()) { 323 *_length = 0; 324 return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE; 325 } 326 327 return inode->ReadAt(pos, (uint8*)buffer, _length); 328 } 329 330 331 static status_t 332 xfs_close(fs_volume *_volume, fs_vnode *_node, void *_cookie) 333 { 334 return B_OK; 335 } 336 337 338 static status_t 339 xfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 340 { 341 TRACE("XFS_FREE_COOKIE:\n"); 342 file_cookie* cookie = (file_cookie*)_cookie; 343 Volume* volume = (Volume*)_volume->private_volume; 344 Inode* inode = (Inode*)_node->private_node; 345 346 if (inode->Size() != cookie->last_size) 347 notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE); 348 349 delete cookie; 350 return B_OK; 351 } 352 353 354 static status_t 355 xfs_access(fs_volume *_volume, fs_vnode *_node, int accessMode) 356 { 357 Inode* inode = (Inode*)_node->private_node; 358 return inode->CheckPermissions(accessMode); 359 } 360 361 362 static status_t 363 xfs_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer, 364 size_t *_bufferSize) 365 { 366 return B_NOT_SUPPORTED; 367 } 368 369 370 status_t 371 xfs_unlink(fs_volume *_volume, fs_vnode *_directory, const char *name) 372 { 373 return B_NOT_SUPPORTED; 374 } 375 376 377 // #pragma mark - Directory functions 378 379 380 static status_t 381 xfs_create_dir(fs_volume *_volume, fs_vnode *_directory, const char *name, 382 int mode) 383 { 384 return B_NOT_SUPPORTED; 385 } 386 387 388 static status_t 389 xfs_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name) 390 { 391 return B_NOT_SUPPORTED; 392 } 393 394 395 static status_t 396 xfs_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie) 397 { 398 Inode* inode = (Inode*)_node->private_node; 399 TRACE("XFS_OPEN_DIR: (%ld)\n", inode->ID()); 400 401 status_t status = inode->CheckPermissions(R_OK); 402 if (status < B_OK) 403 return status; 404 405 if (!inode->IsDirectory()) 406 return B_NOT_A_DIRECTORY; 407 408 DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode); 409 if (iterator == NULL) { 410 delete iterator; 411 return B_NO_MEMORY; 412 } 413 status = iterator->Init(); 414 *_cookie = iterator; 415 return status; 416 } 417 418 419 static status_t 420 xfs_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie, 421 struct dirent *buffer, size_t bufferSize, uint32 *_num) 422 { 423 TRACE("XFS_READ_DIR\n"); 424 DirectoryIterator* iterator = (DirectoryIterator*)_cookie; 425 Volume* volume = (Volume*)_volume->private_volume; 426 427 uint32 maxCount = *_num; 428 uint32 count = 0; 429 430 while (count < maxCount && (bufferSize > sizeof(struct dirent))) { 431 size_t length = bufferSize - sizeof(struct dirent); 432 xfs_ino_t ino; 433 434 status_t status = iterator->GetNext(buffer->d_name, &length, &ino); 435 if (status == B_ENTRY_NOT_FOUND) 436 break; 437 if (status == B_BUFFER_OVERFLOW) { 438 if (count == 0) 439 return status; 440 break; 441 } 442 if (status != B_OK) 443 return status; 444 445 buffer->d_dev = volume->ID(); 446 buffer->d_ino = ino; 447 buffer->d_reclen = offsetof(struct dirent, d_name) + length + 1; 448 bufferSize -= buffer->d_reclen; 449 buffer = (struct dirent*)((uint8*)buffer + buffer->d_reclen); 450 count++; 451 } 452 453 *_num = count; 454 TRACE("Count: (%d)\n", count); 455 return B_OK; 456 } 457 458 459 static status_t 460 xfs_rewind_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void *_cookie) 461 { 462 return B_NOT_SUPPORTED; 463 } 464 465 466 static status_t 467 xfs_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, 468 void * /*_cookie*/) 469 { 470 return B_OK; 471 } 472 473 474 static status_t 475 xfs_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 476 { 477 delete (DirectoryIterator*)_cookie; 478 return B_NOT_SUPPORTED; 479 } 480 481 482 static status_t 483 xfs_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie) 484 { 485 return B_NOT_SUPPORTED; 486 } 487 488 489 static status_t 490 xfs_close_attr_dir(fs_volume *_volume, fs_vnode *_node, void *cookie) 491 { 492 return B_NOT_SUPPORTED; 493 } 494 495 496 static status_t 497 xfs_free_attr_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 498 { 499 return B_NOT_SUPPORTED; 500 } 501 502 503 static status_t 504 xfs_read_attr_dir(fs_volume *_volume, fs_vnode *_node, 505 void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) 506 { 507 return B_NOT_SUPPORTED; 508 } 509 510 511 static status_t 512 xfs_rewind_attr_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie) 513 { 514 return B_NOT_SUPPORTED; 515 } 516 517 518 /* attribute operations */ 519 static status_t 520 xfs_create_attr(fs_volume *_volume, fs_vnode *_node, 521 const char *name, uint32 type, int openMode, void **_cookie) 522 { 523 return B_NOT_SUPPORTED; 524 } 525 526 527 static status_t 528 xfs_open_attr(fs_volume *_volume, fs_vnode *_node, const char *name, 529 int openMode, void **_cookie) 530 { 531 return B_NOT_SUPPORTED; 532 } 533 534 535 static status_t 536 xfs_close_attr(fs_volume *_volume, fs_vnode *_node, 537 void *cookie) 538 { 539 return B_NOT_SUPPORTED; 540 } 541 542 543 static status_t 544 xfs_free_attr_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie) 545 { 546 return B_NOT_SUPPORTED; 547 } 548 549 550 static status_t 551 xfs_read_attr(fs_volume *_volume, fs_vnode *_node, void *_cookie, 552 off_t pos, void *buffer, size_t *_length) 553 { 554 return B_NOT_SUPPORTED; 555 } 556 557 558 static status_t 559 xfs_write_attr(fs_volume *_volume, fs_vnode *_node, void *cookie, 560 off_t pos, const void *buffer, size_t *length) 561 { 562 return B_NOT_SUPPORTED; 563 } 564 565 566 static status_t 567 xfs_read_attr_stat(fs_volume *_volume, fs_vnode *_node, 568 void *_cookie, struct stat *stat) 569 { 570 return B_NOT_SUPPORTED; 571 } 572 573 574 static status_t 575 xfs_write_attr_stat(fs_volume *_volume, fs_vnode *_node, 576 void *cookie, const struct stat *stat, int statMask) 577 { 578 return B_NOT_SUPPORTED; 579 } 580 581 582 static status_t 583 xfs_rename_attr(fs_volume *_volume, fs_vnode *fromVnode, 584 const char *fromName, fs_vnode *toVnode, const char *toName) 585 { 586 return B_NOT_SUPPORTED; 587 } 588 589 590 static status_t 591 xfs_remove_attr(fs_volume *_volume, fs_vnode *vnode, 592 const char *name) 593 { 594 return B_NOT_SUPPORTED; 595 } 596 597 598 static uint32 599 xfs_get_supported_operations(partition_data *partition, uint32 mask) 600 { 601 return B_NOT_SUPPORTED; 602 } 603 604 605 static status_t 606 xfs_initialize(int fd, partition_id partitionID, const char *name, 607 const char *parameterString, off_t partitionSize, disk_job_id job) 608 { 609 return B_NOT_SUPPORTED; 610 } 611 612 613 static status_t 614 xfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 615 uint32 blockSize, disk_job_id job) 616 { 617 return B_NOT_SUPPORTED; 618 } 619 620 621 // #pragma mark - 622 623 624 static status_t 625 xfs_std_ops(int32 op, ...) 626 { 627 switch (op) 628 { 629 case B_MODULE_INIT: 630 #ifdef XFS_DEBUGGER_COMMANDS 631 // Perform nothing at the moment 632 // add_debugger_commands(); 633 #endif 634 return B_OK; 635 case B_MODULE_UNINIT: 636 #ifdef XFS_DEBUGGER_COMMANDS 637 // Perform nothing at the moment 638 // remove_debugger_commands(); 639 #endif 640 return B_OK; 641 642 default: 643 return B_ERROR; 644 } 645 } 646 647 648 fs_volume_ops gxfsVolumeOps = { 649 &xfs_unmount, 650 &xfs_read_fs_info, 651 NULL, // write_fs_info() 652 NULL, // fs_sync, 653 &xfs_get_vnode, 654 }; 655 656 657 fs_vnode_ops gxfsVnodeOps = { 658 /* vnode operations */ 659 &xfs_lookup, 660 NULL, // xfs_get_vnode_name- optional, and we can't do better 661 // than the fallback implementation, so leave as NULL. 662 &xfs_put_vnode, 663 NULL, // xfs_remove_vnode, 664 665 /* VM file access */ 666 &xfs_can_page, 667 &xfs_read_pages, 668 NULL, // xfs_write_pages, 669 670 &xfs_io, // io() 671 NULL, // cancel_io() 672 673 &xfs_get_file_map, 674 675 &xfs_ioctl, 676 NULL, 677 NULL, // fs_select 678 NULL, // fs_deselect 679 NULL, // fs_fsync, 680 681 &xfs_read_link, 682 NULL, // fs_create_symlink, 683 684 NULL, // fs_link, 685 &xfs_unlink, 686 NULL, // fs_rename, 687 688 &xfs_access, 689 &xfs_read_stat, 690 NULL, // fs_write_stat, 691 NULL, // fs_preallocate 692 693 /* file operations */ 694 NULL, // fs_create, 695 &xfs_open, 696 &xfs_close, 697 &xfs_free_cookie, 698 &xfs_read, 699 NULL, // fs_write, 700 701 /* directory operations */ 702 &xfs_create_dir, 703 &xfs_remove_dir, 704 &xfs_open_dir, 705 &xfs_close_dir, 706 &xfs_free_dir_cookie, 707 &xfs_read_dir, 708 &xfs_rewind_dir, 709 710 /* attribute directory operations */ 711 &xfs_open_attr_dir, 712 &xfs_close_attr_dir, 713 &xfs_free_attr_dir_cookie, 714 &xfs_read_attr_dir, 715 &xfs_rewind_attr_dir, 716 717 /* attribute operations */ 718 &xfs_create_attr, 719 &xfs_open_attr, 720 &xfs_close_attr, 721 &xfs_free_attr_cookie, 722 &xfs_read_attr, 723 &xfs_write_attr, 724 &xfs_read_attr_stat, 725 &xfs_write_attr_stat, 726 &xfs_rename_attr, 727 &xfs_remove_attr, 728 }; 729 730 731 static 732 file_system_module_info sxfsFileSystem = { 733 { 734 "file_systems/xfs" B_CURRENT_FS_API_VERSION, 735 0, 736 xfs_std_ops, 737 }, 738 739 "xfs", // short_name 740 "XFS File System", // pretty_name 741 742 // DDM flags 743 0 |B_DISK_SYSTEM_SUPPORTS_INITIALIZING |B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 744 // | B_DISK_SYSTEM_SUPPORTS_WRITING 745 , 746 747 // scanning 748 xfs_identify_partition, 749 xfs_scan_partition, 750 xfs_free_identify_partition_cookie, 751 NULL, // free_partition_content_cookie() 752 753 &xfs_mount, 754 755 /* capability querying operations */ 756 &xfs_get_supported_operations, 757 758 NULL, // validate_resize 759 NULL, // validate_move 760 NULL, // validate_set_content_name 761 NULL, // validate_set_content_parameters 762 NULL, // validate_initialize, 763 764 /* shadow partition modification */ 765 NULL, // shadow_changed 766 767 /* writing */ 768 NULL, // defragment 769 NULL, // repair 770 NULL, // resize 771 NULL, // move 772 NULL, // set_content_name 773 NULL, // set_content_parameters 774 xfs_initialize, 775 xfs_uninitialize}; 776 777 module_info *modules[] = { 778 (module_info *)&sxfsFileSystem, 779 NULL, 780 }; 781