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