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 28 29 extern mode_t __gUmask; 30 // declared in sys/umask.c 31 32 33 //! Creates an uninitialized BDirectory object. 34 BDirectory::BDirectory() 35 : 36 fDirFd(-1) 37 { 38 } 39 40 41 /*! \brief Creates a copy of the supplied BDirectory. 42 \param dir the BDirectory object to be copied 43 */ 44 BDirectory::BDirectory(const BDirectory &dir) 45 : 46 fDirFd(-1) 47 { 48 *this = dir; 49 } 50 51 52 /*! \brief Creates a BDirectory and initializes it to the directory referred 53 to by the supplied entry_ref. 54 \param ref the entry_ref referring to the directory 55 */ 56 BDirectory::BDirectory(const entry_ref *ref) 57 : 58 fDirFd(-1) 59 { 60 SetTo(ref); 61 } 62 63 64 /*! \brief Creates a BDirectory and initializes it to the directory referred 65 to by the supplied node_ref. 66 \param nref the node_ref referring to the directory 67 */ 68 BDirectory::BDirectory(const node_ref *nref) 69 : 70 fDirFd(-1) 71 { 72 SetTo(nref); 73 } 74 75 76 /*! \brief Creates a BDirectory and initializes it to the directory referred 77 to by the supplied BEntry. 78 \param entry the BEntry referring to the directory 79 */ 80 BDirectory::BDirectory(const BEntry *entry) 81 : 82 fDirFd(-1) 83 { 84 SetTo(entry); 85 } 86 87 88 /*! \brief Creates a BDirectory and initializes it to the directory referred 89 to by the supplied path name. 90 \param path the directory's path name 91 */ 92 BDirectory::BDirectory(const char *path) 93 : 94 fDirFd(-1) 95 { 96 SetTo(path); 97 } 98 99 100 /*! \brief Creates a BDirectory and initializes it to the directory referred 101 to by the supplied path name relative to the specified BDirectory. 102 \param dir the BDirectory, relative to which the directory's path name is 103 given 104 \param path the directory's path name relative to \a dir 105 */ 106 BDirectory::BDirectory(const BDirectory *dir, const char *path) 107 : 108 fDirFd(-1) 109 { 110 SetTo(dir, path); 111 } 112 113 114 /*! If the BDirectory is properly initialized, the directory's file descriptor 115 is closed. 116 */ 117 BDirectory::~BDirectory() 118 { 119 // Also called by the BNode destructor, but we rather try to avoid 120 // problems with calling virtual functions in the base class destructor. 121 // Depending on the compiler implementation an object may be degraded to 122 // an object of the base class after the destructor of the derived class 123 // has been executed. 124 close_fd(); 125 } 126 127 128 /*! \brief Re-initializes the BDirectory to the directory referred to by the 129 supplied entry_ref. 130 \param ref the entry_ref referring to the directory 131 \return 132 - \c B_OK: Everything went fine. 133 - \c B_BAD_VALUE: \c NULL \a ref. 134 - \c B_ENTRY_NOT_FOUND: Directory not found. 135 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 136 - \c B_NO_MEMORY: Insufficient memory for operation. 137 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 138 - \c B_BUSY: A node was busy. 139 - \c B_FILE_ERROR: A general file error. 140 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 141 */ 142 status_t 143 BDirectory::SetTo(const entry_ref *ref) 144 { 145 // open node 146 status_t error = _SetTo(ref, true); 147 if (error != B_OK) 148 return error; 149 150 // open dir 151 fDirFd = _kern_open_dir_entry_ref(ref->device, ref->directory, ref->name); 152 if (fDirFd < 0) { 153 status_t error = fDirFd; 154 Unset(); 155 return (fCStatus = error); 156 } 157 158 // set close on exec flag on dir FD 159 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 160 161 return B_OK; 162 } 163 164 165 /*! \brief Re-initializes the BDirectory to the directory referred to by the 166 supplied node_ref. 167 \param nref the node_ref referring to the directory 168 \return 169 - \c B_OK: Everything went fine. 170 - \c B_BAD_VALUE: \c NULL \a nref. 171 - \c B_ENTRY_NOT_FOUND: Directory not found. 172 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 173 - \c B_NO_MEMORY: Insufficient memory for operation. 174 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 175 - \c B_BUSY: A node was busy. 176 - \c B_FILE_ERROR: A general file error. 177 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 178 */ 179 status_t 180 BDirectory::SetTo(const node_ref *nref) 181 { 182 Unset(); 183 status_t error = (nref ? B_OK : B_BAD_VALUE); 184 if (error == B_OK) { 185 entry_ref ref(nref->device, nref->node, "."); 186 error = SetTo(&ref); 187 } 188 set_status(error); 189 return error; 190 } 191 192 193 /*! \brief Re-initializes the BDirectory to the directory referred to by the 194 supplied BEntry. 195 \param entry the BEntry referring to the directory 196 \return 197 - \c B_OK: Everything went fine. 198 - \c B_BAD_VALUE: \c NULL \a entry. 199 - \c B_ENTRY_NOT_FOUND: Directory not found. 200 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 201 - \c B_NO_MEMORY: Insufficient memory for operation. 202 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 203 - \c B_BUSY: A node was busy. 204 - \c B_FILE_ERROR: A general file error. 205 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 206 */ 207 status_t 208 BDirectory::SetTo(const BEntry *entry) 209 { 210 if (!entry) { 211 Unset(); 212 return (fCStatus = B_BAD_VALUE); 213 } 214 215 // open node 216 status_t error = _SetTo(entry->fDirFd, entry->fName, true); 217 if (error != B_OK) 218 return error; 219 220 // open dir 221 fDirFd = _kern_open_dir(entry->fDirFd, entry->fName); 222 if (fDirFd < 0) { 223 status_t error = fDirFd; 224 Unset(); 225 return (fCStatus = error); 226 } 227 228 // set close on exec flag on dir FD 229 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 230 231 return B_OK; 232 } 233 234 235 /*! \brief Re-initializes the BDirectory to the directory referred to by the 236 supplied path name. 237 \param path the directory's path name 238 \return 239 - \c B_OK: Everything went fine. 240 - \c B_BAD_VALUE: \c NULL \a path. 241 - \c B_ENTRY_NOT_FOUND: Directory not found. 242 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 243 - \c B_NO_MEMORY: Insufficient memory for operation. 244 - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. 245 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 246 - \c B_BUSY: A node was busy. 247 - \c B_FILE_ERROR: A general file error. 248 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 249 - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. 250 */ 251 status_t 252 BDirectory::SetTo(const char *path) 253 { 254 // open node 255 status_t error = _SetTo(-1, path, true); 256 if (error != B_OK) 257 return error; 258 259 // open dir 260 fDirFd = _kern_open_dir(-1, path); 261 if (fDirFd < 0) { 262 status_t error = fDirFd; 263 Unset(); 264 return (fCStatus = error); 265 } 266 267 // set close on exec flag on dir FD 268 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 269 270 return B_OK; 271 } 272 273 274 /*! \brief Re-initializes the BDirectory to the directory referred to by the 275 supplied path name relative to the specified BDirectory. 276 \param dir the BDirectory, relative to which the directory's path name is 277 given 278 \param path the directory's path name relative to \a dir 279 \return 280 - \c B_OK: Everything went fine. 281 - \c B_BAD_VALUE: \c NULL \a dir or \a path, or \a path is absolute. 282 - \c B_ENTRY_NOT_FOUND: Directory not found. 283 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 284 - \c B_NO_MEMORY: Insufficient memory for operation. 285 - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. 286 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 287 - \c B_BUSY: A node was busy. 288 - \c B_FILE_ERROR: A general file error. 289 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 290 - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. 291 */ 292 status_t 293 BDirectory::SetTo(const BDirectory *dir, const char *path) 294 { 295 if (!dir || !path || BPrivate::Storage::is_absolute_path(path)) { 296 Unset(); 297 return (fCStatus = B_BAD_VALUE); 298 } 299 300 int dirFD = dir->fDirFd; 301 if (dir == this) { 302 // prevent that our file descriptor goes away in _SetTo() 303 fDirFd = -1; 304 } 305 306 // open node 307 status_t error = _SetTo(dirFD, path, true); 308 if (error != B_OK) 309 return error; 310 311 // open dir 312 fDirFd = _kern_open_dir(dirFD, path); 313 if (fDirFd < 0) { 314 status_t error = fDirFd; 315 Unset(); 316 return (fCStatus = error); 317 } 318 319 if (dir == this) { 320 // cleanup after _SetTo() 321 _kern_close(dirFD); 322 } 323 324 // set close on exec flag on dir FD 325 fcntl(fDirFd, F_SETFD, FD_CLOEXEC); 326 327 return B_OK; 328 } 329 330 331 /*! \brief Returns a BEntry referring to the directory represented by this object. 332 If the initialization of \a entry fails, it is Unset(). 333 \param entry a pointer to the entry that shall be set to refer to the 334 directory 335 \return 336 - \c B_OK: Everything went fine. 337 - \c B_BAD_VALUE: \c NULL \a entry. 338 - \c B_ENTRY_NOT_FOUND: Directory not found. 339 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 340 - \c B_NO_MEMORY: Insufficient memory for operation. 341 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 342 - \c B_BUSY: A node was busy. 343 - \c B_FILE_ERROR: A general file error. 344 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 345 */ 346 status_t 347 BDirectory::GetEntry(BEntry *entry) const 348 { 349 if (!entry) 350 return B_BAD_VALUE; 351 if (InitCheck() != B_OK) 352 return B_NO_INIT; 353 return entry->SetTo(this, ".", false); 354 } 355 356 357 /*! \brief Returns whether the directory represented by this BDirectory is a 358 root directory of a volume. 359 \return 360 - \c true, if the BDirectory is properly initialized and represents a 361 root directory of some volume, 362 - \c false, otherwise. 363 */ 364 bool 365 BDirectory::IsRootDirectory() const 366 { 367 // compare the directory's node ID with the ID of the root node of the FS 368 bool result = false; 369 node_ref ref; 370 fs_info info; 371 if (GetNodeRef(&ref) == B_OK && fs_stat_dev(ref.device, &info) == 0) 372 result = (ref.node == info.root); 373 return result; 374 } 375 376 377 /*! \brief Finds an entry referred to by a path relative to the directory 378 represented by this BDirectory. 379 \a path may be absolute. If the BDirectory is not properly initialized, 380 the entry is search relative to the current directory. 381 If the entry couldn't be found, \a entry is Unset(). 382 \param path the entry's path name. May be relative to this directory or 383 absolute. 384 \param entry a pointer to a BEntry to be initialized with the found entry 385 \param traverse specifies whether to follow it, if the found entry 386 is a symbolic link. 387 \return 388 - \c B_OK: Everything went fine. 389 - \c B_BAD_VALUE: \c NULL \a path or \a entry. 390 - \c B_ENTRY_NOT_FOUND: Entry not found. 391 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 392 - \c B_NO_MEMORY: Insufficient memory for operation. 393 - \c B_NAME_TOO_LONG: The supplied path name (\a path) is too long. 394 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 395 - \c B_BUSY: A node was busy. 396 - \c B_FILE_ERROR: A general file error. 397 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 398 - \c B_NOT_A_DIRECTORY: \a path includes a non-directory. 399 \note The functionality of this method differs from the one of 400 BEntry::SetTo(BDirectory *, const char *, bool) in that the 401 latter doesn't require the entry to be existent, whereas this 402 function does. 403 */ 404 status_t 405 BDirectory::FindEntry(const char *path, BEntry *entry, bool traverse) const 406 { 407 status_t error = (path && entry ? B_OK : B_BAD_VALUE); 408 if (entry) 409 entry->Unset(); 410 if (error == B_OK) { 411 // init a potentially abstract entry 412 if (InitCheck() == B_OK) 413 error = entry->SetTo(this, path, traverse); 414 else 415 error = entry->SetTo(path, traverse); 416 // fail, if entry is abstract 417 if (error == B_OK && !entry->Exists()) { 418 error = B_ENTRY_NOT_FOUND; 419 entry->Unset(); 420 } 421 } 422 return error; 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 // Let BFile do the dirty job. 782 uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE 783 | (failIfExists ? B_FAIL_IF_EXISTS : 0); 784 BFile tmpFile; 785 BFile *realFile = file ? file : &tmpFile; 786 status_t error = B_OK; 787 if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) 788 error = realFile->SetTo(this, path, openMode); 789 else 790 error = realFile->SetTo(path, openMode); 791 if (error != B_OK && file) // mimic R5 behavior 792 file->Unset(); 793 return error; 794 } 795 796 797 /*! \brief Creates a new symbolic link. 798 If an entry with the supplied name does already exist, the method fails. 799 \param path the new symbolic link's path name. May be relative to this 800 directory or absolute. 801 \param linkToPath the path the symbolic link shall point to. 802 \param dir a pointer to a BSymLink to be initialized to the newly 803 created symbolic link. May be \c NULL. 804 \return 805 - \c B_OK: Everything went fine. 806 - \c B_BAD_VALUE: \c NULL \a path or \a linkToPath. 807 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 808 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 809 - \c B_NO_MEMORY: Insufficient memory for operation. 810 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 811 - \c B_BUSY: A node was busy. 812 - \c B_FILE_ERROR: A general file error. 813 - \c B_FILE_EXISTS: An entry with that name does already exist. 814 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 815 */ 816 status_t 817 BDirectory::CreateSymLink(const char *path, const char *linkToPath, 818 BSymLink *link) 819 { 820 if (!path || !linkToPath) 821 return B_BAD_VALUE; 822 823 // create the symlink 824 status_t error = _kern_create_symlink(fDirFd, path, linkToPath, 825 (S_IRWXU | S_IRWXG | S_IRWXO) & ~__gUmask); 826 if (error != B_OK) 827 return error; 828 829 if (link == NULL) 830 return B_OK; 831 832 // init the supplied BSymLink 833 if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) 834 return link->SetTo(path); 835 836 return link->SetTo(this, path); 837 } 838 839 840 /*! \brief Assigns another BDirectory to this BDirectory. 841 If the other BDirectory is uninitialized, this one wi'll be too. Otherwise 842 it will refer to the same directory, unless an error occurs. 843 \param dir the original BDirectory 844 \return a reference to this BDirectory 845 */ 846 BDirectory & 847 BDirectory::operator=(const BDirectory &dir) 848 { 849 if (&dir != this) { // no need to assign us to ourselves 850 Unset(); 851 if (dir.InitCheck() == B_OK) 852 SetTo(&dir, "."); 853 } 854 return *this; 855 } 856 857 858 status_t 859 BDirectory::_GetStatFor(const char *path, struct stat *st) const 860 { 861 if (!st) 862 return B_BAD_VALUE; 863 if (InitCheck() != B_OK) 864 return B_NO_INIT; 865 866 if (path != NULL) { 867 if (path[0] == '\0') 868 return B_ENTRY_NOT_FOUND; 869 return _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat)); 870 } 871 return GetStat(st); 872 } 873 874 875 status_t 876 BDirectory::_GetStatFor(const char *path, struct stat_beos *st) const 877 { 878 struct stat newStat; 879 status_t error = _GetStatFor(path, &newStat); 880 if (error != B_OK) 881 return error; 882 883 convert_to_stat_beos(&newStat, st); 884 return B_OK; 885 } 886 887 888 // FBC 889 void BDirectory::_ErectorDirectory1() {} 890 void BDirectory::_ErectorDirectory2() {} 891 void BDirectory::_ErectorDirectory3() {} 892 void BDirectory::_ErectorDirectory4() {} 893 void BDirectory::_ErectorDirectory5() {} 894 void BDirectory::_ErectorDirectory6() {} 895 896 897 //! Closes the BDirectory's file descriptor. 898 void 899 BDirectory::close_fd() 900 { 901 if (fDirFd >= 0) { 902 _kern_close(fDirFd); 903 fDirFd = -1; 904 } 905 BNode::close_fd(); 906 } 907 908 909 /*! \brief Returns the BDirectory's file descriptor. 910 To be used instead of accessing the BDirectory's private \c fDirFd member 911 directly. 912 \return the file descriptor, or -1, if not properly initialized. 913 */ 914 int 915 BDirectory::get_fd() const 916 { 917 return fDirFd; 918 } 919 920 921 // #pragma mark - C functions 922 923 924 /*! \brief Creates all missing directories along a given path. 925 \param path the directory path name. 926 \param mode a permission specification, which shall be used for the 927 newly created directories. 928 \return 929 - \c B_OK: Everything went fine. 930 - \c B_BAD_VALUE: \c NULL \a path. 931 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 932 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 933 - \c B_NO_MEMORY: Insufficient memory for operation. 934 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 935 - \c B_BUSY: A node was busy. 936 - \c B_FILE_ERROR: A general file error. 937 - \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does 938 already exist. 939 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 940 \todo Check for efficency. 941 */ 942 status_t 943 create_directory(const char *path, mode_t mode) 944 { 945 if (!path) 946 return B_BAD_VALUE; 947 // That's the strategy: We start with the first component of the supplied 948 // path, create a BPath object from it and successively add the following 949 // components. Each time we get a new path, we check, if the entry it 950 // refers to exists and is a directory. If it doesn't exist, we try 951 // to create it. This goes on, until we're done with the input path or 952 // an error occurs. 953 BPath dirPath; 954 char *component; 955 int32 nextComponent; 956 do { 957 // get the next path component 958 status_t error = BPrivate::Storage::parse_first_path_component(path, 959 component, nextComponent); 960 if (error != B_OK) 961 return error; 962 // append it to the BPath 963 if (dirPath.InitCheck() == B_NO_INIT) // first component 964 error = dirPath.SetTo(component); 965 else 966 error = dirPath.Append(component); 967 delete[] component; 968 if (error != B_OK) 969 return error; 970 path += nextComponent; 971 // create a BEntry from the BPath 972 BEntry entry; 973 error = entry.SetTo(dirPath.Path(), true); 974 if (error != B_OK) 975 return error; 976 // check, if it exists 977 if (entry.Exists()) { 978 // yep, it exists 979 if (!entry.IsDirectory()) // but is no directory 980 return B_NOT_A_DIRECTORY; 981 } else { 982 // it doesn't exist -- create it 983 error = _kern_create_dir(-1, dirPath.Path(), mode); 984 if (error != B_OK) 985 return error; 986 } 987 } while (nextComponent != 0); 988 return B_OK; 989 } 990 991 992 // #pragma mark - symbol versions 993 994 995 #if __GNUC__ == 2 // gcc 2 996 997 // BeOS compatible GetStatFor() 998 B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP9stat_beos", 999 "GetStatFor__C10BDirectoryPCcP4stat@LIBBE_BASE"); 1000 1001 // Haiku GetStatFor() 1002 B_DEFINE_SYMBOL_VERSION("_GetStatFor__C10BDirectoryPCcP4stat", 1003 "GetStatFor__C10BDirectoryPCcP4stat@@LIBBE_1_ALPHA1"); 1004 1005 #else // gcc 4 1006 1007 // BeOS compatible GetStatFor() 1008 B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP9stat_beos", 1009 "_ZNK10BDirectory10GetStatForEPKcP4stat@LIBBE_BASE"); 1010 1011 // Haiku GetStatFor() 1012 B_DEFINE_SYMBOL_VERSION("_ZNK10BDirectory11_GetStatForEPKcP4stat", 1013 "_ZNK10BDirectory10GetStatForEPKcP4stat@@LIBBE_1_ALPHA1"); 1014 1015 #endif // gcc 4 1016