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