1 //---------------------------------------------------------------------- 2 // This software is part of the Haiku distribution and is covered 3 // by the MIT license. 4 //---------------------------------------------------------------------- 5 /*! 6 \file Node.cpp 7 BNode implementation. 8 */ 9 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <fs_attr.h> // for struct attr_info 13 #include <new> 14 #include <string.h> 15 #include <unistd.h> 16 17 #include <Directory.h> 18 #include <Entry.h> 19 #include <Node.h> 20 #include <String.h> 21 #include <TypeConstants.h> 22 23 #include <syscalls.h> 24 25 #include "storage_support.h" 26 27 //---------------------------------------------------------------------- 28 // node_ref 29 //---------------------------------------------------------------------- 30 31 // constructor 32 /*! \brief Creates an uninitialized node_ref object. 33 */ 34 node_ref::node_ref() 35 : device((dev_t)-1), 36 node((ino_t)-1) 37 { 38 } 39 40 // copy constructor 41 /*! \brief Creates a copy of the given node_ref object. 42 \param ref the node_ref to be copied 43 */ 44 node_ref::node_ref(const node_ref &ref) 45 : device((dev_t)-1), 46 node((ino_t)-1) 47 { 48 *this = ref; 49 } 50 51 // == 52 /*! \brief Tests whether this node_ref and the supplied one are equal. 53 \param ref the node_ref to be compared with 54 \return \c true, if the objects are equal, \c false otherwise 55 */ 56 bool 57 node_ref::operator==(const node_ref &ref) const 58 { 59 return (device == ref.device && node == ref.node); 60 } 61 62 // != 63 /*! \brief Tests whether this node_ref and the supplied one are not equal. 64 \param ref the node_ref to be compared with 65 \return \c false, if the objects are equal, \c true otherwise 66 */ 67 bool 68 node_ref::operator!=(const node_ref &ref) const 69 { 70 return !(*this == ref); 71 } 72 73 // = 74 /*! \brief Makes this node ref a copy of the supplied one. 75 \param ref the node_ref to be copied 76 \return a reference to this object 77 */ 78 node_ref& 79 node_ref::operator=(const node_ref &ref) 80 { 81 device = ref.device; 82 node = ref.node; 83 return *this; 84 } 85 86 //---------------------------------------------------------------------- 87 // BNode 88 //---------------------------------------------------------------------- 89 90 /*! \brief Creates an uninitialized BNode object 91 */ 92 BNode::BNode() 93 : fFd(-1), 94 fAttrFd(-1), 95 fCStatus(B_NO_INIT) 96 { 97 } 98 99 /*! \brief Creates a BNode object and initializes it to the specified 100 entry_ref. 101 \param ref the entry_ref referring to the entry 102 */ 103 BNode::BNode(const entry_ref *ref) 104 : fFd(-1), 105 fAttrFd(-1), 106 fCStatus(B_NO_INIT) 107 { 108 SetTo(ref); 109 } 110 111 /*! \brief Creates a BNode object and initializes it to the specified 112 filesystem entry. 113 \param entry the BEntry representing the entry 114 */ 115 BNode::BNode(const BEntry *entry) 116 : fFd(-1), 117 fAttrFd(-1), 118 fCStatus(B_NO_INIT) 119 { 120 SetTo(entry); 121 } 122 123 /*! \brief Creates a BNode object and initializes it to the entry referred 124 to by the specified path. 125 \param path the path referring to the entry 126 */ 127 BNode::BNode(const char *path) 128 : fFd(-1), 129 fAttrFd(-1), 130 fCStatus(B_NO_INIT) 131 { 132 SetTo(path); 133 } 134 135 /*! \brief Creates a BNode object and initializes it to the entry referred 136 to by the specified path rooted in the specified directory. 137 \param dir the BDirectory, relative to which the entry's path name is 138 given 139 \param path the entry's path name relative to \a dir 140 */ 141 BNode::BNode(const BDirectory *dir, const char *path) 142 : fFd(-1), 143 fAttrFd(-1), 144 fCStatus(B_NO_INIT) 145 { 146 SetTo(dir, path); 147 } 148 149 /*! \brief Creates a copy of the given BNode. 150 \param node the BNode to be copied 151 */ 152 BNode::BNode(const BNode &node) 153 : fFd(-1), 154 fAttrFd(-1), 155 fCStatus(B_NO_INIT) 156 { 157 *this = node; 158 } 159 160 /*! \brief Frees all resources associated with this BNode. 161 */ 162 BNode::~BNode() 163 { 164 Unset(); 165 } 166 167 /*! \brief Checks whether the object has been properly initialized or not. 168 \return 169 - \c B_OK, if the object has been properly initialized, 170 - an error code, otherwise. 171 */ 172 status_t 173 BNode::InitCheck() const 174 { 175 return fCStatus; 176 } 177 178 /*! \brief Fills in the given stat structure with \code stat() \endcode 179 information for this object. 180 \param st a pointer to a stat structure to be filled in 181 \return 182 - \c B_OK: Everything went fine. 183 - \c B_BAD_VALUE: \c NULL \a st. 184 - another error code, e.g., if the object wasn't properly initialized 185 */ 186 status_t 187 BNode::GetStat(struct stat *st) const 188 { 189 return (fCStatus != B_OK) 190 ? fCStatus 191 : _kern_read_stat(fFd, NULL, false, st, sizeof(struct stat)); 192 } 193 194 /*! \brief Reinitializes the object to the specified entry_ref. 195 \param ref the entry_ref referring to the entry 196 \return 197 - \c B_OK: Everything went fine. 198 - \c B_BAD_VALUE: \c NULL \a ref. 199 - \c B_ENTRY_NOT_FOUND: The entry could not be found. 200 - \c B_BUSY: The entry is locked. 201 */ 202 status_t 203 BNode::SetTo(const entry_ref *ref) 204 { 205 return _SetTo(ref, false); 206 } 207 208 /*! \brief Reinitializes the object to the specified filesystem entry. 209 \param entry the BEntry representing the entry 210 \return 211 - \c B_OK: Everything went fine. 212 - \c B_BAD_VALUE: \c NULL \a entry. 213 - \c B_ENTRY_NOT_FOUND: The entry could not be found. 214 - \c B_BUSY: The entry is locked. 215 */ 216 status_t 217 BNode::SetTo(const BEntry *entry) 218 { 219 if (!entry) { 220 Unset(); 221 return (fCStatus = B_BAD_VALUE); 222 } 223 return _SetTo(entry->fDirFd, entry->fName, false); 224 } 225 226 /*! \brief Reinitializes the object to the entry referred to by the specified 227 path. 228 \param path the path referring to the entry 229 \return 230 - \c B_OK: Everything went fine. 231 - \c B_BAD_VALUE: \c NULL \a path. 232 - \c B_ENTRY_NOT_FOUND: The entry could not be found. 233 - \c B_BUSY: The entry is locked. 234 */ 235 status_t 236 BNode::SetTo(const char *path) 237 { 238 return _SetTo(-1, path, false); 239 } 240 241 /*! \brief Reinitializes the object to the entry referred to by the specified 242 path rooted in the specified directory. 243 \param dir the BDirectory, relative to which the entry's path name is 244 given 245 \param path the entry's path name relative to \a dir 246 \return 247 - \c B_OK: Everything went fine. 248 - \c B_BAD_VALUE: \c NULL \a dir or \a path. 249 - \c B_ENTRY_NOT_FOUND: The entry could not be found. 250 - \c B_BUSY: The entry is locked. 251 */ 252 status_t 253 BNode::SetTo(const BDirectory *dir, const char *path) 254 { 255 if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) { 256 Unset(); 257 return (fCStatus = B_BAD_VALUE); 258 } 259 return _SetTo(dir->fDirFd, path, false); 260 } 261 262 /*! \brief Returns the object to an uninitialized state. 263 */ 264 void 265 BNode::Unset() 266 { 267 close_fd(); 268 fCStatus = B_NO_INIT; 269 } 270 271 /*! \brief Attains an exclusive lock on the data referred to by this node, so 272 that it may not be modified by any other objects or methods. 273 \return 274 - \c B_OK: Everything went fine. 275 - \c B_FILE_ERROR: The object is not initialized. 276 - \c B_BUSY: The node is already locked. 277 */ 278 status_t 279 BNode::Lock() 280 { 281 if (fCStatus != B_OK) 282 return fCStatus; 283 return _kern_lock_node(fFd); 284 } 285 286 /*! \brief Unlocks the node. 287 \return 288 - \c B_OK: Everything went fine. 289 - \c B_FILE_ERROR: The object is not initialized. 290 - \c B_BAD_VALUE: The node is not locked. 291 */ 292 status_t 293 BNode::Unlock() 294 { 295 if (fCStatus != B_OK) 296 return fCStatus; 297 return _kern_unlock_node(fFd); 298 } 299 300 /*! \brief Immediately performs any pending disk actions on the node. 301 \return 302 - \c B_OK: Everything went fine. 303 - an error code, if something went wrong. 304 */ 305 status_t 306 BNode::Sync() 307 { 308 return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_fsync(fFd); 309 } 310 311 /*! \brief Writes data from a buffer to an attribute. 312 Write the \a len bytes of data from \a buffer to 313 the attribute specified by \a name after erasing any data 314 that existed previously. The type specified by \a type \em is 315 remembered, and may be queried with GetAttrInfo(). The value of 316 \a offset is currently ignored. 317 \param attr the name of the attribute 318 \param type the type of the attribute 319 \param offset the index at which to write the data (currently ignored) 320 \param buffer the buffer containing the data to be written 321 \param len the number of bytes to be written 322 \return 323 - the number of bytes actually written 324 - \c B_BAD_VALUE: \c NULL \a attr or \a buffer 325 - \c B_FILE_ERROR: The object is not initialized or the node it refers to 326 is read only. 327 - \c B_NOT_ALLOWED: The node resides on a read only volume. 328 - \c B_DEVICE_FULL: Insufficient disk space. 329 - \c B_NO_MEMORY: Insufficient memory to complete the operation. 330 */ 331 ssize_t 332 BNode::WriteAttr(const char *attr, type_code type, off_t offset, 333 const void *buffer, size_t len) 334 { 335 if (fCStatus != B_OK) 336 return B_FILE_ERROR; 337 if (!attr || !buffer) 338 return B_BAD_VALUE; 339 ssize_t result = fs_write_attr (fFd, attr, type, offset, buffer, len); 340 return (result < 0 ? errno : result); 341 } 342 343 /*! \brief Reads data from an attribute into a buffer. 344 Reads the data of the attribute given by \a name into 345 the buffer specified by \a buffer with length specified 346 by \a len. \a type and \a offset are currently ignored. 347 \param attr the name of the attribute 348 \param type the type of the attribute (currently ignored) 349 \param offset the index from which to read the data (currently ignored) 350 \param buffer the buffer for the data to be read 351 \param len the number of bytes to be read 352 \return 353 - the number of bytes actually read 354 - \c B_BAD_VALUE: \c NULL \a attr or \a buffer 355 - \c B_FILE_ERROR: The object is not initialized. 356 - \c B_ENTRY_NOT_FOUND: The node has no attribute \a attr. 357 */ 358 ssize_t 359 BNode::ReadAttr(const char *attr, type_code type, off_t offset, 360 void *buffer, size_t len) const 361 { 362 if (fCStatus != B_OK) 363 return B_FILE_ERROR; 364 if (!attr || !buffer) 365 return B_BAD_VALUE; 366 ssize_t result = fs_read_attr(fFd, attr, type, offset, buffer, len ); 367 return (result == -1 ? errno : result); 368 } 369 370 /*! \brief Deletes the attribute given by \a name. 371 \param name the name of the attribute 372 - \c B_OK: Everything went fine. 373 - \c B_BAD_VALUE: \c NULL \a name 374 - \c B_FILE_ERROR: The object is not initialized or the node it refers to 375 is read only. 376 - \c B_ENTRY_NOT_FOUND: The node has no attribute \a name. 377 - \c B_NOT_ALLOWED: The node resides on a read only volume. 378 */ 379 status_t 380 BNode::RemoveAttr(const char *name) 381 { 382 return (fCStatus != B_OK) ? B_FILE_ERROR : _kern_remove_attr(fFd, name); 383 } 384 385 /*! \brief Moves the attribute given by \a oldname to \a newname. 386 If \a newname already exists, the current data is clobbered. 387 \param oldname the name of the attribute to be renamed 388 \param newname the new name for the attribute 389 \return 390 - \c B_OK: Everything went fine. 391 - \c B_BAD_VALUE: \c NULL \a oldname or \a newname 392 - \c B_FILE_ERROR: The object is not initialized or the node it refers to 393 is read only. 394 - \c B_ENTRY_NOT_FOUND: The node has no attribute \a oldname. 395 - \c B_NOT_ALLOWED: The node resides on a read only volume. 396 */ 397 status_t 398 BNode::RenameAttr(const char *oldname, const char *newname) 399 { 400 if (fCStatus != B_OK) 401 return B_FILE_ERROR; 402 return _kern_rename_attr(fFd, oldname, fFd, newname); 403 } 404 405 406 /*! \brief Fills in the pre-allocated attr_info struct pointed to by \a info 407 with useful information about the attribute specified by \a name. 408 \param name the name of the attribute 409 \param info the attr_info structure to be filled in 410 \return 411 - \c B_OK: Everything went fine. 412 - \c B_BAD_VALUE: \c NULL \a name 413 - \c B_FILE_ERROR: The object is not initialized. 414 - \c B_ENTRY_NOT_FOUND: The node has no attribute \a name. 415 */ 416 status_t 417 BNode::GetAttrInfo(const char *name, struct attr_info *info) const 418 { 419 if (fCStatus != B_OK) 420 return B_FILE_ERROR; 421 if (!name || !info) 422 return B_BAD_VALUE; 423 return (fs_stat_attr(fFd, name, info) < 0) ? errno : B_OK ; 424 } 425 426 /*! \brief Returns the next attribute in the node's list of attributes. 427 Every BNode maintains a pointer to its list of attributes. 428 GetNextAttrName() retrieves the name of the attribute that the pointer is 429 currently pointing to, and then bumps the pointer to the next attribute. 430 The name is copied into the buffer, which should be at least 431 B_ATTR_NAME_LENGTH characters long. The copied name is NULL-terminated. 432 When you've asked for every name in the list, GetNextAttrName() 433 returns \c B_ENTRY_NOT_FOUND. 434 \param buffer the buffer the name of the next attribute shall be stored in 435 (must be at least \c B_ATTR_NAME_LENGTH bytes long) 436 \return 437 - \c B_OK: Everything went fine. 438 - \c B_BAD_VALUE: \c NULL \a buffer. 439 - \c B_FILE_ERROR: The object is not initialized. 440 - \c B_ENTRY_NOT_FOUND: There are no more attributes, the last attribute 441 name has already been returned. 442 */ 443 status_t 444 BNode::GetNextAttrName(char *buffer) 445 { 446 // We're allowed to assume buffer is at least 447 // B_ATTR_NAME_LENGTH chars long, but NULLs 448 // are not acceptable. 449 if (buffer == NULL) 450 return B_BAD_VALUE; // /new R5 crashed when passed NULL 451 if (InitAttrDir() != B_OK) 452 return B_FILE_ERROR; 453 454 BPrivate::Storage::LongDirEntry entry; 455 ssize_t result = _kern_read_dir(fAttrFd, &entry, sizeof(entry), 1); 456 if (result < 0) 457 return result; 458 if (result == 0) 459 return B_ENTRY_NOT_FOUND; 460 strlcpy(buffer, entry.d_name, B_ATTR_NAME_LENGTH); 461 return B_OK; 462 } 463 464 /*! \brief Resets the object's attribute pointer to the first attribute in the 465 list. 466 \return 467 - \c B_OK: Everything went fine. 468 - \c B_FILE_ERROR: Some error occured. 469 */ 470 status_t 471 BNode::RewindAttrs() 472 { 473 if (InitAttrDir() != B_OK) 474 return B_FILE_ERROR; 475 return _kern_rewind_dir(fAttrFd); 476 } 477 478 /*! Writes the specified string to the specified attribute, clobbering any 479 previous data. 480 \param name the name of the attribute 481 \param data the BString to be written to the attribute 482 - \c B_OK: Everything went fine. 483 - \c B_BAD_VALUE: \c NULL \a name or \a data 484 - \c B_FILE_ERROR: The object is not initialized or the node it refers to 485 is read only. 486 - \c B_NOT_ALLOWED: The node resides on a read only volume. 487 - \c B_DEVICE_FULL: Insufficient disk space. 488 - \c B_NO_MEMORY: Insufficient memory to complete the operation. 489 */ 490 status_t 491 BNode::WriteAttrString(const char *name, const BString *data) 492 { 493 status_t error = (!name || !data) ? B_BAD_VALUE : B_OK; 494 if (error == B_OK) { 495 int32 len = data->Length() + 1; 496 ssize_t sizeWritten = WriteAttr(name, B_STRING_TYPE, 0, data->String(), 497 len); 498 if (sizeWritten != len) 499 error = sizeWritten; 500 } 501 return error; 502 } 503 504 /*! \brief Reads the data of the specified attribute into the pre-allocated 505 \a result. 506 \param name the name of the attribute 507 \param result the BString to be set to the value of the attribute 508 \return 509 - \c B_OK: Everything went fine. 510 - \c B_BAD_VALUE: \c NULL \a name or \a result 511 - \c B_FILE_ERROR: The object is not initialized. 512 - \c B_ENTRY_NOT_FOUND: The node has no attribute \a attr. 513 */ 514 status_t 515 BNode::ReadAttrString(const char *name, BString *result) const 516 { 517 if (!name || !result) 518 return B_BAD_VALUE; 519 520 attr_info info; 521 status_t error; 522 523 error = GetAttrInfo(name, &info); 524 if (error != B_OK) 525 return error; 526 // Lock the string's buffer so we can meddle with it 527 char *data = result->LockBuffer(info.size+1); 528 if (!data) 529 return B_NO_MEMORY; 530 // Read the attribute 531 ssize_t bytes = ReadAttr(name, B_STRING_TYPE, 0, data, info.size); 532 // Check for failure 533 if (bytes < 0) { 534 error = bytes; 535 bytes = 0; // In this instance, we simply clear the string 536 } else 537 error = B_OK; 538 // Null terminate the new string just to be sure (since it *is* 539 // possible to read and write non-NULL-terminated strings) 540 data[bytes] = 0; 541 result->UnlockBuffer(); 542 return error; 543 } 544 545 /*! \brief Reinitializes the object as a copy of the \a node. 546 \param node the BNode to be copied 547 \return a reference to this BNode object. 548 */ 549 BNode& 550 BNode::operator=(const BNode &node) 551 { 552 // No need to do any assignment if already equal 553 if (*this == node) 554 return *this; 555 // Close down out current state 556 Unset(); 557 // We have to manually dup the node, because R5::BNode::Dup() 558 // is not declared to be const (which IMO is retarded). 559 fFd = _kern_dup(node.fFd); 560 fCStatus = (fFd < 0) ? B_NO_INIT : B_OK ; 561 return *this; 562 } 563 564 /*! Tests whether this and the supplied BNode object are equal. 565 Two BNode objects are said to be equal if they're set to the same node, 566 or if they're both \c B_NO_INIT. 567 \param node the BNode to be compared with 568 \return \c true, if the BNode objects are equal, \c false otherwise 569 */ 570 bool 571 BNode::operator==(const BNode &node) const 572 { 573 if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT) 574 return true; 575 if (fCStatus == B_OK && node.InitCheck() == B_OK) { 576 // compare the node_refs 577 node_ref ref1, ref2; 578 if (GetNodeRef(&ref1) != B_OK) 579 return false; 580 if (node.GetNodeRef(&ref2) != B_OK) 581 return false; 582 return (ref1 == ref2); 583 } 584 return false; 585 } 586 587 /*! Tests whether this and the supplied BNode object are not equal. 588 Two BNode objects are said to be equal if they're set to the same node, 589 or if they're both \c B_NO_INIT. 590 \param node the BNode to be compared with 591 \return \c false, if the BNode objects are equal, \c true otherwise 592 */ 593 bool 594 BNode::operator!=(const BNode &node) const 595 { 596 return !(*this == node); 597 } 598 599 /*! \brief Returns a POSIX file descriptor to the node this object refers to. 600 Remember to call close() on the file descriptor when you're through with 601 it. 602 \return a valid file descriptor, or -1, if something went wrong. 603 */ 604 int 605 BNode::Dup() 606 { 607 int fd = _kern_dup(fFd); 608 return (fd >= 0 ? fd : -1); // comply with R5 return value 609 } 610 611 612 /*! (currently unused) */ 613 void BNode::_RudeNode1() { } 614 void BNode::_RudeNode2() { } 615 void BNode::_RudeNode3() { } 616 void BNode::_RudeNode4() { } 617 void BNode::_RudeNode5() { } 618 void BNode::_RudeNode6() { } 619 620 /*! \brief Sets the node's file descriptor. 621 Used by each implementation (i.e. BNode, BFile, BDirectory, etc.) to set 622 the node's file descriptor. This allows each subclass to use the various 623 file-type specific system calls for opening file descriptors. 624 \param fd the file descriptor this BNode should be set to (may be -1) 625 \return \c B_OK, if everything went fine, an error code otherwise. 626 \note This method calls close_fd() to close previously opened FDs. Thus 627 derived classes should take care to first call set_fd() and set 628 class specific resources freed in their close_fd() version 629 thereafter. 630 */ 631 status_t 632 BNode::set_fd(int fd) 633 { 634 if (fFd != -1) 635 close_fd(); 636 fFd = fd; 637 return B_OK; 638 } 639 640 /*! \brief Closes the node's file descriptor(s). 641 To be implemented by subclasses to close the file descriptor using the 642 proper system call for the given file-type. This implementation calls 643 _kern_close(fFd) and also _kern_close(fAttrDir) if necessary. 644 */ 645 void 646 BNode::close_fd() 647 { 648 if (fAttrFd >= 0) 649 { 650 _kern_close(fAttrFd); 651 fAttrFd = -1; 652 } 653 if (fFd >= 0) { 654 _kern_close(fFd); 655 fFd = -1; 656 } 657 } 658 659 // set_status 660 /*! \brief Sets the BNode's status. 661 To be used by derived classes instead of accessing the BNode's private 662 \c fCStatus member directly. 663 \param newStatus the new value for the status variable. 664 */ 665 void 666 BNode::set_status(status_t newStatus) 667 { 668 fCStatus = newStatus; 669 } 670 671 // _SetTo 672 /*! \brief Initializes the BNode's file descriptor to the node referred to 673 by the given FD and path combo. 674 675 \a path must either be \c NULL, an absolute or a relative path. 676 In the first case, \a fd must not be \c NULL; the node it refers to will 677 be opened. If absolute, \a fd is ignored. If relative and \a fd is >= 0, 678 it will be reckoned off the directory identified by \a fd, otherwise off 679 the current working directory. 680 681 The method will first try to open the node with read and write permission. 682 If that fails due to a read-only FS or because the user has no write 683 permission for the node, it will re-try opening the node read-only. 684 685 The \a fCStatus member will be set to the return value of this method. 686 687 \param fd Either a directory FD or a value < 0. In the latter case \a path 688 must be specified. 689 \param path Either \a NULL in which case \a fd must be given, absolute, or 690 relative to the directory specified by \a fd (if given) or to the 691 current working directory. 692 \param traverse If the node identified by \a fd and \a path is a symlink 693 and \a traverse is \c true, the symlink will be resolved recursively. 694 \return \c B_OK, if everything went fine, another error code otherwise. 695 */ 696 status_t 697 BNode::_SetTo(int fd, const char *path, bool traverse) 698 { 699 Unset(); 700 status_t error = (fd >= 0 || path ? B_OK : B_BAD_VALUE); 701 if (error == B_OK) { 702 int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); 703 fFd = _kern_open(fd, path, O_RDWR | traverseFlag, 0); 704 if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) { 705 // opening read-write failed, re-try read-only 706 fFd = _kern_open(fd, path, O_RDONLY | traverseFlag, 0); 707 } 708 if (fFd < 0) 709 error = fFd; 710 else 711 fcntl(fFd, F_SETFD, FD_CLOEXEC); 712 } 713 return fCStatus = error; 714 } 715 716 // _SetTo 717 /*! \brief Initializes the BNode's file descriptor to the node referred to 718 by the given entry_ref. 719 720 The method will first try to open the node with read and write permission. 721 If that fails due to a read-only FS or because the user has no write 722 permission for the node, it will re-try opening the node read-only. 723 724 The \a fCStatus member will be set to the return value of this method. 725 726 \param ref An entry_ref identifying the node to be opened. 727 \param traverse If the node identified by \a ref is a symlink 728 and \a traverse is \c true, the symlink will be resolved recursively. 729 \return \c B_OK, if everything went fine, another error code otherwise. 730 */ 731 status_t 732 BNode::_SetTo(const entry_ref *ref, bool traverse) 733 { 734 Unset(); 735 status_t error = (ref ? B_OK : B_BAD_VALUE); 736 if (error == B_OK) { 737 int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); 738 fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 739 O_RDWR | traverseFlag, 0); 740 if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) { 741 // opening read-write failed, re-try read-only 742 fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 743 O_RDONLY | traverseFlag, 0); 744 } 745 if (fFd < 0) 746 error = fFd; 747 else 748 fcntl(fFd, F_SETFD, FD_CLOEXEC); 749 } 750 return fCStatus = error; 751 } 752 753 /*! \brief Modifies a certain setting for this node based on \a what and the 754 corresponding value in \a st. 755 Inherited from and called by BStatable. 756 \param st a stat structure containing the value to be set 757 \param what specifies what setting to be modified 758 \return \c B_OK if everything went fine, an error code otherwise. 759 */ 760 status_t 761 BNode::set_stat(struct stat &st, uint32 what) 762 { 763 if (fCStatus != B_OK) 764 return B_FILE_ERROR; 765 return _kern_write_stat(fFd, NULL, false, &st, sizeof(struct stat), 766 what); 767 } 768 769 /*! \brief Verifies that the BNode has been properly initialized, and then 770 (if necessary) opens the attribute directory on the node's file 771 descriptor, storing it in fAttrDir. 772 \return \c B_OK if everything went fine, an error code otherwise. 773 */ 774 status_t 775 BNode::InitAttrDir() 776 { 777 if (fCStatus == B_OK && fAttrFd < 0) { 778 fAttrFd = _kern_open_attr_dir(fFd, NULL); 779 if (fAttrFd < 0) 780 return fAttrFd; 781 782 // set close on exec flag 783 fcntl(fAttrFd, F_SETFD, FD_CLOEXEC); 784 } 785 return fCStatus; 786 } 787 788 /*! \var BNode::fFd 789 File descriptor for the given node. 790 */ 791 792 /*! \var BNode::fAttrFd 793 File descriptor for the attribute directory of the node. Initialized lazily. 794 */ 795 796 /*! \var BNode::fCStatus 797 The object's initialization status. 798 */ 799 800