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