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