1 // kernel_interface.cpp 2 // 3 // Copyright (c) 2003, Axel Dörfler (axeld@pinc-software.de) 4 // Copyright (c) 2003, Ingo Weinhold (bonefish@cs.tu-berlin.de) 5 // 6 // This program is free software; you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation; either version 2 of the License, or 9 // (at your option) any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program; if not, write to the Free Software 18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 // 20 // You can alternatively use *this file* under the terms of the the MIT 21 // license included in this package. 22 23 #include <ctype.h> 24 #include <dirent.h> 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <time.h> 30 #include <unistd.h> 31 #include <stdio.h> 32 #include <sys/stat.h> 33 34 #include <fs_index.h> 35 #include <fs_info.h> 36 #include <fs_interface.h> 37 #include <fs_query.h> 38 #include <fs_volume.h> 39 #include <KernelExport.h> 40 #include <NodeMonitor.h> 41 #include <TypeConstants.h> 42 43 #include "AllocationInfo.h" 44 #include "AttributeIndex.h" 45 #include "AttributeIterator.h" 46 #include "AutoDeleter.h" 47 #include "Debug.h" 48 #include "Directory.h" 49 #include "Entry.h" 50 #include "EntryIterator.h" 51 #include "File.h" 52 #include "Index.h" 53 #include "IndexDirectory.h" 54 #include "Locking.h" 55 #include "Misc.h" 56 #include "Node.h" 57 #include "Query.h" 58 #include "ramfs_ioctl.h" 59 #include "SymLink.h" 60 #include "Volume.h" 61 62 63 static const size_t kOptimalIOSize = 65536; 64 static const bigtime_t kNotificationInterval = 1000000LL; 65 66 // notify_if_stat_changed 67 void 68 notify_if_stat_changed(Volume *volume, Node *node) 69 { 70 if (volume && node && node->IsModified()) { 71 uint32 statFields = node->MarkUnmodified(); 72 notify_stat_changed(volume->GetID(), node->GetID(), statFields); 73 } 74 } 75 76 77 // #pragma mark - FS 78 79 80 // ramfs_mount 81 static status_t 82 ramfs_mount(mount_id nsid, const char* /*device*/, uint32 flags, 83 const char* /*args*/, fs_volume* _volume, vnode_id* rootID) 84 { 85 FUNCTION_START(); 86 // parameters are ignored for now 87 status_t error = B_OK; 88 // fail, if read-only mounting is requested 89 if (flags & B_MOUNT_READ_ONLY) 90 error = B_BAD_VALUE; 91 // allocate and init the volume 92 Volume *volume = NULL; 93 if (error == B_OK) { 94 volume = new(nothrow) Volume; 95 if (!volume) 96 SET_ERROR(error, B_NO_MEMORY); 97 if (error == B_OK) 98 error = volume->Mount(nsid); 99 } 100 // set the results 101 if (error == B_OK) { 102 *rootID = volume->GetRootDirectory()->GetID(); 103 *_volume = volume; 104 } 105 // cleanup on failure 106 if (error != B_OK && volume) 107 delete volume; 108 109 RETURN_ERROR(error); 110 } 111 112 // ramfs_unmount 113 static status_t 114 ramfs_unmount(fs_volume fs) 115 { 116 FUNCTION_START(); 117 Volume *volume = (Volume*)fs; 118 status_t error = volume->Unmount(); 119 if (error == B_OK) 120 delete volume; 121 if (error != B_OK) 122 REPORT_ERROR(error); 123 return error; 124 } 125 126 // ramfs_read_fs_info 127 static status_t 128 ramfs_read_fs_info(fs_volume fs, struct fs_info *info) 129 { 130 FUNCTION_START(); 131 Volume *volume = (Volume*)fs; 132 status_t error = B_OK; 133 if (VolumeReadLocker locker = volume) { 134 info->flags = B_FS_IS_PERSISTENT | B_FS_HAS_ATTR | B_FS_HAS_MIME 135 | B_FS_HAS_QUERY; 136 info->block_size = volume->GetBlockSize(); 137 info->io_size = kOptimalIOSize; 138 info->total_blocks = volume->CountBlocks(); 139 info->free_blocks = volume->CountFreeBlocks(); 140 info->device_name[0] = '\0'; 141 strncpy(info->volume_name, volume->GetName(), sizeof(info->volume_name)); 142 strcpy(info->fsh_name, "ramfs"); 143 } else 144 SET_ERROR(error, B_ERROR); 145 return B_OK; 146 } 147 148 149 // ramfs_write_fs_info 150 static status_t 151 ramfs_write_fs_info(fs_volume fs, const struct fs_info *info, uint32 mask) 152 153 { 154 FUNCTION_START(); 155 Volume *volume = (Volume*)fs; 156 status_t error = B_OK; 157 if (VolumeWriteLocker locker = volume) { 158 if (mask & FS_WRITE_FSINFO_NAME) 159 error = volume->SetName(info->volume_name); 160 } else 161 SET_ERROR(error, B_ERROR); 162 RETURN_ERROR(error); 163 } 164 165 // ramfs_sync 166 static status_t 167 ramfs_sync(fs_volume /*fs*/) 168 { 169 FUNCTION_START(); 170 return B_OK; 171 } 172 173 174 // #pragma mark - VNodes 175 176 177 // ramfs_lookup 178 static status_t 179 ramfs_lookup(fs_volume fs, fs_vnode _dir, const char *entryName, vnode_id *vnid, 180 int *type) 181 { 182 // FUNCTION_START(); 183 Volume *volume = (Volume*)fs; 184 Directory *dir = dynamic_cast<Directory*>((Node*)_dir); 185 FUNCTION(("dir: (%llu), entry: `%s'\n", (dir ? dir->GetID() : -1), entryName)); 186 187 // check for non-directories 188 if (!dir) 189 RETURN_ERROR(B_NOT_A_DIRECTORY); 190 191 status_t error = B_OK; 192 if (VolumeReadLocker locker = volume) { 193 Node *node = NULL; 194 195 // special entries: "." and ".." 196 if (!strcmp(entryName, ".")) { 197 *vnid = dir->GetID(); 198 if (volume->GetVNode(*vnid, &node) != B_OK) 199 error = B_BAD_VALUE; 200 } else if (!strcmp(entryName, "..")) { 201 Directory *parent = dir->GetParent(); 202 if (parent && volume->GetVNode(parent->GetID(), &node) == B_OK) 203 *vnid = node->GetID(); 204 else 205 error = B_BAD_VALUE; 206 207 // ordinary entries 208 } else { 209 // find the entry 210 error = dir->FindAndGetNode(entryName, &node); 211 SET_ERROR(error, error); 212 if (error == B_OK) 213 *vnid = node->GetID(); 214 } 215 216 // get the node's type 217 if (error == B_OK) 218 *type = node->GetMode() & S_IFMT; 219 } else 220 SET_ERROR(error, B_ERROR); 221 RETURN_ERROR(error); 222 } 223 224 // ramfs_read_vnode 225 static status_t 226 ramfs_read_vnode(fs_volume fs, vnode_id vnid, fs_vnode *node, bool reenter) 227 { 228 // FUNCTION_START(); 229 FUNCTION(("node: %Ld\n", vnid)); 230 Volume *volume = (Volume*)fs; 231 Node *foundNode = NULL; 232 status_t error = B_OK; 233 if (VolumeReadLocker locker = volume) { 234 error = volume->FindNode(vnid, &foundNode); 235 if (error == B_OK) 236 *node = foundNode; 237 } else 238 SET_ERROR(error, B_ERROR); 239 RETURN_ERROR(error); 240 } 241 242 // ramfs_write_vnode 243 static status_t 244 ramfs_write_vnode(fs_volume /*fs*/, fs_vnode DARG(_node), bool /*reenter*/) 245 { 246 // DANGER: If dbg_printf() is used, this thread will enter another FS and 247 // even perform a write operation. The is dangerous here, since this hook 248 // may be called out of the other FSs, since, for instance a put_vnode() 249 // called from another FS may cause the VFS layer to free vnodes and thus 250 // invoke this hook. 251 // FUNCTION_START(); 252 //FUNCTION(("node: %Ld\n", ((Node*)_node)->GetID())); 253 status_t error = B_OK; 254 RETURN_ERROR(error); 255 } 256 257 // ramfs_remove_vnode 258 static status_t 259 ramfs_remove_vnode(fs_volume fs, fs_vnode _node, bool /*reenter*/) 260 { 261 FUNCTION(("node: %Ld\n", ((Node*)_node)->GetID())); 262 Volume *volume = (Volume*)fs; 263 Node *node = (Node*)_node; 264 status_t error = B_OK; 265 if (VolumeWriteLocker locker = volume) { 266 volume->NodeRemoved(node); 267 delete node; 268 } else 269 SET_ERROR(error, B_ERROR); 270 RETURN_ERROR(error); 271 } 272 273 274 // #pragma mark - Nodes 275 276 277 // ramfs_ioctl 278 static status_t 279 ramfs_ioctl(fs_volume fs, fs_vnode /*node*/, fs_cookie /*cookie*/, ulong cmd, 280 void *buffer, size_t /*length*/) 281 282 { 283 FUNCTION_START(); 284 Volume *volume = (Volume*)fs; 285 status_t error = B_OK; 286 switch (cmd) { 287 case RAMFS_IOCTL_GET_ALLOCATION_INFO: 288 { 289 if (buffer) { 290 if (VolumeReadLocker locker = volume) { 291 AllocationInfo *info = (AllocationInfo*)buffer; 292 volume->GetAllocationInfo(*info); 293 } else 294 SET_ERROR(error, B_ERROR); 295 } else 296 SET_ERROR(error, B_BAD_VALUE); 297 break; 298 } 299 case RAMFS_IOCTL_DUMP_INDEX: 300 { 301 if (buffer) { 302 if (VolumeReadLocker locker = volume) { 303 const char *name = (const char*)buffer; 304 PRINT((" RAMFS_IOCTL_DUMP_INDEX, `%s'\n", name)); 305 IndexDirectory *indexDir = volume->GetIndexDirectory(); 306 if (indexDir) { 307 if (Index *index = indexDir->FindIndex(name)) 308 index->Dump(); 309 else 310 SET_ERROR(error, B_ENTRY_NOT_FOUND); 311 } else 312 SET_ERROR(error, B_ENTRY_NOT_FOUND); 313 } else 314 SET_ERROR(error, B_ERROR); 315 } else 316 SET_ERROR(error, B_BAD_VALUE); 317 break; 318 } 319 default: 320 error = B_BAD_VALUE; 321 break; 322 } 323 RETURN_ERROR(error); 324 } 325 326 // ramfs_set_flags 327 static status_t 328 ramfs_set_flags(fs_volume /*fs*/, fs_vnode /*node*/, fs_cookie /*cookie*/, 329 int /*flags*/) 330 { 331 FUNCTION_START(); 332 // TODO:... 333 return B_OK; 334 } 335 336 // ramfs_fsync 337 static status_t 338 ramfs_fsync(fs_volume /*fs*/, fs_vnode /*node*/) 339 { 340 FUNCTION_START(); 341 return B_OK; 342 } 343 344 // ramfs_read_symlink 345 static status_t 346 ramfs_read_symlink(fs_volume fs, fs_vnode _node, char *buffer, 347 size_t *bufferSize) 348 { 349 FUNCTION_START(); 350 Volume *volume = (Volume*)fs; 351 Node *node = (Node*)_node; 352 status_t error = B_OK; 353 if (VolumeReadLocker locker = volume) { 354 // read symlinks only 355 if (!node->IsSymLink()) 356 error = B_BAD_VALUE; 357 if (error == B_OK) { 358 if (SymLink *symLink = dynamic_cast<SymLink*>(node)) { 359 // copy the link contents 360 size_t toRead = min(*bufferSize, 361 symLink->GetLinkedPathLength()); 362 if (toRead > 0) 363 memcpy(buffer, symLink->GetLinkedPath(), toRead); 364 *bufferSize = toRead; 365 } else { 366 FATAL(("Node %Ld pretends to be a SymLink, but isn't!\n", 367 node->GetID())); 368 error = B_BAD_VALUE; 369 } 370 } 371 } else 372 SET_ERROR(error, B_ERROR); 373 RETURN_ERROR(error); 374 } 375 376 // ramfs_create_symlink 377 static status_t 378 ramfs_create_symlink(fs_volume fs, fs_vnode _dir, const char *name, 379 const char *path, int mode) 380 { 381 FUNCTION(("name: `%s', path: `%s'\n", name, path)); 382 Volume *volume = (Volume*)fs; 383 Directory *dir = dynamic_cast<Directory*>((Node*)_dir); 384 status_t error = B_OK; 385 // check name 386 if (!name || *name == '\0') { 387 SET_ERROR(error, B_BAD_VALUE); 388 // check directory 389 } else if (!dir) { 390 SET_ERROR(error, B_BAD_VALUE); 391 } else if (VolumeWriteLocker locker = volume) { 392 NodeMTimeUpdater mTimeUpdater(dir); 393 // directory deleted? 394 bool removed; 395 if (get_vnode_removed(volume->GetID(), dir->GetID(), &removed) != B_OK 396 || removed) { 397 SET_ERROR(error, B_NOT_ALLOWED); 398 } 399 // check directory write permissions 400 error = dir->CheckPermissions(ACCESS_W); 401 Node *node = NULL; 402 if (error == B_OK) { 403 // check if entry does already exist 404 if (dir->FindNode(name, &node) == B_OK) { 405 SET_ERROR(error, B_FILE_EXISTS); 406 } else { 407 // entry doesn't exist: create a symlink 408 SymLink *symLink = NULL; 409 error = dir->CreateSymLink(name, path, &symLink); 410 if (error == B_OK) { 411 node = symLink; 412 // set permissions, owner and group 413 node->SetMode(mode); 414 node->SetUID(geteuid()); 415 node->SetGID(getegid()); 416 // put the node 417 volume->PutVNode(node->GetID()); 418 } 419 } 420 } 421 NodeMTimeUpdater mTimeUpdater2(node); 422 // notify listeners 423 if (error == B_OK) { 424 notify_entry_created(volume->GetID(), dir->GetID(), name, 425 node->GetID()); 426 } 427 } else 428 SET_ERROR(error, B_ERROR); 429 RETURN_ERROR(error); 430 } 431 432 // ramfs_link 433 static status_t 434 ramfs_link(fs_volume fs, fs_vnode _dir, const char *name, fs_vnode _node) 435 { 436 FUNCTION(("name: `%s'\n", name)); 437 Volume *volume = (Volume*)fs; 438 Directory *dir = dynamic_cast<Directory*>((Node*)_dir); 439 Node *node = (Node*)_node; 440 status_t error = B_OK; 441 // check directory 442 if (!dir) { 443 SET_ERROR(error, B_BAD_VALUE); 444 } else if (VolumeWriteLocker locker = volume) { 445 NodeMTimeUpdater mTimeUpdater(dir); 446 // directory deleted? 447 bool removed; 448 if (get_vnode_removed(volume->GetID(), dir->GetID(), &removed) != B_OK 449 || removed) { 450 SET_ERROR(error, B_NOT_ALLOWED); 451 } 452 // check directory write permissions 453 error = dir->CheckPermissions(ACCESS_W); 454 Entry *entry = NULL; 455 if (error == B_OK) { 456 // check if entry does already exist 457 if (dir->FindEntry(name, &entry) == B_OK) { 458 SET_ERROR(error, B_FILE_EXISTS); 459 } else { 460 // entry doesn't exist: create a link 461 error = dir->CreateEntry(node, name); 462 } 463 } 464 // notify listeners 465 if (error == B_OK) { 466 notify_entry_created(volume->GetID(), dir->GetID(), name, 467 node->GetID()); 468 } 469 } else 470 SET_ERROR(error, B_ERROR); 471 RETURN_ERROR(error); 472 } 473 474 // ramfs_unlink 475 static status_t 476 ramfs_unlink(fs_volume fs, fs_vnode _dir, const char *name) 477 { 478 FUNCTION(("name: `%s'\n", name)); 479 Volume *volume = (Volume*)fs; 480 Directory *dir = dynamic_cast<Directory*>((Node*)_dir); 481 status_t error = B_OK; 482 // check name 483 if (!name || *name == '\0' || !strcmp(name, ".") || !strcmp(name, "..")) { 484 SET_ERROR(error, B_BAD_VALUE); 485 // check node 486 } else if (!dir) { 487 SET_ERROR(error, B_BAD_VALUE); 488 } else if (VolumeWriteLocker locker = volume) { 489 NodeMTimeUpdater mTimeUpdater(dir); 490 // check directory write permissions 491 error = dir->CheckPermissions(ACCESS_W); 492 vnode_id nodeID = -1; 493 if (error == B_OK) { 494 // check if entry exists 495 Node *node = NULL; 496 Entry *entry = NULL; 497 if (dir->FindAndGetNode(name, &node, &entry) == B_OK) { 498 nodeID = node->GetID(); 499 // unlink the entry, if it isn't a non-empty directory 500 if (node->IsDirectory() 501 && !dynamic_cast<Directory*>(node)->IsEmpty()) { 502 SET_ERROR(error, B_DIRECTORY_NOT_EMPTY); 503 } else 504 error = dir->DeleteEntry(entry); 505 volume->PutVNode(node); 506 } else 507 SET_ERROR(error, B_ENTRY_NOT_FOUND); 508 } 509 // notify listeners 510 if (error == B_OK) 511 notify_entry_removed(volume->GetID(), dir->GetID(), name, nodeID); 512 } else 513 SET_ERROR(error, B_ERROR); 514 RETURN_ERROR(error); 515 } 516 517 // ramfs_rename 518 static status_t 519 ramfs_rename(fs_volume fs, fs_vnode _oldDir, const char *oldName, 520 fs_vnode _newDir, const char *newName) 521 { 522 Volume *volume = (Volume*)fs; 523 Directory *oldDir = dynamic_cast<Directory*>((Node*)_oldDir); 524 Directory *newDir = dynamic_cast<Directory*>((Node*)_newDir); 525 status_t error = B_OK; 526 527 // check name 528 if (!oldName || *oldName == '\0' 529 || !strcmp(oldName, ".") || !strcmp(oldName, "..") 530 || !newName || *newName == '\0' 531 || !strcmp(newName, ".") || !strcmp(newName, "..")) { 532 SET_ERROR(error, B_BAD_VALUE); 533 534 // check nodes 535 } else if (!oldDir || !newDir) { 536 SET_ERROR(error, B_BAD_VALUE); 537 538 // check if the entry isn't actually moved or renamed 539 } else if (oldDir == newDir && !strcmp(oldName, newName)) { 540 SET_ERROR(error, B_BAD_VALUE); 541 } else if (VolumeWriteLocker locker = volume) { 542 FUNCTION(("old dir: %Ld, old name: `%s', new dir: %Ld, new name: `%s'\n", 543 oldDir->GetID(), oldName, newDir->GetID(), newName)); 544 NodeMTimeUpdater mTimeUpdater1(oldDir); 545 NodeMTimeUpdater mTimeUpdater2(newDir); 546 547 // target directory deleted? 548 bool removed; 549 if (get_vnode_removed(volume->GetID(), newDir->GetID(), &removed) 550 != B_OK 551 || removed) { 552 SET_ERROR(error, B_NOT_ALLOWED); 553 } 554 555 // check directory write permissions 556 if (error == B_OK) 557 error = oldDir->CheckPermissions(ACCESS_W); 558 if (error == B_OK) 559 error = newDir->CheckPermissions(ACCESS_W); 560 561 Node *node = NULL; 562 Entry *entry = NULL; 563 if (error == B_OK) { 564 // check if entry exists 565 if (oldDir->FindAndGetNode(oldName, &node, &entry) != B_OK) { 566 SET_ERROR(error, B_ENTRY_NOT_FOUND); 567 } else { 568 if (oldDir != newDir) { 569 // check whether the entry is a descendent of the target 570 // directory 571 for (Directory *parent = newDir; 572 parent; 573 parent = parent->GetParent()) { 574 if (parent == node) { 575 error = B_BAD_VALUE; 576 break; 577 } else if (parent == oldDir) 578 break; 579 } 580 } 581 } 582 583 // check the target directory situation 584 Node *clobberNode = NULL; 585 Entry *clobberEntry = NULL; 586 if (error == B_OK) { 587 if (newDir->FindAndGetNode(newName, &clobberNode, 588 &clobberEntry) == B_OK) { 589 if (clobberNode->IsDirectory() 590 && !dynamic_cast<Directory*>(clobberNode)->IsEmpty()) { 591 SET_ERROR(error, B_NAME_IN_USE); 592 } 593 } 594 } 595 596 // do the job 597 if (error == B_OK) { 598 // temporarily acquire an additional reference to make 599 // sure the node isn't deleted when we remove the entry 600 error = node->AddReference(); 601 if (error == B_OK) { 602 // delete the original entry 603 error = oldDir->DeleteEntry(entry); 604 if (error == B_OK) { 605 // create the new one/relink the target entry 606 if (clobberEntry) 607 error = clobberEntry->Link(node); 608 else 609 error = newDir->CreateEntry(node, newName); 610 611 if (error == B_OK) { 612 // send a "removed" notification for the clobbered 613 // entry 614 if (clobberEntry) { 615 notify_entry_removed(volume->GetID(), 616 newDir->GetID(), newName, 617 clobberNode->GetID()); 618 } 619 } else { 620 // try to recreate the original entry, in case of 621 // failure 622 newDir->CreateEntry(node, oldName); 623 } 624 } 625 node->RemoveReference(); 626 } 627 } 628 629 // release the entries 630 if (clobberEntry) 631 volume->PutVNode(clobberNode); 632 if (entry) 633 volume->PutVNode(node); 634 } 635 636 // notify listeners 637 if (error == B_OK) { 638 notify_entry_moved(volume->GetID(), oldDir->GetID(), oldName, 639 newDir->GetID(), newName, node->GetID()); 640 } 641 } else 642 SET_ERROR(error, B_ERROR); 643 644 RETURN_ERROR(error); 645 } 646 647 // ramfs_access 648 static status_t 649 ramfs_access(fs_volume fs, fs_vnode _node, int mode) 650 { 651 FUNCTION_START(); 652 Volume *volume = (Volume*)fs; 653 Node *node = (Node*)_node; 654 status_t error = B_OK; 655 if (VolumeReadLocker locker = volume) { 656 error = node->CheckPermissions(mode); 657 } else 658 SET_ERROR(error, B_ERROR); 659 RETURN_ERROR(error); 660 } 661 662 // ramfs_read_stat 663 static status_t 664 ramfs_read_stat(fs_volume fs, fs_vnode _node, struct stat *st) 665 { 666 // FUNCTION_START(); 667 Volume *volume = (Volume*)fs; 668 Node *node = (Node*)_node; 669 FUNCTION(("node: %Ld\n", node->GetID())); 670 status_t error = B_OK; 671 if (VolumeReadLocker locker = volume) { 672 st->st_dev = volume->GetID(); 673 st->st_ino = node->GetID(); 674 st->st_mode = node->GetMode(); 675 st->st_nlink = node->GetRefCount(); 676 st->st_uid = node->GetUID(); 677 st->st_gid = node->GetGID(); 678 st->st_size = node->GetSize(); 679 st->st_blksize = kOptimalIOSize; 680 st->st_atime = node->GetATime(); 681 st->st_mtime = node->GetMTime(); 682 st->st_ctime = node->GetCTime(); 683 st->st_crtime = node->GetCrTime(); 684 } else 685 SET_ERROR(error, B_ERROR); 686 RETURN_ERROR(error); 687 } 688 689 // ramfs_write_stat 690 static status_t 691 ramfs_write_stat(fs_volume fs, fs_vnode _node, const struct stat *st, 692 uint32 mask) 693 { 694 FUNCTION(("mask: %lx\n", mask)); 695 Volume *volume = (Volume*)fs; 696 Node *node = (Node*)_node; 697 status_t error = B_OK; 698 if (VolumeWriteLocker locker = volume) { 699 NodeMTimeUpdater mTimeUpdater(node); 700 // check permissions 701 error = node->CheckPermissions(ACCESS_W); 702 // size 703 if (error == B_OK && (mask & FS_WRITE_STAT_SIZE)) 704 error = node->SetSize(st->st_size); 705 if (error == B_OK) { 706 // permissions 707 if (mask & FS_WRITE_STAT_MODE) { 708 node->SetMode(node->GetMode() & ~S_IUMSK 709 | st->st_mode & S_IUMSK); 710 } 711 // UID 712 if (mask & FS_WRITE_STAT_UID) 713 node->SetUID(st->st_uid); 714 // GID 715 if (mask & FS_WRITE_STAT_GID) 716 node->SetGID(st->st_gid); 717 // mtime 718 if (mask & FS_WRITE_STAT_MTIME) 719 node->SetMTime(st->st_mtime); 720 // crtime 721 if (mask & FS_WRITE_STAT_CRTIME) 722 node->SetCrTime(st->st_crtime); 723 } 724 // notify listeners 725 if (error == B_OK) 726 notify_if_stat_changed(volume, node); 727 } else 728 SET_ERROR(error, B_ERROR); 729 RETURN_ERROR(error); 730 } 731 732 733 // #pragma mark - Files 734 735 736 // FileCookie 737 class FileCookie { 738 public: 739 FileCookie(int openMode) : fOpenMode(openMode), fLastNotificationTime(0) {} 740 741 inline int GetOpenMode() { return fOpenMode; } 742 743 inline bigtime_t GetLastNotificationTime() 744 { return fLastNotificationTime; } 745 746 inline bool NotificationIntervalElapsed(bool set = false) 747 { 748 bigtime_t currentTime = system_time(); 749 bool result = (currentTime - fLastNotificationTime 750 > kNotificationInterval); 751 if (set && result) 752 fLastNotificationTime = currentTime; 753 return result; 754 } 755 756 private: 757 int fOpenMode; 758 bigtime_t fLastNotificationTime; 759 }; 760 761 // ramfs_create 762 static status_t 763 ramfs_create(fs_volume fs, fs_vnode _dir, const char *name, int openMode, 764 int mode, fs_cookie *_cookie, vnode_id *vnid) 765 { 766 // FUNCTION_START(); 767 FUNCTION(("name: `%s', open mode: %x, mode: %x\n", name, openMode, mode)); 768 Volume *volume = (Volume*)fs; 769 Directory *dir = dynamic_cast<Directory*>((Node*)_dir); 770 status_t error = B_OK; 771 // check name 772 if (!name || *name == '\0') { 773 SET_ERROR(error, B_BAD_VALUE); 774 // check directory 775 } else if (!dir) { 776 SET_ERROR(error, B_BAD_VALUE); 777 } else if (VolumeWriteLocker locker = volume) { 778 NodeMTimeUpdater mTimeUpdater(dir); 779 // directory deleted? 780 bool removed; 781 if (get_vnode_removed(volume->GetID(), dir->GetID(), &removed) != B_OK 782 || removed) { 783 SET_ERROR(error, B_NOT_ALLOWED); 784 } 785 // create the file cookie 786 FileCookie *cookie = NULL; 787 if (error == B_OK) { 788 cookie = new(nothrow) FileCookie(openMode); 789 if (!cookie) 790 SET_ERROR(error, B_NO_MEMORY); 791 } 792 Node *node = NULL; 793 if (error == B_OK) { 794 // check if entry does already exist 795 if (dir->FindNode(name, &node) == B_OK) { 796 // entry does already exist 797 // fail, if we shall fail, when the file exists 798 if (openMode & O_EXCL) { 799 SET_ERROR(error, B_FILE_EXISTS); 800 // don't create a file over an existing directory or symlink 801 } else if (!node->IsFile()) { 802 SET_ERROR(error, B_NOT_ALLOWED); 803 // the user must have write permission for an existing entry 804 } else if ((error = node->CheckPermissions(ACCESS_W)) 805 == B_OK) { 806 // truncate, if requested 807 if (openMode & O_TRUNC) 808 error = node->SetSize(0); 809 // we ignore the supplied permissions in this case 810 // get vnode 811 if (error == B_OK) { 812 *vnid = node->GetID(); 813 error = volume->GetVNode(node->GetID(), &node); 814 } 815 } 816 // the user must have dir write permission to create a new entry 817 } else if ((error = dir->CheckPermissions(ACCESS_W)) == B_OK) { 818 // entry doesn't exist: create a file 819 File *file = NULL; 820 error = dir->CreateFile(name, &file); 821 if (error == B_OK) { 822 node = file; 823 *vnid = node->GetID(); 824 // set permissions, owner and group 825 node->SetMode(mode); 826 node->SetUID(geteuid()); 827 node->SetGID(getegid()); 828 } 829 } 830 // set result / cleanup on failure 831 if (error == B_OK) 832 *_cookie = cookie; 833 else if (cookie) 834 delete cookie; 835 } 836 NodeMTimeUpdater mTimeUpdater2(node); 837 // notify listeners 838 if (error == B_OK) 839 notify_entry_created(volume->GetID(), dir->GetID(), name, *vnid); 840 } else 841 SET_ERROR(error, B_ERROR); 842 RETURN_ERROR(error); 843 } 844 845 // ramfs_open 846 static status_t 847 ramfs_open(fs_volume fs, fs_vnode _node, int openMode, fs_cookie *_cookie) 848 { 849 // FUNCTION_START(); 850 Volume *volume = (Volume*)fs; 851 Node *node = (Node*)_node; 852 FUNCTION(("node: %Ld\n", node->GetID())); 853 status_t error = B_OK; 854 if (VolumeReadLocker locker = volume) { 855 // directory can be opened read-only 856 if (node->IsDirectory() && (openMode & O_RWMASK)) 857 openMode &= ~O_RWMASK; 858 int accessMode = open_mode_to_access(openMode); 859 // truncating requires write permission 860 if (error == B_OK && (openMode & O_TRUNC)) 861 accessMode |= ACCESS_W; 862 // check open mode against permissions 863 if (error == B_OK) 864 error = node->CheckPermissions(accessMode); 865 // create the cookie 866 FileCookie *cookie = NULL; 867 if (error == B_OK) { 868 cookie = new(nothrow) FileCookie(openMode); 869 if (!cookie) 870 SET_ERROR(error, B_NO_MEMORY); 871 } 872 // truncate if requested 873 if (error == B_OK && (openMode & O_TRUNC)) 874 error = node->SetSize(0); 875 NodeMTimeUpdater mTimeUpdater(node); 876 // set result / cleanup on failure 877 if (error == B_OK) 878 *_cookie = cookie; 879 else if (cookie) 880 delete cookie; 881 } else 882 SET_ERROR(error, B_ERROR); 883 RETURN_ERROR(error); 884 } 885 886 // ramfs_close 887 static status_t 888 ramfs_close(fs_volume fs, fs_vnode _node, fs_cookie /*cookie*/) 889 { 890 // FUNCTION_START(); 891 Volume *volume = (Volume*)fs; 892 Node *node = (Node*)_node; 893 FUNCTION(("node: %Ld\n", node->GetID())); 894 status_t error = B_OK; 895 // notify listeners 896 if (VolumeReadLocker locker = volume) { 897 notify_if_stat_changed(volume, node); 898 } else 899 SET_ERROR(error, B_ERROR); 900 return B_OK; 901 902 } 903 904 // ramfs_free_cookie 905 static status_t 906 ramfs_free_cookie(fs_volume /*fs*/, fs_vnode /*_node*/, fs_cookie _cookie) 907 { 908 FUNCTION_START(); 909 FileCookie *cookie = (FileCookie*)_cookie; 910 delete cookie; 911 return B_OK; 912 } 913 914 // ramfs_read 915 static status_t 916 ramfs_read(fs_volume fs, fs_vnode _node, fs_cookie _cookie, off_t pos, 917 void *buffer, size_t *bufferSize) 918 { 919 // FUNCTION_START(); 920 Volume *volume = (Volume*)fs; 921 Node *node = (Node*)_node; 922 FileCookie *cookie = (FileCookie*)_cookie; 923 // FUNCTION(("((%lu, %lu), %Ld, %p, %lu)\n", node->GetDirID(), 924 // node->GetObjectID(), pos, buffer, *bufferSize)); 925 status_t error = B_OK; 926 if (VolumeReadLocker locker = volume) { 927 // don't read anything but files 928 if (!node->IsFile()) 929 SET_ERROR(error, B_BAD_VALUE); 930 // check, if reading is allowed 931 int rwMode = cookie->GetOpenMode() & O_RWMASK; 932 if (error == B_OK && rwMode != O_RDONLY && rwMode != O_RDWR) 933 SET_ERROR(error, B_FILE_ERROR); 934 // read 935 if (error == B_OK) { 936 if (File *file = dynamic_cast<File*>(node)) 937 error = file->ReadAt(pos, buffer, *bufferSize, bufferSize); 938 else { 939 FATAL(("Node %Ld pretends to be a File, but isn't!\n", 940 node->GetID())); 941 error = B_BAD_VALUE; 942 } 943 } 944 } else 945 SET_ERROR(error, B_ERROR); 946 RETURN_ERROR(error); 947 } 948 949 // ramfs_write 950 static status_t 951 ramfs_write(fs_volume fs, fs_vnode _node, fs_cookie _cookie, off_t pos, 952 const void *buffer, size_t *bufferSize) 953 { 954 // FUNCTION_START(); 955 Volume *volume = (Volume*)fs; 956 Node *node = (Node*)_node; 957 FileCookie *cookie = (FileCookie*)_cookie; 958 // FUNCTION(("((%lu, %lu), %Ld, %p, %lu)\n", node->GetDirID(), 959 // node->GetObjectID(), pos, buffer, *bufferSize)); 960 status_t error = B_OK; 961 if (VolumeWriteLocker locker = volume) { 962 // don't write anything but files 963 if (!node->IsFile()) 964 SET_ERROR(error, B_BAD_VALUE); 965 if (error == B_OK) { 966 // check, if reading is allowed 967 int rwMode = cookie->GetOpenMode() & O_RWMASK; 968 if (error == B_OK && rwMode != O_WRONLY && rwMode != O_RDWR) 969 SET_ERROR(error, B_FILE_ERROR); 970 if (error == B_OK) { 971 // reset the position, if opened in append mode 972 if (cookie->GetOpenMode() & O_APPEND) 973 pos = node->GetSize(); 974 // write 975 if (File *file = dynamic_cast<File*>(node)) { 976 error = file->WriteAt(pos, buffer, *bufferSize, 977 bufferSize); 978 } else { 979 FATAL(("Node %Ld pretends to be a File, but isn't!\n", 980 node->GetID())); 981 error = B_BAD_VALUE; 982 } 983 } 984 } 985 // notify listeners 986 if (error == B_OK && cookie->NotificationIntervalElapsed(true)) 987 notify_if_stat_changed(volume, node); 988 NodeMTimeUpdater mTimeUpdater(node); 989 } else 990 SET_ERROR(error, B_ERROR); 991 RETURN_ERROR(error); 992 } 993 994 995 // #pragma mark - Directories 996 997 998 // DirectoryCookie 999 class DirectoryCookie { 1000 public: 1001 DirectoryCookie(Directory *directory = NULL) 1002 : fIterator(directory), 1003 fDotIndex(DOT_INDEX), 1004 // debugging 1005 fIteratorID(atomic_add(&fNextIteratorID, 1)), 1006 fGetNextCounter(0) 1007 { 1008 } 1009 1010 void Unset() { fIterator.Unset(); } 1011 1012 // EntryIterator *GetIterator() const { return &fIterator; } 1013 1014 status_t GetNext(ino_t *nodeID, const char **entryName) 1015 { 1016 fGetNextCounter++; 1017 status_t error = B_OK; 1018 if (fDotIndex == DOT_INDEX) { 1019 // "." 1020 Node *entry = fIterator.GetDirectory(); 1021 *nodeID = entry->GetID(); 1022 *entryName = "."; 1023 fDotIndex++; 1024 } else if (fDotIndex == DOT_DOT_INDEX) { 1025 // ".." 1026 Directory *dir = fIterator.GetDirectory(); 1027 if (dir->GetParent()) 1028 *nodeID = dir->GetParent()->GetID(); 1029 else 1030 *nodeID = dir->GetID(); 1031 *entryName = ".."; 1032 fDotIndex++; 1033 } else { 1034 // ordinary entries 1035 Entry *entry = NULL; 1036 error = fIterator.GetNext(&entry); 1037 if (error == B_OK) { 1038 *nodeID = entry->GetNode()->GetID(); 1039 *entryName = entry->GetName(); 1040 } 1041 } 1042 PRINT(("EntryIterator %ld, GetNext() counter: %ld, entry: %p (%Ld)\n", 1043 fIteratorID, fGetNextCounter, fIterator.GetCurrent(), 1044 (fIterator.GetCurrent() ? fIterator.GetCurrent()->GetNode()->GetID() : -1))); 1045 return error; 1046 } 1047 1048 status_t Rewind() 1049 { 1050 fDotIndex = DOT_INDEX; 1051 return fIterator.Rewind(); 1052 } 1053 1054 status_t Suspend() { return fIterator.Suspend(); } 1055 status_t Resume() { return fIterator.Resume(); } 1056 1057 private: 1058 enum { 1059 DOT_INDEX = 0, 1060 DOT_DOT_INDEX = 1, 1061 ENTRY_INDEX = 2, 1062 }; 1063 1064 private: 1065 EntryIterator fIterator; 1066 uint32 fDotIndex; 1067 1068 // debugging 1069 int32 fIteratorID; 1070 int32 fGetNextCounter; 1071 static vint32 fNextIteratorID; 1072 }; 1073 vint32 DirectoryCookie::fNextIteratorID = 0; 1074 1075 // ramfs_create_dir 1076 static status_t 1077 ramfs_create_dir(fs_volume fs, fs_vnode _dir, const char *name, 1078 int mode, vnode_id *_vnid) 1079 { 1080 FUNCTION(("name: `%s', mode: %x\n", name, mode)); 1081 Volume *volume = (Volume*)fs; 1082 Directory *dir = dynamic_cast<Directory*>((Node*)_dir); 1083 status_t error = B_OK; 1084 // check name 1085 if (!name || *name == '\0') { 1086 SET_ERROR(error, B_BAD_VALUE); 1087 // check directory 1088 } else if (!dir) { 1089 SET_ERROR(error, B_BAD_VALUE); 1090 } else if (VolumeWriteLocker locker = volume) { 1091 NodeMTimeUpdater mTimeUpdater(dir); 1092 // directory deleted? 1093 bool removed; 1094 if (get_vnode_removed(volume->GetID(), dir->GetID(), &removed) != B_OK 1095 || removed) { 1096 SET_ERROR(error, B_NOT_ALLOWED); 1097 } 1098 // check directory write permissions 1099 error = dir->CheckPermissions(ACCESS_W); 1100 Node *node = NULL; 1101 if (error == B_OK) { 1102 // check if entry does already exist 1103 if (dir->FindNode(name, &node) == B_OK) { 1104 SET_ERROR(error, B_FILE_EXISTS); 1105 } else { 1106 // entry doesn't exist: create a directory 1107 Directory *newDir = NULL; 1108 error = dir->CreateDirectory(name, &newDir); 1109 if (error == B_OK) { 1110 node = newDir; 1111 // set permissions, owner and group 1112 node->SetMode(mode); 1113 node->SetUID(geteuid()); 1114 node->SetGID(getegid()); 1115 // put the node 1116 volume->PutVNode(node->GetID()); 1117 *_vnid = node->GetID(); 1118 } 1119 } 1120 } 1121 NodeMTimeUpdater mTimeUpdater2(node); 1122 // notify listeners 1123 if (error == B_OK) { 1124 notify_entry_created(volume->GetID(), dir->GetID(), name, 1125 node->GetID()); 1126 } 1127 } else 1128 SET_ERROR(error, B_ERROR); 1129 RETURN_ERROR(error); 1130 } 1131 1132 // ramfs_remove_dir 1133 static status_t 1134 ramfs_remove_dir(fs_volume fs, fs_vnode _dir, const char *name) 1135 { 1136 FUNCTION(("name: `%s'\n", name)); 1137 Volume *volume = (Volume*)fs; 1138 Directory *dir = dynamic_cast<Directory*>((Node*)_dir); 1139 status_t error = B_OK; 1140 // check name 1141 if (!name || *name == '\0' || !strcmp(name, ".") || !strcmp(name, "..")) { 1142 SET_ERROR(error, B_BAD_VALUE); 1143 // check node 1144 } else if (!dir) { 1145 SET_ERROR(error, B_BAD_VALUE); 1146 } else if (VolumeWriteLocker locker = volume) { 1147 NodeMTimeUpdater mTimeUpdater(dir); 1148 // check directory write permissions 1149 error = dir->CheckPermissions(ACCESS_W); 1150 vnode_id nodeID = -1; 1151 if (error == B_OK) { 1152 // check if entry exists 1153 Node *node = NULL; 1154 Entry *entry = NULL; 1155 if (dir->FindAndGetNode(name, &node, &entry) == B_OK) { 1156 nodeID = node->GetID(); 1157 if (!node->IsDirectory()) { 1158 SET_ERROR(error, B_NOT_A_DIRECTORY); 1159 } else if (!dynamic_cast<Directory*>(node)->IsEmpty()) { 1160 SET_ERROR(error, B_DIRECTORY_NOT_EMPTY); 1161 } else 1162 error = dir->DeleteEntry(entry); 1163 volume->PutVNode(node); 1164 } else 1165 SET_ERROR(error, B_ENTRY_NOT_FOUND); 1166 } 1167 // notify listeners 1168 if (error == B_OK) 1169 notify_entry_removed(volume->GetID(), dir->GetID(), name, nodeID); 1170 } else 1171 SET_ERROR(error, B_ERROR); 1172 RETURN_ERROR(error); 1173 } 1174 1175 // ramfs_open_dir 1176 static status_t 1177 ramfs_open_dir(fs_volume /*fs*/, fs_vnode _node, fs_cookie *_cookie) 1178 { 1179 // FUNCTION_START(); 1180 // Volume *volume = (Volume*)fs; 1181 Node *node = (Node*)_node; 1182 FUNCTION(("dir: (%Lu)\n", node->GetID())); 1183 // get the Directory 1184 status_t error = (node->IsDirectory() ? B_OK : B_BAD_VALUE); 1185 Directory *dir = NULL; 1186 if (error == B_OK) { 1187 dir = dynamic_cast<Directory*>(node); 1188 if (!dir) { 1189 FATAL(("Node %Ld pretends to be a Directory, but isn't!\n", 1190 node->GetID())); 1191 error = B_BAD_VALUE; 1192 } 1193 } 1194 // create a DirectoryCookie 1195 if (error == B_OK) { 1196 DirectoryCookie *cookie = new(nothrow) DirectoryCookie(dir); 1197 if (cookie) { 1198 error = cookie->Suspend(); 1199 if (error == B_OK) 1200 *_cookie = cookie; 1201 else 1202 delete cookie; 1203 } else 1204 SET_ERROR(error, B_NO_MEMORY); 1205 } 1206 FUNCTION_END(); 1207 RETURN_ERROR(error); 1208 } 1209 1210 // ramfs_close_dir 1211 static status_t 1212 ramfs_close_dir(fs_volume /*fs*/, fs_vnode DARG(_node), fs_cookie _cookie) 1213 { 1214 FUNCTION_START(); 1215 FUNCTION(("dir: (%Lu)\n", ((Node*)_node)->GetID())); 1216 // No locking needed, since the Directory is guaranteed to live at this 1217 // time and for iterators there is a separate locking. 1218 DirectoryCookie *cookie = (DirectoryCookie*)_cookie; 1219 cookie->Unset(); 1220 return B_OK; 1221 } 1222 1223 // ramfs_free_dir_cookie 1224 static status_t 1225 ramfs_free_dir_cookie(fs_volume /*fs*/, fs_vnode /*_node*/, fs_cookie _cookie) 1226 { 1227 FUNCTION_START(); 1228 DirectoryCookie *cookie = (DirectoryCookie*)_cookie; 1229 delete cookie; 1230 return B_OK; 1231 } 1232 1233 // ramfs_read_dir 1234 static status_t 1235 ramfs_read_dir(fs_volume fs, fs_vnode DARG(_node), fs_cookie _cookie, 1236 struct dirent *buffer, size_t bufferSize, uint32 *count) 1237 { 1238 FUNCTION_START(); 1239 Volume *volume = (Volume*)fs; 1240 DARG(Node *node = (Node*)_node; ) 1241 FUNCTION(("dir: (%Lu)\n", node->GetID())); 1242 DirectoryCookie *cookie = (DirectoryCookie*)_cookie; 1243 status_t error = B_OK; 1244 if (VolumeReadLocker locker = volume) { 1245 error = cookie->Resume(); 1246 if (error == B_OK) { 1247 // read one entry 1248 ino_t nodeID = -1; 1249 const char *name = NULL; 1250 if (cookie->GetNext(&nodeID, &name) == B_OK) { 1251 PRINT((" entry: `%s'\n", name)); 1252 size_t nameLen = strlen(name); 1253 // check, whether the entry fits into the buffer, 1254 // and fill it in 1255 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer; 1256 if (length <= bufferSize) { 1257 buffer->d_dev = volume->GetID(); 1258 buffer->d_ino = nodeID; 1259 memcpy(buffer->d_name, name, nameLen); 1260 buffer->d_name[nameLen] = '\0'; 1261 buffer->d_reclen = length; 1262 *count = 1; 1263 } else { 1264 SET_ERROR(error, B_BUFFER_OVERFLOW); 1265 } 1266 } else 1267 *count = 0; 1268 cookie->Suspend(); 1269 } 1270 } else 1271 SET_ERROR(error, B_ERROR); 1272 RETURN_ERROR(error); 1273 } 1274 1275 // ramfs_rewind_dir 1276 static status_t 1277 ramfs_rewind_dir(fs_volume /*fs*/, fs_vnode /*_node*/, fs_cookie _cookie) 1278 { 1279 FUNCTION_START(); 1280 // No locking needed, since the Directory is guaranteed to live at this 1281 // time and for iterators there is a separate locking. 1282 DirectoryCookie *cookie = (DirectoryCookie*)_cookie; 1283 // no need to Resume(), iterator remains suspended 1284 status_t error = cookie->Rewind(); 1285 RETURN_ERROR(error); 1286 } 1287 1288 1289 // #pragma mark - Attribute Directories 1290 1291 1292 // ramfs_open_attr_dir 1293 static status_t 1294 ramfs_open_attr_dir(fs_volume fs, fs_vnode _node, fs_cookie *cookie) 1295 { 1296 FUNCTION_START(); 1297 Volume *volume = (Volume*)fs; 1298 Node *node = (Node*)_node; 1299 status_t error = B_OK; 1300 if (VolumeReadLocker locker = volume) { 1301 // check permissions 1302 error = node->CheckPermissions(ACCESS_R); 1303 // create iterator 1304 AttributeIterator *iterator = NULL; 1305 if (error == B_OK) { 1306 iterator = new(nothrow) AttributeIterator(node); 1307 if (iterator) 1308 error = iterator->Suspend(); 1309 else 1310 SET_ERROR(error, B_NO_MEMORY); 1311 } 1312 // set result / cleanup on failure 1313 if (error == B_OK) 1314 *cookie = iterator; 1315 else 1316 delete iterator; 1317 } else 1318 SET_ERROR(error, B_ERROR); 1319 RETURN_ERROR(error); 1320 } 1321 1322 // ramfs_close_attr_dir 1323 static status_t 1324 ramfs_close_attr_dir(fs_volume /*fs*/, fs_vnode /*_node*/, fs_cookie cookie) 1325 { 1326 FUNCTION_START(); 1327 // No locking needed, since the Node is guaranteed to live at this time 1328 // and for iterators there is a separate locking. 1329 AttributeIterator *iterator = (AttributeIterator*)cookie; 1330 iterator->Unset(); 1331 return B_OK; 1332 } 1333 1334 // ramfs_free_attr_dir_cookie 1335 static status_t 1336 ramfs_free_attr_dir_cookie(fs_volume /*fs*/, fs_vnode /*_node*/, 1337 fs_cookie cookie) 1338 { 1339 FUNCTION_START(); 1340 // No locking needed, since the Node is guaranteed to live at this time 1341 // and for iterators there is a separate locking. 1342 AttributeIterator *iterator = (AttributeIterator*)cookie; 1343 delete iterator; 1344 return B_OK; 1345 } 1346 1347 // ramfs_read_attr_dir 1348 static status_t 1349 ramfs_read_attr_dir(fs_volume fs, fs_vnode _node, fs_cookie cookie, 1350 struct dirent *buffer, size_t bufferSize, uint32 *count) 1351 { 1352 FUNCTION_START(); 1353 Volume *volume = (Volume*)fs; 1354 AttributeIterator *iterator = (AttributeIterator*)cookie; 1355 status_t error = B_OK; 1356 if (VolumeReadLocker locker = volume) { 1357 error = iterator->Resume(); 1358 if (error == B_OK) { 1359 // get next attribute 1360 Attribute *attribute = NULL; 1361 if (iterator->GetNext(&attribute) == B_OK) { 1362 const char *name = attribute->GetName(); 1363 size_t nameLen = strlen(name); 1364 // check, whether the entry fits into the buffer, 1365 // and fill it in 1366 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer; 1367 if (length <= bufferSize) { 1368 buffer->d_dev = volume->GetID(); 1369 buffer->d_ino = -1; // attributes don't have a node ID 1370 memcpy(buffer->d_name, name, nameLen); 1371 buffer->d_name[nameLen] = '\0'; 1372 buffer->d_reclen = length; 1373 *count = 1; 1374 } else { 1375 SET_ERROR(error, B_BUFFER_OVERFLOW); 1376 } 1377 } else 1378 *count = 0; 1379 iterator->Suspend(); 1380 } 1381 } else 1382 SET_ERROR(error, B_ERROR); 1383 RETURN_ERROR(error); 1384 } 1385 1386 // ramfs_rewind_attr_dir 1387 static status_t 1388 ramfs_rewind_attr_dir(fs_volume /*fs*/, fs_vnode /*_node*/, fs_cookie cookie) 1389 { 1390 FUNCTION_START(); 1391 // No locking needed, since the Node is guaranteed to live at this time 1392 // and for iterators there is a separate locking. 1393 AttributeIterator *iterator = (AttributeIterator*)cookie; 1394 // no need to Resume(), iterator remains suspended 1395 status_t error = iterator->Rewind(); 1396 RETURN_ERROR(error); 1397 } 1398 1399 1400 // #pragma mark - Attributes 1401 1402 1403 // AttributeCookie 1404 class AttributeCookie { 1405 public: 1406 AttributeCookie() : fOpenMode(0), fLastNotificationTime(0) {} 1407 1408 status_t Init(const char* name, int openMode) 1409 { 1410 if (!fName.SetTo(name)) 1411 return B_NO_MEMORY; 1412 fOpenMode = openMode; 1413 1414 return B_OK; 1415 } 1416 1417 inline const char* GetName() const { return fName.GetString(); } 1418 1419 inline int GetOpenMode() const { return fOpenMode; } 1420 1421 inline bigtime_t GetLastNotificationTime() const 1422 { return fLastNotificationTime; } 1423 1424 inline bool NotificationIntervalElapsed(bool set = false) 1425 { 1426 bigtime_t currentTime = system_time(); 1427 bool result = (currentTime - fLastNotificationTime 1428 > kNotificationInterval); 1429 if (set && result) 1430 fLastNotificationTime = currentTime; 1431 return result; 1432 } 1433 1434 private: 1435 String fName; 1436 int fOpenMode; 1437 bigtime_t fLastNotificationTime; 1438 }; 1439 1440 // ramfs_create_attr 1441 static status_t 1442 ramfs_create_attr(fs_volume fs, fs_vnode _node, const char *name, uint32 type, 1443 int openMode, fs_cookie *_cookie) 1444 { 1445 1446 Volume *volume = (Volume*)fs; 1447 Node *node = (Node*)_node; 1448 1449 if (VolumeWriteLocker locker = volume) { 1450 // try to find the attribute 1451 Attribute *attribute = NULL; 1452 node->FindAttribute(name, &attribute); 1453 1454 // in case the attribute exists we fail if required by the openMode 1455 if (attribute && (openMode & O_EXCL)) 1456 RETURN_ERROR(B_FILE_EXISTS); 1457 1458 // creating and truncating require write permission 1459 int accessMode = open_mode_to_access(openMode); 1460 if (!attribute || (openMode & O_TRUNC)) 1461 accessMode |= ACCESS_W; 1462 1463 // check required permissions against node permissions 1464 status_t error = node->CheckPermissions(accessMode); 1465 if (error != B_OK) 1466 RETURN_ERROR(error); 1467 1468 // create the cookie 1469 AttributeCookie *cookie = new(nothrow) AttributeCookie(); 1470 if (!cookie) 1471 return B_NO_MEMORY; 1472 ObjectDeleter<AttributeCookie> cookieDeleter(cookie); 1473 1474 // init the cookie 1475 error = cookie->Init(name, openMode); 1476 if (error != B_OK) 1477 RETURN_ERROR(error); 1478 1479 // if not existing yet, create the attribute and set its type 1480 if (!attribute) { 1481 error = node->CreateAttribute(name, &attribute); 1482 if (error != B_OK) 1483 RETURN_ERROR(error); 1484 1485 attribute->SetType(type); 1486 1487 notify_attribute_changed(volume->GetID(), node->GetID(), name, 1488 B_ATTR_CREATED); 1489 1490 // else truncate if requested 1491 } else if (openMode & O_TRUNC) { 1492 error = attribute->SetSize(0); 1493 if (error != B_OK) 1494 return error; 1495 1496 notify_attribute_changed(volume->GetID(), node->GetID(), name, 1497 B_ATTR_CHANGED); 1498 } 1499 NodeMTimeUpdater mTimeUpdater(node); 1500 1501 // success 1502 cookieDeleter.Detach(); 1503 *_cookie = cookie; 1504 } else 1505 RETURN_ERROR(B_ERROR); 1506 1507 return B_OK; 1508 } 1509 1510 // ramfs_open_attr 1511 static status_t 1512 ramfs_open_attr(fs_volume fs, fs_vnode _node, const char *name, int openMode, 1513 fs_cookie *_cookie) 1514 { 1515 // FUNCTION_START(); 1516 Volume *volume = (Volume*)fs; 1517 Node *node = (Node*)_node; 1518 FUNCTION(("node: %lld\n", node->GetID())); 1519 status_t error = B_OK; 1520 1521 if (VolumeWriteLocker locker = volume) { 1522 // find the attribute 1523 Attribute *attribute = NULL; 1524 if (error == B_OK) 1525 error = node->FindAttribute(name, &attribute); 1526 1527 // truncating requires write permission 1528 int accessMode = open_mode_to_access(openMode); 1529 if (error == B_OK && (openMode & O_TRUNC)) 1530 accessMode |= ACCESS_W; 1531 1532 // check open mode against permissions 1533 if (error == B_OK) 1534 error = node->CheckPermissions(accessMode); 1535 1536 // create the cookie 1537 AttributeCookie *cookie = NULL; 1538 if (error == B_OK) { 1539 cookie = new(nothrow) AttributeCookie(); 1540 if (cookie) { 1541 SET_ERROR(error, cookie->Init(name, openMode)); 1542 } else { 1543 SET_ERROR(error, B_NO_MEMORY); 1544 } 1545 } 1546 1547 // truncate if requested 1548 if (error == B_OK && (openMode & O_TRUNC)) { 1549 error = attribute->SetSize(0); 1550 1551 if (error == B_OK) { 1552 notify_attribute_changed(volume->GetID(), node->GetID(), name, 1553 B_ATTR_CHANGED); 1554 } 1555 } 1556 NodeMTimeUpdater mTimeUpdater(node); 1557 1558 // set result / cleanup on failure 1559 if (error == B_OK) 1560 *_cookie = cookie; 1561 else if (cookie) 1562 delete cookie; 1563 } else 1564 SET_ERROR(error, B_ERROR); 1565 RETURN_ERROR(error); 1566 } 1567 1568 // ramfs_close_attr 1569 static status_t 1570 ramfs_close_attr(fs_volume fs, fs_vnode _node, fs_cookie cookie) 1571 { 1572 // FUNCTION_START(); 1573 Volume *volume = (Volume*)fs; 1574 Node *node = (Node*)_node; 1575 FUNCTION(("node: %lld\n", node->GetID())); 1576 status_t error = B_OK; 1577 1578 // notify listeners 1579 if (VolumeReadLocker locker = volume) { 1580 notify_if_stat_changed(volume, node); 1581 } else 1582 SET_ERROR(error, B_ERROR); 1583 return B_OK; 1584 1585 } 1586 1587 // ramfs_free_attr_cookie 1588 static status_t 1589 ramfs_free_attr_cookie(fs_volume /*fs*/, fs_vnode /*_node*/, fs_cookie _cookie) 1590 { 1591 FUNCTION_START(); 1592 AttributeCookie *cookie = (AttributeCookie*)_cookie; 1593 delete cookie; 1594 return B_OK; 1595 } 1596 1597 // ramfs_read_attr 1598 static status_t 1599 ramfs_read_attr(fs_volume fs, fs_vnode _node, fs_cookie _cookie, off_t pos, 1600 void *buffer, size_t *bufferSize) 1601 { 1602 // FUNCTION_START(); 1603 Volume *volume = (Volume*)fs; 1604 Node *node = (Node*)_node; 1605 AttributeCookie *cookie = (AttributeCookie*)_cookie; 1606 status_t error = B_OK; 1607 1608 if (VolumeReadLocker locker = volume) { 1609 // find the attribute 1610 Attribute *attribute = NULL; 1611 if (error == B_OK) 1612 error = node->FindAttribute(cookie->GetName(), &attribute); 1613 1614 // check permissions 1615 int accessMode = open_mode_to_access(cookie->GetOpenMode()); 1616 if (error == B_OK && !(accessMode & ACCESS_R)) 1617 SET_ERROR(error, B_NOT_ALLOWED); 1618 1619 // read 1620 if (error == B_OK) 1621 error = attribute->ReadAt(pos, buffer, *bufferSize, bufferSize); 1622 } else 1623 SET_ERROR(error, B_ERROR); 1624 RETURN_ERROR(error); 1625 } 1626 1627 // ramfs_write_attr 1628 static status_t 1629 ramfs_write_attr(fs_volume fs, fs_vnode _node, fs_cookie _cookie, off_t pos, 1630 const void *buffer, size_t *bufferSize) 1631 { 1632 // FUNCTION_START(); 1633 Volume *volume = (Volume*)fs; 1634 Node *node = (Node*)_node; 1635 AttributeCookie *cookie = (AttributeCookie*)_cookie; 1636 status_t error = B_OK; 1637 1638 // Don't allow writing the reserved attributes. 1639 const char *name = cookie->GetName(); 1640 if (name[0] == '\0' || !strcmp(name, "name") 1641 || !strcmp(name, "last_modified") || !strcmp(name, "size")) { 1642 //FUNCTION(("failed: node: %s, attribute: %s\n", node->GetName(), name)); 1643 RETURN_ERROR(B_NOT_ALLOWED); 1644 } 1645 1646 if (VolumeWriteLocker locker = volume) { 1647 NodeMTimeUpdater mTimeUpdater(node); 1648 1649 // find the attribute 1650 Attribute *attribute = NULL; 1651 if (error == B_OK) 1652 error = node->FindAttribute(cookie->GetName(), &attribute); 1653 1654 // check permissions 1655 int accessMode = open_mode_to_access(cookie->GetOpenMode()); 1656 if (error == B_OK && !(accessMode & ACCESS_W)) 1657 SET_ERROR(error, B_NOT_ALLOWED); 1658 1659 // write the data 1660 if (error == B_OK) 1661 error = attribute->WriteAt(pos, buffer, *bufferSize, bufferSize); 1662 1663 // notify listeners 1664 if (error == B_OK) { 1665 notify_attribute_changed(volume->GetID(), node->GetID(), name, 1666 B_ATTR_CHANGED); 1667 } 1668 } else 1669 SET_ERROR(error, B_ERROR); 1670 RETURN_ERROR(error); 1671 } 1672 1673 // ramfs_read_attr_stat 1674 static status_t 1675 ramfs_read_attr_stat(fs_volume fs, fs_vnode _node, fs_cookie _cookie, 1676 struct stat *st) 1677 { 1678 // FUNCTION_START(); 1679 Volume *volume = (Volume*)fs; 1680 Node *node = (Node*)_node; 1681 AttributeCookie *cookie = (AttributeCookie*)_cookie; 1682 status_t error = B_OK; 1683 1684 if (VolumeReadLocker locker = volume) { 1685 // find the attribute 1686 Attribute *attribute = NULL; 1687 if (error == B_OK) 1688 error = node->FindAttribute(cookie->GetName(), &attribute); 1689 1690 // check permissions 1691 int accessMode = open_mode_to_access(cookie->GetOpenMode()); 1692 if (error == B_OK && !(accessMode & ACCESS_R)) 1693 SET_ERROR(error, B_NOT_ALLOWED); 1694 1695 // read 1696 if (error == B_OK) { 1697 st->st_type = attribute->GetType(); 1698 st->st_size = attribute->GetSize(); 1699 } 1700 } else 1701 SET_ERROR(error, B_ERROR); 1702 RETURN_ERROR(error); 1703 } 1704 1705 // ramfs_rename_attr 1706 static status_t 1707 ramfs_rename_attr(fs_volume /*fs*/, fs_vnode /*_fromNode*/, 1708 const char */*fromName*/, fs_vnode /*_toNode*/, const char */*toName*/) 1709 { 1710 // TODO:... 1711 return B_BAD_VALUE; 1712 } 1713 1714 // ramfs_remove_attr 1715 static status_t 1716 ramfs_remove_attr(fs_volume fs, fs_vnode _node, const char *name) 1717 1718 { 1719 FUNCTION_START(); 1720 Volume *volume = (Volume*)fs; 1721 Node *node = (Node*)_node; 1722 status_t error = B_OK; 1723 if (VolumeWriteLocker locker = volume) { 1724 NodeMTimeUpdater mTimeUpdater(node); 1725 1726 // check permissions 1727 error = node->CheckPermissions(ACCESS_W); 1728 1729 // find the attribute 1730 Attribute *attribute = NULL; 1731 if (error == B_OK) 1732 error = node->FindAttribute(name, &attribute); 1733 1734 // delete it 1735 if (error == B_OK) 1736 error = node->DeleteAttribute(attribute); 1737 1738 // notify listeners 1739 if (error == B_OK) { 1740 notify_attribute_changed(volume->GetID(), node->GetID(), name, 1741 B_ATTR_REMOVED); 1742 } 1743 } else 1744 SET_ERROR(error, B_ERROR); 1745 RETURN_ERROR(error); 1746 } 1747 1748 1749 // #pragma mark - Indices 1750 1751 1752 // IndexDirCookie 1753 class IndexDirCookie { 1754 public: 1755 IndexDirCookie() : index_index(0) {} 1756 1757 int32 index_index; 1758 }; 1759 1760 // ramfs_open_index_dir 1761 static status_t 1762 ramfs_open_index_dir(fs_volume fs, fs_cookie *_cookie) 1763 { 1764 FUNCTION_START(); 1765 Volume *volume = (Volume*)fs; 1766 status_t error = B_OK; 1767 if (VolumeReadLocker locker = volume) { 1768 // check whether an index directory exists 1769 if (volume->GetIndexDirectory()) { 1770 IndexDirCookie *cookie = new(nothrow) IndexDirCookie; 1771 if (cookie) 1772 *_cookie = cookie; 1773 else 1774 SET_ERROR(error, B_NO_MEMORY); 1775 } else 1776 SET_ERROR(error, B_ENTRY_NOT_FOUND); 1777 } else 1778 SET_ERROR(error, B_ERROR); 1779 RETURN_ERROR(error); 1780 } 1781 1782 // ramfs_close_index_dir 1783 static status_t 1784 ramfs_close_index_dir(fs_volume /*fs*/, fs_cookie /*_cookie*/) 1785 { 1786 FUNCTION_START(); 1787 return B_OK; 1788 } 1789 1790 // ramfs_free_index_dir_cookie 1791 static status_t 1792 ramfs_free_index_dir_cookie(fs_volume /*fs*/, fs_cookie _cookie) 1793 { 1794 FUNCTION_START(); 1795 IndexDirCookie *cookie = (IndexDirCookie*)_cookie; 1796 delete cookie; 1797 return B_OK; 1798 } 1799 1800 // ramfs_read_index_dir 1801 static status_t 1802 ramfs_read_index_dir(fs_volume fs, fs_cookie _cookie, struct dirent *buffer, 1803 size_t bufferSize, uint32 *count) 1804 { 1805 FUNCTION_START(); 1806 Volume *volume = (Volume*)fs; 1807 IndexDirCookie *cookie = (IndexDirCookie*)_cookie; 1808 status_t error = B_OK; 1809 if (VolumeReadLocker locker = volume) { 1810 // get the next index 1811 Index *index = volume->GetIndexDirectory()->IndexAt( 1812 cookie->index_index++); 1813 if (index) { 1814 const char *name = index->GetName(); 1815 size_t nameLen = strlen(name); 1816 // check, whether the entry fits into the buffer, 1817 // and fill it in 1818 size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer; 1819 if (length <= bufferSize) { 1820 buffer->d_dev = volume->GetID(); 1821 buffer->d_ino = -1; // indices don't have a node ID 1822 memcpy(buffer->d_name, name, nameLen); 1823 buffer->d_name[nameLen] = '\0'; 1824 buffer->d_reclen = length; 1825 *count = 1; 1826 } else { 1827 SET_ERROR(error, B_BUFFER_OVERFLOW); 1828 } 1829 } else 1830 *count = 0; 1831 } else 1832 SET_ERROR(error, B_ERROR); 1833 RETURN_ERROR(error); 1834 } 1835 1836 // ramfs_rewind_index_dir 1837 static status_t 1838 ramfs_rewind_index_dir(fs_volume /*fs*/, fs_cookie _cookie) 1839 { 1840 FUNCTION_START(); 1841 IndexDirCookie *cookie = (IndexDirCookie*)_cookie; 1842 cookie->index_index = 0; 1843 return B_OK; 1844 } 1845 1846 // ramfs_create_index 1847 static status_t 1848 ramfs_create_index(fs_volume fs, const char *name, uint32 type, 1849 uint32 /*flags*/) 1850 { 1851 FUNCTION_START(); 1852 Volume *volume = (Volume*)fs; 1853 status_t error = B_OK; 1854 // only root is allowed to manipulate the indices 1855 if (geteuid() != 0) { 1856 SET_ERROR(error, B_NOT_ALLOWED); 1857 } else if (VolumeWriteLocker locker = volume) { 1858 // get the index directory 1859 if (IndexDirectory *indexDir = volume->GetIndexDirectory()) { 1860 // check whether an index with that name does already exist 1861 if (indexDir->FindIndex(name)) { 1862 SET_ERROR(error, B_FILE_EXISTS); 1863 } else { 1864 // create the index 1865 AttributeIndex *index; 1866 error = indexDir->CreateIndex(name, type, &index); 1867 } 1868 } else 1869 SET_ERROR(error, B_ENTRY_NOT_FOUND); 1870 } else 1871 SET_ERROR(error, B_ERROR); 1872 RETURN_ERROR(error); 1873 } 1874 1875 // ramfs_remove_index 1876 static status_t 1877 ramfs_remove_index(fs_volume fs, const char *name) 1878 { 1879 FUNCTION_START(); 1880 Volume *volume = (Volume*)fs; 1881 status_t error = B_OK; 1882 // only root is allowed to manipulate the indices 1883 if (geteuid() != 0) { 1884 SET_ERROR(error, B_NOT_ALLOWED); 1885 } else if (VolumeWriteLocker locker = volume) { 1886 // get the index directory 1887 if (IndexDirectory *indexDir = volume->GetIndexDirectory()) { 1888 // check whether an index with that name does exist 1889 if (Index *index = indexDir->FindIndex(name)) { 1890 // don't delete a special index 1891 if (indexDir->IsSpecialIndex(index)) { 1892 SET_ERROR(error, B_BAD_VALUE); 1893 } else 1894 indexDir->DeleteIndex(index); 1895 } else 1896 SET_ERROR(error, B_ENTRY_NOT_FOUND); 1897 } else 1898 SET_ERROR(error, B_ENTRY_NOT_FOUND); 1899 } else 1900 SET_ERROR(error, B_ERROR); 1901 RETURN_ERROR(error); 1902 } 1903 1904 // ramfs_read_index_stat 1905 static status_t 1906 ramfs_read_index_stat(fs_volume fs, const char *name, struct stat *st) 1907 { 1908 FUNCTION_START(); 1909 Volume *volume = (Volume*)fs; 1910 status_t error = B_OK; 1911 if (VolumeReadLocker locker = volume) { 1912 // get the index directory 1913 if (IndexDirectory *indexDir = volume->GetIndexDirectory()) { 1914 // find the index 1915 if (Index *index = indexDir->FindIndex(name)) { 1916 st->st_type = index->GetType(); 1917 if (index->HasFixedKeyLength()) 1918 st->st_size = index->GetKeyLength(); 1919 else 1920 st->st_size = kMaxIndexKeyLength; 1921 st->st_atime = 0; // TODO: index times 1922 st->st_mtime = 0; // ... 1923 st->st_ctime = 0; // ... 1924 st->st_crtime = 0; // ... 1925 st->st_uid = 0; // root owns the indices 1926 st->st_gid = 0; // 1927 } else 1928 SET_ERROR(error, B_ENTRY_NOT_FOUND); 1929 } else 1930 SET_ERROR(error, B_ENTRY_NOT_FOUND); 1931 } else 1932 SET_ERROR(error, B_ERROR); 1933 RETURN_ERROR(error); 1934 } 1935 1936 1937 // #pragma mark - Queries 1938 1939 // Query implementation by Axel Dörfler. Slightly adjusted. 1940 1941 // ramfs_open_query 1942 static status_t 1943 ramfs_open_query(fs_volume fs, const char *queryString, uint32 flags, 1944 port_id port, uint32 token, fs_cookie *cookie) 1945 { 1946 FUNCTION_START(); 1947 PRINT(("query = \"%s\", flags = %lu, port_id = %ld, token = %ld\n", queryString, flags, port, token)); 1948 1949 Volume *volume = (Volume *)fs; 1950 1951 // lock the volume 1952 VolumeReadLocker locker(volume); 1953 if (!locker.IsLocked()) 1954 RETURN_ERROR(B_ERROR); 1955 1956 // parse the query expression 1957 Expression *expression = new Expression((char *)queryString); 1958 if (expression == NULL) 1959 RETURN_ERROR(B_NO_MEMORY); 1960 ObjectDeleter<Expression> expressionDeleter(expression); 1961 1962 if (expression->InitCheck() < B_OK) { 1963 WARN(("Could not parse query, stopped at: \"%s\"\n", 1964 expression->Position())); 1965 RETURN_ERROR(B_BAD_VALUE); 1966 } 1967 1968 // create the query 1969 Query *query = new Query(volume, expression, flags); 1970 if (query == NULL) 1971 RETURN_ERROR(B_NO_MEMORY); 1972 expressionDeleter.Detach(); 1973 // TODO: The Query references an Index, but nothing prevents the Index 1974 // from being deleted, while the Query is in existence. 1975 1976 if (flags & B_LIVE_QUERY) 1977 query->SetLiveMode(port, token); 1978 1979 *cookie = (void *)query; 1980 1981 return B_OK; 1982 } 1983 1984 // ramfs_close_query 1985 static status_t 1986 ramfs_close_query(fs_volume /*fs*/, fs_cookie /*cookie*/) 1987 { 1988 FUNCTION_START(); 1989 return B_OK; 1990 } 1991 1992 // ramfs_free_query_cookie 1993 static status_t 1994 ramfs_free_query_cookie(fs_volume fs, fs_cookie cookie) 1995 { 1996 FUNCTION_START(); 1997 1998 Volume *volume = (Volume *)fs; 1999 2000 // lock the volume 2001 VolumeReadLocker locker(volume); 2002 if (!locker.IsLocked()) 2003 RETURN_ERROR(B_ERROR); 2004 2005 Query *query = (Query *)cookie; 2006 Expression *expression = query->GetExpression(); 2007 delete query; 2008 delete expression; 2009 2010 return B_OK; 2011 } 2012 2013 // ramfs_read_query 2014 static status_t 2015 ramfs_read_query(fs_volume fs, fs_cookie cookie, struct dirent *buffer, 2016 size_t bufferSize, uint32 *count) 2017 { 2018 FUNCTION_START(); 2019 Query *query = (Query *)cookie; 2020 Volume *volume = (Volume *)fs; 2021 2022 // lock the volume 2023 VolumeReadLocker locker(volume); 2024 if (!locker.IsLocked()) 2025 RETURN_ERROR(B_ERROR); 2026 2027 status_t status = query->GetNextEntry(buffer, bufferSize); 2028 if (status == B_OK) 2029 *count = 1; 2030 else if (status == B_ENTRY_NOT_FOUND) 2031 *count = 0; 2032 else 2033 return status; 2034 2035 return B_OK; 2036 } 2037 2038 // TODO: status_t (*rewind_query)(fs_volume fs, fs_cookie cookie); 2039 2040 2041 // #pragma mark - Module Interface 2042 2043 2044 static status_t 2045 ramfs_std_ops(int32 op, ...) 2046 { 2047 switch (op) { 2048 case B_MODULE_INIT: 2049 { 2050 init_debugging(); 2051 PRINT(("ramfs_std_ops(): B_MODULE_INIT\n")); 2052 return B_OK; 2053 } 2054 2055 case B_MODULE_UNINIT: 2056 PRINT(("ramfs_std_ops(): B_MODULE_UNINIT\n")); 2057 exit_debugging(); 2058 return B_OK; 2059 2060 default: 2061 return B_ERROR; 2062 } 2063 } 2064 2065 static file_system_module_info sRamFSModuleInfo = { 2066 { 2067 "file_systems/ramfs" B_CURRENT_FS_API_VERSION, 2068 0, 2069 ramfs_std_ops, 2070 }, 2071 2072 "RAM File System", 2073 2074 // scanning 2075 NULL, // identify_partition() 2076 NULL, // scan_partition() 2077 NULL, // free_identify_partition_cookie() 2078 NULL, // free_partition_content_cookie() 2079 2080 &ramfs_mount, 2081 &ramfs_unmount, 2082 &ramfs_read_fs_info, 2083 &ramfs_write_fs_info, 2084 &ramfs_sync, 2085 2086 /* vnode operations */ 2087 &ramfs_lookup, 2088 NULL, // &ramfs_get_vnode_name, 2089 &ramfs_read_vnode, 2090 &ramfs_write_vnode, 2091 &ramfs_remove_vnode, 2092 2093 /* VM file access */ 2094 NULL, // &ramfs_can_page, 2095 NULL, // &ramfs_read_pages, 2096 NULL, // &ramfs_write_pages, 2097 2098 NULL, // &ramfs_get_file_map, 2099 2100 &ramfs_ioctl, 2101 &ramfs_set_flags, 2102 NULL, // &ramfs_select, 2103 NULL, // &ramfs_deselect, 2104 &ramfs_fsync, 2105 2106 &ramfs_read_symlink, 2107 &ramfs_create_symlink, 2108 2109 &ramfs_link, 2110 &ramfs_unlink, 2111 &ramfs_rename, 2112 2113 &ramfs_access, 2114 &ramfs_read_stat, 2115 &ramfs_write_stat, 2116 2117 /* file operations */ 2118 &ramfs_create, 2119 &ramfs_open, 2120 &ramfs_close, 2121 &ramfs_free_cookie, 2122 &ramfs_read, 2123 &ramfs_write, 2124 2125 /* directory operations */ 2126 &ramfs_create_dir, 2127 &ramfs_remove_dir, 2128 &ramfs_open_dir, 2129 &ramfs_close_dir, 2130 &ramfs_free_dir_cookie, 2131 &ramfs_read_dir, 2132 &ramfs_rewind_dir, 2133 2134 /* attribute directory operations */ 2135 &ramfs_open_attr_dir, 2136 &ramfs_close_attr_dir, 2137 &ramfs_free_attr_dir_cookie, 2138 &ramfs_read_attr_dir, 2139 &ramfs_rewind_attr_dir, 2140 2141 /* attribute operations */ 2142 &ramfs_create_attr, 2143 &ramfs_open_attr, 2144 &ramfs_close_attr, 2145 &ramfs_free_attr_cookie, 2146 &ramfs_read_attr, 2147 &ramfs_write_attr, 2148 2149 &ramfs_read_attr_stat, 2150 NULL, // &ramfs_write_attr_stat, 2151 &ramfs_rename_attr, 2152 &ramfs_remove_attr, 2153 2154 /* index directory & index operations */ 2155 &ramfs_open_index_dir, 2156 &ramfs_close_index_dir, 2157 &ramfs_free_index_dir_cookie, 2158 &ramfs_read_index_dir, 2159 &ramfs_rewind_index_dir, 2160 2161 &ramfs_create_index, 2162 &ramfs_remove_index, 2163 &ramfs_read_index_stat, 2164 2165 /* query operations */ 2166 &ramfs_open_query, 2167 &ramfs_close_query, 2168 &ramfs_free_query_cookie, 2169 &ramfs_read_query, 2170 NULL, // &ramfs_rewind_query, 2171 }; 2172 2173 module_info *modules[] = { 2174 (module_info *)&sRamFSModuleInfo, 2175 NULL, 2176 }; 2177