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