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/SmallString.h" 32 #include "llvm/ADT/Twine.h" 33 #include "llvm/Support/DataTypes.h" 34 #include "llvm/Support/ErrorHandling.h" 35 #include "llvm/Support/TimeValue.h" 36 #include <ctime> 37 #include <iterator> 38 #include <stack> 39 #include <string> 40 #include <system_error> 41 #include <tuple> 42 #include <vector> 43 44 #ifdef HAVE_SYS_STAT_H 45 #include <sys/stat.h> 46 #endif 47 48 namespace llvm { 49 namespace sys { 50 namespace fs { 51 52 /// An enumeration for the file system's view of the type. 53 enum class file_type { 54 status_error, 55 file_not_found, 56 regular_file, 57 directory_file, 58 symlink_file, 59 block_file, 60 character_file, 61 fifo_file, 62 socket_file, 63 type_unknown 64 }; 65 66 /// space_info - Self explanatory. 67 struct space_info { 68 uint64_t capacity; 69 uint64_t free; 70 uint64_t available; 71 }; 72 73 enum perms { 74 no_perms = 0, 75 owner_read = 0400, 76 owner_write = 0200, 77 owner_exe = 0100, 78 owner_all = owner_read | owner_write | owner_exe, 79 group_read = 040, 80 group_write = 020, 81 group_exe = 010, 82 group_all = group_read | group_write | group_exe, 83 others_read = 04, 84 others_write = 02, 85 others_exe = 01, 86 others_all = others_read | others_write | others_exe, 87 all_read = owner_read | group_read | others_read, 88 all_write = owner_write | group_write | others_write, 89 all_exe = owner_exe | group_exe | others_exe, 90 all_all = owner_all | group_all | others_all, 91 set_uid_on_exe = 04000, 92 set_gid_on_exe = 02000, 93 sticky_bit = 01000, 94 perms_not_known = 0xFFFF 95 }; 96 97 // Helper functions so that you can use & and | to manipulate perms bits: 98 inline perms operator|(perms l , perms r) { 99 return static_cast<perms>( 100 static_cast<unsigned short>(l) | static_cast<unsigned short>(r)); 101 } 102 inline perms operator&(perms l , perms r) { 103 return static_cast<perms>( 104 static_cast<unsigned short>(l) & static_cast<unsigned short>(r)); 105 } 106 inline perms &operator|=(perms &l, perms r) { 107 l = l | r; 108 return l; 109 } 110 inline perms &operator&=(perms &l, perms r) { 111 l = l & r; 112 return l; 113 } 114 inline perms operator~(perms x) { 115 return static_cast<perms>(~static_cast<unsigned short>(x)); 116 } 117 118 class UniqueID { 119 uint64_t Device; 120 uint64_t File; 121 122 public: 123 UniqueID() = default; 124 UniqueID(uint64_t Device, uint64_t File) : Device(Device), File(File) {} 125 bool operator==(const UniqueID &Other) const { 126 return Device == Other.Device && File == Other.File; 127 } 128 bool operator!=(const UniqueID &Other) const { return !(*this == Other); } 129 bool operator<(const UniqueID &Other) const { 130 return std::tie(Device, File) < std::tie(Other.Device, Other.File); 131 } 132 uint64_t getDevice() const { return Device; } 133 uint64_t getFile() const { return File; } 134 }; 135 136 /// file_status - Represents the result of a call to stat and friends. It has 137 /// a platform-specific member to store the result. 138 class file_status 139 { 140 #if defined(LLVM_ON_UNIX) 141 dev_t fs_st_dev; 142 ino_t fs_st_ino; 143 time_t fs_st_mtime; 144 uid_t fs_st_uid; 145 gid_t fs_st_gid; 146 off_t fs_st_size; 147 #elif defined (LLVM_ON_WIN32) 148 uint32_t LastWriteTimeHigh; 149 uint32_t LastWriteTimeLow; 150 uint32_t VolumeSerialNumber; 151 uint32_t FileSizeHigh; 152 uint32_t FileSizeLow; 153 uint32_t FileIndexHigh; 154 uint32_t FileIndexLow; 155 #endif 156 friend bool equivalent(file_status A, file_status B); 157 file_type Type; 158 perms Perms; 159 public: 160 #if defined(LLVM_ON_UNIX) 161 file_status() : fs_st_dev(0), fs_st_ino(0), fs_st_mtime(0), 162 fs_st_uid(0), fs_st_gid(0), fs_st_size(0), 163 Type(file_type::status_error), Perms(perms_not_known) {} 164 165 file_status(file_type Type) : fs_st_dev(0), fs_st_ino(0), fs_st_mtime(0), 166 fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type), 167 Perms(perms_not_known) {} 168 169 file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t MTime, 170 uid_t UID, gid_t GID, off_t Size) 171 : fs_st_dev(Dev), fs_st_ino(Ino), fs_st_mtime(MTime), fs_st_uid(UID), 172 fs_st_gid(GID), fs_st_size(Size), Type(Type), Perms(Perms) {} 173 #elif defined(LLVM_ON_WIN32) 174 file_status() : LastWriteTimeHigh(0), LastWriteTimeLow(0), 175 VolumeSerialNumber(0), FileSizeHigh(0), FileSizeLow(0), 176 FileIndexHigh(0), FileIndexLow(0), Type(file_type::status_error), 177 Perms(perms_not_known) {} 178 179 file_status(file_type Type) : LastWriteTimeHigh(0), LastWriteTimeLow(0), 180 VolumeSerialNumber(0), FileSizeHigh(0), FileSizeLow(0), 181 FileIndexHigh(0), FileIndexLow(0), Type(Type), 182 Perms(perms_not_known) {} 183 184 file_status(file_type Type, uint32_t LastWriteTimeHigh, 185 uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber, 186 uint32_t FileSizeHigh, uint32_t FileSizeLow, 187 uint32_t FileIndexHigh, uint32_t FileIndexLow) 188 : LastWriteTimeHigh(LastWriteTimeHigh), 189 LastWriteTimeLow(LastWriteTimeLow), 190 VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), 191 FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), 192 FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {} 193 #endif 194 195 // getters 196 file_type type() const { return Type; } 197 perms permissions() const { return Perms; } 198 TimeValue getLastModificationTime() const; 199 UniqueID getUniqueID() const; 200 201 #if defined(LLVM_ON_UNIX) 202 uint32_t getUser() const { return fs_st_uid; } 203 uint32_t getGroup() const { return fs_st_gid; } 204 uint64_t getSize() const { return fs_st_size; } 205 #elif defined (LLVM_ON_WIN32) 206 uint32_t getUser() const { 207 return 9999; // Not applicable to Windows, so... 208 } 209 uint32_t getGroup() const { 210 return 9999; // Not applicable to Windows, so... 211 } 212 uint64_t getSize() const { 213 return (uint64_t(FileSizeHigh) << 32) + FileSizeLow; 214 } 215 #endif 216 217 // setters 218 void type(file_type v) { Type = v; } 219 void permissions(perms p) { Perms = p; } 220 }; 221 222 /// file_magic - An "enum class" enumeration of file types based on magic (the first 223 /// N bytes of the file). 224 struct file_magic { 225 enum Impl { 226 unknown = 0, ///< Unrecognized file 227 bitcode, ///< Bitcode file 228 archive, ///< ar style archive file 229 elf, ///< ELF Unknown type 230 elf_relocatable, ///< ELF Relocatable object file 231 elf_executable, ///< ELF Executable image 232 elf_shared_object, ///< ELF dynamically linked shared lib 233 elf_core, ///< ELF core image 234 macho_object, ///< Mach-O Object file 235 macho_executable, ///< Mach-O Executable 236 macho_fixed_virtual_memory_shared_lib, ///< Mach-O Shared Lib, FVM 237 macho_core, ///< Mach-O Core File 238 macho_preload_executable, ///< Mach-O Preloaded Executable 239 macho_dynamically_linked_shared_lib, ///< Mach-O dynlinked shared lib 240 macho_dynamic_linker, ///< The Mach-O dynamic linker 241 macho_bundle, ///< Mach-O Bundle file 242 macho_dynamically_linked_shared_lib_stub, ///< Mach-O Shared lib stub 243 macho_dsym_companion, ///< Mach-O dSYM companion file 244 macho_kext_bundle, ///< Mach-O kext bundle file 245 macho_universal_binary, ///< Mach-O universal binary 246 coff_object, ///< COFF object file 247 coff_import_library, ///< COFF import library 248 pecoff_executable, ///< PECOFF executable file 249 windows_resource ///< Windows compiled resource file (.rc) 250 }; 251 252 bool is_object() const { 253 return V == unknown ? false : true; 254 } 255 256 file_magic() : V(unknown) {} 257 file_magic(Impl V) : V(V) {} 258 operator Impl() const { return V; } 259 260 private: 261 Impl V; 262 }; 263 264 /// @} 265 /// @name Physical Operators 266 /// @{ 267 268 /// @brief Make \a path an absolute path. 269 /// 270 /// Makes \a path absolute using the current directory if it is not already. An 271 /// empty \a path will result in the current directory. 272 /// 273 /// /absolute/path => /absolute/path 274 /// relative/../path => <current-directory>/relative/../path 275 /// 276 /// @param path A path that is modified to be an absolute path. 277 /// @returns errc::success if \a path has been made absolute, otherwise a 278 /// platform-specific error_code. 279 std::error_code make_absolute(SmallVectorImpl<char> &path); 280 281 /// @brief Create all the non-existent directories in path. 282 /// 283 /// @param path Directories to create. 284 /// @returns errc::success if is_directory(path), otherwise a platform 285 /// specific error_code. If IgnoreExisting is false, also returns 286 /// error if the directory already existed. 287 std::error_code create_directories(const Twine &path, 288 bool IgnoreExisting = true); 289 290 /// @brief Create the directory in path. 291 /// 292 /// @param path Directory to create. 293 /// @returns errc::success if is_directory(path), otherwise a platform 294 /// specific error_code. If IgnoreExisting is false, also returns 295 /// error if the directory already existed. 296 std::error_code create_directory(const Twine &path, bool IgnoreExisting = true); 297 298 /// @brief Create a link from \a from to \a to. 299 /// 300 /// The link may be a soft or a hard link, depending on the platform. The caller 301 /// may not assume which one. Currently on windows it creates a hard link since 302 /// soft links require extra privileges. On unix, it creates a soft link since 303 /// hard links don't work on SMB file systems. 304 /// 305 /// @param to The path to hard link to. 306 /// @param from The path to hard link from. This is created. 307 /// @returns errc::success if the link was created, otherwise a platform 308 /// specific error_code. 309 std::error_code create_link(const Twine &to, const Twine &from); 310 311 /// @brief Get the current path. 312 /// 313 /// @param result Holds the current path on return. 314 /// @returns errc::success if the current path has been stored in result, 315 /// otherwise a platform-specific error_code. 316 std::error_code current_path(SmallVectorImpl<char> &result); 317 318 /// @brief Remove path. Equivalent to POSIX remove(). 319 /// 320 /// @param path Input path. 321 /// @returns errc::success if path has been removed or didn't exist, otherwise a 322 /// platform-specific error code. If IgnoreNonExisting is false, also 323 /// returns error if the file didn't exist. 324 std::error_code remove(const Twine &path, bool IgnoreNonExisting = true); 325 326 /// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename(). 327 /// 328 /// @param from The path to rename from. 329 /// @param to The path to rename to. This is created. 330 std::error_code rename(const Twine &from, const Twine &to); 331 332 /// @brief Copy the contents of \a From to \a To. 333 /// 334 /// @param From The path to copy from. 335 /// @param To The path to copy to. This is created. 336 std::error_code copy_file(const Twine &From, const Twine &To); 337 338 /// @brief Resize path to size. File is resized as if by POSIX truncate(). 339 /// 340 /// @param FD Input file descriptor. 341 /// @param Size Size to resize to. 342 /// @returns errc::success if \a path has been resized to \a size, otherwise a 343 /// platform-specific error_code. 344 std::error_code resize_file(int FD, uint64_t Size); 345 346 /// @} 347 /// @name Physical Observers 348 /// @{ 349 350 /// @brief Does file exist? 351 /// 352 /// @param status A file_status previously returned from stat. 353 /// @returns True if the file represented by status exists, false if it does 354 /// not. 355 bool exists(file_status status); 356 357 enum class AccessMode { Exist, Write, Execute }; 358 359 /// @brief Can the file be accessed? 360 /// 361 /// @param Path Input path. 362 /// @returns errc::success if the path can be accessed, otherwise a 363 /// platform-specific error_code. 364 std::error_code access(const Twine &Path, AccessMode Mode); 365 366 /// @brief Does file exist? 367 /// 368 /// @param Path Input path. 369 /// @returns True if it exists, false otherwise. 370 inline bool exists(const Twine &Path) { 371 return !access(Path, AccessMode::Exist); 372 } 373 374 /// @brief Can we execute this file? 375 /// 376 /// @param Path Input path. 377 /// @returns True if we can execute it, false otherwise. 378 inline bool can_execute(const Twine &Path) { 379 return !access(Path, AccessMode::Execute); 380 } 381 382 /// @brief Can we write this file? 383 /// 384 /// @param Path Input path. 385 /// @returns True if we can write to it, false otherwise. 386 inline bool can_write(const Twine &Path) { 387 return !access(Path, AccessMode::Write); 388 } 389 390 /// @brief Do file_status's represent the same thing? 391 /// 392 /// @param A Input file_status. 393 /// @param B Input file_status. 394 /// 395 /// assert(status_known(A) || status_known(B)); 396 /// 397 /// @returns True if A and B both represent the same file system entity, false 398 /// otherwise. 399 bool equivalent(file_status A, file_status B); 400 401 /// @brief Do paths represent the same thing? 402 /// 403 /// assert(status_known(A) || status_known(B)); 404 /// 405 /// @param A Input path A. 406 /// @param B Input path B. 407 /// @param result Set to true if stat(A) and stat(B) have the same device and 408 /// inode (or equivalent). 409 /// @returns errc::success if result has been successfully set, otherwise a 410 /// platform-specific error_code. 411 std::error_code equivalent(const Twine &A, const Twine &B, bool &result); 412 413 /// @brief Simpler version of equivalent for clients that don't need to 414 /// differentiate between an error and false. 415 inline bool equivalent(const Twine &A, const Twine &B) { 416 bool result; 417 return !equivalent(A, B, result) && result; 418 } 419 420 /// @brief Does status represent a directory? 421 /// 422 /// @param status A file_status previously returned from status. 423 /// @returns status.type() == file_type::directory_file. 424 bool is_directory(file_status status); 425 426 /// @brief Is path a directory? 427 /// 428 /// @param path Input path. 429 /// @param result Set to true if \a path is a directory, false if it is not. 430 /// Undefined otherwise. 431 /// @returns errc::success if result has been successfully set, otherwise a 432 /// platform-specific error_code. 433 std::error_code is_directory(const Twine &path, bool &result); 434 435 /// @brief Simpler version of is_directory for clients that don't need to 436 /// differentiate between an error and false. 437 inline bool is_directory(const Twine &Path) { 438 bool Result; 439 return !is_directory(Path, Result) && Result; 440 } 441 442 /// @brief Does status represent a regular file? 443 /// 444 /// @param status A file_status previously returned from status. 445 /// @returns status_known(status) && status.type() == file_type::regular_file. 446 bool is_regular_file(file_status status); 447 448 /// @brief Is path a regular file? 449 /// 450 /// @param path Input path. 451 /// @param result Set to true if \a path is a regular file, false if it is not. 452 /// Undefined otherwise. 453 /// @returns errc::success if result has been successfully set, otherwise a 454 /// platform-specific error_code. 455 std::error_code is_regular_file(const Twine &path, bool &result); 456 457 /// @brief Simpler version of is_regular_file for clients that don't need to 458 /// differentiate between an error and false. 459 inline bool is_regular_file(const Twine &Path) { 460 bool Result; 461 if (is_regular_file(Path, Result)) 462 return false; 463 return Result; 464 } 465 466 /// @brief Does this status represent something that exists but is not a 467 /// directory, regular file, or symlink? 468 /// 469 /// @param status A file_status previously returned from status. 470 /// @returns exists(s) && !is_regular_file(s) && !is_directory(s) 471 bool is_other(file_status status); 472 473 /// @brief Is path something that exists but is not a directory, 474 /// regular file, or symlink? 475 /// 476 /// @param path Input path. 477 /// @param result Set to true if \a path exists, but is not a directory, regular 478 /// file, or a symlink, false if it does not. Undefined otherwise. 479 /// @returns errc::success if result has been successfully set, otherwise a 480 /// platform-specific error_code. 481 std::error_code is_other(const Twine &path, bool &result); 482 483 /// @brief Get file status as if by POSIX stat(). 484 /// 485 /// @param path Input path. 486 /// @param result Set to the file status. 487 /// @returns errc::success if result has been successfully set, otherwise a 488 /// platform-specific error_code. 489 std::error_code status(const Twine &path, file_status &result); 490 491 /// @brief A version for when a file descriptor is already available. 492 std::error_code status(int FD, file_status &Result); 493 494 /// @brief Get file size. 495 /// 496 /// @param Path Input path. 497 /// @param Result Set to the size of the file in \a Path. 498 /// @returns errc::success if result has been successfully set, otherwise a 499 /// platform-specific error_code. 500 inline std::error_code file_size(const Twine &Path, uint64_t &Result) { 501 file_status Status; 502 std::error_code EC = status(Path, Status); 503 if (EC) 504 return EC; 505 Result = Status.getSize(); 506 return std::error_code(); 507 } 508 509 /// @brief Set the file modification and access time. 510 /// 511 /// @returns errc::success if the file times were successfully set, otherwise a 512 /// platform-specific error_code or errc::function_not_supported on 513 /// platforms where the functionality isn't available. 514 std::error_code setLastModificationAndAccessTime(int FD, TimeValue Time); 515 516 /// @brief Is status available? 517 /// 518 /// @param s Input file status. 519 /// @returns True if status() != status_error. 520 bool status_known(file_status s); 521 522 /// @brief Is status available? 523 /// 524 /// @param path Input path. 525 /// @param result Set to true if status() != status_error. 526 /// @returns errc::success if result has been successfully set, otherwise a 527 /// platform-specific error_code. 528 std::error_code status_known(const Twine &path, bool &result); 529 530 /// @brief Create a uniquely named file. 531 /// 532 /// Generates a unique path suitable for a temporary file and then opens it as a 533 /// file. The name is based on \a model with '%' replaced by a random char in 534 /// [0-9a-f]. If \a model is not an absolute path, a suitable temporary 535 /// directory will be prepended. 536 /// 537 /// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s 538 /// 539 /// This is an atomic operation. Either the file is created and opened, or the 540 /// file system is left untouched. 541 /// 542 /// The intendend use is for files that are to be kept, possibly after 543 /// renaming them. For example, when running 'clang -c foo.o', the file can 544 /// be first created as foo-abc123.o and then renamed. 545 /// 546 /// @param Model Name to base unique path off of. 547 /// @param ResultFD Set to the opened file's file descriptor. 548 /// @param ResultPath Set to the opened file's absolute path. 549 /// @returns errc::success if Result{FD,Path} have been successfully set, 550 /// otherwise a platform-specific error_code. 551 std::error_code createUniqueFile(const Twine &Model, int &ResultFD, 552 SmallVectorImpl<char> &ResultPath, 553 unsigned Mode = all_read | all_write); 554 555 /// @brief Simpler version for clients that don't want an open file. 556 std::error_code createUniqueFile(const Twine &Model, 557 SmallVectorImpl<char> &ResultPath); 558 559 /// @brief Create a file in the system temporary directory. 560 /// 561 /// The filename is of the form prefix-random_chars.suffix. Since the directory 562 /// is not know to the caller, Prefix and Suffix cannot have path separators. 563 /// The files are created with mode 0600. 564 /// 565 /// This should be used for things like a temporary .s that is removed after 566 /// running the assembler. 567 std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, 568 int &ResultFD, 569 SmallVectorImpl<char> &ResultPath); 570 571 /// @brief Simpler version for clients that don't want an open file. 572 std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix, 573 SmallVectorImpl<char> &ResultPath); 574 575 std::error_code createUniqueDirectory(const Twine &Prefix, 576 SmallVectorImpl<char> &ResultPath); 577 578 enum OpenFlags : unsigned { 579 F_None = 0, 580 581 /// F_Excl - When opening a file, this flag makes raw_fd_ostream 582 /// report an error if the file already exists. 583 F_Excl = 1, 584 585 /// F_Append - When opening a file, if it already exists append to the 586 /// existing file instead of returning an error. This may not be specified 587 /// with F_Excl. 588 F_Append = 2, 589 590 /// The file should be opened in text mode on platforms that make this 591 /// distinction. 592 F_Text = 4, 593 594 /// Open the file for read and write. 595 F_RW = 8 596 }; 597 598 inline OpenFlags operator|(OpenFlags A, OpenFlags B) { 599 return OpenFlags(unsigned(A) | unsigned(B)); 600 } 601 602 inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) { 603 A = A | B; 604 return A; 605 } 606 607 std::error_code openFileForWrite(const Twine &Name, int &ResultFD, 608 OpenFlags Flags, unsigned Mode = 0666); 609 610 std::error_code openFileForRead(const Twine &Name, int &ResultFD); 611 612 /// @brief Identify the type of a binary file based on how magical it is. 613 file_magic identify_magic(StringRef magic); 614 615 /// @brief Get and identify \a path's type based on its content. 616 /// 617 /// @param path Input path. 618 /// @param result Set to the type of file, or file_magic::unknown. 619 /// @returns errc::success if result has been successfully set, otherwise a 620 /// platform-specific error_code. 621 std::error_code identify_magic(const Twine &path, file_magic &result); 622 623 std::error_code getUniqueID(const Twine Path, UniqueID &Result); 624 625 /// This class represents a memory mapped file. It is based on 626 /// boost::iostreams::mapped_file. 627 class mapped_file_region { 628 mapped_file_region() = delete; 629 mapped_file_region(mapped_file_region&) = delete; 630 mapped_file_region &operator =(mapped_file_region&) = delete; 631 632 public: 633 enum mapmode { 634 readonly, ///< May only access map via const_data as read only. 635 readwrite, ///< May access map via data and modify it. Written to path. 636 priv ///< May modify via data, but changes are lost on destruction. 637 }; 638 639 private: 640 /// Platform-specific mapping state. 641 uint64_t Size; 642 void *Mapping; 643 644 std::error_code init(int FD, uint64_t Offset, mapmode Mode); 645 646 public: 647 /// \param fd An open file descriptor to map. mapped_file_region takes 648 /// ownership if closefd is true. It must have been opended in the correct 649 /// mode. 650 mapped_file_region(int fd, mapmode mode, uint64_t length, uint64_t offset, 651 std::error_code &ec); 652 653 ~mapped_file_region(); 654 655 uint64_t size() const; 656 char *data() const; 657 658 /// Get a const view of the data. Modifying this memory has undefined 659 /// behavior. 660 const char *const_data() const; 661 662 /// \returns The minimum alignment offset must be. 663 static int alignment(); 664 }; 665 666 /// Return the path to the main executable, given the value of argv[0] from 667 /// program startup and the address of main itself. In extremis, this function 668 /// may fail and return an empty path. 669 std::string getMainExecutable(const char *argv0, void *MainExecAddr); 670 671 /// @} 672 /// @name Iterators 673 /// @{ 674 675 /// directory_entry - A single entry in a directory. Caches the status either 676 /// from the result of the iteration syscall, or the first time status is 677 /// called. 678 class directory_entry { 679 std::string Path; 680 mutable file_status Status; 681 682 public: 683 explicit directory_entry(const Twine &path, file_status st = file_status()) 684 : Path(path.str()) 685 , Status(st) {} 686 687 directory_entry() {} 688 689 void assign(const Twine &path, file_status st = file_status()) { 690 Path = path.str(); 691 Status = st; 692 } 693 694 void replace_filename(const Twine &filename, file_status st = file_status()); 695 696 const std::string &path() const { return Path; } 697 std::error_code status(file_status &result) const; 698 699 bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; } 700 bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); } 701 bool operator< (const directory_entry& rhs) const; 702 bool operator<=(const directory_entry& rhs) const; 703 bool operator> (const directory_entry& rhs) const; 704 bool operator>=(const directory_entry& rhs) const; 705 }; 706 707 namespace detail { 708 struct DirIterState; 709 710 std::error_code directory_iterator_construct(DirIterState &, StringRef); 711 std::error_code directory_iterator_increment(DirIterState &); 712 std::error_code directory_iterator_destruct(DirIterState &); 713 714 /// DirIterState - Keeps state for the directory_iterator. It is reference 715 /// counted in order to preserve InputIterator semantics on copy. 716 struct DirIterState : public RefCountedBase<DirIterState> { 717 DirIterState() 718 : IterationHandle(0) {} 719 720 ~DirIterState() { 721 directory_iterator_destruct(*this); 722 } 723 724 intptr_t IterationHandle; 725 directory_entry CurrentEntry; 726 }; 727 } 728 729 /// directory_iterator - Iterates through the entries in path. There is no 730 /// operator++ because we need an error_code. If it's really needed we can make 731 /// it call report_fatal_error on error. 732 class directory_iterator { 733 IntrusiveRefCntPtr<detail::DirIterState> State; 734 735 public: 736 explicit directory_iterator(const Twine &path, std::error_code &ec) { 737 State = new detail::DirIterState; 738 SmallString<128> path_storage; 739 ec = detail::directory_iterator_construct(*State, 740 path.toStringRef(path_storage)); 741 } 742 743 explicit directory_iterator(const directory_entry &de, std::error_code &ec) { 744 State = new detail::DirIterState; 745 ec = detail::directory_iterator_construct(*State, de.path()); 746 } 747 748 /// Construct end iterator. 749 directory_iterator() : State(nullptr) {} 750 751 // No operator++ because we need error_code. 752 directory_iterator &increment(std::error_code &ec) { 753 ec = directory_iterator_increment(*State); 754 return *this; 755 } 756 757 const directory_entry &operator*() const { return State->CurrentEntry; } 758 const directory_entry *operator->() const { return &State->CurrentEntry; } 759 760 bool operator==(const directory_iterator &RHS) const { 761 if (State == RHS.State) 762 return true; 763 if (!RHS.State) 764 return State->CurrentEntry == directory_entry(); 765 if (!State) 766 return RHS.State->CurrentEntry == directory_entry(); 767 return State->CurrentEntry == RHS.State->CurrentEntry; 768 } 769 770 bool operator!=(const directory_iterator &RHS) const { 771 return !(*this == RHS); 772 } 773 // Other members as required by 774 // C++ Std, 24.1.1 Input iterators [input.iterators] 775 }; 776 777 namespace detail { 778 /// RecDirIterState - Keeps state for the recursive_directory_iterator. It is 779 /// reference counted in order to preserve InputIterator semantics on copy. 780 struct RecDirIterState : public RefCountedBase<RecDirIterState> { 781 RecDirIterState() 782 : Level(0) 783 , HasNoPushRequest(false) {} 784 785 std::stack<directory_iterator, std::vector<directory_iterator> > Stack; 786 uint16_t Level; 787 bool HasNoPushRequest; 788 }; 789 } 790 791 /// recursive_directory_iterator - Same as directory_iterator except for it 792 /// recurses down into child directories. 793 class recursive_directory_iterator { 794 IntrusiveRefCntPtr<detail::RecDirIterState> State; 795 796 public: 797 recursive_directory_iterator() {} 798 explicit recursive_directory_iterator(const Twine &path, std::error_code &ec) 799 : State(new detail::RecDirIterState) { 800 State->Stack.push(directory_iterator(path, ec)); 801 if (State->Stack.top() == directory_iterator()) 802 State.reset(); 803 } 804 // No operator++ because we need error_code. 805 recursive_directory_iterator &increment(std::error_code &ec) { 806 const directory_iterator end_itr; 807 808 if (State->HasNoPushRequest) 809 State->HasNoPushRequest = false; 810 else { 811 file_status st; 812 if ((ec = State->Stack.top()->status(st))) return *this; 813 if (is_directory(st)) { 814 State->Stack.push(directory_iterator(*State->Stack.top(), ec)); 815 if (ec) return *this; 816 if (State->Stack.top() != end_itr) { 817 ++State->Level; 818 return *this; 819 } 820 State->Stack.pop(); 821 } 822 } 823 824 while (!State->Stack.empty() 825 && State->Stack.top().increment(ec) == end_itr) { 826 State->Stack.pop(); 827 --State->Level; 828 } 829 830 // Check if we are done. If so, create an end iterator. 831 if (State->Stack.empty()) 832 State.reset(); 833 834 return *this; 835 } 836 837 const directory_entry &operator*() const { return *State->Stack.top(); } 838 const directory_entry *operator->() const { return &*State->Stack.top(); } 839 840 // observers 841 /// Gets the current level. Starting path is at level 0. 842 int level() const { return State->Level; } 843 844 /// Returns true if no_push has been called for this directory_entry. 845 bool no_push_request() const { return State->HasNoPushRequest; } 846 847 // modifiers 848 /// Goes up one level if Level > 0. 849 void pop() { 850 assert(State && "Cannot pop an end iterator!"); 851 assert(State->Level > 0 && "Cannot pop an iterator with level < 1"); 852 853 const directory_iterator end_itr; 854 std::error_code ec; 855 do { 856 if (ec) 857 report_fatal_error("Error incrementing directory iterator."); 858 State->Stack.pop(); 859 --State->Level; 860 } while (!State->Stack.empty() 861 && State->Stack.top().increment(ec) == end_itr); 862 863 // Check if we are done. If so, create an end iterator. 864 if (State->Stack.empty()) 865 State.reset(); 866 } 867 868 /// Does not go down into the current directory_entry. 869 void no_push() { State->HasNoPushRequest = true; } 870 871 bool operator==(const recursive_directory_iterator &RHS) const { 872 return State == RHS.State; 873 } 874 875 bool operator!=(const recursive_directory_iterator &RHS) const { 876 return !(*this == RHS); 877 } 878 // Other members as required by 879 // C++ Std, 24.1.1 Input iterators [input.iterators] 880 }; 881 882 /// @} 883 884 } // end namespace fs 885 } // end namespace sys 886 } // end namespace llvm 887 888 #endif 889