1 //===- llvm/Support/FileSystem.h - File System OS Concept -------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file declares the llvm::sys::fs namespace. It is designed after 11 // TR2/boost filesystem (v3), but modified to remove exception handling and the 12 // path class. 13 // 14 // All functions return an error_code and their actual work via the last out 15 // argument. The out argument is defined if and only if errc::success is 16 // returned. A function may return any error code in the generic or system 17 // category. However, they shall be equivalent to any error conditions listed 18 // in each functions respective documentation if the condition applies. [ note: 19 // this does not guarantee that error_code will be in the set of explicitly 20 // listed codes, but it does guarantee that if any of the explicitly listed 21 // errors occur, the correct error_code will be used ]. All functions may 22 // return errc::not_enough_memory if there is not enough memory to complete the 23 // operation. 24 // 25 //===----------------------------------------------------------------------===// 26 27 #ifndef LLVM_SUPPORT_FILESYSTEM_H 28 #define LLVM_SUPPORT_FILESYSTEM_H 29 30 #include "llvm/ADT/IntrusiveRefCntPtr.h" 31 #include "llvm/ADT/OwningPtr.h" 32 #include "llvm/ADT/SmallString.h" 33 #include "llvm/ADT/Twine.h" 34 #include "llvm/Support/DataTypes.h" 35 #include "llvm/Support/ErrorHandling.h" 36 #include "llvm/Support/system_error.h" 37 #include <ctime> 38 #include <iterator> 39 #include <stack> 40 #include <string> 41 #include <vector> 42 43 #ifdef HAVE_SYS_STAT_H 44 #include <sys/stat.h> 45 #endif 46 47 namespace llvm { 48 namespace sys { 49 namespace fs { 50 51 /// file_type - An "enum class" enumeration for the file system's view of the 52 /// type. 53 struct file_type { 54 enum _ { 55 status_error, 56 file_not_found, 57 regular_file, 58 directory_file, 59 symlink_file, 60 block_file, 61 character_file, 62 fifo_file, 63 socket_file, 64 type_unknown 65 }; 66 67 file_type(_ v) : v_(v) {} 68 explicit file_type(int v) : v_(_(v)) {} 69 operator int() const {return v_;} 70 71 private: 72 int v_; 73 }; 74 75 /// copy_option - An "enum class" enumeration of copy semantics for copy 76 /// operations. 77 struct copy_option { 78 enum _ { 79 fail_if_exists, 80 overwrite_if_exists 81 }; 82 83 copy_option(_ v) : v_(v) {} 84 explicit copy_option(int v) : v_(_(v)) {} 85 operator int() const {return v_;} 86 87 private: 88 int v_; 89 }; 90 91 /// space_info - Self explanatory. 92 struct space_info { 93 uint64_t capacity; 94 uint64_t free; 95 uint64_t available; 96 }; 97 98 99 enum perms { 100 no_perms = 0, 101 owner_read = 0400, 102 owner_write = 0200, 103 owner_exe = 0100, 104 owner_all = owner_read | owner_write | owner_exe, 105 group_read = 040, 106 group_write = 020, 107 group_exe = 010, 108 group_all = group_read | group_write | group_exe, 109 others_read = 04, 110 others_write = 02, 111 others_exe = 01, 112 others_all = others_read | others_write | others_exe, 113 all_all = owner_all | group_all | others_all, 114 set_uid_on_exe = 04000, 115 set_gid_on_exe = 02000, 116 sticky_bit = 01000, 117 perms_mask = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit, 118 perms_not_known = 0xFFFF, 119 add_perms = 0x1000, 120 remove_perms = 0x2000, 121 symlink_perms = 0x4000 122 }; 123 124 // Helper functions so that you can use & and | to manipulate perms bits: 125 inline perms operator|(perms l , perms r) { 126 return static_cast<perms>( 127 static_cast<unsigned short>(l) | static_cast<unsigned short>(r)); 128 } 129 inline perms operator&(perms l , perms r) { 130 return static_cast<perms>( 131 static_cast<unsigned short>(l) & static_cast<unsigned short>(r)); 132 } 133 inline perms &operator|=(perms &l, perms r) { 134 l = l | r; 135 return l; 136 } 137 inline perms &operator&=(perms &l, perms r) { 138 l = l & r; 139 return l; 140 } 141 inline perms operator~(perms x) { 142 return static_cast<perms>(~static_cast<unsigned short>(x)); 143 } 144 145 146 147 /// file_status - Represents the result of a call to stat and friends. It has 148 /// a platform specific member to store the result. 149 class file_status 150 { 151 #if defined(LLVM_ON_UNIX) 152 dev_t fs_st_dev; 153 ino_t fs_st_ino; 154 #elif defined (LLVM_ON_WIN32) 155 uint32_t LastWriteTimeHigh; 156 uint32_t LastWriteTimeLow; 157 uint32_t VolumeSerialNumber; 158 uint32_t FileSizeHigh; 159 uint32_t FileSizeLow; 160 uint32_t FileIndexHigh; 161 uint32_t FileIndexLow; 162 #endif 163 friend bool equivalent(file_status A, file_status B); 164 friend error_code status(const Twine &path, file_status &result); 165 file_type Type; 166 perms Perms; 167 public: 168 explicit file_status(file_type v=file_type::status_error, 169 perms prms=perms_not_known) 170 : Type(v), Perms(prms) {} 171 172 // getters 173 file_type type() const { return Type; } 174 perms permissions() const { return Perms; } 175 176 // setters 177 void type(file_type v) { Type = v; } 178 void permissions(perms p) { Perms = p; } 179 }; 180 181 /// file_magic - An "enum class" enumeration of file types based on magic (the first 182 /// N bytes of the file). 183 struct file_magic { 184 enum _ { 185 unknown = 0, ///< Unrecognized file 186 bitcode, ///< Bitcode file 187 archive, ///< ar style archive file 188 elf_relocatable, ///< ELF Relocatable object file 189 elf_executable, ///< ELF Executable image 190 elf_shared_object, ///< ELF dynamically linked shared lib 191 elf_core, ///< ELF core image 192 macho_object, ///< Mach-O Object file 193 macho_executable, ///< Mach-O Executable 194 macho_fixed_virtual_memory_shared_lib, ///< Mach-O Shared Lib, FVM 195 macho_core, ///< Mach-O Core File 196 macho_preload_executabl, ///< Mach-O Preloaded Executable 197 macho_dynamically_linked_shared_lib, ///< Mach-O dynlinked shared lib 198 macho_dynamic_linker, ///< The Mach-O dynamic linker 199 macho_bundle, ///< Mach-O Bundle file 200 macho_dynamically_linked_shared_lib_stub, ///< Mach-O Shared lib stub 201 macho_dsym_companion, ///< Mach-O dSYM companion file 202 coff_object, ///< COFF object file 203 pecoff_executable ///< PECOFF executable file 204 }; 205 206 bool is_object() const { 207 return v_ == unknown ? false : true; 208 } 209 210 file_magic() : v_(unknown) {} 211 file_magic(_ v) : v_(v) {} 212 explicit file_magic(int v) : v_(_(v)) {} 213 operator int() const {return v_;} 214 215 private: 216 int v_; 217 }; 218 219 /// @} 220 /// @name Physical Operators 221 /// @{ 222 223 /// @brief Make \a path an absolute path. 224 /// 225 /// Makes \a path absolute using the current directory if it is not already. An 226 /// empty \a path will result in the current directory. 227 /// 228 /// /absolute/path => /absolute/path 229 /// relative/../path => <current-directory>/relative/../path 230 /// 231 /// @param path A path that is modified to be an absolute path. 232 /// @returns errc::success if \a path has been made absolute, otherwise a 233 /// platform specific error_code. 234 error_code make_absolute(SmallVectorImpl<char> &path); 235 236 /// @brief Copy the file at \a from to the path \a to. 237 /// 238 /// @param from The path to copy the file from. 239 /// @param to The path to copy the file to. 240 /// @param copt Behavior if \a to already exists. 241 /// @returns errc::success if the file has been successfully copied. 242 /// errc::file_exists if \a to already exists and \a copt == 243 /// copy_option::fail_if_exists. Otherwise a platform specific 244 /// error_code. 245 error_code copy_file(const Twine &from, const Twine &to, 246 copy_option copt = copy_option::fail_if_exists); 247 248 /// @brief Create all the non-existent directories in path. 249 /// 250 /// @param path Directories to create. 251 /// @param existed Set to true if \a path already existed, false otherwise. 252 /// @returns errc::success if is_directory(path) and existed have been set, 253 /// otherwise a platform specific error_code. 254 error_code create_directories(const Twine &path, bool &existed); 255 256 /// @brief Create the directory in path. 257 /// 258 /// @param path Directory to create. 259 /// @param existed Set to true if \a path already existed, false otherwise. 260 /// @returns errc::success if is_directory(path) and existed have been set, 261 /// otherwise a platform specific error_code. 262 error_code create_directory(const Twine &path, bool &existed); 263 264 /// @brief Create a hard link from \a from to \a to. 265 /// 266 /// @param to The path to hard link to. 267 /// @param from The path to hard link from. This is created. 268 /// @returns errc::success if exists(to) && exists(from) && equivalent(to, from) 269 /// , otherwise a platform specific error_code. 270 error_code create_hard_link(const Twine &to, const Twine &from); 271 272 /// @brief Create a symbolic link from \a from to \a to. 273 /// 274 /// @param to The path to symbolically link to. 275 /// @param from The path to symbolically link from. This is created. 276 /// @returns errc::success if exists(to) && exists(from) && is_symlink(from), 277 /// otherwise a platform specific error_code. 278 error_code create_symlink(const Twine &to, const Twine &from); 279 280 /// @brief Get the current path. 281 /// 282 /// @param result Holds the current path on return. 283 /// @returns errc::success if the current path has been stored in result, 284 /// otherwise a platform specific error_code. 285 error_code current_path(SmallVectorImpl<char> &result); 286 287 /// @brief Remove path. Equivalent to POSIX remove(). 288 /// 289 /// @param path Input path. 290 /// @param existed Set to true if \a path existed, false if it did not. 291 /// undefined otherwise. 292 /// @returns errc::success if path has been removed and existed has been 293 /// successfully set, otherwise a platform specific error_code. 294 error_code remove(const Twine &path, bool &existed); 295 296 /// @brief Recursively remove all files below \a path, then \a path. Files are 297 /// removed as if by POSIX remove(). 298 /// 299 /// @param path Input path. 300 /// @param num_removed Number of files removed. 301 /// @returns errc::success if path has been removed and num_removed has been 302 /// successfully set, otherwise a platform specific error_code. 303 error_code remove_all(const Twine &path, uint32_t &num_removed); 304 305 /// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename(). 306 /// 307 /// @param from The path to rename from. 308 /// @param to The path to rename to. This is created. 309 error_code rename(const Twine &from, const Twine &to); 310 311 /// @brief Resize path to size. File is resized as if by POSIX truncate(). 312 /// 313 /// @param path Input path. 314 /// @param size Size to resize to. 315 /// @returns errc::success if \a path has been resized to \a size, otherwise a 316 /// platform specific error_code. 317 error_code resize_file(const Twine &path, uint64_t size); 318 319 /// @} 320 /// @name Physical Observers 321 /// @{ 322 323 /// @brief Does file exist? 324 /// 325 /// @param status A file_status previously returned from stat. 326 /// @returns True if the file represented by status exists, false if it does 327 /// not. 328 bool exists(file_status status); 329 330 /// @brief Does file exist? 331 /// 332 /// @param path Input path. 333 /// @param result Set to true if the file represented by status exists, false if 334 /// it does not. Undefined otherwise. 335 /// @returns errc::success if result has been successfully set, otherwise a 336 /// platform specific error_code. 337 error_code exists(const Twine &path, bool &result); 338 339 /// @brief Simpler version of exists for clients that don't need to 340 /// differentiate between an error and false. 341 inline bool exists(const Twine &path) { 342 bool result; 343 return !exists(path, result) && result; 344 } 345 346 /// @brief Do file_status's represent the same thing? 347 /// 348 /// @param A Input file_status. 349 /// @param B Input file_status. 350 /// 351 /// assert(status_known(A) || status_known(B)); 352 /// 353 /// @returns True if A and B both represent the same file system entity, false 354 /// otherwise. 355 bool equivalent(file_status A, file_status B); 356 357 /// @brief Do paths represent the same thing? 358 /// 359 /// assert(status_known(A) || status_known(B)); 360 /// 361 /// @param A Input path A. 362 /// @param B Input path B. 363 /// @param result Set to true if stat(A) and stat(B) have the same device and 364 /// inode (or equivalent). 365 /// @returns errc::success if result has been successfully set, otherwise a 366 /// platform specific error_code. 367 error_code equivalent(const Twine &A, const Twine &B, bool &result); 368 369 /// @brief Simpler version of equivalent for clients that don't need to 370 /// differentiate between an error and false. 371 inline bool equivalent(const Twine &A, const Twine &B) { 372 bool result; 373 return !equivalent(A, B, result) && result; 374 } 375 376 /// @brief Get file size. 377 /// 378 /// @param path Input path. 379 /// @param result Set to the size of the file in \a path. 380 /// @returns errc::success if result has been successfully set, otherwise a 381 /// platform specific error_code. 382 error_code file_size(const Twine &path, uint64_t &result); 383 384 /// @brief Does status represent a directory? 385 /// 386 /// @param status A file_status previously returned from status. 387 /// @returns status.type() == file_type::directory_file. 388 bool is_directory(file_status status); 389 390 /// @brief Is path a directory? 391 /// 392 /// @param path Input path. 393 /// @param result Set to true if \a path is a directory, false if it is not. 394 /// Undefined otherwise. 395 /// @returns errc::success if result has been successfully set, otherwise a 396 /// platform specific error_code. 397 error_code is_directory(const Twine &path, bool &result); 398 399 /// @brief Does status represent a regular file? 400 /// 401 /// @param status A file_status previously returned from status. 402 /// @returns status_known(status) && status.type() == file_type::regular_file. 403 bool is_regular_file(file_status status); 404 405 /// @brief Is path a regular file? 406 /// 407 /// @param path Input path. 408 /// @param result Set to true if \a path is a regular file, false if it is not. 409 /// Undefined otherwise. 410 /// @returns errc::success if result has been successfully set, otherwise a 411 /// platform specific error_code. 412 error_code is_regular_file(const Twine &path, bool &result); 413 414 /// @brief Does this status represent something that exists but is not a 415 /// directory, regular file, or symlink? 416 /// 417 /// @param status A file_status previously returned from status. 418 /// @returns exists(s) && !is_regular_file(s) && !is_directory(s) && 419 /// !is_symlink(s) 420 bool is_other(file_status status); 421 422 /// @brief Is path something that exists but is not a directory, 423 /// regular file, or symlink? 424 /// 425 /// @param path Input path. 426 /// @param result Set to true if \a path exists, but is not a directory, regular 427 /// file, or a symlink, false if it does not. Undefined otherwise. 428 /// @returns errc::success if result has been successfully set, otherwise a 429 /// platform specific error_code. 430 error_code is_other(const Twine &path, bool &result); 431 432 /// @brief Does status represent a symlink? 433 /// 434 /// @param status A file_status previously returned from stat. 435 /// @returns status.type() == symlink_file. 436 bool is_symlink(file_status status); 437 438 /// @brief Is path a symlink? 439 /// 440 /// @param path Input path. 441 /// @param result Set to true if \a path is a symlink, false if it is not. 442 /// Undefined otherwise. 443 /// @returns errc::success if result has been successfully set, otherwise a 444 /// platform specific error_code. 445 error_code is_symlink(const Twine &path, bool &result); 446 447 /// @brief Get file status as if by POSIX stat(). 448 /// 449 /// @param path Input path. 450 /// @param result Set to the file status. 451 /// @returns errc::success if result has been successfully set, otherwise a 452 /// platform specific error_code. 453 error_code status(const Twine &path, file_status &result); 454 455 /// @brief Modifies permission bits on a file 456 /// 457 /// @param path Input path. 458 /// @returns errc::success if permissions have been changed, otherwise a 459 /// platform specific error_code. 460 error_code permissions(const Twine &path, perms prms); 461 462 /// @brief Is status available? 463 /// 464 /// @param s Input file status. 465 /// @returns True if status() != status_error. 466 bool status_known(file_status s); 467 468 /// @brief Is status available? 469 /// 470 /// @param path Input path. 471 /// @param result Set to true if status() != status_error. 472 /// @returns errc::success if result has been successfully set, otherwise a 473 /// platform specific error_code. 474 error_code status_known(const Twine &path, bool &result); 475 476 /// @brief Generate a unique path and open it as a file. 477 /// 478 /// Generates a unique path suitable for a temporary file and then opens it as a 479 /// file. The name is based on \a model with '%' replaced by a random char in 480 /// [0-9a-f]. If \a model is not an absolute path, a suitable temporary 481 /// directory will be prepended. 482 /// 483 /// This is an atomic operation. Either the file is created and opened, or the 484 /// file system is left untouched. 485 /// 486 /// clang-%%-%%-%%-%%-%%.s => /tmp/clang-a0-b1-c2-d3-e4.s 487 /// 488 /// @param model Name to base unique path off of. 489 /// @param result_fd Set to the opened file's file descriptor. 490 /// @param result_path Set to the opened file's absolute path. 491 /// @param makeAbsolute If true and \a model is not an absolute path, a temp 492 /// directory will be prepended. 493 /// @returns errc::success if result_{fd,path} have been successfully set, 494 /// otherwise a platform specific error_code. 495 error_code unique_file(const Twine &model, int &result_fd, 496 SmallVectorImpl<char> &result_path, 497 bool makeAbsolute = true, unsigned mode = 0600); 498 499 /// @brief Canonicalize path. 500 /// 501 /// Sets result to the file system's idea of what path is. The result is always 502 /// absolute and has the same capitalization as the file system. 503 /// 504 /// @param path Input path. 505 /// @param result Set to the canonicalized version of \a path. 506 /// @returns errc::success if result has been successfully set, otherwise a 507 /// platform specific error_code. 508 error_code canonicalize(const Twine &path, SmallVectorImpl<char> &result); 509 510 /// @brief Are \a path's first bytes \a magic? 511 /// 512 /// @param path Input path. 513 /// @param magic Byte sequence to compare \a path's first len(magic) bytes to. 514 /// @returns errc::success if result has been successfully set, otherwise a 515 /// platform specific error_code. 516 error_code has_magic(const Twine &path, const Twine &magic, bool &result); 517 518 /// @brief Get \a path's first \a len bytes. 519 /// 520 /// @param path Input path. 521 /// @param len Number of magic bytes to get. 522 /// @param result Set to the first \a len bytes in the file pointed to by 523 /// \a path. Or the entire file if file_size(path) < len, in which 524 /// case result.size() returns the size of the file. 525 /// @returns errc::success if result has been successfully set, 526 /// errc::value_too_large if len is larger then the file pointed to by 527 /// \a path, otherwise a platform specific error_code. 528 error_code get_magic(const Twine &path, uint32_t len, 529 SmallVectorImpl<char> &result); 530 531 /// @brief Identify the type of a binary file based on how magical it is. 532 file_magic identify_magic(StringRef magic); 533 534 /// @brief Get and identify \a path's type based on its content. 535 /// 536 /// @param path Input path. 537 /// @param result Set to the type of file, or LLVMFileType::Unknown_FileType. 538 /// @returns errc::success if result has been successfully set, otherwise a 539 /// platform specific error_code. 540 error_code identify_magic(const Twine &path, file_magic &result); 541 542 /// @brief Get library paths the system linker uses. 543 /// 544 /// @param result Set to the list of system library paths. 545 /// @returns errc::success if result has been successfully set, otherwise a 546 /// platform specific error_code. 547 error_code GetSystemLibraryPaths(SmallVectorImpl<std::string> &result); 548 549 /// @brief Get bitcode library paths the system linker uses 550 /// + LLVM_LIB_SEARCH_PATH + LLVM_LIBDIR. 551 /// 552 /// @param result Set to the list of bitcode library paths. 553 /// @returns errc::success if result has been successfully set, otherwise a 554 /// platform specific error_code. 555 error_code GetBitcodeLibraryPaths(SmallVectorImpl<std::string> &result); 556 557 /// @brief Find a library. 558 /// 559 /// Find the path to a library using its short name. Use the system 560 /// dependent library paths to locate the library. 561 /// 562 /// c => /usr/lib/libc.so 563 /// 564 /// @param short_name Library name one would give to the system linker. 565 /// @param result Set to the absolute path \a short_name represents. 566 /// @returns errc::success if result has been successfully set, otherwise a 567 /// platform specific error_code. 568 error_code FindLibrary(const Twine &short_name, SmallVectorImpl<char> &result); 569 570 /// @brief Get absolute path of main executable. 571 /// 572 /// @param argv0 The program name as it was spelled on the command line. 573 /// @param MainAddr Address of some symbol in the executable (not in a library). 574 /// @param result Set to the absolute path of the current executable. 575 /// @returns errc::success if result has been successfully set, otherwise a 576 /// platform specific error_code. 577 error_code GetMainExecutable(const char *argv0, void *MainAddr, 578 SmallVectorImpl<char> &result); 579 580 /// This class represents a memory mapped file. It is based on 581 /// boost::iostreams::mapped_file. 582 class mapped_file_region { 583 mapped_file_region() LLVM_DELETED_FUNCTION; 584 mapped_file_region(mapped_file_region&) LLVM_DELETED_FUNCTION; 585 mapped_file_region &operator =(mapped_file_region&) LLVM_DELETED_FUNCTION; 586 587 public: 588 enum mapmode { 589 readonly, ///< May only access map via const_data as read only. 590 readwrite, ///< May access map via data and modify it. Written to path. 591 priv ///< May modify via data, but changes are lost on destruction. 592 }; 593 594 private: 595 /// Platform specific mapping state. 596 mapmode Mode; 597 uint64_t Size; 598 void *Mapping; 599 #ifdef LLVM_ON_WIN32 600 int FileDescriptor; 601 void *FileHandle; 602 void *FileMappingHandle; 603 #endif 604 605 error_code init(int FD, bool CloseFD, uint64_t Offset); 606 607 public: 608 typedef char char_type; 609 610 #if LLVM_HAS_RVALUE_REFERENCES 611 mapped_file_region(mapped_file_region&&); 612 mapped_file_region &operator =(mapped_file_region&&); 613 #endif 614 615 /// Construct a mapped_file_region at \a path starting at \a offset of length 616 /// \a length and with access \a mode. 617 /// 618 /// \param path Path to the file to map. If it does not exist it will be 619 /// created. 620 /// \param mode How to map the memory. 621 /// \param length Number of bytes to map in starting at \a offset. If the file 622 /// is shorter than this, it will be extended. If \a length is 623 /// 0, the entire file will be mapped. 624 /// \param offset Byte offset from the beginning of the file where the map 625 /// should begin. Must be a multiple of 626 /// mapped_file_region::alignment(). 627 /// \param ec This is set to errc::success if the map was constructed 628 /// sucessfully. Otherwise it is set to a platform dependent error. 629 mapped_file_region(const Twine &path, 630 mapmode mode, 631 uint64_t length, 632 uint64_t offset, 633 error_code &ec); 634 635 /// \param fd An open file descriptor to map. mapped_file_region takes 636 /// ownership if closefd is true. It must have been opended in the correct 637 /// mode. 638 mapped_file_region(int fd, 639 bool closefd, 640 mapmode mode, 641 uint64_t length, 642 uint64_t offset, 643 error_code &ec); 644 645 ~mapped_file_region(); 646 647 mapmode flags() const; 648 uint64_t size() const; 649 char *data() const; 650 651 /// Get a const view of the data. Modifying this memory has undefined 652 /// behaivor. 653 const char *const_data() const; 654 655 /// \returns The minimum alignment offset must be. 656 static int alignment(); 657 }; 658 659 /// @brief Memory maps the contents of a file 660 /// 661 /// @param path Path to file to map. 662 /// @param file_offset Byte offset in file where mapping should begin. 663 /// @param size Byte length of range of the file to map. 664 /// @param map_writable If true, the file will be mapped in r/w such 665 /// that changes to the mapped buffer will be flushed back 666 /// to the file. If false, the file will be mapped read-only 667 /// and the buffer will be read-only. 668 /// @param result Set to the start address of the mapped buffer. 669 /// @returns errc::success if result has been successfully set, otherwise a 670 /// platform specific error_code. 671 error_code map_file_pages(const Twine &path, off_t file_offset, size_t size, 672 bool map_writable, void *&result); 673 674 675 /// @brief Memory unmaps the contents of a file 676 /// 677 /// @param base Pointer to the start of the buffer. 678 /// @param size Byte length of the range to unmmap. 679 /// @returns errc::success if result has been successfully set, otherwise a 680 /// platform specific error_code. 681 error_code unmap_file_pages(void *base, size_t size); 682 683 684 685 /// @} 686 /// @name Iterators 687 /// @{ 688 689 /// directory_entry - A single entry in a directory. Caches the status either 690 /// from the result of the iteration syscall, or the first time status is 691 /// called. 692 class directory_entry { 693 std::string Path; 694 mutable file_status Status; 695 696 public: 697 explicit directory_entry(const Twine &path, file_status st = file_status()) 698 : Path(path.str()) 699 , Status(st) {} 700 701 directory_entry() {} 702 703 void assign(const Twine &path, file_status st = file_status()) { 704 Path = path.str(); 705 Status = st; 706 } 707 708 void replace_filename(const Twine &filename, file_status st = file_status()); 709 710 const std::string &path() const { return Path; } 711 error_code status(file_status &result) const; 712 713 bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; } 714 bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); } 715 bool operator< (const directory_entry& rhs) const; 716 bool operator<=(const directory_entry& rhs) const; 717 bool operator> (const directory_entry& rhs) const; 718 bool operator>=(const directory_entry& rhs) const; 719 }; 720 721 namespace detail { 722 struct DirIterState; 723 724 error_code directory_iterator_construct(DirIterState&, StringRef); 725 error_code directory_iterator_increment(DirIterState&); 726 error_code directory_iterator_destruct(DirIterState&); 727 728 /// DirIterState - Keeps state for the directory_iterator. It is reference 729 /// counted in order to preserve InputIterator semantics on copy. 730 struct DirIterState : public RefCountedBase<DirIterState> { 731 DirIterState() 732 : IterationHandle(0) {} 733 734 ~DirIterState() { 735 directory_iterator_destruct(*this); 736 } 737 738 intptr_t IterationHandle; 739 directory_entry CurrentEntry; 740 }; 741 } 742 743 /// directory_iterator - Iterates through the entries in path. There is no 744 /// operator++ because we need an error_code. If it's really needed we can make 745 /// it call report_fatal_error on error. 746 class directory_iterator { 747 IntrusiveRefCntPtr<detail::DirIterState> State; 748 749 public: 750 explicit directory_iterator(const Twine &path, error_code &ec) { 751 State = new detail::DirIterState; 752 SmallString<128> path_storage; 753 ec = detail::directory_iterator_construct(*State, 754 path.toStringRef(path_storage)); 755 } 756 757 explicit directory_iterator(const directory_entry &de, error_code &ec) { 758 State = new detail::DirIterState; 759 ec = detail::directory_iterator_construct(*State, de.path()); 760 } 761 762 /// Construct end iterator. 763 directory_iterator() : State(new detail::DirIterState) {} 764 765 // No operator++ because we need error_code. 766 directory_iterator &increment(error_code &ec) { 767 ec = directory_iterator_increment(*State); 768 return *this; 769 } 770 771 const directory_entry &operator*() const { return State->CurrentEntry; } 772 const directory_entry *operator->() const { return &State->CurrentEntry; } 773 774 bool operator==(const directory_iterator &RHS) const { 775 return State->CurrentEntry == RHS.State->CurrentEntry; 776 } 777 778 bool operator!=(const directory_iterator &RHS) const { 779 return !(*this == RHS); 780 } 781 // Other members as required by 782 // C++ Std, 24.1.1 Input iterators [input.iterators] 783 }; 784 785 namespace detail { 786 /// RecDirIterState - Keeps state for the recursive_directory_iterator. It is 787 /// reference counted in order to preserve InputIterator semantics on copy. 788 struct RecDirIterState : public RefCountedBase<RecDirIterState> { 789 RecDirIterState() 790 : Level(0) 791 , HasNoPushRequest(false) {} 792 793 std::stack<directory_iterator, std::vector<directory_iterator> > Stack; 794 uint16_t Level; 795 bool HasNoPushRequest; 796 }; 797 } 798 799 /// recursive_directory_iterator - Same as directory_iterator except for it 800 /// recurses down into child directories. 801 class recursive_directory_iterator { 802 IntrusiveRefCntPtr<detail::RecDirIterState> State; 803 804 public: 805 recursive_directory_iterator() {} 806 explicit recursive_directory_iterator(const Twine &path, error_code &ec) 807 : State(new detail::RecDirIterState) { 808 State->Stack.push(directory_iterator(path, ec)); 809 if (State->Stack.top() == directory_iterator()) 810 State.reset(); 811 } 812 // No operator++ because we need error_code. 813 recursive_directory_iterator &increment(error_code &ec) { 814 static const directory_iterator end_itr; 815 816 if (State->HasNoPushRequest) 817 State->HasNoPushRequest = false; 818 else { 819 file_status st; 820 if ((ec = State->Stack.top()->status(st))) return *this; 821 if (is_directory(st)) { 822 State->Stack.push(directory_iterator(*State->Stack.top(), ec)); 823 if (ec) return *this; 824 if (State->Stack.top() != end_itr) { 825 ++State->Level; 826 return *this; 827 } 828 State->Stack.pop(); 829 } 830 } 831 832 while (!State->Stack.empty() 833 && State->Stack.top().increment(ec) == end_itr) { 834 State->Stack.pop(); 835 --State->Level; 836 } 837 838 // Check if we are done. If so, create an end iterator. 839 if (State->Stack.empty()) 840 State.reset(); 841 842 return *this; 843 } 844 845 const directory_entry &operator*() const { return *State->Stack.top(); } 846 const directory_entry *operator->() const { return &*State->Stack.top(); } 847 848 // observers 849 /// Gets the current level. Starting path is at level 0. 850 int level() const { return State->Level; } 851 852 /// Returns true if no_push has been called for this directory_entry. 853 bool no_push_request() const { return State->HasNoPushRequest; } 854 855 // modifiers 856 /// Goes up one level if Level > 0. 857 void pop() { 858 assert(State && "Cannot pop and end itertor!"); 859 assert(State->Level > 0 && "Cannot pop an iterator with level < 1"); 860 861 static const directory_iterator end_itr; 862 error_code ec; 863 do { 864 if (ec) 865 report_fatal_error("Error incrementing directory iterator."); 866 State->Stack.pop(); 867 --State->Level; 868 } while (!State->Stack.empty() 869 && State->Stack.top().increment(ec) == end_itr); 870 871 // Check if we are done. If so, create an end iterator. 872 if (State->Stack.empty()) 873 State.reset(); 874 } 875 876 /// Does not go down into the current directory_entry. 877 void no_push() { State->HasNoPushRequest = true; } 878 879 bool operator==(const recursive_directory_iterator &RHS) const { 880 return State == RHS.State; 881 } 882 883 bool operator!=(const recursive_directory_iterator &RHS) const { 884 return !(*this == RHS); 885 } 886 // Other members as required by 887 // C++ Std, 24.1.1 Input iterators [input.iterators] 888 }; 889 890 /// @} 891 892 } // end namespace fs 893 } // end namespace sys 894 } // end namespace llvm 895 896 #endif 897