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