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 longEntry; 323 struct dirent* entry = longEntry.dirent(); 324 ssize_t result = _kern_read_dir(fAttrFd, entry, sizeof(longEntry), 1); 325 if (result < 0) 326 return result; 327 328 if (result == 0) 329 return B_ENTRY_NOT_FOUND; 330 331 strlcpy(buffer, entry->d_name, B_ATTR_NAME_LENGTH); 332 333 return B_OK; 334 } 335 336 337 status_t 338 BNode::RewindAttrs() 339 { 340 if (InitAttrDir() != B_OK) 341 return B_FILE_ERROR; 342 343 return _kern_rewind_dir(fAttrFd); 344 } 345 346 347 status_t 348 BNode::WriteAttrString(const char* name, const BString* data) 349 { 350 status_t error = (!name || !data) ? B_BAD_VALUE : B_OK; 351 if (error == B_OK) { 352 int32 length = data->Length() + 1; 353 ssize_t sizeWritten = WriteAttr(name, B_STRING_TYPE, 0, data->String(), 354 length); 355 if (sizeWritten != length) 356 error = sizeWritten; 357 } 358 359 return error; 360 } 361 362 363 status_t 364 BNode::ReadAttrString(const char* name, BString* result) const 365 { 366 if (name == NULL || result == NULL) 367 return B_BAD_VALUE; 368 369 attr_info info; 370 status_t error; 371 372 error = GetAttrInfo(name, &info); 373 if (error != B_OK) 374 return error; 375 376 // Lock the string's buffer so we can meddle with it 377 char* data = result->LockBuffer(info.size + 1); 378 if (data == NULL) 379 return B_NO_MEMORY; 380 381 // Read the attribute 382 ssize_t bytes = ReadAttr(name, B_STRING_TYPE, 0, data, info.size); 383 // Check for failure 384 if (bytes < 0) { 385 error = bytes; 386 bytes = 0; 387 // In this instance, we simply clear the string 388 } else 389 error = B_OK; 390 391 // Null terminate the new string just to be sure (since it *is* 392 // possible to read and write non-NULL-terminated strings) 393 data[bytes] = 0; 394 result->UnlockBuffer(); 395 396 return error; 397 } 398 399 400 BNode& 401 BNode::operator=(const BNode& node) 402 { 403 // No need to do any assignment if already equal 404 if (*this == node) 405 return *this; 406 407 // Close down out current state 408 Unset(); 409 // We have to manually dup the node, because R5::BNode::Dup() 410 // is not declared to be const (which IMO is retarded). 411 fFd = _kern_dup(node.fFd); 412 fCStatus = (fFd < 0) ? B_NO_INIT : B_OK ; 413 414 return *this; 415 } 416 417 418 bool 419 BNode::operator==(const BNode& node) const 420 { 421 if (fCStatus == B_NO_INIT && node.InitCheck() == B_NO_INIT) 422 return true; 423 424 if (fCStatus == B_OK && node.InitCheck() == B_OK) { 425 // compare the node_refs 426 node_ref ref1, ref2; 427 if (GetNodeRef(&ref1) != B_OK) 428 return false; 429 430 if (node.GetNodeRef(&ref2) != B_OK) 431 return false; 432 433 return (ref1 == ref2); 434 } 435 436 return false; 437 } 438 439 440 bool 441 BNode::operator!=(const BNode& node) const 442 { 443 return !(*this == node); 444 } 445 446 447 int 448 BNode::Dup() 449 { 450 int fd = _kern_dup(fFd); 451 452 return (fd >= 0 ? fd : -1); 453 // comply with R5 return value 454 } 455 456 457 /*! (currently unused) */ 458 void BNode::_RudeNode1() { } 459 void BNode::_RudeNode2() { } 460 void BNode::_RudeNode3() { } 461 void BNode::_RudeNode4() { } 462 void BNode::_RudeNode5() { } 463 void BNode::_RudeNode6() { } 464 465 466 /*! Sets the node's file descriptor. 467 468 Used by each implementation (i.e. BNode, BFile, BDirectory, etc.) to set 469 the node's file descriptor. This allows each subclass to use the various 470 file-type specific system calls for opening file descriptors. 471 472 \note This method calls close_fd() to close previously opened FDs. Thus 473 derived classes should take care to first call set_fd() and set 474 class specific resources freed in their close_fd() version 475 thereafter. 476 477 \param fd the file descriptor this BNode should be set to (may be -1). 478 479 \returns \c B_OK if everything went fine, or an error code if something 480 went wrong. 481 */ 482 status_t 483 BNode::set_fd(int fd) 484 { 485 if (fFd != -1) 486 close_fd(); 487 488 fFd = fd; 489 490 return B_OK; 491 } 492 493 494 /*! Closes the node's file descriptor(s). 495 496 To be implemented by subclasses to close the file descriptor using the 497 proper system call for the given file-type. This implementation calls 498 _kern_close(fFd) and also _kern_close(fAttrDir) if necessary. 499 */ 500 void 501 BNode::close_fd() 502 { 503 if (fAttrFd >= 0) { 504 _kern_close(fAttrFd); 505 fAttrFd = -1; 506 } 507 if (fFd >= 0) { 508 _kern_close(fFd); 509 fFd = -1; 510 } 511 } 512 513 514 /*! Sets the BNode's status. 515 516 To be used by derived classes instead of accessing the BNode's private 517 \c fCStatus member directly. 518 519 \param newStatus the new value for the status variable. 520 */ 521 void 522 BNode::set_status(status_t newStatus) 523 { 524 fCStatus = newStatus; 525 } 526 527 528 /*! Initializes the BNode's file descriptor to the node referred to 529 by the given FD and path combo. 530 531 \a path must either be \c NULL, an absolute or a relative path. 532 In the first case, \a fd must not be \c NULL; the node it refers to will 533 be opened. If absolute, \a fd is ignored. If relative and \a fd is >= 0, 534 it will be reckoned off the directory identified by \a fd, otherwise off 535 the current working directory. 536 537 The method will first try to open the node with read and write permission. 538 If that fails due to a read-only FS or because the user has no write 539 permission for the node, it will re-try opening the node read-only. 540 541 The \a fCStatus member will be set to the return value of this method. 542 543 \param fd Either a directory FD or a value < 0. In the latter case \a path 544 must be specified. 545 \param path Either \a NULL in which case \a fd must be given, absolute, or 546 relative to the directory specified by \a fd (if given) or to the 547 current working directory. 548 \param traverse If the node identified by \a fd and \a path is a symlink 549 and \a traverse is \c true, the symlink will be resolved recursively. 550 551 \returns \c B_OK if everything went fine, or an error code otherwise. 552 */ 553 status_t 554 BNode::_SetTo(int fd, const char* path, bool traverse) 555 { 556 Unset(); 557 558 status_t error = (fd >= 0 || path ? B_OK : B_BAD_VALUE); 559 if (error == B_OK) { 560 int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); 561 fFd = _kern_open(fd, path, O_RDWR | O_CLOEXEC | traverseFlag, 0); 562 if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) { 563 // opening read-write failed, re-try read-only 564 fFd = _kern_open(fd, path, O_RDONLY | O_CLOEXEC | traverseFlag, 0); 565 } 566 if (fFd < 0) 567 error = fFd; 568 } 569 570 return fCStatus = error; 571 } 572 573 574 /*! Initializes the BNode's file descriptor to the node referred to 575 by the given entry_ref. 576 577 The method will first try to open the node with read and write permission. 578 If that fails due to a read-only FS or because the user has no write 579 permission for the node, it will re-try opening the node read-only. 580 581 The \a fCStatus member will be set to the return value of this method. 582 583 \param ref An entry_ref identifying the node to be opened. 584 \param traverse If the node identified by \a ref is a symlink and 585 \a traverse is \c true, the symlink will be resolved recursively. 586 587 \returns \c B_OK if everything went fine, or an error code otherwise. 588 */ 589 status_t 590 BNode::_SetTo(const entry_ref* ref, bool traverse) 591 { 592 Unset(); 593 594 status_t result = (ref ? B_OK : B_BAD_VALUE); 595 if (result == B_OK) { 596 int traverseFlag = (traverse ? 0 : O_NOTRAVERSE); 597 fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 598 O_RDWR | O_CLOEXEC | traverseFlag, 0); 599 if (fFd < B_OK && fFd != B_ENTRY_NOT_FOUND) { 600 // opening read-write failed, re-try read-only 601 fFd = _kern_open_entry_ref(ref->device, ref->directory, ref->name, 602 O_RDONLY | O_CLOEXEC | traverseFlag, 0); 603 } 604 if (fFd < 0) 605 result = fFd; 606 } 607 608 return fCStatus = result; 609 } 610 611 612 /*! Modifies a certain setting for this node based on \a what and the 613 corresponding value in \a st. 614 615 Inherited from and called by BStatable. 616 617 \param st a stat structure containing the value to be set. 618 \param what specifies what setting to be modified. 619 620 \returns \c B_OK if everything went fine, or an error code otherwise. 621 */ 622 status_t 623 BNode::set_stat(struct stat& stat, uint32 what) 624 { 625 if (fCStatus != B_OK) 626 return B_FILE_ERROR; 627 628 return _kern_write_stat(fFd, NULL, false, &stat, sizeof(struct stat), 629 what); 630 } 631 632 633 634 /*! Verifies that the BNode has been properly initialized, and then 635 (if necessary) opens the attribute directory on the node's file 636 descriptor, storing it in fAttrDir. 637 638 \returns \c B_OK if everything went fine, or an error code otherwise. 639 */ 640 status_t 641 BNode::InitAttrDir() 642 { 643 if (fCStatus == B_OK && fAttrFd < 0) { 644 fAttrFd = _kern_open_attr_dir(fFd, NULL, false); 645 if (fAttrFd < 0) 646 return fAttrFd; 647 648 // set close on exec flag 649 fcntl(fAttrFd, F_SETFD, FD_CLOEXEC); 650 } 651 652 return fCStatus; 653 } 654 655 656 status_t 657 BNode::_GetStat(struct stat* stat) const 658 { 659 return fCStatus != B_OK 660 ? fCStatus 661 : _kern_read_stat(fFd, NULL, false, stat, sizeof(struct stat)); 662 } 663 664 665 status_t 666 BNode::_GetStat(struct stat_beos* stat) const 667 { 668 struct stat newStat; 669 status_t error = _GetStat(&newStat); 670 if (error != B_OK) 671 return error; 672 673 convert_to_stat_beos(&newStat, stat); 674 675 return B_OK; 676 } 677 678 679 // #pragma mark - symbol versions 680 681 682 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST 683 # if __GNUC__ == 2 // gcc 2 684 685 B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP4stat", 686 "GetStat__C5BNodeP4stat@@LIBBE_TEST"); 687 688 # else // gcc 4 689 690 B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP4stat", 691 "_ZNK5BNode7GetStatEP4stat@@LIBBE_TEST"); 692 693 # endif // gcc 4 694 #else // !HAIKU_TARGET_PLATFORM_LIBBE_TEST 695 # if __GNUC__ == 2 // gcc 2 696 697 // BeOS compatible GetStat() 698 B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP9stat_beos", 699 "GetStat__C5BNodeP4stat@LIBBE_BASE"); 700 701 // Haiku GetStat() 702 B_DEFINE_SYMBOL_VERSION("_GetStat__C5BNodeP4stat", 703 "GetStat__C5BNodeP4stat@@LIBBE_1_ALPHA1"); 704 705 # else // gcc 4 706 707 // BeOS compatible GetStat() 708 B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP9stat_beos", 709 "_ZNK5BNode7GetStatEP4stat@LIBBE_BASE"); 710 711 // Haiku GetStat() 712 B_DEFINE_SYMBOL_VERSION("_ZNK5BNode8_GetStatEP4stat", 713 "_ZNK5BNode7GetStatEP4stat@@LIBBE_1_ALPHA1"); 714 715 # endif // gcc 4 716 #endif // !HAIKU_TARGET_PLATFORM_LIBBE_TEST 717