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