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