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 21using std::nothrow; 22 23static int open_mode_to_access(int openMode); 24 25 26// AttributeCookie 27class BeOSKernelVolume::AttributeCookie { 28public: 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 48inline BeOSKernelFileSystem* 49BeOSKernelVolume::_FileSystem() const 50{ 51 return static_cast<BeOSKernelFileSystem*>(fFileSystem); 52} 53 54 55// constructor 56BeOSKernelVolume::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 68BeOSKernelVolume::~BeOSKernelVolume() 69{ 70} 71 72// #pragma mark - 73// #pragma mark ----- FS ----- 74 75// Mount 76status_t 77BeOSKernelVolume::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 94status_t 95BeOSKernelVolume::Unmount() 96{ 97 if (!fFSOps->unmount) 98 return B_BAD_VALUE; 99 return fFSOps->unmount(fVolumeCookie); 100} 101 102// Sync 103status_t 104BeOSKernelVolume::Sync() 105{ 106 if (!fFSOps->sync) 107 return B_BAD_VALUE; 108 return fFSOps->sync(fVolumeCookie); 109} 110 111// ReadFSInfo 112status_t 113BeOSKernelVolume::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 123status_t 124BeOSKernelVolume::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 138status_t 139BeOSKernelVolume::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 148status_t 149BeOSKernelVolume::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 178status_t 179BeOSKernelVolume::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 207status_t 208BeOSKernelVolume::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 216status_t 217BeOSKernelVolume::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 229status_t 230BeOSKernelVolume::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 240status_t 241BeOSKernelVolume::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 249status_t 250BeOSKernelVolume::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 261status_t 262BeOSKernelVolume::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 271status_t 272BeOSKernelVolume::FSync(void* node) 273{ 274 if (!fFSOps->fsync) 275 return B_BAD_VALUE; 276 return fFSOps->fsync(fVolumeCookie, node); 277} 278 279// ReadSymlink 280status_t 281BeOSKernelVolume::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 291status_t 292BeOSKernelVolume::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 302status_t 303BeOSKernelVolume::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 311status_t 312BeOSKernelVolume::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 320status_t 321BeOSKernelVolume::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 330status_t 331BeOSKernelVolume::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 339status_t 340BeOSKernelVolume::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 351status_t 352BeOSKernelVolume::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 368status_t 369BeOSKernelVolume::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 379status_t 380BeOSKernelVolume::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 388status_t 389BeOSKernelVolume::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 397status_t 398BeOSKernelVolume::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 406status_t 407BeOSKernelVolume::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 417status_t 418BeOSKernelVolume::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 433status_t 434BeOSKernelVolume::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 443status_t 444BeOSKernelVolume::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 452status_t 453BeOSKernelVolume::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 461status_t 462BeOSKernelVolume::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 470status_t 471BeOSKernelVolume::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 479status_t 480BeOSKernelVolume::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 494status_t 495BeOSKernelVolume::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 507status_t 508BeOSKernelVolume::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 516status_t 517BeOSKernelVolume::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 525status_t 526BeOSKernelVolume::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 534status_t 535BeOSKernelVolume::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 549status_t 550BeOSKernelVolume::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 562status_t 563BeOSKernelVolume::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 570status_t 571BeOSKernelVolume::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 578status_t 579BeOSKernelVolume::CloseAttr(void* node, void* cookie) 580{ 581 return B_OK; 582} 583 584// FreeAttrCookie 585status_t 586BeOSKernelVolume::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 600status_t 601BeOSKernelVolume::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 620status_t 621BeOSKernelVolume::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 640status_t 641BeOSKernelVolume::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 664status_t 665BeOSKernelVolume::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 677status_t 678BeOSKernelVolume::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 690status_t 691BeOSKernelVolume::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 699status_t 700BeOSKernelVolume::CloseIndexDir(void* cookie) 701{ 702 if (!fFSOps->close_indexdir) 703 return B_OK; 704 return fFSOps->close_indexdir(fVolumeCookie, cookie); 705} 706 707// FreeIndexDirCookie 708status_t 709BeOSKernelVolume::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 717status_t 718BeOSKernelVolume::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 732status_t 733BeOSKernelVolume::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 741status_t 742BeOSKernelVolume::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 750status_t 751BeOSKernelVolume::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 759status_t 760BeOSKernelVolume::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 786status_t 787BeOSKernelVolume::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 797status_t 798BeOSKernelVolume::CloseQuery(void* cookie) 799{ 800 if (!fFSOps->close_query) 801 return B_OK; 802 return fFSOps->close_query(fVolumeCookie, cookie); 803} 804 805// FreeQueryCookie 806status_t 807BeOSKernelVolume::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 815status_t 816BeOSKernelVolume::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 834status_t 835BeOSKernelVolume::_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 877static int 878open_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