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