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