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