1 // kernel_interface.cpp 2 // 3 // Copyright (c) 2003-2010, Ingo Weinhold (bonefish@cs.tu-berlin.de) 4 // 5 // This program is free software; you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation; either version 2 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with this program; if not, write to the Free Software 17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 // 19 // You can alternatively use *this file* under the terms of the the MIT 20 // license included in this package. 21 22 23 #include <new> 24 25 #include <ctype.h> 26 #include <dirent.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <time.h> 32 #include <unistd.h> 33 #include <stdio.h> 34 #include <sys/stat.h> 35 36 #include <fs_cache.h> 37 #include <fs_info.h> 38 #include <fs_interface.h> 39 #include <KernelExport.h> 40 41 #include "DirItem.h" 42 #include "Iterators.h" 43 #include "StatItem.h" 44 #include "Tree.h" 45 #include "VNode.h" 46 #include "Volume.h" 47 48 49 using std::nothrow; 50 51 static const size_t kOptimalIOSize = 65536; 52 53 extern fs_volume_ops gReiserFSVolumeOps; 54 extern fs_vnode_ops gReiserFSVnodeOps; 55 56 57 // #pragma mark - FS 58 59 60 // reiserfs_identify_partition 61 static float 62 reiserfs_identify_partition(int fd, partition_data *partition, void **cookie) 63 { 64 Volume* volume = new(nothrow) Volume(); 65 if (volume == NULL) 66 return -1.0; 67 68 status_t status = volume->Identify(fd, partition); 69 if (status != B_OK) { 70 delete volume; 71 return -1.0; 72 } 73 74 *cookie = (void*)volume; 75 return 0.8; 76 } 77 78 79 // reiserfs_scan_partition 80 static status_t 81 reiserfs_scan_partition(int fd, partition_data *partition, void *_cookie) 82 { 83 Volume* volume = (Volume*)_cookie; 84 85 partition->status = B_PARTITION_VALID; 86 partition->flags |= B_PARTITION_FILE_SYSTEM; 87 partition->content_size = volume->CountBlocks() 88 * volume->GetBlockSize(); 89 partition->block_size = volume->GetBlockSize(); 90 91 volume->UpdateName(partition->id); 92 // must be done after setting the content size 93 partition->content_name = strdup(volume->GetName()); 94 if (partition->content_name == NULL) 95 return B_NO_MEMORY; 96 97 return B_OK; 98 } 99 100 101 // reiserfs_free_identify_partition_cookie 102 static void 103 reiserfs_free_identify_partition_cookie(partition_data* partition, 104 void* _cookie) 105 { 106 delete (Volume*)_cookie; 107 } 108 109 110 // #pragma mark - 111 112 113 // reiserfs_mount 114 static status_t 115 reiserfs_mount(fs_volume *_volume, const char *device, uint32 flags, 116 const char *parameters, ino_t *rootID) 117 { 118 TOUCH(flags); TOUCH(parameters); 119 FUNCTION_START(); 120 // parameters are ignored for now 121 status_t error = B_OK; 122 123 // allocate and init the volume 124 Volume *volume = new(nothrow) Volume; 125 if (!volume) 126 error = B_NO_MEMORY; 127 if (error == B_OK) 128 error = volume->Mount(_volume, device); 129 130 // set the results 131 if (error == B_OK) { 132 *rootID = volume->GetRootVNode()->GetID(); 133 _volume->private_volume = volume; 134 _volume->ops = &gReiserFSVolumeOps; 135 } 136 137 // cleanup on failure 138 if (error != B_OK && volume) 139 delete volume; 140 RETURN_ERROR(error); 141 } 142 143 144 // reiserfs_unmount 145 static status_t 146 reiserfs_unmount(fs_volume* fs) 147 { 148 FUNCTION_START(); 149 Volume *volume = (Volume*)fs->private_volume; 150 status_t error = volume->Unmount(); 151 if (error == B_OK) 152 delete volume; 153 RETURN_ERROR(error); 154 } 155 156 // reiserfs_read_fs_info 157 static status_t 158 reiserfs_read_fs_info(fs_volume* fs, struct fs_info *info) 159 { 160 FUNCTION_START(); 161 Volume *volume = (Volume*)fs->private_volume; 162 info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY; 163 info->block_size = volume->GetBlockSize(); 164 info->io_size = kOptimalIOSize; 165 info->total_blocks = volume->CountBlocks(); 166 info->free_blocks = volume->CountFreeBlocks(); 167 strlcpy(info->device_name, volume->GetDeviceName(), 168 sizeof(info->device_name)); 169 strlcpy(info->volume_name, volume->GetName(), sizeof(info->volume_name)); 170 return B_OK; 171 } 172 173 174 // #pragma mark - VNodes 175 176 177 // reiserfs_lookup 178 static status_t 179 reiserfs_lookup(fs_volume* fs, fs_vnode* _dir, const char *entryName, 180 ino_t *vnid) 181 { 182 // FUNCTION_START(); 183 Volume *volume = (Volume*)fs->private_volume; 184 VNode *dir = (VNode*)_dir->private_node; 185 FUNCTION(("dir: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 "), " 186 "entry: `%s'\n", 187 dir->GetID(), dir->GetDirID(), dir->GetObjectID(), 188 entryName)); 189 status_t error = B_OK; 190 VNode *entryNode = NULL; 191 192 // check for non-directories 193 if (!dir->IsDir()) { 194 error = B_ENTRY_NOT_FOUND; 195 196 // special entries: "." and ".." 197 } else if (!strcmp(entryName, ".")) { 198 *vnid = dir->GetID(); 199 if (volume->GetVNode(*vnid, &entryNode) != B_OK) 200 error = B_BAD_VALUE; 201 } else if (!strcmp(entryName, "..")) { 202 *vnid = dir->GetParentID(); 203 if (volume->GetVNode(*vnid, &entryNode) != B_OK) 204 error = B_BAD_VALUE; 205 206 // ordinary entries 207 } else { 208 // find the entry 209 VNode foundNode; 210 error = volume->FindDirEntry(dir, entryName, &foundNode, true); 211 212 // hide non-file/dir/symlink entries, if the user desires that, and 213 // those entries explicitly set to hidden 214 if (error == B_OK 215 && ((foundNode.IsEsoteric() && volume->GetHideEsoteric()) 216 || volume->IsNegativeEntry(foundNode.GetID()))) { 217 error = B_ENTRY_NOT_FOUND; 218 } 219 if (error == B_OK) { 220 *vnid = foundNode.GetID(); 221 error = volume->GetVNode(*vnid, &entryNode); 222 } 223 } 224 225 // add to the entry cache 226 if (error == B_OK) { 227 entry_cache_add(volume->GetID(), dir->GetID(), entryName, 228 *vnid); 229 } 230 231 RETURN_ERROR(error); 232 } 233 234 // reiserfs_read_vnode 235 static status_t 236 reiserfs_read_vnode(fs_volume *fs, ino_t vnid, fs_vnode *node, int *_type, 237 uint32 *_flags, bool reenter) 238 { 239 TOUCH(reenter); 240 // FUNCTION_START(); 241 FUNCTION(("(%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 242 vnid, VNode::GetDirIDFor(vnid), VNode::GetObjectIDFor(vnid))); 243 Volume *volume = (Volume*)fs->private_volume; 244 status_t error = B_OK; 245 VNode *foundNode = new(nothrow) VNode; 246 if (foundNode) { 247 error = volume->FindVNode(vnid, foundNode); 248 if (error == B_OK) { 249 node->private_node = foundNode; 250 node->ops = &gReiserFSVnodeOps; 251 *_type = foundNode->GetStatData()->GetMode() & S_IFMT; 252 *_flags = 0; 253 } else 254 delete foundNode; 255 } else 256 error = B_NO_MEMORY; 257 RETURN_ERROR(error); 258 } 259 260 // reiserfs_write_vnode 261 static status_t 262 reiserfs_write_vnode(fs_volume *fs, fs_vnode *_node, bool reenter) 263 { 264 TOUCH(reenter); 265 // DANGER: If dbg_printf() is used, this thread will enter another FS and 266 // even perform a write operation. The is dangerous here, since this hook 267 // may be called out of the other FSs, since, for instance a put_vnode() 268 // called from another FS may cause the VFS layer to free vnodes and thus 269 // invoke this hook. 270 // FUNCTION_START(); 271 Volume *volume = (Volume*)fs->private_volume; 272 VNode *node = (VNode*)_node->private_node; 273 status_t error = B_OK; 274 if (node != volume->GetRootVNode()) 275 delete node; 276 // RETURN_ERROR(error); 277 return error; 278 } 279 280 281 // #pragma mark - Nodes 282 283 284 // reiserfs_read_symlink 285 static status_t 286 reiserfs_read_symlink(fs_volume *fs, fs_vnode *_node, char *buffer, 287 size_t *bufferSize) 288 { 289 // FUNCTION_START(); 290 Volume *volume = (Volume*)fs->private_volume; 291 VNode *node = (VNode*)_node->private_node; 292 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 293 node->GetID(), node->GetDirID(), node->GetObjectID())); 294 status_t error = B_OK; 295 // read symlinks only 296 if (!node->IsSymlink()) 297 error = B_BAD_VALUE; 298 // read 299 if (error == B_OK) 300 error = volume->ReadLink(node, buffer, *bufferSize, bufferSize); 301 RETURN_ERROR(error); 302 } 303 304 // reiserfs_access 305 static status_t 306 reiserfs_access(fs_volume *fs, fs_vnode *_node, int mode) 307 { 308 TOUCH(fs); 309 VNode *node = (VNode*)_node->private_node; 310 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 311 node->GetID(), node->GetDirID(), node->GetObjectID())); 312 313 // write access requested? 314 if (mode & W_OK) 315 return B_READ_ONLY_DEVICE; 316 317 // get node permissions 318 StatData *statData = node->GetStatData(); 319 320 return check_access_permissions(mode, statData->GetMode(), 321 statData->GetGID(), statData->GetUID()); 322 } 323 324 // reiserfs_read_stat 325 static status_t 326 reiserfs_read_stat(fs_volume *fs, fs_vnode *_node, struct stat *st) 327 { 328 // FUNCTION_START(); 329 Volume *volume = (Volume*)fs->private_volume; 330 VNode *node = (VNode*)_node->private_node; 331 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 332 node->GetID(), node->GetDirID(), node->GetObjectID())); 333 status_t error = B_OK; 334 StatData *statData = node->GetStatData(); 335 st->st_dev = volume->GetID(); 336 st->st_ino = node->GetID(); 337 st->st_mode = statData->GetMode(); 338 st->st_nlink = statData->GetNLink(); 339 st->st_uid = statData->GetUID(); 340 st->st_gid = statData->GetGID(); 341 st->st_size = statData->GetSize(); 342 st->st_blksize = kOptimalIOSize; 343 st->st_atime = statData->GetATime(); 344 st->st_mtime = st->st_ctime = statData->GetMTime(); 345 st->st_crtime = statData->GetCTime(); 346 RETURN_ERROR(error); 347 } 348 349 350 // #pragma mark - Files 351 352 353 // reiserfs_open 354 static status_t 355 reiserfs_open(fs_volume *fs, fs_vnode *_node, int openMode, void **cookie) 356 { 357 // FUNCTION_START(); 358 Volume *volume = (Volume*)fs->private_volume; 359 VNode *node = (VNode*)_node->private_node; 360 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 361 node->GetID(), node->GetDirID(), node->GetObjectID())); 362 status_t error = B_OK; 363 // check the open mode 364 if ((openMode & O_RWMASK) == O_WRONLY || (openMode & O_RWMASK) == O_RDWR 365 || (openMode & (O_TRUNC | O_CREAT))) { 366 error = B_READ_ONLY_DEVICE; 367 } 368 // create a StreamReader 369 if (error == B_OK) { 370 StreamReader *reader = new(nothrow) StreamReader(volume->GetTree(), 371 node->GetDirID(), node->GetObjectID()); 372 if (reader) { 373 error = reader->Suspend(); 374 if (error == B_OK) 375 *cookie = reader; 376 else 377 delete reader; 378 } else 379 error = B_NO_MEMORY; 380 } 381 RETURN_ERROR(error); 382 } 383 384 // reiserfs_close 385 static status_t 386 reiserfs_close(fs_volume *fs, fs_vnode *_node, void *cookie) 387 { 388 TOUCH(fs); TOUCH(cookie); 389 // FUNCTION_START(); 390 VNode *node = (VNode*)_node->private_node; 391 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 392 node->GetID(), node->GetDirID(), node->GetObjectID())); 393 TOUCH(node); 394 return B_OK; 395 } 396 397 // reiserfs_free_cookie 398 static status_t 399 reiserfs_free_cookie(fs_volume *fs, fs_vnode *_node, void *cookie) 400 { 401 TOUCH(fs); 402 // FUNCTION_START(); 403 VNode *node = (VNode*)_node->private_node; 404 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 405 node->GetID(), node->GetDirID(), node->GetObjectID())); 406 TOUCH(node); 407 StreamReader *reader = (StreamReader*)cookie; 408 delete reader; 409 return B_OK; 410 } 411 412 // reiserfs_read 413 static status_t 414 reiserfs_read(fs_volume *fs, fs_vnode *_node, void *cookie, off_t pos, 415 void *buffer, size_t *bufferSize) 416 { 417 TOUCH(fs); 418 // FUNCTION_START(); 419 // Volume *volume = (Volume*)fs->private_volume; 420 VNode *node = (VNode*)_node->private_node; 421 FUNCTION(("((%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 "), " 422 "%" B_PRIdOFF ", %p, %lu)\n", 423 node->GetID(), node->GetDirID(), node->GetObjectID(), 424 pos, buffer, *bufferSize)); 425 status_t error = B_OK; 426 // don't read anything but files 427 if (!node->IsFile()) { 428 if (node->IsDir()) 429 error = B_IS_A_DIRECTORY; 430 else 431 error = B_BAD_VALUE; 432 } 433 434 // read 435 StreamReader *reader = (StreamReader*)cookie; 436 if (error == B_OK) { 437 error = reader->Resume(); 438 if (error == B_OK) { 439 error = reader->ReadAt(pos, buffer, *bufferSize, bufferSize); 440 reader->Suspend(); 441 } 442 } 443 RETURN_ERROR(error); 444 } 445 446 447 class DirectoryCookie : public DirEntryIterator { 448 public: 449 DirectoryCookie(Tree *tree, uint32 dirID, uint32 objectID, 450 uint64 startOffset = 0, bool fixedHash = false) 451 : DirEntryIterator(tree, dirID, objectID, startOffset, 452 fixedHash), 453 fEncounteredDotDot(false) 454 { 455 } 456 457 bool EncounteredDotDot() const 458 { 459 return fEncounteredDotDot; 460 } 461 462 void SetEncounteredDotDot(bool flag) 463 { 464 fEncounteredDotDot = flag; 465 } 466 467 bool fEncounteredDotDot; 468 }; 469 470 471 // #pragma mark - Directories 472 473 474 // reiserfs_open_dir 475 static status_t 476 reiserfs_open_dir(fs_volume *fs, fs_vnode *_node, void **cookie) 477 { 478 // FUNCTION_START(); 479 Volume *volume = (Volume*)fs->private_volume; 480 VNode *node = (VNode*)_node->private_node; 481 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 482 node->GetID(), node->GetDirID(), node->GetObjectID())); 483 status_t error = (node->IsDir() ? B_OK : B_NOT_A_DIRECTORY); 484 if (error == B_OK) { 485 DirectoryCookie *iterator = new(nothrow) DirectoryCookie( 486 volume->GetTree(), node->GetDirID(), node->GetObjectID()); 487 if (iterator) { 488 error = iterator->Suspend(); 489 if (error == B_OK) 490 *cookie = iterator; 491 else 492 delete iterator; 493 } else 494 error = B_NO_MEMORY; 495 } 496 FUNCTION_END(); 497 RETURN_ERROR(error); 498 } 499 500 // set_dirent_name 501 static status_t 502 set_dirent_name(struct dirent *buffer, size_t bufferSize, 503 const char *name, int32 nameLen) 504 { 505 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer; 506 if (length <= bufferSize) { 507 memcpy(buffer->d_name, name, nameLen); 508 buffer->d_name[nameLen] = '\0'; 509 buffer->d_reclen = length; 510 return B_OK; 511 } else 512 RETURN_ERROR(B_BUFFER_OVERFLOW); 513 } 514 515 // reiserfs_close_dir 516 static status_t 517 reiserfs_close_dir(fs_volume *fs, fs_vnode *_node, void *cookie) 518 { 519 TOUCH(fs); TOUCH(cookie); 520 // FUNCTION_START(); 521 VNode *node = (VNode*)_node->private_node; 522 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 523 node->GetID(), node->GetDirID(), node->GetObjectID())); 524 TOUCH(node); 525 return B_OK; 526 } 527 528 // reiserfs_free_dir_cookie 529 static status_t 530 reiserfs_free_dir_cookie(fs_volume *fs, fs_vnode *_node, void *cookie) 531 { 532 TOUCH(fs); 533 // FUNCTION_START(); 534 VNode *node = (VNode*)_node->private_node; 535 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 536 node->GetID(), node->GetDirID(), node->GetObjectID())); 537 TOUCH(node); 538 DirectoryCookie *iterator = (DirectoryCookie*)cookie; 539 delete iterator; 540 return B_OK; 541 } 542 543 // reiserfs_read_dir 544 static status_t 545 reiserfs_read_dir(fs_volume *fs, fs_vnode *_node, void *cookie, 546 struct dirent *buffer, size_t bufferSize, uint32 *count) 547 { 548 // FUNCTION_START(); 549 Volume *volume = (Volume*)fs->private_volume; 550 VNode *node = (VNode*)_node->private_node; 551 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 552 node->GetID(), node->GetDirID(), node->GetObjectID())); 553 DirectoryCookie *iterator = (DirectoryCookie*)cookie; 554 status_t error = iterator->Resume(); 555 if (error == B_OK) { 556 // read one entry 557 DirItem item; 558 int32 index = 0; 559 DirEntry *entry = NULL; 560 bool done = false; 561 while (error == B_OK && !done 562 && (error = iterator->GetNext(&item, &index, &entry)) == B_OK) { 563 uint32 dirID = entry->GetDirID(); 564 uint32 objectID = entry->GetObjectID(); 565 // skip hidden entries and entries the user specified to be hidden 566 if (entry->IsHidden() || volume->IsNegativeEntry(dirID, objectID)) 567 continue; 568 // skip entry, if we can't get the stat data, or it is neither a 569 // file, a dir nor a symlink and the user desired to hide those. 570 StatData statData; 571 StatItem statItem; 572 if (volume->GetTree()->FindStatItem(dirID, objectID, &statItem) 573 != B_OK 574 || statItem.GetStatData(&statData) != B_OK 575 || (statData.IsEsoteric() && volume->GetHideEsoteric())) { 576 continue; 577 } 578 // get the name 579 size_t nameLen = 0; 580 const char *name = item.EntryNameAt(index, &nameLen); 581 if (!name || nameLen == 0) // bad data: skip it gracefully 582 continue; 583 // fill in the entry name -- checks whether the 584 // entry fits into the buffer 585 error = set_dirent_name(buffer, bufferSize, name, nameLen); 586 if (error == B_OK) { 587 // fill in the other data 588 buffer->d_dev = volume->GetID(); 589 buffer->d_ino = VNode::GetIDFor(dirID, objectID); 590 *count = 1; 591 PRINT(("Successfully read entry: dir: (%" B_PRIdINO ": " 592 "%" B_PRIu32 ", %" B_PRIu32 "), name: `%s', " 593 "id: (%" B_PRIdINO ", %" B_PRIu32 ", %" B_PRIu32 "), " 594 "reclen: %hu\n", 595 node->GetID(), 596 node->GetDirID(), node->GetObjectID(), buffer->d_name, 597 buffer->d_ino, dirID, objectID, 598 buffer->d_reclen)); 599 if (!strcmp("..", buffer->d_name)) 600 iterator->SetEncounteredDotDot(true); 601 done = true; 602 } 603 } 604 if (error == B_ENTRY_NOT_FOUND) { 605 if (iterator->EncounteredDotDot()) { 606 error = B_OK; 607 *count = 0; 608 } else { 609 // this is necessary for the root directory 610 // it usually has no ".." entry, so we simulate one 611 // get the name 612 const char *name = ".."; 613 size_t nameLen = strlen(name); 614 // fill in the entry name -- checks whether the 615 // entry fits into the buffer 616 error = set_dirent_name(buffer, bufferSize, name, 617 nameLen); 618 if (error == B_OK) { 619 // fill in the other data 620 buffer->d_dev = volume->GetID(); 621 buffer->d_ino = node->GetID(); 622 // < That's not correct! 623 *count = 1; 624 PRINT(("faking `..' entry: dir: (%" B_PRIdINO ": " 625 "%" B_PRIu32 ", %" B_PRIu32 "), name: `%s', " 626 "id: (%" B_PRIdINO ", %" B_PRIu32 ", %" B_PRIu32 627 "), reclen: %hu\n", 628 node->GetID(), 629 node->GetDirID(), node->GetObjectID(), buffer->d_name, 630 buffer->d_ino, node->GetDirID(), node->GetObjectID(), 631 buffer->d_reclen)); 632 iterator->SetEncounteredDotDot(true); 633 } 634 } 635 } 636 iterator->Suspend(); 637 } 638 PRINT(("returning %" B_PRIu32 " entries\n", *count)); 639 RETURN_ERROR(error); 640 } 641 642 // reiserfs_rewind_dir 643 static status_t 644 reiserfs_rewind_dir(fs_volume *fs, fs_vnode *_node, void *cookie) 645 { 646 TOUCH(fs); 647 // FUNCTION_START(); 648 VNode *node = (VNode*)_node->private_node; 649 FUNCTION(("node: (%" B_PRIdINO ": %" B_PRIu32 ", %" B_PRIu32 ")\n", 650 node->GetID(), node->GetDirID(), node->GetObjectID())); 651 TOUCH(node); 652 DirectoryCookie *iterator = (DirectoryCookie*)cookie; 653 status_t error = iterator->Rewind(); // no need to Resume() 654 if (error == B_OK) 655 error = iterator->Suspend(); 656 RETURN_ERROR(error); 657 } 658 659 660 // #pragma mark - Module Interface 661 662 663 // reiserfs_std_ops 664 static status_t 665 reiserfs_std_ops(int32 op, ...) 666 { 667 switch (op) { 668 case B_MODULE_INIT: 669 { 670 init_debugging(); 671 PRINT(("reiserfs_std_ops(): B_MODULE_INIT\n")); 672 return B_OK; 673 } 674 675 case B_MODULE_UNINIT: 676 PRINT(("reiserfs_std_ops(): B_MODULE_UNINIT\n")); 677 exit_debugging(); 678 return B_OK; 679 680 default: 681 return B_ERROR; 682 } 683 } 684 685 686 687 688 static file_system_module_info sReiserFSModuleInfo = { 689 { 690 "file_systems/reiserfs" B_CURRENT_FS_API_VERSION, 691 0, 692 reiserfs_std_ops, 693 }, 694 695 "reiserfs", // short_name 696 "Reiser File System", // pretty_name 697 0, // DDM flags 698 699 700 // scanning 701 &reiserfs_identify_partition, 702 &reiserfs_scan_partition, 703 &reiserfs_free_identify_partition_cookie, 704 NULL, // free_partition_content_cookie() 705 706 &reiserfs_mount 707 }; 708 709 710 fs_volume_ops gReiserFSVolumeOps = { 711 &reiserfs_unmount, 712 &reiserfs_read_fs_info, 713 NULL, // &reiserfs_write_fs_info, 714 NULL, // &reiserfs_sync, 715 716 &reiserfs_read_vnode 717 }; 718 719 720 fs_vnode_ops gReiserFSVnodeOps = { 721 /* vnode operations */ 722 &reiserfs_lookup, 723 NULL, // &reiserfs_get_vnode_name, 724 &reiserfs_write_vnode, 725 NULL, // &reiserfs_remove_vnode, 726 727 /* VM file access */ 728 NULL, // &reiserfs_can_page, 729 NULL, // &reiserfs_read_pages, 730 NULL, // &reiserfs_write_pages, 731 732 NULL, // io() 733 NULL, // cancel_io() 734 735 NULL, // &reiserfs_get_file_map, 736 737 NULL, // &reiserfs_ioctl, 738 NULL, // &reiserfs_set_flags, 739 NULL, // &reiserfs_select, 740 NULL, // &reiserfs_deselect, 741 NULL, // &reiserfs_fsync, 742 743 &reiserfs_read_symlink, 744 NULL, // &reiserfs_create_symlink, 745 746 NULL, // &reiserfs_link, 747 NULL, // &reiserfs_unlink, 748 NULL, // &reiserfs_rename, 749 750 &reiserfs_access, 751 &reiserfs_read_stat, 752 NULL, // &reiserfs_write_stat, 753 NULL, // &reiserfs_preallocate, 754 755 /* file operations */ 756 NULL, // &reiserfs_create, 757 &reiserfs_open, 758 &reiserfs_close, 759 &reiserfs_free_cookie, 760 &reiserfs_read, 761 NULL, // &reiserfs_write, 762 763 /* directory operations */ 764 NULL, // &reiserfs_create_dir, 765 NULL, // &reiserfs_remove_dir, 766 &reiserfs_open_dir, 767 &reiserfs_close_dir, 768 &reiserfs_free_dir_cookie, 769 &reiserfs_read_dir, 770 &reiserfs_rewind_dir 771 }; 772 773 774 module_info *modules[] = { 775 (module_info *)&sReiserFSModuleInfo, 776 NULL, 777 }; 778