1 /* 2 * Copyright 2002-2008, 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 if (nodeFlags != B_ANY_NODE) { 490 // test the node kind 491 bool result = false; 492 if ((nodeFlags & B_FILE_NODE) != 0) 493 result = entry->IsFile(); 494 if (!result && (nodeFlags & B_DIRECTORY_NODE) != 0) 495 result = entry->IsDirectory(); 496 if (!result && (nodeFlags & B_SYMLINK_NODE) != 0) 497 result = entry->IsSymLink(); 498 if (!result) 499 return false; 500 } 501 502 // If the directory is initialized, get the canonical paths of the dir and 503 // the entry and check, if the latter is a prefix of the first one. 504 BPath dirPath(this, ".", true); 505 BPath entryPath(entry); 506 if (dirPath.InitCheck() == B_OK && entryPath.InitCheck() != B_OK) 507 return false; 508 509 return !strncmp(dirPath.Path(), entryPath.Path(), strlen(dirPath.Path())); 510 } 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 if (!st) 536 return B_BAD_VALUE; 537 if (InitCheck() != B_OK) 538 return B_NO_INIT; 539 status_t error = B_OK; 540 if (path) { 541 if (strlen(path) == 0) 542 return B_ENTRY_NOT_FOUND; 543 error = _kern_read_stat(fDirFd, path, false, st, sizeof(struct stat)); 544 } else 545 error = GetStat(st); 546 return error; 547 } 548 549 // GetNextEntry 550 //! Returns the BDirectory's next entry as a BEntry. 551 /*! Unlike GetNextDirents() this method ignores the entries "." and "..". 552 \param entry a pointer to a BEntry to be initialized to the found entry 553 \param traverse specifies whether to follow it, if the found entry 554 is a symbolic link. 555 \note The iterator used by this method is the same one used by 556 GetNextRef(), GetNextDirents(), Rewind() and CountEntries(). 557 \return 558 - \c B_OK: Everything went fine. 559 - \c B_BAD_VALUE: \c NULL \a entry. 560 - \c B_ENTRY_NOT_FOUND: No more entries found. 561 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 562 - \c B_NO_MEMORY: Insufficient memory for operation. 563 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 564 - \c B_BUSY: A node was busy. 565 - \c B_FILE_ERROR: A general file error. 566 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 567 */ 568 status_t 569 BDirectory::GetNextEntry(BEntry *entry, bool traverse) 570 { 571 status_t error = (entry ? B_OK : B_BAD_VALUE); 572 if (error == B_OK) { 573 entry_ref ref; 574 error = GetNextRef(&ref); 575 if (error == B_OK) 576 error = entry->SetTo(&ref, traverse); 577 } 578 return error; 579 } 580 581 // GetNextRef 582 //! Returns the BDirectory's next entry as an entry_ref. 583 /*! Unlike GetNextDirents() this method ignores the entries "." and "..". 584 \param ref a pointer to an entry_ref to be filled in with the data of the 585 found entry 586 \param traverse specifies whether to follow it, if the found entry 587 is a symbolic link. 588 \note The iterator used be this method is the same one used by 589 GetNextEntry(), GetNextDirents(), Rewind() and CountEntries(). 590 \return 591 - \c B_OK: Everything went fine. 592 - \c B_BAD_VALUE: \c NULL \a ref. 593 - \c B_ENTRY_NOT_FOUND: No more entries found. 594 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 595 - \c B_NO_MEMORY: Insufficient memory for operation. 596 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 597 - \c B_BUSY: A node was busy. 598 - \c B_FILE_ERROR: A general file error. 599 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 600 */ 601 status_t 602 BDirectory::GetNextRef(entry_ref *ref) 603 { 604 status_t error = (ref ? B_OK : B_BAD_VALUE); 605 if (error == B_OK && InitCheck() != B_OK) 606 error = B_FILE_ERROR; 607 if (error == B_OK) { 608 BPrivate::Storage::LongDirEntry entry; 609 bool next = true; 610 while (error == B_OK && next) { 611 if (GetNextDirents(&entry, sizeof(entry), 1) != 1) { 612 error = B_ENTRY_NOT_FOUND; 613 } else { 614 next = (!strcmp(entry.d_name, ".") 615 || !strcmp(entry.d_name, "..")); 616 } 617 } 618 if (error == B_OK) { 619 ref->device = entry.d_pdev; 620 ref->directory = entry.d_pino; 621 error = ref->set_name(entry.d_name); 622 } 623 } 624 return error; 625 } 626 627 // GetNextDirents 628 //! Returns the BDirectory's next entries as dirent structures. 629 /*! Unlike GetNextEntry() and GetNextRef(), this method returns also 630 the entries "." and "..". 631 \param buf a pointer to a buffer to be filled with dirent structures of 632 the found entries 633 \param count the maximal number of entries to be returned. 634 \note The iterator used by this method is the same one used by 635 GetNextEntry(), GetNextRef(), Rewind() and CountEntries(). 636 \return 637 - The number of dirent structures stored in the buffer, 0 when there are 638 no more entries to be returned. 639 - \c B_BAD_VALUE: \c NULL \a buf. 640 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 641 - \c B_NO_MEMORY: Insufficient memory for operation. 642 - \c B_NAME_TOO_LONG: The entry's name is too long for the buffer. 643 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 644 - \c B_BUSY: A node was busy. 645 - \c B_FILE_ERROR: A general file error. 646 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 647 */ 648 int32 649 BDirectory::GetNextDirents(dirent *buf, size_t bufSize, int32 count) 650 { 651 if (!buf) 652 return B_BAD_VALUE; 653 if (InitCheck() != B_OK) 654 return B_FILE_ERROR; 655 return _kern_read_dir(fDirFd, buf, bufSize, count); 656 } 657 658 // Rewind 659 //! Rewinds the directory iterator. 660 /*! \return 661 - \c B_OK: Everything went fine. 662 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 663 - \c B_NO_MEMORY: Insufficient memory for operation. 664 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 665 - \c B_BUSY: A node was busy. 666 - \c B_FILE_ERROR: A general file error. 667 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 668 \see GetNextEntry(), GetNextRef(), GetNextDirents(), CountEntries() 669 */ 670 status_t 671 BDirectory::Rewind() 672 { 673 if (InitCheck() != B_OK) 674 return B_FILE_ERROR; 675 return _kern_rewind_dir(fDirFd); 676 } 677 678 // CountEntries 679 //! Returns the number of entries in this directory. 680 /*! CountEntries() uses the directory iterator also used by GetNextEntry(), 681 GetNextRef() and GetNextDirents(). It does a Rewind(), iterates through 682 the entries and Rewind()s again. The entries "." and ".." are not counted. 683 \return 684 - the number of entries in the directory (not counting "." and ".."). 685 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 686 - \c B_NO_MEMORY: Insufficient memory for operation. 687 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 688 - \c B_BUSY: A node was busy. 689 - \c B_FILE_ERROR: A general file error. 690 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 691 \see GetNextEntry(), GetNextRef(), GetNextDirents(), Rewind() 692 */ 693 int32 694 BDirectory::CountEntries() 695 { 696 status_t error = Rewind(); 697 if (error != B_OK) 698 return error; 699 int32 count = 0; 700 BPrivate::Storage::LongDirEntry entry; 701 while (error == B_OK) { 702 if (GetNextDirents(&entry, sizeof(entry), 1) != 1) 703 break; 704 if (strcmp(entry.d_name, ".") != 0 && strcmp(entry.d_name, "..") != 0) 705 count++; 706 } 707 Rewind(); 708 return (error == B_OK ? count : error); 709 } 710 711 // CreateDirectory 712 //! Creates a new directory. 713 /*! If an entry with the supplied name does already exist, the method fails. 714 \param path the new directory's path name. May be relative to this 715 directory or absolute. 716 \param dir a pointer to a BDirectory to be initialized to the newly 717 created directory. May be \c NULL. 718 \return 719 - \c B_OK: Everything went fine. 720 - \c B_BAD_VALUE: \c NULL \a path. 721 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 722 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 723 - \c B_NO_MEMORY: Insufficient memory for operation. 724 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 725 - \c B_BUSY: A node was busy. 726 - \c B_FILE_ERROR: A general file error. 727 - \c B_FILE_EXISTS: An entry with that name does already exist. 728 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 729 */ 730 status_t 731 BDirectory::CreateDirectory(const char *path, BDirectory *dir) 732 { 733 if (!path) 734 return B_BAD_VALUE; 735 // create the dir 736 status_t error = _kern_create_dir(fDirFd, path, 737 S_IRWXU | S_IRWXG | S_IRWXO); 738 if (error != B_OK) 739 return error; 740 if (!dir) 741 return B_OK; 742 // init the supplied BDirectory 743 if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) 744 return dir->SetTo(path); 745 else 746 return dir->SetTo(this, path); 747 } 748 749 // CreateFile 750 //! Creates a new file. 751 /*! If a file with the supplied name does already exist, the method fails, 752 unless it is passed \c false to \a failIfExists -- in that case the file 753 is truncated to zero size. The new BFile will operate in \c B_READ_WRITE 754 mode. 755 \param path the new file's path name. May be relative to this 756 directory or absolute. 757 \param file a pointer to a BFile to be initialized to the newly 758 created file. May be \c NULL. 759 \param failIfExists \c true, if the method should fail when the file 760 already exists, \c false otherwise 761 \return 762 - \c B_OK: Everything went fine. 763 - \c B_BAD_VALUE: \c NULL \a path. 764 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 765 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 766 - \c B_NO_MEMORY: Insufficient memory for operation. 767 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 768 - \c B_BUSY: A node was busy. 769 - \c B_FILE_ERROR: A general file error. 770 - \c B_FILE_EXISTS: A file with that name does already exist and 771 \c true has been passed for \a failIfExists. 772 - \c B_IS_A_DIRECTORY: A directory with the supplied name does already 773 exist. 774 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 775 */ 776 status_t 777 BDirectory::CreateFile(const char *path, BFile *file, bool failIfExists) 778 { 779 if (!path) 780 return B_BAD_VALUE; 781 // Let BFile do the dirty job. 782 uint32 openMode = B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE 783 | (failIfExists ? B_FAIL_IF_EXISTS : 0); 784 BFile tmpFile; 785 BFile *realFile = (file ? file : &tmpFile); 786 status_t error = B_OK; 787 if (InitCheck() == B_OK && !BPrivate::Storage::is_absolute_path(path)) 788 error = realFile->SetTo(this, path, openMode); 789 else 790 error = realFile->SetTo(path, openMode); 791 if (error != B_OK && file) // mimic R5 behavior 792 file->Unset(); 793 return error; 794 } 795 796 // CreateSymLink 797 //! Creates a new symbolic link. 798 /*! If an entry with the supplied name does already exist, the method fails. 799 \param path the new symbolic link's path name. May be relative to this 800 directory or absolute. 801 \param linkToPath the path the symbolic link shall point to. 802 \param dir a pointer to a BSymLink to be initialized to the newly 803 created symbolic link. May be \c NULL. 804 \return 805 - \c B_OK: Everything went fine. 806 - \c B_BAD_VALUE: \c NULL \a path or \a linkToPath. 807 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 808 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 809 - \c B_NO_MEMORY: Insufficient memory for operation. 810 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 811 - \c B_BUSY: A node was busy. 812 - \c B_FILE_ERROR: A general file error. 813 - \c B_FILE_EXISTS: An entry with that name does already exist. 814 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 815 */ 816 status_t 817 BDirectory::CreateSymLink(const char *path, const char *linkToPath, 818 BSymLink *link) 819 { 820 if (!path || !linkToPath) 821 return B_BAD_VALUE; 822 // create the symlink 823 status_t error = _kern_create_symlink(fDirFd, path, linkToPath, 824 S_IRWXU | S_IRWXG | S_IRWXO); 825 if (error != B_OK) 826 return error; 827 if (!link) 828 return B_OK; 829 // init the supplied BSymLink 830 if (InitCheck() != B_OK || BPrivate::Storage::is_absolute_path(path)) 831 return link->SetTo(path); 832 else 833 return link->SetTo(this, path); 834 } 835 836 // = 837 //! Assigns another BDirectory to this BDirectory. 838 /*! If the other BDirectory is uninitialized, this one wi'll be too. Otherwise 839 it will refer to the same directory, unless an error occurs. 840 \param dir the original BDirectory 841 \return a reference to this BDirectory 842 */ 843 BDirectory & 844 BDirectory::operator=(const BDirectory &dir) 845 { 846 if (&dir != this) { // no need to assign us to ourselves 847 Unset(); 848 if (dir.InitCheck() == B_OK) 849 SetTo(&dir, "."); 850 } 851 return *this; 852 } 853 854 855 // FBC 856 void BDirectory::_ErectorDirectory1() {} 857 void BDirectory::_ErectorDirectory2() {} 858 void BDirectory::_ErectorDirectory3() {} 859 void BDirectory::_ErectorDirectory4() {} 860 void BDirectory::_ErectorDirectory5() {} 861 void BDirectory::_ErectorDirectory6() {} 862 863 // close_fd 864 //! Closes the BDirectory's file descriptor. 865 void 866 BDirectory::close_fd() 867 { 868 if (fDirFd >= 0) { 869 _kern_close(fDirFd); 870 fDirFd = -1; 871 } 872 BNode::close_fd(); 873 } 874 875 //! Returns the BDirectory's file descriptor. 876 /*! To be used instead of accessing the BDirectory's private \c fDirFd member 877 directly. 878 \return the file descriptor, or -1, if not properly initialized. 879 */ 880 int 881 BDirectory::get_fd() const 882 { 883 return fDirFd; 884 } 885 886 887 // C functions 888 889 // create_directory 890 //! Creates all missing directories along a given path. 891 /*! \param path the directory path name. 892 \param mode a permission specification, which shall be used for the 893 newly created directories. 894 \return 895 - \c B_OK: Everything went fine. 896 - \c B_BAD_VALUE: \c NULL \a path. 897 - \c B_ENTRY_NOT_FOUND: \a path does not refer to a possible entry. 898 - \c B_PERMISSION_DENIED: Directory permissions didn't allow operation. 899 - \c B_NO_MEMORY: Insufficient memory for operation. 900 - \c B_LINK_LIMIT: Indicates a cyclic loop within the file system. 901 - \c B_BUSY: A node was busy. 902 - \c B_FILE_ERROR: A general file error. 903 - \c B_NOT_A_DIRECTORY: An entry other than a directory with that name does 904 already exist. 905 - \c B_NO_MORE_FDS: The application has run out of file descriptors. 906 \todo Check for efficency. 907 */ 908 status_t 909 create_directory(const char *path, mode_t mode) 910 { 911 if (!path) 912 return B_BAD_VALUE; 913 // That's the strategy: We start with the first component of the supplied 914 // path, create a BPath object from it and successively add the following 915 // components. Each time we get a new path, we check, if the entry it 916 // refers to exists and is a directory. If it doesn't exist, we try 917 // to create it. This goes on, until we're done with the input path or 918 // an error occurs. 919 BPath dirPath; 920 char *component; 921 int32 nextComponent; 922 do { 923 // get the next path component 924 status_t error = BPrivate::Storage::parse_first_path_component(path, 925 component, nextComponent); 926 if (error != B_OK) 927 return error; 928 // append it to the BPath 929 if (dirPath.InitCheck() == B_NO_INIT) // first component 930 error = dirPath.SetTo(component); 931 else 932 error = dirPath.Append(component); 933 delete[] component; 934 if (error != B_OK) 935 return error; 936 path += nextComponent; 937 // create a BEntry from the BPath 938 BEntry entry; 939 error = entry.SetTo(dirPath.Path(), true); 940 if (error != B_OK) 941 return error; 942 // check, if it exists 943 if (entry.Exists()) { 944 // yep, it exists 945 if (!entry.IsDirectory()) // but is no directory 946 return B_NOT_A_DIRECTORY; 947 } else { 948 // it doesn't exist -- create it 949 error = _kern_create_dir(-1, dirPath.Path(), mode); 950 if (error != B_OK) 951 return error; 952 } 953 } while (nextComponent != 0); 954 return B_OK; 955 } 956 957