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