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 = 209 new(std::nothrow) DirectoryIterator(directory); 210 if (iterator == NULL) 211 return B_NO_MEMORY; 212 213 status = iterator->Init(); 214 if (status != B_OK) { 215 delete iterator; 216 return status; 217 } 218 219 status = iterator->Lookup(name, strlen(name), (xfs_ino_t*)_vnodeID); 220 if (status != B_OK) { 221 delete iterator; 222 return status; 223 } 224 225 TRACE("XFS_LOOKUP: ID: (%ld)\n", *_vnodeID); 226 status = get_vnode(volume->FSVolume(), *_vnodeID, NULL); 227 TRACE("get_vnode status: (%d)\n", status); 228 return status; 229 } 230 231 232 static status_t 233 xfs_ioctl(fs_volume *_volume, fs_vnode *_node, void *_cookie, uint32 cmd, 234 void *buffer, size_t bufferLength) 235 { 236 return B_NOT_SUPPORTED; 237 } 238 239 240 static status_t 241 xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) 242 { 243 Inode* inode = (Inode*)_node->private_node; 244 TRACE("XFS_READ_STAT: id: (%ld)\n", inode->ID()); 245 stat->st_dev = inode->GetVolume()->ID(); 246 stat->st_ino = inode->ID(); 247 stat->st_nlink = 1; 248 stat->st_blksize = XFS_IO_SIZE; 249 250 stat->st_uid = inode->UserId(); 251 stat->st_gid = inode->GroupId(); 252 stat->st_mode = inode->Mode(); 253 stat->st_type = 0; // TODO 254 255 stat->st_size = inode->Size(); 256 stat->st_blocks = inode->BlockCount(); 257 258 inode->GetAccessTime(stat->st_atim); 259 inode->GetModificationTime(stat->st_mtim); 260 inode->GetChangeTime(stat->st_ctim); 261 262 // Only version 3 Inodes has creation time 263 if(inode->Version() == 3) 264 inode->GetCreationTime(stat->st_crtim); 265 else 266 inode->GetChangeTime(stat->st_crtim); 267 268 return B_OK; 269 } 270 271 272 static status_t 273 xfs_open(fs_volume * /*_volume*/, fs_vnode *_node, int openMode, 274 void **_cookie) 275 { 276 TRACE("XFS_OPEN:\n"); 277 Inode* inode = (Inode*)_node->private_node; 278 279 // opening a directory read-only is allowed, although you can't read 280 // any data from it. 281 if (inode->IsDirectory() && (openMode & O_RWMASK) != 0) 282 return B_IS_A_DIRECTORY; 283 284 status_t status = inode->CheckPermissions(open_mode_to_access(openMode) 285 | (openMode & O_TRUNC ? W_OK : 0)); 286 if (status != B_OK) 287 return status; 288 289 // Prepare the cookie 290 file_cookie* cookie = new(std::nothrow) file_cookie; 291 if (cookie == NULL) 292 return B_NO_MEMORY; 293 ObjectDeleter<file_cookie> cookieDeleter(cookie); 294 295 cookie->open_mode = openMode & XFS_OPEN_MODE_USER_MASK; 296 cookie->last_size = inode->Size(); 297 cookie->last_notification = system_time(); 298 299 cookieDeleter.Detach(); 300 *_cookie = cookie; 301 302 return B_OK; 303 } 304 305 306 static status_t 307 xfs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, 308 void *buffer, size_t *_length) 309 { 310 TRACE("Inode::ReadAt: pos:(%ld), *length:(%ld)\n", pos, *_length); 311 Inode* inode = (Inode*)_node->private_node; 312 313 if (!inode->IsFile()) { 314 *_length = 0; 315 return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE; 316 } 317 318 return inode->ReadAt(pos, (uint8*)buffer, _length); 319 } 320 321 322 static status_t 323 xfs_close(fs_volume *_volume, fs_vnode *_node, void *_cookie) 324 { 325 return B_OK; 326 } 327 328 329 static status_t 330 xfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 331 { 332 TRACE("XFS_FREE_COOKIE:\n"); 333 file_cookie* cookie = (file_cookie*)_cookie; 334 Volume* volume = (Volume*)_volume->private_volume; 335 Inode* inode = (Inode*)_node->private_node; 336 337 if (inode->Size() != cookie->last_size) 338 notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE); 339 340 delete cookie; 341 return B_OK; 342 } 343 344 345 static status_t 346 xfs_access(fs_volume *_volume, fs_vnode *_node, int accessMode) 347 { 348 Inode* inode = (Inode*)_node->private_node; 349 return inode->CheckPermissions(accessMode); 350 } 351 352 353 static status_t 354 xfs_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer, 355 size_t *_bufferSize) 356 { 357 TRACE("XFS_READ_SYMLINK\n"); 358 359 Inode* inode = (Inode*)_node->private_node; 360 361 if (!inode->IsSymLink()) 362 return B_BAD_VALUE; 363 364 Symlink symlink(inode); 365 366 status_t result = symlink.ReadLink(0, buffer, _bufferSize); 367 368 return result; 369 } 370 371 372 status_t 373 xfs_unlink(fs_volume *_volume, fs_vnode *_directory, const char *name) 374 { 375 return B_NOT_SUPPORTED; 376 } 377 378 379 // #pragma mark - Directory functions 380 381 382 static status_t 383 xfs_create_dir(fs_volume *_volume, fs_vnode *_directory, const char *name, 384 int mode) 385 { 386 return B_NOT_SUPPORTED; 387 } 388 389 390 static status_t 391 xfs_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name) 392 { 393 return B_NOT_SUPPORTED; 394 } 395 396 397 static status_t 398 xfs_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie) 399 { 400 Inode* inode = (Inode*)_node->private_node; 401 TRACE("XFS_OPEN_DIR: (%ld)\n", inode->ID()); 402 403 status_t status = inode->CheckPermissions(R_OK); 404 if (status < B_OK) 405 return status; 406 407 if (!inode->IsDirectory()) 408 return B_NOT_A_DIRECTORY; 409 410 DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode); 411 if (iterator == NULL) { 412 delete iterator; 413 return B_NO_MEMORY; 414 } 415 status = iterator->Init(); 416 *_cookie = iterator; 417 return status; 418 } 419 420 421 static status_t 422 xfs_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie, 423 struct dirent *buffer, size_t bufferSize, uint32 *_num) 424 { 425 TRACE("XFS_READ_DIR\n"); 426 DirectoryIterator* iterator = (DirectoryIterator*)_cookie; 427 Volume* volume = (Volume*)_volume->private_volume; 428 429 uint32 maxCount = *_num; 430 uint32 count = 0; 431 432 while (count < maxCount && (bufferSize > sizeof(struct dirent))) { 433 size_t length = bufferSize - sizeof(struct dirent); 434 xfs_ino_t ino; 435 436 status_t status = iterator->GetNext(buffer->d_name, &length, &ino); 437 if (status == B_ENTRY_NOT_FOUND) 438 break; 439 if (status == B_BUFFER_OVERFLOW) { 440 if (count == 0) 441 return status; 442 break; 443 } 444 if (status != B_OK) 445 return status; 446 447 buffer->d_dev = volume->ID(); 448 buffer->d_ino = ino; 449 buffer->d_reclen = offsetof(struct dirent, d_name) + length + 1; 450 bufferSize -= buffer->d_reclen; 451 buffer = (struct dirent*)((uint8*)buffer + buffer->d_reclen); 452 count++; 453 } 454 455 *_num = count; 456 TRACE("Count: (%d)\n", count); 457 return B_OK; 458 } 459 460 461 static status_t 462 xfs_rewind_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void *_cookie) 463 { 464 return B_NOT_SUPPORTED; 465 } 466 467 468 static status_t 469 xfs_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, 470 void * /*_cookie*/) 471 { 472 return B_OK; 473 } 474 475 476 static status_t 477 xfs_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 478 { 479 delete (DirectoryIterator*)_cookie; 480 return B_NOT_SUPPORTED; 481 } 482 483 484 static status_t 485 xfs_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie) 486 { 487 Inode* inode = (Inode*)_node->private_node; 488 TRACE("%s()\n", __FUNCTION__); 489 490 // Attributes are only on files 491 if (!inode->IsFile()) 492 return B_NOT_SUPPORTED; 493 494 Attribute* iterator = Attribute::Init(inode); 495 if (iterator == NULL) 496 return B_BAD_VALUE; 497 498 *_cookie = iterator; 499 return B_OK; 500 } 501 502 503 static status_t 504 xfs_close_attr_dir(fs_volume *_volume, fs_vnode *_node, void *cookie) 505 { 506 TRACE("%s()\n", __FUNCTION__); 507 return B_OK; 508 } 509 510 511 static status_t 512 xfs_free_attr_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 513 { 514 delete (Attribute*)_cookie; 515 return B_OK; 516 } 517 518 519 static status_t 520 xfs_read_attr_dir(fs_volume *_volume, fs_vnode *_node, 521 void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) 522 { 523 TRACE("%s()\n", __FUNCTION__); 524 Attribute* iterator = (Attribute*)_cookie; 525 526 size_t length = bufferSize; 527 status_t status = iterator->GetNext(dirent->d_name, &length); 528 if (status == B_ENTRY_NOT_FOUND) { 529 *_num = 0; 530 return B_OK; 531 } 532 533 if (status != B_OK) 534 return status; 535 536 Volume* volume = (Volume*)_volume->private_volume; 537 Inode* inode = (Inode*)_node->private_node; 538 dirent->d_dev = volume->ID(); 539 dirent->d_ino = inode->ID(); 540 dirent->d_reclen = offsetof(struct dirent, d_name) + length + 1; 541 *_num = 1; 542 543 return B_OK; 544 } 545 546 547 static status_t 548 xfs_rewind_attr_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie) 549 { 550 return B_NOT_SUPPORTED; 551 } 552 553 554 /* attribute operations */ 555 static status_t 556 xfs_create_attr(fs_volume *_volume, fs_vnode *_node, 557 const char *name, uint32 type, int openMode, void **_cookie) 558 { 559 return B_NOT_SUPPORTED; 560 } 561 562 563 static status_t 564 xfs_open_attr(fs_volume *_volume, fs_vnode *_node, const char *name, 565 int openMode, void **_cookie) 566 { 567 TRACE("%s()\n", __FUNCTION__); 568 569 status_t status; 570 571 Inode* inode = (Inode*)_node->private_node; 572 573 int accessMode = open_mode_to_access(openMode) | (openMode & O_TRUNC ? W_OK : 0); 574 status = inode->CheckPermissions(accessMode); 575 if (status < B_OK) 576 return status; 577 578 Attribute* attribute = Attribute::Init(inode); 579 580 if (attribute == NULL) 581 return B_BAD_VALUE; 582 583 status = attribute->Open(name, openMode, (attr_cookie**)_cookie); 584 delete attribute; 585 586 return status; 587 } 588 589 590 static status_t 591 xfs_close_attr(fs_volume *_volume, fs_vnode *_node, 592 void *cookie) 593 { 594 return B_OK; 595 } 596 597 598 static status_t 599 xfs_free_attr_cookie(fs_volume *_volume, fs_vnode *_node, void *cookie) 600 { 601 delete (attr_cookie*)cookie; 602 return B_OK; 603 } 604 605 606 static status_t 607 xfs_read_attr(fs_volume *_volume, fs_vnode *_node, void *_cookie, 608 off_t pos, void *buffer, size_t *_length) 609 { 610 TRACE("%s()\n", __FUNCTION__); 611 612 attr_cookie* cookie = (attr_cookie*)_cookie; 613 Inode* inode = (Inode*)_node->private_node; 614 615 Attribute* attribute = Attribute::Init(inode); 616 617 if (attribute == NULL) 618 return B_BAD_VALUE; 619 620 status_t status = attribute->Read(cookie, pos, (uint8*)buffer, _length); 621 delete attribute; 622 623 return status; 624 } 625 626 627 static status_t 628 xfs_write_attr(fs_volume *_volume, fs_vnode *_node, void *cookie, 629 off_t pos, const void *buffer, size_t *length) 630 { 631 return B_NOT_SUPPORTED; 632 } 633 634 635 static status_t 636 xfs_read_attr_stat(fs_volume *_volume, fs_vnode *_node, 637 void *_cookie, struct stat *stat) 638 { 639 TRACE("%s()\n", __FUNCTION__); 640 641 attr_cookie* cookie = (attr_cookie*)_cookie; 642 Inode* inode = (Inode*)_node->private_node; 643 644 Attribute* attribute = Attribute::Init(inode); 645 646 if (attribute == NULL) 647 return B_BAD_VALUE; 648 649 status_t status = attribute->Stat(cookie, *stat); 650 delete attribute; 651 652 return status; 653 } 654 655 656 static status_t 657 xfs_write_attr_stat(fs_volume *_volume, fs_vnode *_node, 658 void *cookie, const struct stat *stat, int statMask) 659 { 660 return B_NOT_SUPPORTED; 661 } 662 663 664 static status_t 665 xfs_rename_attr(fs_volume *_volume, fs_vnode *fromVnode, 666 const char *fromName, fs_vnode *toVnode, const char *toName) 667 { 668 return B_NOT_SUPPORTED; 669 } 670 671 672 static status_t 673 xfs_remove_attr(fs_volume *_volume, fs_vnode *vnode, 674 const char *name) 675 { 676 return B_NOT_SUPPORTED; 677 } 678 679 680 static uint32 681 xfs_get_supported_operations(partition_data *partition, uint32 mask) 682 { 683 return B_NOT_SUPPORTED; 684 } 685 686 687 static status_t 688 xfs_initialize(int fd, partition_id partitionID, const char *name, 689 const char *parameterString, off_t partitionSize, disk_job_id job) 690 { 691 return B_NOT_SUPPORTED; 692 } 693 694 695 static status_t 696 xfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 697 uint32 blockSize, disk_job_id job) 698 { 699 return B_NOT_SUPPORTED; 700 } 701 702 703 // #pragma mark - 704 705 706 static status_t 707 xfs_std_ops(int32 op, ...) 708 { 709 switch (op) 710 { 711 case B_MODULE_INIT: 712 #ifdef XFS_DEBUGGER_COMMANDS 713 // Perform nothing at the moment 714 // add_debugger_commands(); 715 #endif 716 return B_OK; 717 case B_MODULE_UNINIT: 718 #ifdef XFS_DEBUGGER_COMMANDS 719 // Perform nothing at the moment 720 // remove_debugger_commands(); 721 #endif 722 return B_OK; 723 724 default: 725 return B_ERROR; 726 } 727 } 728 729 730 fs_volume_ops gxfsVolumeOps = { 731 &xfs_unmount, 732 &xfs_read_fs_info, 733 NULL, // write_fs_info() 734 NULL, // fs_sync, 735 &xfs_get_vnode, 736 }; 737 738 739 fs_vnode_ops gxfsVnodeOps = { 740 /* vnode operations */ 741 &xfs_lookup, 742 NULL, // xfs_get_vnode_name- optional, and we can't do better 743 // than the fallback implementation, so leave as NULL. 744 &xfs_put_vnode, 745 NULL, // xfs_remove_vnode, 746 747 /* VM file access */ 748 &xfs_can_page, 749 &xfs_read_pages, 750 NULL, // xfs_write_pages, 751 752 &xfs_io, // io() 753 NULL, // cancel_io() 754 755 &xfs_get_file_map, 756 757 &xfs_ioctl, 758 NULL, 759 NULL, // fs_select 760 NULL, // fs_deselect 761 NULL, // fs_fsync, 762 763 &xfs_read_link, 764 NULL, // fs_create_symlink, 765 766 NULL, // fs_link, 767 &xfs_unlink, 768 NULL, // fs_rename, 769 770 &xfs_access, 771 &xfs_read_stat, 772 NULL, // fs_write_stat, 773 NULL, // fs_preallocate 774 775 /* file operations */ 776 NULL, // fs_create, 777 &xfs_open, 778 &xfs_close, 779 &xfs_free_cookie, 780 &xfs_read, 781 NULL, // fs_write, 782 783 /* directory operations */ 784 &xfs_create_dir, 785 &xfs_remove_dir, 786 &xfs_open_dir, 787 &xfs_close_dir, 788 &xfs_free_dir_cookie, 789 &xfs_read_dir, 790 &xfs_rewind_dir, 791 792 /* attribute directory operations */ 793 &xfs_open_attr_dir, 794 &xfs_close_attr_dir, 795 &xfs_free_attr_dir_cookie, 796 &xfs_read_attr_dir, 797 &xfs_rewind_attr_dir, 798 799 /* attribute operations */ 800 &xfs_create_attr, 801 &xfs_open_attr, 802 &xfs_close_attr, 803 &xfs_free_attr_cookie, 804 &xfs_read_attr, 805 &xfs_write_attr, 806 &xfs_read_attr_stat, 807 &xfs_write_attr_stat, 808 &xfs_rename_attr, 809 &xfs_remove_attr, 810 }; 811 812 813 static 814 file_system_module_info sxfsFileSystem = { 815 { 816 "file_systems/xfs" B_CURRENT_FS_API_VERSION, 817 0, 818 xfs_std_ops, 819 }, 820 821 "xfs", // short_name 822 "XFS File System", // pretty_name 823 824 // DDM flags 825 0 |B_DISK_SYSTEM_SUPPORTS_INITIALIZING |B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 826 // | B_DISK_SYSTEM_SUPPORTS_WRITING 827 , 828 829 // scanning 830 xfs_identify_partition, 831 xfs_scan_partition, 832 xfs_free_identify_partition_cookie, 833 NULL, // free_partition_content_cookie() 834 835 &xfs_mount, 836 837 /* capability querying operations */ 838 &xfs_get_supported_operations, 839 840 NULL, // validate_resize 841 NULL, // validate_move 842 NULL, // validate_set_content_name 843 NULL, // validate_set_content_parameters 844 NULL, // validate_initialize, 845 846 /* shadow partition modification */ 847 NULL, // shadow_changed 848 849 /* writing */ 850 NULL, // defragment 851 NULL, // repair 852 NULL, // resize 853 NULL, // move 854 NULL, // set_content_name 855 NULL, // set_content_parameters 856 xfs_initialize, 857 xfs_uninitialize}; 858 859 860 module_info *modules[] = { 861 (module_info *)&sxfsFileSystem, 862 NULL, 863 }; 864