1 /* 2 * Copyright 2002-2009, Haiku Inc. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Ingo Weinhold, bonefish@users.sf.net 8 * Axel Dörfler, axeld@pinc-software.de 9 */ 10 11 12 #include "storage_support.h" 13 14 #include <fcntl.h> 15 #include <string.h> 16 17 #include <compat/sys/stat.h> 18 19 #include <Directory.h> 20 #include <Entry.h> 21 #include <File.h> 22 #include <fs_info.h> 23 #include <Path.h> 24 #include <SymLink.h> 25 26 #include <syscalls.h> 27 #include <umask.h> 28 29 30 //! Creates an uninitialized BDirectory object. 31 BDirectory::BDirectory() 32 : 33 fDirFd(-1) 34 { 35 } 36 37 38 /*! \brief Creates a copy of the supplied BDirectory. 39 \param dir the BDirectory object to be copied 40 */ 41 BDirectory::BDirectory(const BDirectory& dir) 42 : 43 fDirFd(-1) 44 { 45 *this = dir; 46 } 47 48 49 /*! \brief Creates a BDirectory and initializes it to the directory referred 50 to by the supplied entry_ref. 51 \param ref the entry_ref referring to the directory 52 */ 53 BDirectory::BDirectory(const entry_ref* ref) 54 : 55 fDirFd(-1) 56 { 57 SetTo(ref); 58 } 59 60 61 /*! \brief Creates a BDirectory and initializes it to the directory referred 62 to by the supplied node_ref. 63 \param nref the node_ref referring to the directory 64 */ 65 BDirectory::BDirectory(const node_ref* nref) 66 : 67 fDirFd(-1) 68 { 69 SetTo(nref); 70 } 71 72 73 /*! \brief Creates a BDirectory and initializes it to the directory referred 74 to by the supplied BEntry. 75 \param entry the BEntry referring to the directory 76 */ 77 BDirectory::BDirectory(const BEntry* entry) 78 : 79 fDirFd(-1) 80 { 81 SetTo(entry); 82 } 83 84 85 /*! \brief Creates a BDirectory and initializes it to the directory referred 86 to by the supplied path name. 87 \param path the directory's path name 88 */ 89 BDirectory::BDirectory(const char* path) 90 : 91 fDirFd(-1) 92 { 93 SetTo(path); 94 } 95 96 97 /*! \brief Creates a BDirectory and initializes it to the directory referred 98 to by the supplied path name relative to the specified BDirectory. 99 \param dir the BDirectory, relative to which the directory's path name is 100 given 101 \param path the directory's path name relative to \a dir 102 */ 103 BDirectory::BDirectory(const BDirectory* dir, const char* path) 104 : 105 fDirFd(-1) 106 { 107 SetTo(dir, path); 108 } 109 110 111 /*! If the BDirectory is properly initialized, the directory's file descriptor 112 is closed. 113 */ 114 BDirectory::~BDirectory() 115 { 116 // Also called by the BNode destructor, but we rather try to avoid 117 // problems with calling virtual functions in the base class destructor. 118 // Depending on the compiler implementation an object may be degraded to 119 // an object of the base class after the destructor of the derived class 120 // has been executed. 121 close_fd(); 122 } 123 124 125 /*! \brief Re-initializes the BDirectory to the directory referred to by the 126 supplied entry_ref. 127 \param ref the entry_ref referring to the directory 128 \return 129 - \c B_OK: Everything went fine. 130 - \c B_BAD_VALUE: \c NULL \a ref. 131 - \c B_ENTRY_NOT_FOUND: Directory not found. 132 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 133 - \c B_NO_MEMORY: Insufficient memory for operation. 134 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 135 - \c B_BUSY: A node was busy. 136 - \c B_FILE_ERROR: A general file error. 137 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 138 */ 139 status_t 140 BDirectory::SetTo(const entry_ref* ref) 141 { 142 // open node 143 status_t error = _SetTo(ref, true); 144 if (error != B_OK) 145 return error; 146 147 // open dir 148 fDirFd = _kern_open_dir_entry_ref(ref->device, ref->directory, ref->name); 149 if (fDirFd < 0) { 150 status_t error = fDirFd; 151 Unset(); 152 return (fCStatus = error); 153 } 154 155 // set close on exec flag on dir FD 156 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 157 158 return B_OK; 159 } 160 161 162 /*! \brief Re-initializes the BDirectory to the directory referred to by the 163 supplied node_ref. 164 \param nref the node_ref referring to the directory 165 \return 166 - \c B_OK: Everything went fine. 167 - \c B_BAD_VALUE: \c NULL \a nref. 168 - \c B_ENTRY_NOT_FOUND: Directory not found. 169 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 170 - \c B_NO_MEMORY: Insufficient memory for operation. 171 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 172 - \c B_BUSY: A node was busy. 173 - \c B_FILE_ERROR: A general file error. 174 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 175 */ 176 status_t 177 BDirectory::SetTo(const node_ref* nref) 178 { 179 Unset(); 180 status_t error = (nref ? B_OK : B_BAD_VALUE); 181 if (error == B_OK) { 182 entry_ref ref(nref->device, nref->node, "."); 183 error = SetTo(&ref); 184 } 185 set_status(error); 186 return error; 187 } 188 189 190 /*! \brief Re-initializes the BDirectory to the directory referred to by the 191 supplied BEntry. 192 \param entry the BEntry referring to the directory 193 \return 194 - \c B_OK: Everything went fine. 195 - \c B_BAD_VALUE: \c NULL \a entry. 196 - \c B_ENTRY_NOT_FOUND: Directory not found. 197 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 198 - \c B_NO_MEMORY: Insufficient memory for operation. 199 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 200 - \c B_BUSY: A node was busy. 201 - \c B_FILE_ERROR: A general file error. 202 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 203 */ 204 status_t 205 BDirectory::SetTo(const BEntry* entry) 206 { 207 if (!entry) { 208 Unset(); 209 return (fCStatus = B_BAD_VALUE); 210 } 211 212 // open node 213 status_t error = _SetTo(entry->fDirFd, entry->fName, true); 214 if (error != B_OK) 215 return error; 216 217 // open dir 218 fDirFd = _kern_open_dir(entry->fDirFd, entry->fName); 219 if (fDirFd < 0) { 220 status_t error = fDirFd; 221 Unset(); 222 return (fCStatus = error); 223 } 224 225 // set close on exec flag on dir FD 226 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 227 228 return B_OK; 229 } 230 231 232 /*! \brief Re-initializes the BDirectory to the directory referred to by the 233 supplied path name. 234 \param path the directory's path name 235 \return 236 - \c B_OK: Everything went fine. 237 - \c B_BAD_VALUE: \c NULL \a path. 238 - \c B_ENTRY_NOT_FOUND: Directory not found. 239 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 240 - \c B_NO_MEMORY: Insufficient memory for operation. 241 - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. 242 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 243 - \c B_BUSY: A node was busy. 244 - \c B_FILE_ERROR: A general file error. 245 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 246 - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. 247 */ 248 status_t 249 BDirectory::SetTo(const char* path) 250 { 251 // open node 252 status_t error = _SetTo(-1, path, true); 253 if (error != B_OK) 254 return error; 255 256 // open dir 257 fDirFd = _kern_open_dir(-1, path); 258 if (fDirFd < 0) { 259 status_t error = fDirFd; 260 Unset(); 261 return (fCStatus = error); 262 } 263 264 // set close on exec flag on dir FD 265 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 266 267 return B_OK; 268 } 269 270 271 /*! \brief Re-initializes the BDirectory to the directory referred to by the 272 supplied path name relative to the specified BDirectory. 273 \param dir the BDirectory, relative to which the directory's path name is 274 given 275 \param path the directory's path name relative to \a dir 276 \return 277 - \c B_OK: Everything went fine. 278 - \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute. 279 - \c B_ENTRY_NOT_FOUND: Directory not found. 280 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 281 - \c B_NO_MEMORY: Insufficient memory for operation. 282 - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. 283 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 284 - \c B_BUSY: A node was busy. 285 - \c B_FILE_ERROR: A general file error. 286 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 287 - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. 288 */ 289 status_t 290 BDirectory::SetTo(const BDirectory* dir, const char* path) 291 { 292 if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) { 293 Unset(); 294 return (fCStatus = B_BAD_VALUE); 295 } 296 297 int dirFD = dir->fDirFd; 298 if (dir == this) { 299 // prevent that our file descriptor goes away in _SetTo() 300 fDirFd = -1; 301 } 302 303 // open node 304 status_t error = _SetTo(dirFD, path, true); 305 if (error != B_OK) 306 return error; 307 308 // open dir 309 fDirFd = _kern_open_dir(dirFD, path); 310 if (fDirFd < 0) { 311 status_t error = fDirFd; 312 Unset(); 313 return (fCStatus = error); 314 } 315 316 if (dir == this) { 317 // cleanup after _SetTo() 318 _kern_close(dirFD); 319 } 320 321 // set close on exec flag on dir FD 322 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 323 324 return B_OK; 325 } 326 327 328 /*! \brief Returns a BEntry referring to the directory represented by this object. 329 If the initialization of \a entry fails, it is Unset(). 330 \param entry a pointer to the entry that shall be set to refer to the 331 directory 332 \return 333 - \c B_OK: Everything went fine. 334 - \c B_BAD_VALUE: \c NULL \a entry. 335 - \c B_ENTRY_NOT_FOUND: Directory not found. 336 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 337 - \c B_NO_MEMORY: Insufficient memory for operation. 338 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 339 - \c B_BUSY: A node was busy. 340 - \c B_FILE_ERROR: A general file error. 341 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 342 */ 343 status_t 344 BDirectory::GetEntry(BEntry* entry) const 345 { 346 if (!entry) 347 return B_BAD_VALUE; 348 if (InitCheck() != B_OK) 349 return B_NO_INIT; 350 return entry->SetTo(this, ".", false); 351 } 352 353 354 /*! \brief Returns whether the directory represented by this BDirectory is a 355 root directory of a volume. 356 \return 357 - \c true, if the BDirectory is properly initialized and represents a 358 root directory of some volume, 359 - \c false, otherwise. 360 */ 361 bool 362 BDirectory::IsRootDirectory() const 363 { 364 // compare the directory's node ID with the ID of the root node of the FS 365 bool result = false; 366 node_ref ref; 367 fs_info info; 368 if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0) 369 result = (ref.node == info.root); 370 return result; 371 } 372 373 374 /*! \brief Finds an entry referred to by a path relative to the directory 375 represented by this BDirectory. 376 \a path may be absolute. If the BDirectory is not properly initialized, 377 the entry is search relative to the current directory. 378 If the entry couldn't be found, \a entry is Unset(). 379 \param path the entry's path name. May be relative to this directory or 380 absolute. 381 \param entry a pointer to a BEntry to be initialized with the found entry 382 \param traverse specifies whether to follow it, if the found entry 383 is a symbolic link. 384 \return 385 - \c B_OK: Everything went fine. 386 - \c B_BAD_VALUE: \c NULL \a path or \a entry. 387 - \c B_ENTRY_NOT_FOUND: Entry not found. 388 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 389 - \c B_NO_MEMORY: Insufficient memory for operation. 390 - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. 391 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 392 - \c B_BUSY: A node was busy. 393 - \c B_FILE_ERROR: A general file error. 394 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 395 - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. 396 \note The functionality of this method differs from the one of 397 BEntry::SetTo(BDirectory *, const char *, bool) in that the 398 latter doesn't require the entry to be existent, whereas this 399 function does. 400 */ 401 status_t 402 BDirectory::FindEntry(const char* path, BEntry* entry, bool traverse) const 403 { 404 if (path == NULL || entry == NULL) 405 return B_BAD_VALUE; 406 407 entry->Unset(); 408 409 // init a potentially abstract entry 410 status_t status; 411 if (InitCheck() == B_OK) 412 status = entry->SetTo(this, path, traverse); 413 else 414 status = entry->SetTo(path, traverse); 415 416 // fail, if entry is abstract 417 if (status == B_OK && !entry->Exists()) { 418 status = B_ENTRY_NOT_FOUND; 419 entry->Unset(); 420 } 421 422 return status; 423 } 424 425 426 /*! \brief Returns whether this directory or any of its subdirectories 427 at any level contain the entry referred to by the supplied path name. 428 Only entries that match the node flavor specified by \a nodeFlags are 429 considered. 430 If the BDirectory is not properly initialized, the method returns \c false. 431 A non-absolute path is considered relative to the current directory. 432 433 \note R5's implementation always returns \c true given an absolute path or 434 an unitialized directory. This implementation is not compatible with that 435 behavior. Instead it converts the path into a BEntry and passes it to the 436 other version of Contains(). 437 438 \param path the entry's path name. May be relative to this directory or 439 absolute. 440 \param nodeFlags Any of the following: 441 - \c B_FILE_NODE: The entry must be a file. 442 - \c B_DIRECTORY_NODE: The entry must be a directory. 443 - \c B_SYMLINK_NODE: The entry must be a symbolic link. 444 - \c B_ANY_NODE: The entry may be of any kind. 445 \return 446 - \c true, if the entry exists, its kind does match \nodeFlags and the 447 BDirectory is properly initialized and does contain the entry at any 448 level, 449 - \c false, otherwise 450 */ 451 bool 452 BDirectory::Contains(const char* path, int32 nodeFlags) const 453 { 454 // check initialization and parameters 455 if (InitCheck() != B_OK) 456 return false; 457 if (!path) 458 return true; // mimic R5 behavior 459 460 // turn the path into a BEntry and let the other version do the work 461 BEntry entry; 462 if (BPrivate::Storage::is_absolute_path(path)) 463 entry.SetTo(path); 464 else 465 entry.SetTo(this, path); 466 467 return Contains(&entry, nodeFlags); 468 } 469 470 471 /*! \brief Returns whether this directory or any of its subdirectories 472 at any level contain the entry referred to by the supplied BEntry. 473 Only entries that match the node flavor specified by \a nodeFlags are 474 considered. 475 \param entry a BEntry referring to the entry 476 \param nodeFlags Any of the following: 477 - \c B_FILE_NODE: The entry must be a file. 478 - \c B_DIRECTORY_NODE: The entry must be a directory. 479 - \c B_SYMLINK_NODE: The entry must be a symbolic link. 480 - \c B_ANY_NODE: The entry may be of any kind. 481 \return 482 - \c true, if the BDirectory is properly initialized and the entry of the 483 matching kind could be found, 484 - \c false, otherwise 485 */ 486 bool 487 BDirectory::Contains(const BEntry* entry, int32 nodeFlags) const 488 { 489 // check, if the entry exists at all 490 if (entry == NULL || !entry->Exists() || InitCheck() != B_OK) 491 return false; 492 493 if (nodeFlags != B_ANY_NODE) { 494 // test the node kind 495 bool result = false; 496 if ((nodeFlags & B_FILE_NODE) != 0) 497 result = entry->IsFile(); 498 if (!result && (nodeFlags & B_DIRECTORY_NODE) != 0) 499 result = entry->IsDirectory(); 500 if (!result && (nodeFlags & B_SYMLINK_NODE) != 0) 501 result = entry->IsSymLink(); 502 if (!result) 503 return false; 504 } 505 506 // If the directory is initialized, get the canonical paths of the dir and 507 // the entry and check, if the latter is a prefix of the first one. 508 BPath dirPath(this, ".", true); 509 BPath entryPath(entry); 510 if (dirPath.InitCheck() != B_OK || entryPath.InitCheck() != B_OK) 511 return false; 512 513 uint32 dirLen = strlen(dirPath.Path()); 514 515 if (!strncmp(dirPath.Path(), entryPath.Path(), dirLen)) { 516 // if the paths are identical, return a match to stay consistent with 517 // BeOS behavior. 518 if (entryPath.Path()[dirLen] == '\0' || entryPath.Path()[dirLen] == '/') 519 return true; 520 } 521 return false; 522 } 523 524 525 /*! \fn status_t BDirectory::GetStatFor(const char* path, struct stat* st) const 526 \brief Returns the stat structure of the entry referred to by the supplied 527 path name. 528 \param path the entry's path name. May be relative to this directory or 529 absolute, or \c NULL to get the directories stat info. 530 \param st a pointer to the stat structure to be filled in by this function 531 \return 532 - \c B_OK: Everything went fine. 533 - \c B_BAD_VALUE: \c NULL \a st. 534 - \c B_ENTRY_NOT_FOUND: Entry not found. 535 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 536 - \c B_NO_MEMORY: Insufficient memory for operation. 537 - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. 538 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 539 - \c B_BUSY: A node was busy. 540 - \c B_FILE_ERROR: A general file error. 541 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 542 - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. 543 */ 544 // Implemented as BDirectory::_GetStatFor(). 545 546 547 /*! \brief Returns the BDirectory's next entry as a BEntry. 548 Unlike GetNextDirents() this method ignores the entries "." and "..". 549 \param entry a pointer to a BEntry to be initialized to the found entry 550 \param traverse specifies whether to follow it, if the found entry 551 is a symbolic link. 552 \note The iterator used by this method is the same one used by 553 GetNextRef(), GetNextDirents(), Rewind() and CountEntries(). 554 \return 555 - \c B_OK: Everything went fine. 556 - \c B_BAD_VALUE: \c NULL \a entry. 557 - \c B_ENTRY_NOT_FOUND: No more entries found. 558 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 559 - \c B_NO_MEMORY: Insufficient memory for operation. 560 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 561 - \c B_BUSY: A node was busy. 562 - \c B_FILE_ERROR: A general file error. 563 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 564 */ 565 status_t 566 BDirectory::GetNextEntry(BEntry* entry, bool traverse) 567 { 568 status_t error = (entry ? B_OK : B_BAD_VALUE); 569 if (error == B_OK) { 570 entry_ref ref; 571 error = GetNextRef(&ref); 572 if (error == B_OK) 573 error = entry->SetTo(&ref, traverse); 574 } 575 return error; 576 } 577 578 579 /*! \brief Returns the BDirectory's next entry as an entry_ref. 580 Unlike GetNextDirents() this method ignores the entries "." and "..". 581 \param ref a pointer to an entry_ref to be filled in with the data of the 582 found entry 583 \param traverse specifies whether to follow it, if the found entry 584 is a symbolic link. 585 \note The iterator used be this method is the same one used by 586 GetNextEntry(), GetNextDirents(), Rewind() and CountEntries(). 587 \return 588 - \c B_OK: Everything went fine. 589 - \c B_BAD_VALUE: \c NULL \a ref. 590 - \c B_ENTRY_NOT_FOUND: No more entries found. 591 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 592 - \c B_NO_MEMORY: Insufficient memory for operation. 593 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 594 - \c B_BUSY: A node was busy. 595 - \c B_FILE_ERROR: A general file error. 596 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 597 */ 598 status_t 599 BDirectory::GetNextRef(entry_ref* ref) 600 { 601 status_t error = (ref ? B_OK : B_BAD_VALUE); 602 if (error == B_OK && InitCheck() != B_OK) 603 error = B_FILE_ERROR; 604 if (error == B_OK) { 605 BPrivate::Storage::LongDirEntry entry; 606 bool next = true; 607 while (error == B_OK && next) { 608 if (GetNextDirents(&entry, sizeof(entry), 1) != 1) { 609 error = B_ENTRY_NOT_FOUND; 610 } else { 611 next = (!strcmp(entry.d_name, ".") 612 || !strcmp(entry.d_name, "..")); 613 } 614 } 615 if (error == B_OK) { 616 ref->device = entry.d_pdev; 617 ref->directory = entry.d_pino; 618 error = ref->set_name(entry.d_name); 619 } 620 } 621 return error; 622 } 623 624 625 /*! \brief Returns the BDirectory's next entries as dirent structures. 626 Unlike GetNextEntry() and GetNextRef(), this method returns also 627 the entries "." and "..". 628 \param buf a pointer to a buffer to be filled with dirent structures of 629 the found entries 630 \param count the maximal number of entries to be returned. 631 \note The iterator used by this method is the same one used by 632 GetNextEntry(), GetNextRef(), Rewind() and CountEntries(). 633 \return 634 - The number of dirent structures stored in the buffer, 0 when there are 635 no more entries to be returned. 636 - \c B_BAD_VALUE: \c NULL \a buf. 637 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 638 - \c B_NO_MEMORY: Insufficient memory for operation. 639 - \c B_NAME_TOO_LONG: The entry's name is too long for the buffer. 640 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 641 - \c B_BUSY: A node was busy. 642 - \c B_FILE_ERROR: A general file error. 643 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 644 */ 645 int32 646 BDirectory::GetNextDirents(dirent* buf, size_t bufSize, int32 count) 647 { 648 if (!buf) 649 return B_BAD_VALUE; 650 if (InitCheck() != B_OK) 651 return B_FILE_ERROR; 652 return _kern_read_dir(fDirFd, buf, bufSize, count); 653 } 654 655 656 /*! \brief Rewinds the directory iterator. 657 \return 658 - \c B_OK: Everything went fine. 659 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 660 - \c B_NO_MEMORY: Insufficient memory for operation. 661 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 662 - \c B_BUSY: A node was busy. 663 - \c B_FILE_ERROR: A general file error. 664 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 665 \see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries() 666 */ 667 status_t 668 BDirectory::Rewind() 669 { 670 if (InitCheck() != B_OK) 671 return B_FILE_ERROR; 672 return _kern_rewind_dir(fDirFd); 673 } 674 675 676 /*! \brief Returns the number of entries in this directory. 677 CountEntries() uses the directory iterator also used by GetNextEntry(), 678 GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through 679 the entries and Rewind()s again. The entries "." and ".." are not counted. 680 \return 681 - the number of entries in the directory (not counting "." and ".."). 682 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 683 - \c B_NO_MEMORY: Insufficient memory for operation. 684 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 685 - \c B_BUSY: A node was busy. 686 - \c B_FILE_ERROR: A general file error. 687 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 688 \see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind() 689 */ 690 int32 691 BDirectory::CountEntries() 692 { 693 status_t error = Rewind(); 694 if (error != B_OK) 695 return error; 696 int32 count = 0; 697 BPrivate::Storage::LongDirEntry entry; 698 while (error == B_OK) { 699 if (GetNextDirents(&entry, sizeof(entry), 1) != 1) 700 break; 701 if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0) 702 count++; 703 } 704 Rewind(); 705 return (error == B_OK ? count : error); 706 } 707 708 709 /*! \brief Creates a new directory. 710 If an entry with the supplied name does already exist, the method fails. 711 \param path the new directory's path name. May be relative to this 712 directory or absolute. 713 \param dir a pointer to a BDirectory to be initialized to the newly 714 created directory. May be \c NULL. 715 \return 716 - \c B_OK: Everything went fine. 717 - \c B_BAD_VALUE: \c NULL \a path. 718 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 719 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 720 - \c B_NO_MEMORY: Insufficient memory for operation. 721 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 722 - \c B_BUSY: A node was busy. 723 - \c B_FILE_ERROR: A general file error. 724 - \c B_FILE_EXISTS: An entry with that name does already exist. 725 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 726 */ 727 status_t 728 BDirectory::CreateDirectory(const char* path, BDirectory* dir) 729 { 730 if (!path) 731 return B_BAD_VALUE; 732 733 // create the dir 734 status_t error = _kern_create_dir(fDirFd, path, 735 (S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask); 736 if (error != B_OK) 737 return error; 738 739 if (dir == NULL) 740 return B_OK; 741 742 // init the supplied BDirectory 743 if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) 744 return dir->SetTo(path); 745 746 return dir->SetTo(this, path); 747 } 748 749 750 /*! \brief Creates a new file. 751 If a file with the supplied name does already exist, the method fails, 752 unless it is passed \c false to \a failIfExists -- in that case the file 753 is truncated to zero size. The new BFile will operate in \c B_READ_WRITE 754 mode. 755 \param path the new file's path name. May be relative to this 756 directory or absolute. 757 \param file a pointer to a BFile to be initialized to the newly 758 created file. May be \c NULL. 759 \param failIfExists \c true, if the method should fail when the file 760 already exists, \c false otherwise 761 \return 762 - \c B_OK: Everything went fine. 763 - \c B_BAD_VALUE: \c NULL \a path. 764 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 765 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 766 - \c B_NO_MEMORY: Insufficient memory for operation. 767 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 768 - \c B_BUSY: A node was busy. 769 - \c B_FILE_ERROR: A general file error. 770 - \c B_FILE_EXISTS: A file with that name does already exist and 771 \c true has been passed for \a failIfExists. 772 - \c B_IS_A_DIRECTORY: A directory with the supplied name does already 773 exist. 774 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 775 */ 776 status_t 777 BDirectory::CreateFile(const char* path, BFile* file, bool failIfExists) 778 { 779 if (!path) 780 return B_BAD_VALUE; 781 782 // Let BFile do the dirty job. 783 uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE 784 | (failIfExists ? B_FAIL_IF_EXISTS : 0); 785 BFile tmpFile; 786 BFile* realFile = file ? file : &tmpFile; 787 status_t error = B_OK; 788 if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) 789 error = realFile->SetTo(this, path, openMode); 790 else 791 error = realFile->SetTo(path, openMode); 792 if (error != B_OK && file) // mimic R5 behavior 793 file->Unset(); 794 return error; 795 } 796 797 798 /*! \brief Creates a new symbolic link. 799 If an entry with the supplied name does already exist, the method fails. 800 \param path the new symbolic link's path name. May be relative to this 801 directory or absolute. 802 \param linkToPath the path the symbolic link shall point to. 803 \param dir a pointer to a BSymLink to be initialized to the newly 804 created symbolic link. May be \c NULL. 805 \return 806 - \c B_OK: Everything went fine. 807 - \c B_BAD_VALUE: \c NULL \a path or \a linkToPath. 808 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 809 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 810 - \c B_NO_MEMORY: Insufficient memory for operation. 811 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 812 - \c B_BUSY: A node was busy. 813 - \c B_FILE_ERROR: A general file error. 814 - \c B_FILE_EXISTS: An entry with that name does already exist. 815 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 816 */ 817 status_t 818 BDirectory::CreateSymLink(const char* path, const char* linkToPath, 819 BSymLink* link) 820 { 821 if (!path || !linkToPath) 822 return B_BAD_VALUE; 823 824 // create the symlink 825 status_t error = _kern_create_symlink(fDirFd, path, linkToPath, 826 (S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask); 827 if (error != B_OK) 828 return error; 829 830 if (link == NULL) 831 return B_OK; 832 833 // init the supplied BSymLink 834 if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) 835 return link->SetTo(path); 836 837 return link->SetTo(this, path); 838 } 839 840 841 /*! \brief Assigns another BDirectory to this BDirectory. 842 If the other BDirectory is uninitialized, this one wi'll be too. Otherwise 843 it will refer to the same directory, unless an error occurs. 844 \param dir the original BDirectory 845 \return a reference to this BDirectory 846 */ 847 BDirectory& 848 BDirectory::operator=(const BDirectory& dir) 849 { 850 if (&dir != this) { // no need to assign us to ourselves 851 Unset(); 852 if (dir.InitCheck() == B_OK) 853 SetTo(&dir, "."); 854 } 855 return *this; 856 } 857 858 859 status_t 860 BDirectory::_GetStatFor(const char* path, struct stat* st) const 861 { 862 if (!st) 863 return B_BAD_VALUE; 864 if (InitCheck() != B_OK) 865 return B_NO_INIT; 866 867 if (path != NULL) { 868 if (path[0] == '\0') 869 return B_ENTRY_NOT_FOUND; 870 return _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat)); 871 } 872 return GetStat(st); 873 } 874 875 876 status_t 877 BDirectory::_GetStatFor(const char* path, struct stat_beos* st) const 878 { 879 struct stat newStat; 880 status_t error = _GetStatFor(path, &newStat); 881 if (error != B_OK) 882 return error; 883 884 convert_to_stat_beos(&newStat, st); 885 return B_OK; 886 } 887 888 889 // FBC 890 void BDirectory::_ErectorDirectory1() {} 891 void BDirectory::_ErectorDirectory2() {} 892 void BDirectory::_ErectorDirectory3() {} 893 void BDirectory::_ErectorDirectory4() {} 894 void BDirectory::_ErectorDirectory5() {} 895 void BDirectory::_ErectorDirectory6() {} 896 897 898 //! Closes the BDirectory's file descriptor. 899 void 900 BDirectory::close_fd() 901 { 902 if (fDirFd >= 0) { 903 _kern_close(fDirFd); 904 fDirFd = -1; 905 } 906 BNode::close_fd(); 907 } 908 909 910 /*! \brief Returns the BDirectory's file descriptor. 911 To be used instead of accessing the BDirectory's private \c fDirFd member 912 directly. 913 \return the file descriptor, or -1, if not properly initialized. 914 */ 915 int 916 BDirectory::get_fd() const 917 { 918 return fDirFd; 919 } 920 921 922 // #pragma mark - C functions 923 924 925 /*! \brief Creates all missing directories along a given path. 926 \param path the directory path name. 927 \param mode a permission specification, which shall be used for the 928 newly created directories. 929 \return 930 - \c B_OK: Everything went fine. 931 - \c B_BAD_VALUE: \c NULL \a path. 932 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 933 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 934 - \c B_NO_MEMORY: Insufficient memory for operation. 935 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 936 - \c B_BUSY: A node was busy. 937 - \c B_FILE_ERROR: A general file error. 938 - \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does 939 already exist. 940 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 941 \todo Check for efficency. 942 */ 943 status_t 944 create_directory(const char* path, mode_t mode) 945 { 946 if (!path) 947 return B_BAD_VALUE; 948 949 // That's the strategy: We start with the first component of the supplied 950 // path, create a BPath object from it and successively add the following 951 // components. Each time we get a new path, we check, if the entry it 952 // refers to exists and is a directory. If it doesn't exist, we try 953 // to create it. This goes on, until we're done with the input path or 954 // an error occurs. 955 BPath dirPath; 956 char* component; 957 int32 nextComponent; 958 do { 959 // get the next path component 960 status_t error = BPrivate::Storage::parse_first_path_component(path, 961 component, nextComponent); 962 if (error != B_OK) 963 return error; 964 965 // append it to the BPath 966 if (dirPath.InitCheck() == B_NO_INIT) // first component 967 error = dirPath.SetTo(component); 968 else 969 error = dirPath.Append(component); 970 delete[] component; 971 if (error != B_OK) 972 return error; 973 path += nextComponent; 974 975 // create a BEntry from the BPath 976 BEntry entry; 977 error = entry.SetTo(dirPath.Path(), true); 978 if (error != B_OK) 979 return error; 980 981 // check, if it exists 982 if (entry.Exists()) { 983 // yep, it exists 984 if (!entry.IsDirectory()) // but is no directory 985 return B_NOT_A_DIRECTORY; 986 } else { 987 // it doesn't exist -- create it 988 error = _kern_create_dir(-1, dirPath.Path(), mode & ~__gUmask); 989 if (error != B_OK) 990 return error; 991 } 992 } while (nextComponent != 0); 993 return B_OK; 994 } 995 996 997 // #pragma mark - symbol versions 998 999 1000 #ifdef HAIKU_TARGET_PLATFORM_LIBBE_TEST 1001 # if __GNUC__ == 2 // gcc 2 1002 1003 B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP4stat", 1004 "GetStatFor__C10BDirectoryPCcP4stat@@LIBBE_TEST"); 1005 1006 # else // gcc 4 1007 1008 B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP4stat", 1009 "_ZNK10BDirectory10GetStatForEPKcP4stat@@LIBBE_TEST"); 1010 1011 # endif // gcc 4 1012 #else // !HAIKU_TARGET_PLATFORM_LIBBE_TEST 1013 # if __GNUC__ == 2 // gcc 2 1014 1015 // BeOS compatible GetStatFor() 1016 B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP9stat_beos", 1017 "GetStatFor__C10BDirectoryPCcP4stat@LIBBE_BASE"); 1018 1019 // Haiku GetStatFor() 1020 B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP4stat", 1021 "GetStatFor__C10BDirectoryPCcP4stat@@LIBBE_1_ALPHA1"); 1022 1023 # else // gcc 4 1024 1025 // BeOS compatible GetStatFor() 1026 B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP9stat_beos", 1027 "_ZNK10BDirectory10GetStatForEPKcP4stat@LIBBE_BASE"); 1028 1029 // Haiku GetStatFor() 1030 B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP4stat", 1031 "_ZNK10BDirectory10GetStatForEPKcP4stat@@LIBBE_1_ALPHA1"); 1032 1033 # endif // gcc 4 1034 #endif // !HAIKU_TARGET_PLATFORM_LIBBE_TEST 1035