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