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