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 "Volume.h" 14 15 #include <file_systems/fs_ops_support.h> 16 17 18 #define XFS_IO_SIZE 65536 19 20 struct identify_cookie { 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 441 buffer = next_dirent(buffer, length, bufferSize); 442 count++; 443 } 444 445 *_num = count; 446 TRACE("Count: (%d)\n", count); 447 return B_OK; 448 } 449 450 451 static status_t 452 xfs_rewind_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void *_cookie) 453 { 454 return B_NOT_SUPPORTED; 455 } 456 457 458 static status_t 459 xfs_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, 460 void * /*_cookie*/) 461 { 462 return B_OK; 463 } 464 465 466 static status_t 467 xfs_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 468 { 469 delete (DirectoryIterator*)_cookie; 470 return B_OK; 471 } 472 473 474 static status_t 475 xfs_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie) 476 { 477 Inode* inode = (Inode*)_node->private_node; 478 TRACE("%s()\n", __FUNCTION__); 479 480 Attribute* iterator = Attribute::Init(inode); 481 if (iterator == NULL) 482 return B_BAD_VALUE; 483 484 *_cookie = iterator; 485 return B_OK; 486 } 487 488 489 static status_t 490 xfs_close_attr_dir(fs_volume *_volume, fs_vnode *_node, void *cookie) 491 { 492 TRACE("%s()\n", __FUNCTION__); 493 return B_OK; 494 } 495 496 497 static status_t 498 xfs_free_attr_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 499 { 500 delete (Attribute*)_cookie; 501 return B_OK; 502 } 503 504 505 static status_t 506 xfs_read_attr_dir(fs_volume *_volume, fs_vnode *_node, 507 void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) 508 { 509 TRACE("%s()\n", __FUNCTION__); 510 Attribute* iterator = (Attribute*)_cookie; 511 512 size_t length = bufferSize; 513 status_t status = iterator->GetNext(dirent->d_name, &length); 514 if (status == B_ENTRY_NOT_FOUND) { 515 *_num = 0; 516 return B_OK; 517 } 518 519 if (status != B_OK) 520 return status; 521 522 Volume* volume = (Volume*)_volume->private_volume; 523 Inode* inode = (Inode*)_node->private_node; 524 dirent->d_dev = volume->ID(); 525 dirent->d_ino = inode->ID(); 526 dirent->d_reclen = offsetof(struct dirent, d_name) + length + 1; 527 *_num = 1; 528 529 return B_OK; 530 } 531 532 533 static status_t 534 xfs_rewind_attr_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie) 535 { 536 return B_NOT_SUPPORTED; 537 } 538 539 540 /* attribute operations */ 541 static status_t 542 xfs_create_attr(fs_volume *_volume, fs_vnode *_node, 543 const char *name, uint32 type, int openMode, void **_cookie) 544 { 545 return B_NOT_SUPPORTED; 546 } 547 548 549 static status_t 550 xfs_open_attr(fs_volume *_volume, fs_vnode *_node, const char *name, 551 int openMode, void **_cookie) 552 { 553 TRACE("%s()\n", __FUNCTION__); 554 555 status_t status; 556 557 Inode* inode = (Inode*)_node->private_node; 558 559 int accessMode = open_mode_to_access(openMode) | (openMode & O_TRUNC ? W_OK : 0); 560 status = inode->CheckPermissions(accessMode); 561 if (status < B_OK) 562 return status; 563 564 Attribute* attribute = Attribute::Init(inode); 565 566 if (attribute == NULL) 567 return B_BAD_VALUE; 568 569 status = attribute->Open(name, openMode, (attr_cookie**)_cookie); 570 delete attribute; 571 572 return status; 573 } 574 575 576 static status_t 577 xfs_close_attr(fs_volume *_volume, fs_vnode *_node, 578 void *cookie) 579 { 580 return B_OK; 581 } 582 583 584 static status_t 585 xfs_free_attr_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie) 586 { 587 delete (attr_cookie*)cookie; 588 return B_OK; 589 } 590 591 592 static status_t 593 xfs_read_attr(fs_volume *_volume, fs_vnode *_node, void *_cookie, 594 off_t pos, void *buffer, size_t *_length) 595 { 596 TRACE("%s()\n", __FUNCTION__); 597 598 attr_cookie* cookie = (attr_cookie*)_cookie; 599 Inode* inode = (Inode*)_node->private_node; 600 601 Attribute* attribute = Attribute::Init(inode); 602 603 if (attribute == NULL) 604 return B_BAD_VALUE; 605 606 status_t status = attribute->Read(cookie, pos, (uint8*)buffer, _length); 607 delete attribute; 608 609 return status; 610 } 611 612 613 static status_t 614 xfs_write_attr(fs_volume *_volume, fs_vnode *_node, void *cookie, 615 off_t pos, const void *buffer, size_t *length) 616 { 617 return B_NOT_SUPPORTED; 618 } 619 620 621 static status_t 622 xfs_read_attr_stat(fs_volume *_volume, fs_vnode *_node, 623 void *_cookie, struct stat *stat) 624 { 625 TRACE("%s()\n", __FUNCTION__); 626 627 attr_cookie* cookie = (attr_cookie*)_cookie; 628 Inode* inode = (Inode*)_node->private_node; 629 630 Attribute* attribute = Attribute::Init(inode); 631 632 if (attribute == NULL) 633 return B_BAD_VALUE; 634 635 status_t status = attribute->Stat(cookie, *stat); 636 delete attribute; 637 638 return status; 639 } 640 641 642 static status_t 643 xfs_write_attr_stat(fs_volume *_volume, fs_vnode *_node, 644 void *cookie, const struct stat *stat, int statMask) 645 { 646 return B_NOT_SUPPORTED; 647 } 648 649 650 static status_t 651 xfs_rename_attr(fs_volume *_volume, fs_vnode *fromVnode, 652 const char *fromName, fs_vnode *toVnode, const char *toName) 653 { 654 return B_NOT_SUPPORTED; 655 } 656 657 658 static status_t 659 xfs_remove_attr(fs_volume *_volume, fs_vnode *vnode, 660 const char *name) 661 { 662 return B_NOT_SUPPORTED; 663 } 664 665 666 static uint32 667 xfs_get_supported_operations(partition_data *partition, uint32 mask) 668 { 669 return B_NOT_SUPPORTED; 670 } 671 672 673 static status_t 674 xfs_initialize(int fd, partition_id partitionID, const char *name, 675 const char *parameterString, off_t partitionSize, disk_job_id job) 676 { 677 return B_NOT_SUPPORTED; 678 } 679 680 681 static status_t 682 xfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 683 uint32 blockSize, disk_job_id job) 684 { 685 return B_NOT_SUPPORTED; 686 } 687 688 689 // #pragma mark - 690 691 692 static status_t 693 xfs_std_ops(int32 op, ...) 694 { 695 switch (op) 696 { 697 case B_MODULE_INIT: 698 #ifdef XFS_DEBUGGER_COMMANDS 699 // Perform nothing at the moment 700 // add_debugger_commands(); 701 #endif 702 return B_OK; 703 case B_MODULE_UNINIT: 704 #ifdef XFS_DEBUGGER_COMMANDS 705 // Perform nothing at the moment 706 // remove_debugger_commands(); 707 #endif 708 return B_OK; 709 710 default: 711 return B_ERROR; 712 } 713 } 714 715 716 fs_volume_ops gxfsVolumeOps = { 717 &xfs_unmount, 718 &xfs_read_fs_info, 719 NULL, // write_fs_info() 720 NULL, // fs_sync, 721 &xfs_get_vnode, 722 }; 723 724 725 fs_vnode_ops gxfsVnodeOps = { 726 /* vnode operations */ 727 &xfs_lookup, 728 NULL, // xfs_get_vnode_name- optional, and we can't do better 729 // than the fallback implementation, so leave as NULL. 730 &xfs_put_vnode, 731 NULL, // xfs_remove_vnode, 732 733 /* VM file access */ 734 &xfs_can_page, 735 &xfs_read_pages, 736 NULL, // xfs_write_pages, 737 738 &xfs_io, // io() 739 NULL, // cancel_io() 740 741 &xfs_get_file_map, 742 743 &xfs_ioctl, 744 NULL, 745 NULL, // fs_select 746 NULL, // fs_deselect 747 NULL, // fs_fsync, 748 749 &xfs_read_link, 750 NULL, // fs_create_symlink, 751 752 NULL, // fs_link, 753 &xfs_unlink, 754 NULL, // fs_rename, 755 756 &xfs_access, 757 &xfs_read_stat, 758 NULL, // fs_write_stat, 759 NULL, // fs_preallocate 760 761 /* file operations */ 762 NULL, // fs_create, 763 &xfs_open, 764 &xfs_close, 765 &xfs_free_cookie, 766 &xfs_read, 767 NULL, // fs_write, 768 769 /* directory operations */ 770 &xfs_create_dir, 771 &xfs_remove_dir, 772 &xfs_open_dir, 773 &xfs_close_dir, 774 &xfs_free_dir_cookie, 775 &xfs_read_dir, 776 &xfs_rewind_dir, 777 778 /* attribute directory operations */ 779 &xfs_open_attr_dir, 780 &xfs_close_attr_dir, 781 &xfs_free_attr_dir_cookie, 782 &xfs_read_attr_dir, 783 &xfs_rewind_attr_dir, 784 785 /* attribute operations */ 786 &xfs_create_attr, 787 &xfs_open_attr, 788 &xfs_close_attr, 789 &xfs_free_attr_cookie, 790 &xfs_read_attr, 791 &xfs_write_attr, 792 &xfs_read_attr_stat, 793 &xfs_write_attr_stat, 794 &xfs_rename_attr, 795 &xfs_remove_attr, 796 }; 797 798 799 static 800 file_system_module_info sxfsFileSystem = { 801 { 802 "file_systems/xfs" B_CURRENT_FS_API_VERSION, 803 0, 804 xfs_std_ops, 805 }, 806 807 "xfs", // short_name 808 "XFS File System", // pretty_name 809 810 // DDM flags 811 0 |B_DISK_SYSTEM_SUPPORTS_INITIALIZING |B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 812 // | B_DISK_SYSTEM_SUPPORTS_WRITING 813 , 814 815 // scanning 816 xfs_identify_partition, 817 xfs_scan_partition, 818 xfs_free_identify_partition_cookie, 819 NULL, // free_partition_content_cookie() 820 821 &xfs_mount, 822 823 /* capability querying operations */ 824 &xfs_get_supported_operations, 825 826 NULL, // validate_resize 827 NULL, // validate_move 828 NULL, // validate_set_content_name 829 NULL, // validate_set_content_parameters 830 NULL, // validate_initialize, 831 832 /* shadow partition modification */ 833 NULL, // shadow_changed 834 835 /* writing */ 836 NULL, // defragment 837 NULL, // repair 838 NULL, // resize 839 NULL, // move 840 NULL, // set_content_name 841 NULL, // set_content_parameters 842 xfs_initialize, 843 xfs_uninitialize}; 844 845 846 module_info *modules[] = { 847 (module_info *)&sxfsFileSystem, 848 NULL, 849 }; 850