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