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