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