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