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