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