1 /* 2 * Copyright 2020 Suhel Mehta, mehtasuhel@gmail.com 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 6 #include "DirectoryIterator.h" 7 #include "Inode.h" 8 #include "system_dependencies.h" 9 #include "ufs2.h" 10 #include "Volume.h" 11 12 #define TRACE_UFS2 13 #ifdef TRACE_UFS2 14 #define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x) 15 #else 16 #define TRACE(x...) ; 17 #endif 18 #define ERROR(x...) dprintf("\33[34mufs2:\33[0m " x) 19 20 21 struct identify_cookie 22 { 23 ufs2_super_block super_block; 24 int cookie; 25 }; 26 27 28 #if 0 29 //! ufs2_io() callback hook 30 static status_t 31 iterative_io_get_vecs_hook(void *cookie, io_request *request, off_t offset, 32 size_t size, struct file_io_vec *vecs, size_t *_count) 33 { 34 return B_NOT_SUPPORTED; 35 } 36 37 38 //! ufs2_io() callback hook 39 static status_t 40 iterative_io_finished_hook(void *cookie, io_request *request, status_t status, 41 bool partialTransfer, size_t bytesTransferred) 42 { 43 return B_NOT_SUPPORTED; 44 } 45 #endif 46 47 48 // #pragma mark - Scanning 49 static float 50 ufs2_identify_partition(int fd, partition_data *partition, void **_cookie) 51 { 52 ufs2_super_block superBlock; 53 status_t status = Volume::Identify(fd, &superBlock); 54 if (status != B_OK) 55 return -1; 56 57 identify_cookie* cookie = new identify_cookie; 58 memcpy(&cookie->super_block, &superBlock, sizeof(ufs2_super_block)); 59 *_cookie = cookie; 60 61 return 0.8f; 62 } 63 64 65 static status_t 66 ufs2_scan_partition(int fd, partition_data *partition, void *_cookie) 67 { 68 identify_cookie* cookie = (identify_cookie*)_cookie; 69 70 partition->status = B_PARTITION_VALID; 71 partition->flags |= B_PARTITION_FILE_SYSTEM | B_PARTITION_READ_ONLY; 72 partition->block_size = cookie->super_block.fs_bsize; 73 partition->content_size = partition->block_size 74 * cookie->super_block.fs_size; 75 partition->content_name = strdup(cookie->super_block.fs_volname); 76 if (partition->content_name == NULL) 77 return B_NO_MEMORY; 78 79 return B_OK; 80 } 81 82 83 static void 84 ufs2_free_identify_partition_cookie(partition_data *partition, void *_cookie) 85 { 86 identify_cookie* cookie = (identify_cookie*)_cookie; 87 delete cookie; 88 return; 89 } 90 91 92 // #pragma mark - 93 static status_t 94 ufs2_mount(fs_volume *_volume, const char *device, uint32 flags, 95 const char *args, ino_t *_rootID) 96 { 97 TRACE("Tracing mount()\n"); 98 Volume* volume = new(std::nothrow) Volume(_volume); 99 if (volume == NULL) 100 return B_NO_MEMORY; 101 102 _volume->private_volume = volume; 103 _volume->ops = &gUfs2VolumeOps; 104 *_rootID = UFS2_ROOT; 105 status_t status = volume->Mount(device, flags); 106 if (status != B_OK){ 107 ERROR("Failed mounting the volume. Error: %s\n", strerror(status)); 108 delete volume; 109 return status; 110 } 111 return B_OK; 112 } 113 114 115 static status_t 116 ufs2_unmount(fs_volume *_volume) 117 { 118 return B_NOT_SUPPORTED; 119 } 120 121 122 static status_t 123 ufs2_read_fs_info(fs_volume *_volume, struct fs_info *info) 124 { 125 Volume* volume = (Volume*)_volume->private_volume; 126 127 // File system flags 128 info->flags = B_FS_IS_PERSISTENT 129 | (volume->IsReadOnly() ? B_FS_IS_READONLY : 0); 130 info->io_size = 65536; 131 info->block_size = volume->SuperBlock().fs_sbsize; 132 info->total_blocks = volume->SuperBlock().fs_size; 133 134 strlcpy(info->volume_name, volume->Name(), sizeof(info->volume_name)); 135 136 return B_OK; 137 } 138 139 140 // #pragma mark - 141 142 static status_t 143 ufs2_get_vnode(fs_volume *_volume, ino_t id, fs_vnode *_node, int *_type, 144 uint32 *_flags, bool reenter) 145 { 146 Volume* volume = (Volume*)_volume->private_volume; 147 148 Inode* inode = new(std::nothrow) Inode(volume, id); 149 if (inode == NULL) 150 return B_NO_MEMORY; 151 152 status_t status = inode->InitCheck(); 153 if (status != B_OK) { 154 delete inode; 155 ERROR("get_vnode: InitCheck() failed. Error: %s\n", strerror(status)); 156 return status; 157 } 158 _node->private_node = inode; 159 _node->ops = &gufs2VnodeOps; 160 *_type = inode->Mode(); 161 *_flags = 0; 162 163 return B_OK; 164 165 } 166 167 168 static status_t 169 ufs2_put_vnode(fs_volume *_volume, fs_vnode *_node, bool reenter) 170 { 171 return B_NOT_SUPPORTED; 172 } 173 174 175 static bool 176 ufs2_can_page(fs_volume *_volume, fs_vnode *_node, void *_cookie) 177 { 178 return B_NOT_SUPPORTED; 179 } 180 181 182 static status_t 183 ufs2_read_pages(fs_volume *_volume, fs_vnode *_node, void *_cookie, 184 off_t pos, const iovec *vecs, size_t count, size_t *_numBytes) 185 { 186 return B_NOT_SUPPORTED; 187 } 188 189 190 static status_t 191 ufs2_io(fs_volume *_volume, fs_vnode *_node, void *_cookie, 192 io_request *request) 193 { 194 return B_NOT_SUPPORTED; 195 } 196 197 198 static status_t 199 ufs2_get_file_map(fs_volume *_volume, fs_vnode *_node, off_t offset, 200 size_t size, struct file_io_vec *vecs, size_t *_count) 201 { 202 return B_NOT_SUPPORTED; 203 } 204 205 206 // #pragma mark - 207 208 static status_t 209 ufs2_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name, 210 ino_t *_vnodeID) 211 { 212 Volume* volume = (Volume*)_volume->private_volume; 213 Inode* directory = (Inode*)_directory->private_node; 214 215 status_t status = DirectoryIterator(directory).Lookup(name, strlen(name), 216 (ino_t*)_vnodeID); 217 218 if (status != B_OK) 219 return status; 220 221 status = get_vnode(volume->FSVolume(), *_vnodeID, NULL); 222 return status; 223 } 224 225 226 static status_t 227 ufs2_ioctl(fs_volume *_volume, fs_vnode *_node, void *_cookie, uint32 cmd, 228 void *buffer, size_t bufferLength) 229 { 230 return B_NOT_SUPPORTED; 231 } 232 233 234 static status_t 235 ufs2_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) 236 { 237 Inode* inode = (Inode*)_node->private_node; 238 stat->st_dev = inode->GetVolume()->ID(); 239 stat->st_ino = inode->ID(); 240 // TODO handle hardlinks which will have nlink > 1. Maybe linkCount in inode 241 // structure may help? 242 stat->st_nlink = 1; 243 stat->st_blksize = 65536; 244 245 stat->st_uid = inode->UserID(); 246 stat->st_gid = inode->GroupID(); 247 stat->st_mode = inode->Mode(); 248 stat->st_type = 0; 249 250 inode->GetAccessTime(stat->st_atim); 251 inode->GetModificationTime(stat->st_mtim); 252 inode->GetChangeTime(stat->st_ctim); 253 inode->GetCreationTime(stat->st_crtim); 254 255 stat->st_size = inode->Size(); 256 stat->st_blocks = (inode->Size() + 511) / 512; 257 258 return B_OK; 259 } 260 261 262 static status_t 263 ufs2_open(fs_volume * _volume, fs_vnode *_node, int openMode, 264 void **_cookie) 265 { 266 //Volume* volume = (Volume*)_volume->private_volume; 267 Inode* inode = (Inode*)_node->private_node; 268 if (inode->IsDirectory()) 269 return B_IS_A_DIRECTORY; 270 271 file_cookie* cookie = new(std::nothrow) file_cookie; 272 if (cookie == NULL) 273 return B_NO_MEMORY; 274 ObjectDeleter<file_cookie> cookieDeleter(cookie); 275 276 cookie->last_size = inode->Size(); 277 cookie->last_notification = system_time(); 278 279 // fileCacheEnabler.Detach(); 280 cookieDeleter.Detach(); 281 *_cookie = cookie; 282 return B_OK; 283 } 284 285 286 static status_t 287 ufs2_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, 288 void *buffer, size_t *_length) 289 { 290 Inode* inode = (Inode*)_node->private_node; 291 292 if (!inode->IsFile()) { 293 *_length = 0; 294 return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE; 295 } 296 297 return inode->ReadAt(pos, (uint8*)buffer, _length); 298 } 299 300 301 static status_t 302 ufs2_close(fs_volume *_volume, fs_vnode *_node, void *_cookie) 303 { 304 return B_NOT_SUPPORTED; 305 } 306 307 308 static status_t 309 ufs2_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 310 { 311 return B_NOT_SUPPORTED; 312 } 313 314 static status_t 315 ufs2_access(fs_volume *_volume, fs_vnode *_node, int accessMode) 316 { 317 return B_OK; 318 } 319 320 321 static status_t 322 ufs2_read_link(fs_volume *_volume, fs_vnode *_node, char *buffer, 323 size_t *_bufferSize) 324 { 325 Inode* inode = (Inode*)_node->private_node; 326 327 return inode->ReadLink(buffer, _bufferSize); 328 } 329 330 331 status_t 332 ufs2_unlink(fs_volume *_volume, fs_vnode *_directory, const char *name) 333 { 334 return B_NOT_SUPPORTED; 335 } 336 337 338 // #pragma mark - Directory functions 339 340 static status_t 341 ufs2_create_dir(fs_volume *_volume, fs_vnode *_directory, const char *name, 342 int mode) 343 { 344 return B_NOT_SUPPORTED; 345 } 346 347 348 static status_t 349 ufs2_remove_dir(fs_volume *_volume, fs_vnode *_directory, const char *name) 350 { 351 return B_NOT_SUPPORTED; 352 } 353 354 355 static status_t 356 ufs2_open_dir(fs_volume * /*_volume*/, fs_vnode *_node, void **_cookie) 357 { 358 Inode* inode = (Inode*)_node->private_node; 359 360 if (!inode->IsDirectory()) 361 return B_NOT_A_DIRECTORY; 362 363 DirectoryIterator* iterator = new(std::nothrow) DirectoryIterator(inode); 364 if (iterator == NULL) 365 return B_NO_MEMORY; 366 367 *_cookie = iterator; 368 return B_OK; 369 } 370 371 372 static status_t 373 ufs2_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie, 374 struct dirent *dirent, size_t bufferSize, uint32 *_num) 375 { 376 DirectoryIterator* iterator = (DirectoryIterator*)_cookie; 377 Volume* volume = (Volume*)_volume->private_volume; 378 379 uint32 maxCount = *_num; 380 uint32 count = 0; 381 382 while (count < maxCount 383 && (bufferSize >= sizeof(struct dirent) + B_FILE_NAME_LENGTH)) { 384 size_t length = bufferSize - offsetof(struct dirent, d_name); 385 ino_t iNodeNo; 386 387 status_t status = iterator->GetNext(dirent->d_name, &length, &iNodeNo); 388 if (status == B_ENTRY_NOT_FOUND) 389 break; 390 if (status == B_BUFFER_OVERFLOW) { 391 if (count == 0) 392 return status; 393 break; 394 } 395 if (status != B_OK) 396 return status; 397 398 dirent->d_dev = volume->ID(); 399 dirent->d_ino = iNodeNo; 400 dirent->d_reclen = offsetof(struct dirent, d_name) + length + 1; 401 bufferSize -= dirent->d_reclen; 402 dirent = (struct dirent*)((uint8*)dirent + dirent->d_reclen); 403 count++; 404 } 405 406 *_num = count; 407 return B_OK; 408 409 } 410 411 412 static status_t 413 ufs2_rewind_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, void *_cookie) 414 { 415 return B_NOT_SUPPORTED; 416 } 417 418 419 static status_t 420 ufs2_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/, 421 void * /*_cookie*/) 422 { 423 return B_NOT_SUPPORTED; 424 } 425 426 427 static status_t 428 ufs2_free_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 429 { 430 return B_NOT_SUPPORTED; 431 } 432 433 434 static status_t 435 ufs2_open_attr_dir(fs_volume *_volume, fs_vnode *_node, void **_cookie) 436 { 437 return B_NOT_SUPPORTED; 438 } 439 440 441 static status_t 442 ufs2_close_attr_dir(fs_volume *_volume, fs_vnode *_node, void *cookie) 443 { 444 return B_NOT_SUPPORTED; 445 } 446 447 448 static status_t 449 ufs2_free_attr_dir_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie) 450 { 451 return B_NOT_SUPPORTED; 452 } 453 454 455 static status_t 456 ufs2_read_attr_dir(fs_volume *_volume, fs_vnode *_node, 457 void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) 458 { 459 return B_NOT_SUPPORTED; 460 } 461 462 463 static status_t 464 ufs2_rewind_attr_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie) 465 { 466 return B_NOT_SUPPORTED; 467 } 468 469 470 /* attribute operations */ 471 static status_t 472 ufs2_create_attr(fs_volume *_volume, fs_vnode *_node, 473 const char *name, uint32 type, int openMode, void **_cookie) 474 { 475 return B_NOT_SUPPORTED; 476 } 477 478 479 static status_t 480 ufs2_open_attr(fs_volume *_volume, fs_vnode *_node, const char *name, 481 int openMode, void **_cookie) 482 { 483 return B_NOT_SUPPORTED; 484 } 485 486 487 static status_t 488 ufs2_close_attr(fs_volume *_volume, fs_vnode *_node, 489 void *cookie) 490 { 491 return B_NOT_SUPPORTED; 492 } 493 494 495 static status_t 496 ufs2_free_attr_cookie(fs_volume *_volume, fs_vnode *_node, 497 void *cookie) 498 { 499 return B_NOT_SUPPORTED; 500 } 501 502 503 static status_t 504 ufs2_read_attr(fs_volume *_volume, fs_vnode *_node, void *_cookie, 505 off_t pos, void *buffer, size_t *_length) 506 { 507 return B_NOT_SUPPORTED; 508 } 509 510 511 static status_t 512 ufs2_write_attr(fs_volume *_volume, fs_vnode *_node, void *cookie, 513 off_t pos, const void *buffer, size_t *length) 514 { 515 return B_NOT_SUPPORTED; 516 } 517 518 519 static status_t 520 ufs2_read_attr_stat(fs_volume *_volume, fs_vnode *_node, 521 void *_cookie, struct stat *stat) 522 { 523 return B_NOT_SUPPORTED; 524 } 525 526 527 static status_t 528 ufs2_write_attr_stat(fs_volume *_volume, fs_vnode *_node, 529 void *cookie, const struct stat *stat, int statMask) 530 { 531 return B_NOT_SUPPORTED; 532 } 533 534 535 static status_t 536 ufs2_rename_attr(fs_volume *_volume, fs_vnode *fromVnode, 537 const char *fromName, fs_vnode *toVnode, const char *toName) 538 { 539 return B_NOT_SUPPORTED; 540 } 541 542 543 static status_t 544 ufs2_remove_attr(fs_volume *_volume, fs_vnode *vnode, 545 const char *name) 546 { 547 return B_NOT_SUPPORTED; 548 } 549 550 551 static uint32 552 ufs2_get_supported_operations(partition_data *partition, uint32 mask) 553 { 554 return B_NOT_SUPPORTED; 555 } 556 557 558 static status_t 559 ufs2_initialize(int fd, partition_id partitionID, const char *name, 560 const char *parameterString, off_t partitionSize, disk_job_id job) 561 { 562 return B_NOT_SUPPORTED; 563 } 564 565 566 static status_t 567 ufs2_uninitialize(int fd, partition_id partitionID, off_t partitionSize, 568 uint32 blockSize, disk_job_id job) 569 { 570 return B_NOT_SUPPORTED; 571 } 572 573 574 // #pragma mark - 575 576 static status_t 577 ufs2_std_ops(int32 op, ...) 578 { 579 switch (op) 580 { 581 case B_MODULE_INIT: 582 #ifdef ufs2_DEBUGGER_COMMANDS 583 // Perform nothing at the moment 584 // add_debugger_commands(); 585 #endif 586 return B_OK; 587 case B_MODULE_UNINIT: 588 #ifdef ufs2_DEBUGGER_COMMANDS 589 // Perform nothing at the moment 590 // remove_debugger_commands(); 591 #endif 592 return B_OK; 593 594 default: 595 return B_ERROR; 596 } 597 } 598 599 fs_volume_ops gUfs2VolumeOps = { 600 &ufs2_unmount, 601 &ufs2_read_fs_info, 602 NULL, //write_fs_info() 603 NULL, // fs_sync, 604 &ufs2_get_vnode, 605 }; 606 607 fs_vnode_ops gufs2VnodeOps = { 608 /* vnode operations */ 609 &ufs2_lookup, 610 NULL, // ufs2_get_vnode_name - optional, and we can't do better than the 611 // fallback implementation, so leave as NULL. 612 &ufs2_put_vnode, 613 NULL, // ufs2_remove_vnode, 614 615 /* VM file access */ 616 &ufs2_can_page, 617 &ufs2_read_pages, 618 NULL, // ufs2_write_pages, 619 620 &ufs2_io, // io() 621 NULL, // cancel_io() 622 623 &ufs2_get_file_map, 624 625 &ufs2_ioctl, 626 NULL, 627 NULL, // fs_select 628 NULL, // fs_deselect 629 NULL, // fs_fsync, 630 631 &ufs2_read_link, 632 NULL, // fs_create_symlink, 633 634 NULL, // fs_link, 635 &ufs2_unlink, 636 NULL, // fs_rename, 637 638 &ufs2_access, 639 &ufs2_read_stat, 640 NULL, // fs_write_stat, 641 NULL, // fs_preallocate 642 643 /* file operations */ 644 NULL, // fs_create, 645 &ufs2_open, 646 &ufs2_close, 647 &ufs2_free_cookie, 648 &ufs2_read, 649 NULL, // fs_write, 650 651 /* directory operations */ 652 &ufs2_create_dir, 653 &ufs2_remove_dir, 654 &ufs2_open_dir, 655 &ufs2_close_dir, 656 &ufs2_free_dir_cookie, 657 &ufs2_read_dir, 658 &ufs2_rewind_dir, 659 660 /* attribute directory operations */ 661 &ufs2_open_attr_dir, 662 &ufs2_close_attr_dir, 663 &ufs2_free_attr_dir_cookie, 664 &ufs2_read_attr_dir, 665 &ufs2_rewind_attr_dir, 666 667 /* attribute operations */ 668 &ufs2_create_attr, 669 &ufs2_open_attr, 670 &ufs2_close_attr, 671 &ufs2_free_attr_cookie, 672 &ufs2_read_attr, 673 &ufs2_write_attr, 674 &ufs2_read_attr_stat, 675 &ufs2_write_attr_stat, 676 &ufs2_rename_attr, 677 &ufs2_remove_attr, 678 }; 679 680 681 static file_system_module_info sufs2FileSystem = { 682 { 683 "file_systems/ufs2" B_CURRENT_FS_API_VERSION, 684 0, 685 ufs2_std_ops, 686 }, 687 688 "ufs2", // short_name 689 "Unix Filesystem 2", // pretty_name 690 691 // DDM flags 692 0| B_DISK_SYSTEM_SUPPORTS_INITIALIZING |B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 693 // | B_DISK_SYSTEM_SUPPORTS_WRITING 694 , 695 696 // scanning 697 ufs2_identify_partition, 698 ufs2_scan_partition, 699 ufs2_free_identify_partition_cookie, 700 NULL, // free_partition_content_cookie() 701 702 &ufs2_mount, 703 704 /* capability querying operations */ 705 &ufs2_get_supported_operations, 706 707 NULL, // validate_resize 708 NULL, // validate_move 709 NULL, // validate_set_content_name 710 NULL, // validate_set_content_parameters 711 NULL, // validate_initialize, 712 713 /* shadow partition modification */ 714 NULL, // shadow_changed 715 716 /* writing */ 717 NULL, // defragment 718 NULL, // repair 719 NULL, // resize 720 NULL, // move 721 NULL, // set_content_name 722 NULL, // set_content_parameters 723 ufs2_initialize, 724 ufs2_uninitialize}; 725 726 module_info *modules[] = { 727 (module_info *)&sufs2FileSystem, 728 NULL, 729 }; 730