1 /* 2 * Copyright 2001-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "BeOSKernelVolume.h" 7 8 #include <new> 9 10 #include <fcntl.h> 11 #include <unistd.h> 12 13 #include "Debug.h" 14 15 #include "../kernel_emu.h" 16 17 #include "BeOSKernelFileSystem.h" 18 #include "fs_interface.h" 19 20 21 using std::nothrow; 22 23 static int open_mode_to_access(int openMode); 24 25 26 // AttributeCookie 27 class BeOSKernelVolume::AttributeCookie { 28 public: 29 AttributeCookie(const char* name, uint32 type, int openMode, bool exists, 30 bool create) 31 : fType(type), 32 fOpenMode(openMode), 33 fExists(exists), 34 fCreate(create) 35 { 36 strcpy(fName, name); 37 } 38 39 char fName[B_ATTR_NAME_LENGTH]; 40 uint32 fType; 41 int fOpenMode; 42 bool fExists; 43 bool fCreate; 44 }; 45 46 47 // _FileSystem 48 inline BeOSKernelFileSystem* 49 BeOSKernelVolume::_FileSystem() const 50 { 51 return static_cast<BeOSKernelFileSystem*>(fFileSystem); 52 } 53 54 55 // constructor 56 BeOSKernelVolume::BeOSKernelVolume(FileSystem* fileSystem, dev_t id, 57 beos_vnode_ops* fsOps, const FSVolumeCapabilities& capabilities) 58 : 59 Volume(fileSystem, id), 60 fFSOps(fsOps), 61 fVolumeCookie(NULL), 62 fMounted(false) 63 { 64 fCapabilities = capabilities; 65 } 66 67 // destructor 68 BeOSKernelVolume::~BeOSKernelVolume() 69 { 70 } 71 72 // #pragma mark - 73 // #pragma mark ----- FS ----- 74 75 // Mount 76 status_t 77 BeOSKernelVolume::Mount(const char* device, uint32 flags, 78 const char* parameters, ino_t* rootID) 79 { 80 if (!fFSOps->mount) 81 return B_BAD_VALUE; 82 83 size_t len = (parameters ? strlen(parameters) : 0); 84 status_t error = fFSOps->mount(GetID(), device, flags, (void*)parameters, 85 len, &fVolumeCookie, rootID); 86 if (error != B_OK) 87 return error; 88 89 fMounted = true; 90 return B_OK; 91 } 92 93 // Unmount 94 status_t 95 BeOSKernelVolume::Unmount() 96 { 97 if (!fFSOps->unmount) 98 return B_BAD_VALUE; 99 return fFSOps->unmount(fVolumeCookie); 100 } 101 102 // Sync 103 status_t 104 BeOSKernelVolume::Sync() 105 { 106 if (!fFSOps->sync) 107 return B_BAD_VALUE; 108 return fFSOps->sync(fVolumeCookie); 109 } 110 111 // ReadFSInfo 112 status_t 113 BeOSKernelVolume::ReadFSInfo(fs_info* info) 114 { 115 if (!fFSOps->rfsstat) 116 return B_BAD_VALUE; 117 118 // Haiku's fs_info equals BeOS's version 119 return fFSOps->rfsstat(fVolumeCookie, (beos_fs_info*)info); 120 } 121 122 // WriteFSInfo 123 status_t 124 BeOSKernelVolume::WriteFSInfo(const struct fs_info* info, uint32 mask) 125 { 126 if (!fFSOps->wfsstat) 127 return B_BAD_VALUE; 128 129 // Haiku's fs_info equals BeOS's version 130 return fFSOps->wfsstat(fVolumeCookie, (beos_fs_info*)info, (long)mask); 131 } 132 133 134 // #pragma mark - vnodes 135 136 137 // Lookup 138 status_t 139 BeOSKernelVolume::Lookup(void* dir, const char* entryName, ino_t* vnid) 140 { 141 if (!fFSOps->walk) 142 return B_BAD_VALUE; 143 return fFSOps->walk(fVolumeCookie, dir, entryName, NULL, vnid); 144 } 145 146 147 // GetVNodeType 148 status_t 149 BeOSKernelVolume::GetVNodeType(void* node, int* type) 150 { 151 if (fMounted) { 152 // The volume is mounted. We can stat() the node to get its type. 153 struct stat st; 154 status_t error = ReadStat(node, &st); 155 if (error != B_OK) 156 return error; 157 158 *type = st.st_mode & S_IFMT; 159 } else { 160 // Not mounted yet. That particularly means we don't have a volume 161 // cookie yet and cannot use calls into the FS to get the node type. 162 // Just assume the node is a directory. That definitely is the case for 163 // the root node and shouldn't do harm for the index directory or 164 // indices, which could get published while mounting as well. 165 *type = S_IFDIR; 166 // TODO: Store the concerned nodes and check their type as soon as 167 // possible (at the end of Mount()). The incorrect ones could be 168 // corrected in the kernel: remove_vnode(), x*put_vnode() (catching 169 // the "remove_vnode()" callback), publish_vnode(), 170 // (x-1)*get_vnode(). 171 } 172 173 return B_OK; 174 } 175 176 177 // ReadVNode 178 status_t 179 BeOSKernelVolume::ReadVNode(ino_t vnid, bool reenter, void** node, int* type, 180 uint32* flags, FSVNodeCapabilities* _capabilities) 181 { 182 if (!fFSOps->read_vnode) 183 return B_BAD_VALUE; 184 185 // get the node 186 status_t error = fFSOps->read_vnode(fVolumeCookie, vnid, (char)reenter, 187 node); 188 if (error != B_OK) 189 return error; 190 191 // stat it -- we need to get the node type 192 struct stat st; 193 error = ReadStat(node, &st); 194 if (error != B_OK) { 195 WriteVNode(node, reenter); 196 return error; 197 } 198 199 *type = (st.st_mode & S_IFMT); 200 *flags = 0; 201 _FileSystem()->GetNodeCapabilities(*_capabilities); 202 203 return B_OK; 204 } 205 206 // WriteVNode 207 status_t 208 BeOSKernelVolume::WriteVNode(void* node, bool reenter) 209 { 210 if (!fFSOps->write_vnode) 211 return B_BAD_VALUE; 212 return fFSOps->write_vnode(fVolumeCookie, node, (char)reenter); 213 } 214 215 // RemoveVNode 216 status_t 217 BeOSKernelVolume::RemoveVNode(void* node, bool reenter) 218 { 219 if (!fFSOps->remove_vnode) 220 return B_BAD_VALUE; 221 return fFSOps->remove_vnode(fVolumeCookie, node, (char)reenter); 222 } 223 224 225 // #pragma mark - nodes 226 227 228 // IOCtl 229 status_t 230 BeOSKernelVolume::IOCtl(void* node, void* cookie, uint32 command, 231 void* buffer, size_t size) 232 { 233 if (!fFSOps->ioctl) 234 return B_BAD_VALUE; 235 return fFSOps->ioctl(fVolumeCookie, node, cookie, (int)command, buffer, 236 size); 237 } 238 239 // SetFlags 240 status_t 241 BeOSKernelVolume::SetFlags(void* node, void* cookie, int flags) 242 { 243 if (!fFSOps->setflags) 244 return B_BAD_VALUE; 245 return fFSOps->setflags(fVolumeCookie, node, cookie, flags); 246 } 247 248 // Select 249 status_t 250 BeOSKernelVolume::Select(void* node, void* cookie, uint8 event, 251 selectsync* sync) 252 { 253 if (!fFSOps->select) { 254 UserlandFS::KernelEmu::notify_select_event(sync, event, false); 255 return B_OK; 256 } 257 return fFSOps->select(fVolumeCookie, node, cookie, event, 0, sync); 258 } 259 260 // Deselect 261 status_t 262 BeOSKernelVolume::Deselect(void* node, void* cookie, uint8 event, 263 selectsync* sync) 264 { 265 if (!fFSOps->select || !fFSOps->deselect) 266 return B_OK; 267 return fFSOps->deselect(fVolumeCookie, node, cookie, event, sync); 268 } 269 270 // FSync 271 status_t 272 BeOSKernelVolume::FSync(void* node) 273 { 274 if (!fFSOps->fsync) 275 return B_BAD_VALUE; 276 return fFSOps->fsync(fVolumeCookie, node); 277 } 278 279 // ReadSymlink 280 status_t 281 BeOSKernelVolume::ReadSymlink(void* node, char* buffer, size_t bufferSize, 282 size_t* bytesRead) 283 { 284 if (!fFSOps->readlink) 285 return B_BAD_VALUE; 286 *bytesRead = bufferSize; 287 return fFSOps->readlink(fVolumeCookie, node, buffer, bytesRead); 288 } 289 290 // CreateSymlink 291 status_t 292 BeOSKernelVolume::CreateSymlink(void* dir, const char* name, 293 const char* target, int mode) 294 { 295 if (!fFSOps->symlink) 296 return B_BAD_VALUE; 297 // TODO: Don't ignore mode? 298 return fFSOps->symlink(fVolumeCookie, dir, name, target); 299 } 300 301 // Link 302 status_t 303 BeOSKernelVolume::Link(void* dir, const char* name, void* node) 304 { 305 if (!fFSOps->link) 306 return B_BAD_VALUE; 307 return fFSOps->link(fVolumeCookie, dir, name, node); 308 } 309 310 // Unlink 311 status_t 312 BeOSKernelVolume::Unlink(void* dir, const char* name) 313 { 314 if (!fFSOps->unlink) 315 return B_BAD_VALUE; 316 return fFSOps->unlink(fVolumeCookie, dir, name); 317 } 318 319 // Rename 320 status_t 321 BeOSKernelVolume::Rename(void* oldDir, const char* oldName, void* newDir, 322 const char* newName) 323 { 324 if (!fFSOps->rename) 325 return B_BAD_VALUE; 326 return fFSOps->rename(fVolumeCookie, oldDir, oldName, newDir, newName); 327 } 328 329 // Access 330 status_t 331 BeOSKernelVolume::Access(void* node, int mode) 332 { 333 if (!fFSOps->access) 334 return B_OK; 335 return fFSOps->access(fVolumeCookie, node, mode); 336 } 337 338 // ReadStat 339 status_t 340 BeOSKernelVolume::ReadStat(void* node, struct stat* st) 341 { 342 if (!fFSOps->rstat) 343 return B_BAD_VALUE; 344 345 // Haiku's struct stat has an additional st_type field (for an attribute 346 // type), but that doesn't matter here 347 return fFSOps->rstat(fVolumeCookie, node, (struct beos_stat*)st); 348 } 349 350 // WriteStat 351 status_t 352 BeOSKernelVolume::WriteStat(void* node, const struct stat *st, uint32 mask) 353 { 354 if (!fFSOps->wstat) 355 return B_BAD_VALUE; 356 357 // Haiku's struct stat has an additional st_type field (for an attribute 358 // type), but that doesn't matter here 359 return fFSOps->wstat(fVolumeCookie, node, (struct beos_stat*)st, 360 (long)mask); 361 } 362 363 364 // #pragma mark - files 365 366 367 // Create 368 status_t 369 BeOSKernelVolume::Create(void* dir, const char* name, int openMode, int mode, 370 void** cookie, ino_t* vnid) 371 { 372 if (!fFSOps->create) 373 return B_BAD_VALUE; 374 return fFSOps->create(fVolumeCookie, dir, name, openMode, mode, vnid, 375 cookie); 376 } 377 378 // Open 379 status_t 380 BeOSKernelVolume::Open(void* node, int openMode, void** cookie) 381 { 382 if (!fFSOps->open) 383 return B_BAD_VALUE; 384 return fFSOps->open(fVolumeCookie, node, openMode, cookie); 385 } 386 387 // Close 388 status_t 389 BeOSKernelVolume::Close(void* node, void* cookie) 390 { 391 if (!fFSOps->close) 392 return B_OK; 393 return fFSOps->close(fVolumeCookie, node, cookie); 394 } 395 396 // FreeCookie 397 status_t 398 BeOSKernelVolume::FreeCookie(void* node, void* cookie) 399 { 400 if (!fFSOps->free_cookie) 401 return B_OK; 402 return fFSOps->free_cookie(fVolumeCookie, node, cookie); 403 } 404 405 // Read 406 status_t 407 BeOSKernelVolume::Read(void* node, void* cookie, off_t pos, void* buffer, 408 size_t bufferSize, size_t* bytesRead) 409 { 410 if (!fFSOps->read) 411 return B_BAD_VALUE; 412 *bytesRead = bufferSize; 413 return fFSOps->read(fVolumeCookie, node, cookie, pos, buffer, bytesRead); 414 } 415 416 // Write 417 status_t 418 BeOSKernelVolume::Write(void* node, void* cookie, off_t pos, 419 const void* buffer, size_t bufferSize, size_t* bytesWritten) 420 { 421 if (!fFSOps->write) 422 return B_BAD_VALUE; 423 *bytesWritten = bufferSize; 424 return fFSOps->write(fVolumeCookie, node, cookie, pos, buffer, 425 bytesWritten); 426 } 427 428 429 // #pragma mark - directories 430 431 432 // CreateDir 433 status_t 434 BeOSKernelVolume::CreateDir(void* dir, const char* name, int mode) 435 { 436 if (!fFSOps->mkdir) 437 return B_BAD_VALUE; 438 439 return fFSOps->mkdir(fVolumeCookie, dir, name, mode); 440 } 441 442 // RemoveDir 443 status_t 444 BeOSKernelVolume::RemoveDir(void* dir, const char* name) 445 { 446 if (!fFSOps->rmdir) 447 return B_BAD_VALUE; 448 return fFSOps->rmdir(fVolumeCookie, dir, name); 449 } 450 451 // OpenDir 452 status_t 453 BeOSKernelVolume::OpenDir(void* node, void** cookie) 454 { 455 if (!fFSOps->opendir) 456 return B_BAD_VALUE; 457 return fFSOps->opendir(fVolumeCookie, node, cookie); 458 } 459 460 // CloseDir 461 status_t 462 BeOSKernelVolume::CloseDir(void* node, void* cookie) 463 { 464 if (!fFSOps->closedir) 465 return B_OK; 466 return fFSOps->closedir(fVolumeCookie, node, cookie); 467 } 468 469 // FreeDirCookie 470 status_t 471 BeOSKernelVolume::FreeDirCookie(void* node, void* cookie) 472 { 473 if (!fFSOps->free_dircookie) 474 return B_OK; 475 return fFSOps->free_dircookie(fVolumeCookie, node, cookie); 476 } 477 478 // ReadDir 479 status_t 480 BeOSKernelVolume::ReadDir(void* node, void* cookie, void* buffer, 481 size_t bufferSize, uint32 count, uint32* countRead) 482 { 483 if (!fFSOps->readdir) 484 return B_BAD_VALUE; 485 486 *countRead = count; 487 488 // Haiku's struct dirent equals BeOS's version 489 return fFSOps->readdir(fVolumeCookie, node, cookie, (long*)countRead, 490 (beos_dirent*)buffer, bufferSize); 491 } 492 493 // RewindDir 494 status_t 495 BeOSKernelVolume::RewindDir(void* node, void* cookie) 496 { 497 if (!fFSOps->rewinddir) 498 return B_BAD_VALUE; 499 return fFSOps->rewinddir(fVolumeCookie, node, cookie); 500 } 501 502 503 // #pragma mark - attribute directories 504 505 506 // OpenAttrDir 507 status_t 508 BeOSKernelVolume::OpenAttrDir(void* node, void** cookie) 509 { 510 if (!fFSOps->open_attrdir) 511 return B_BAD_VALUE; 512 return fFSOps->open_attrdir(fVolumeCookie, node, cookie); 513 } 514 515 // CloseAttrDir 516 status_t 517 BeOSKernelVolume::CloseAttrDir(void* node, void* cookie) 518 { 519 if (!fFSOps->close_attrdir) 520 return B_OK; 521 return fFSOps->close_attrdir(fVolumeCookie, node, cookie); 522 } 523 524 // FreeAttrDirCookie 525 status_t 526 BeOSKernelVolume::FreeAttrDirCookie(void* node, void* cookie) 527 { 528 if (!fFSOps->free_attrdircookie) 529 return B_OK; 530 return fFSOps->free_attrdircookie(fVolumeCookie, node, cookie); 531 } 532 533 // ReadAttrDir 534 status_t 535 BeOSKernelVolume::ReadAttrDir(void* node, void* cookie, void* buffer, 536 size_t bufferSize, uint32 count, uint32* countRead) 537 { 538 if (!fFSOps->read_attrdir) 539 return B_BAD_VALUE; 540 541 *countRead = count; 542 543 // Haiku's struct dirent equals BeOS's version 544 return fFSOps->read_attrdir(fVolumeCookie, node, cookie, (long*)countRead, 545 (struct beos_dirent*)buffer, bufferSize); 546 } 547 548 // RewindAttrDir 549 status_t 550 BeOSKernelVolume::RewindAttrDir(void* node, void* cookie) 551 { 552 if (!fFSOps->rewind_attrdir) 553 return B_BAD_VALUE; 554 return fFSOps->rewind_attrdir(fVolumeCookie, node, cookie); 555 } 556 557 558 // #pragma mark - attributes 559 560 561 // CreateAttr 562 status_t 563 BeOSKernelVolume::CreateAttr(void* node, const char* name, uint32 type, 564 int openMode, void** cookie) 565 { 566 return _OpenAttr(node, name, type, openMode, true, cookie); 567 } 568 569 // OpenAttr 570 status_t 571 BeOSKernelVolume::OpenAttr(void* node, const char* name, int openMode, 572 void** cookie) 573 { 574 return _OpenAttr(node, name, 0, openMode, false, cookie); 575 } 576 577 // CloseAttr 578 status_t 579 BeOSKernelVolume::CloseAttr(void* node, void* cookie) 580 { 581 return B_OK; 582 } 583 584 // FreeAttrCookie 585 status_t 586 BeOSKernelVolume::FreeAttrCookie(void* node, void* _cookie) 587 { 588 AttributeCookie* cookie = (AttributeCookie*)_cookie; 589 590 // If the attribute doesn't exist yet and it was opened with 591 // CreateAttr(), we could create it now. We have a race condition here 592 // though, since someone else could have created it in the meantime. 593 594 delete cookie; 595 596 return B_OK; 597 } 598 599 // ReadAttr 600 status_t 601 BeOSKernelVolume::ReadAttr(void* node, void* _cookie, off_t pos, 602 void* buffer, size_t bufferSize, size_t* bytesRead) 603 { 604 AttributeCookie* cookie = (AttributeCookie*)_cookie; 605 606 // check, if open mode allows reading 607 if ((open_mode_to_access(cookie->fOpenMode) | R_OK) == 0) 608 return B_FILE_ERROR; 609 610 // read 611 if (!fFSOps->read_attr) 612 return B_BAD_VALUE; 613 614 *bytesRead = bufferSize; 615 return fFSOps->read_attr(fVolumeCookie, node, cookie->fName, cookie->fType, 616 buffer, bytesRead, pos); 617 } 618 619 // WriteAttr 620 status_t 621 BeOSKernelVolume::WriteAttr(void* node, void* _cookie, off_t pos, 622 const void* buffer, size_t bufferSize, size_t* bytesWritten) 623 { 624 AttributeCookie* cookie = (AttributeCookie*)_cookie; 625 626 // check, if open mode allows writing 627 if ((open_mode_to_access(cookie->fOpenMode) | W_OK) == 0) 628 return B_FILE_ERROR; 629 630 // write 631 if (!fFSOps->write_attr) 632 return B_BAD_VALUE; 633 634 *bytesWritten = bufferSize; 635 return fFSOps->write_attr(fVolumeCookie, node, cookie->fName, cookie->fType, 636 buffer, bytesWritten, pos); 637 } 638 639 // ReadAttrStat 640 status_t 641 BeOSKernelVolume::ReadAttrStat(void* node, void* _cookie, 642 struct stat *st) 643 { 644 AttributeCookie* cookie = (AttributeCookie*)_cookie; 645 646 // get the stats 647 beos_attr_info attrInfo; 648 if (!fFSOps->stat_attr) 649 return B_BAD_VALUE; 650 651 status_t error = fFSOps->stat_attr(fVolumeCookie, node, cookie->fName, 652 &attrInfo); 653 if (error != B_OK) 654 return error; 655 656 // translate to struct stat 657 st->st_size = attrInfo.size; 658 st->st_type = attrInfo.type; 659 660 return B_OK; 661 } 662 663 // RenameAttr 664 status_t 665 BeOSKernelVolume::RenameAttr(void* oldNode, const char* oldName, 666 void* newNode, const char* newName) 667 { 668 if (!fFSOps->rename_attr) 669 return B_BAD_VALUE; 670 if (oldNode != newNode) 671 return B_BAD_VALUE; 672 673 return fFSOps->rename_attr(fVolumeCookie, oldNode, oldName, newName); 674 } 675 676 // RemoveAttr 677 status_t 678 BeOSKernelVolume::RemoveAttr(void* node, const char* name) 679 { 680 if (!fFSOps->remove_attr) 681 return B_BAD_VALUE; 682 return fFSOps->remove_attr(fVolumeCookie, node, name); 683 } 684 685 686 // #pragma mark - indices 687 688 689 // OpenIndexDir 690 status_t 691 BeOSKernelVolume::OpenIndexDir(void** cookie) 692 { 693 if (!fFSOps->open_indexdir) 694 return B_BAD_VALUE; 695 return fFSOps->open_indexdir(fVolumeCookie, cookie); 696 } 697 698 // CloseIndexDir 699 status_t 700 BeOSKernelVolume::CloseIndexDir(void* cookie) 701 { 702 if (!fFSOps->close_indexdir) 703 return B_OK; 704 return fFSOps->close_indexdir(fVolumeCookie, cookie); 705 } 706 707 // FreeIndexDirCookie 708 status_t 709 BeOSKernelVolume::FreeIndexDirCookie(void* cookie) 710 { 711 if (!fFSOps->free_indexdircookie) 712 return B_OK; 713 return fFSOps->free_indexdircookie(fVolumeCookie, NULL, cookie); 714 } 715 716 // ReadIndexDir 717 status_t 718 BeOSKernelVolume::ReadIndexDir(void* cookie, void* buffer, 719 size_t bufferSize, uint32 count, uint32* countRead) 720 { 721 if (!fFSOps->read_indexdir) 722 return B_BAD_VALUE; 723 724 *countRead = count; 725 726 // Haiku's struct dirent equals BeOS's version 727 return fFSOps->read_indexdir(fVolumeCookie, cookie, (long*)countRead, 728 (struct beos_dirent*)buffer, bufferSize); 729 } 730 731 // RewindIndexDir 732 status_t 733 BeOSKernelVolume::RewindIndexDir(void* cookie) 734 { 735 if (!fFSOps->rewind_indexdir) 736 return B_BAD_VALUE; 737 return fFSOps->rewind_indexdir(fVolumeCookie, cookie); 738 } 739 740 // CreateIndex 741 status_t 742 BeOSKernelVolume::CreateIndex(const char* name, uint32 type, uint32 flags) 743 { 744 if (!fFSOps->create_index) 745 return B_BAD_VALUE; 746 return fFSOps->create_index(fVolumeCookie, name, (int)type, (int)flags); 747 } 748 749 // RemoveIndex 750 status_t 751 BeOSKernelVolume::RemoveIndex(const char* name) 752 { 753 if (!fFSOps->remove_index) 754 return B_BAD_VALUE; 755 return fFSOps->remove_index(fVolumeCookie, name); 756 } 757 758 // StatIndex 759 status_t 760 BeOSKernelVolume::ReadIndexStat(const char *name, struct stat *st) 761 { 762 if (!fFSOps->stat_index) 763 return B_BAD_VALUE; 764 765 beos_index_info indexInfo; 766 status_t error = fFSOps->stat_index(fVolumeCookie, name, &indexInfo); 767 if (error != B_OK) 768 return error; 769 770 // translate index_info into struct stat 771 st->st_type = indexInfo.type; 772 st->st_size = indexInfo.size; 773 st->st_mtime = indexInfo.modification_time; 774 st->st_crtime = indexInfo.creation_time; 775 st->st_uid = indexInfo.uid; 776 st->st_gid = indexInfo.gid; 777 778 return B_OK; 779 } 780 781 782 // #pragma mark - queries 783 784 785 // OpenQuery 786 status_t 787 BeOSKernelVolume::OpenQuery(const char* queryString, uint32 flags, port_id port, 788 uint32 token, void** cookie) 789 { 790 if (!fFSOps->open_query) 791 return B_BAD_VALUE; 792 return fFSOps->open_query(fVolumeCookie, queryString, flags, port, 793 (long)token, cookie); 794 } 795 796 // CloseQuery 797 status_t 798 BeOSKernelVolume::CloseQuery(void* cookie) 799 { 800 if (!fFSOps->close_query) 801 return B_OK; 802 return fFSOps->close_query(fVolumeCookie, cookie); 803 } 804 805 // FreeQueryCookie 806 status_t 807 BeOSKernelVolume::FreeQueryCookie(void* cookie) 808 { 809 if (!fFSOps->free_querycookie) 810 return B_OK; 811 return fFSOps->free_querycookie(fVolumeCookie, NULL, cookie); 812 } 813 814 // ReadQuery 815 status_t 816 BeOSKernelVolume::ReadQuery(void* cookie, void* buffer, size_t bufferSize, 817 uint32 count, uint32* countRead) 818 { 819 if (!fFSOps->read_query) 820 return B_BAD_VALUE; 821 822 *countRead = count; 823 824 // Haiku's struct dirent equals BeOS's version 825 return fFSOps->read_query(fVolumeCookie, cookie, (long*)countRead, 826 (struct beos_dirent*)buffer, bufferSize); 827 } 828 829 830 // #pragma mark - Private 831 832 833 // _OpenAttr 834 status_t 835 BeOSKernelVolume::_OpenAttr(void* node, const char* name, uint32 type, 836 int openMode, bool create, void** _cookie) 837 { 838 // check permissions first 839 int accessMode = open_mode_to_access(openMode) | (create ? W_OK : 0); 840 status_t error = Access(node, accessMode); 841 if (error != B_OK) 842 return error; 843 844 // check whether the attribute already exists 845 beos_attr_info attrInfo; 846 if (!fFSOps->stat_attr) 847 return B_BAD_VALUE; 848 bool exists 849 = (fFSOps->stat_attr(fVolumeCookie, node, name, &attrInfo) == B_OK); 850 851 if (create) { 852 // create: fail, if attribute exists and non-existence was required 853 if (exists && (openMode & O_EXCL)) 854 return B_FILE_EXISTS; 855 } else { 856 // open: fail, if attribute doesn't exist 857 if (!exists) 858 return B_ENTRY_NOT_FOUND; 859 860 // keep the attribute type 861 type = attrInfo.type; 862 } 863 864 // create an attribute cookie 865 AttributeCookie* cookie = new(nothrow) AttributeCookie(name, type, 866 openMode, exists, create); 867 if (!cookie) 868 return B_NO_MEMORY; 869 870 // TODO: If we want to support O_TRUNC, we should do that here. 871 872 *_cookie = cookie; 873 return B_OK; 874 } 875 876 // open_mode_to_access 877 static int 878 open_mode_to_access(int openMode) 879 { 880 switch (openMode & O_RWMASK) { 881 case O_RDONLY: 882 return R_OK; 883 case O_WRONLY: 884 return W_OK; 885 case O_RDWR: 886 default: 887 return W_OK | R_OK; 888 } 889 } 890 891