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