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