10b57cec5SDimitry Andric //===- llvm/Support/FileSystem.h - File System OS Concept -------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file declares the llvm::sys::fs namespace. It is designed after
100b57cec5SDimitry Andric // TR2/boost filesystem (v3), but modified to remove exception handling and the
110b57cec5SDimitry Andric // path class.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric // All functions return an error_code and their actual work via the last out
140b57cec5SDimitry Andric // argument. The out argument is defined if and only if errc::success is
150b57cec5SDimitry Andric // returned. A function may return any error code in the generic or system
160b57cec5SDimitry Andric // category. However, they shall be equivalent to any error conditions listed
170b57cec5SDimitry Andric // in each functions respective documentation if the condition applies. [ note:
180b57cec5SDimitry Andric // this does not guarantee that error_code will be in the set of explicitly
190b57cec5SDimitry Andric // listed codes, but it does guarantee that if any of the explicitly listed
200b57cec5SDimitry Andric // errors occur, the correct error_code will be used ]. All functions may
210b57cec5SDimitry Andric // return errc::not_enough_memory if there is not enough memory to complete the
220b57cec5SDimitry Andric // operation.
230b57cec5SDimitry Andric //
240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_FILESYSTEM_H
270b57cec5SDimitry Andric #define LLVM_SUPPORT_FILESYSTEM_H
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
300b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
310b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
320b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
330b57cec5SDimitry Andric #include "llvm/Support/Chrono.h"
340b57cec5SDimitry Andric #include "llvm/Support/Error.h"
350b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
360b57cec5SDimitry Andric #include "llvm/Support/ErrorOr.h"
37e8d8bef9SDimitry Andric #include "llvm/Support/FileSystem/UniqueID.h"
380b57cec5SDimitry Andric #include "llvm/Support/MD5.h"
390b57cec5SDimitry Andric #include <cassert>
400b57cec5SDimitry Andric #include <cstdint>
410b57cec5SDimitry Andric #include <ctime>
420b57cec5SDimitry Andric #include <memory>
430b57cec5SDimitry Andric #include <stack>
440b57cec5SDimitry Andric #include <string>
450b57cec5SDimitry Andric #include <system_error>
460b57cec5SDimitry Andric #include <vector>
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric #ifdef HAVE_SYS_STAT_H
490b57cec5SDimitry Andric #include <sys/stat.h>
500b57cec5SDimitry Andric #endif
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric namespace llvm {
530b57cec5SDimitry Andric namespace sys {
540b57cec5SDimitry Andric namespace fs {
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric #if defined(_WIN32)
570b57cec5SDimitry Andric // A Win32 HANDLE is a typedef of void*
580b57cec5SDimitry Andric using file_t = void *;
590b57cec5SDimitry Andric #else
600b57cec5SDimitry Andric using file_t = int;
610b57cec5SDimitry Andric #endif
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric extern const file_t kInvalidFile;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric /// An enumeration for the file system's view of the type.
660b57cec5SDimitry Andric enum class file_type {
670b57cec5SDimitry Andric   status_error,
680b57cec5SDimitry Andric   file_not_found,
690b57cec5SDimitry Andric   regular_file,
700b57cec5SDimitry Andric   directory_file,
710b57cec5SDimitry Andric   symlink_file,
720b57cec5SDimitry Andric   block_file,
730b57cec5SDimitry Andric   character_file,
740b57cec5SDimitry Andric   fifo_file,
750b57cec5SDimitry Andric   socket_file,
760b57cec5SDimitry Andric   type_unknown
770b57cec5SDimitry Andric };
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric /// space_info - Self explanatory.
800b57cec5SDimitry Andric struct space_info {
810b57cec5SDimitry Andric   uint64_t capacity;
820b57cec5SDimitry Andric   uint64_t free;
830b57cec5SDimitry Andric   uint64_t available;
840b57cec5SDimitry Andric };
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric enum perms {
870b57cec5SDimitry Andric   no_perms = 0,
880b57cec5SDimitry Andric   owner_read = 0400,
890b57cec5SDimitry Andric   owner_write = 0200,
900b57cec5SDimitry Andric   owner_exe = 0100,
910b57cec5SDimitry Andric   owner_all = owner_read | owner_write | owner_exe,
920b57cec5SDimitry Andric   group_read = 040,
930b57cec5SDimitry Andric   group_write = 020,
940b57cec5SDimitry Andric   group_exe = 010,
950b57cec5SDimitry Andric   group_all = group_read | group_write | group_exe,
960b57cec5SDimitry Andric   others_read = 04,
970b57cec5SDimitry Andric   others_write = 02,
980b57cec5SDimitry Andric   others_exe = 01,
990b57cec5SDimitry Andric   others_all = others_read | others_write | others_exe,
1000b57cec5SDimitry Andric   all_read = owner_read | group_read | others_read,
1010b57cec5SDimitry Andric   all_write = owner_write | group_write | others_write,
1020b57cec5SDimitry Andric   all_exe = owner_exe | group_exe | others_exe,
1030b57cec5SDimitry Andric   all_all = owner_all | group_all | others_all,
1040b57cec5SDimitry Andric   set_uid_on_exe = 04000,
1050b57cec5SDimitry Andric   set_gid_on_exe = 02000,
1060b57cec5SDimitry Andric   sticky_bit = 01000,
1070b57cec5SDimitry Andric   all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
1080b57cec5SDimitry Andric   perms_not_known = 0xFFFF
1090b57cec5SDimitry Andric };
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric // Helper functions so that you can use & and | to manipulate perms bits:
1120b57cec5SDimitry Andric inline perms operator|(perms l, perms r) {
1130b57cec5SDimitry Andric   return static_cast<perms>(static_cast<unsigned short>(l) |
1140b57cec5SDimitry Andric                             static_cast<unsigned short>(r));
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric inline perms operator&(perms l, perms r) {
1170b57cec5SDimitry Andric   return static_cast<perms>(static_cast<unsigned short>(l) &
1180b57cec5SDimitry Andric                             static_cast<unsigned short>(r));
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric inline perms &operator|=(perms &l, perms r) {
1210b57cec5SDimitry Andric   l = l | r;
1220b57cec5SDimitry Andric   return l;
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric inline perms &operator&=(perms &l, perms r) {
1250b57cec5SDimitry Andric   l = l & r;
1260b57cec5SDimitry Andric   return l;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric inline perms operator~(perms x) {
1290b57cec5SDimitry Andric   // Avoid UB by explicitly truncating the (unsigned) ~ result.
1300b57cec5SDimitry Andric   return static_cast<perms>(
1310b57cec5SDimitry Andric       static_cast<unsigned short>(~static_cast<unsigned short>(x)));
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric /// Represents the result of a call to directory_iterator::status(). This is a
1350b57cec5SDimitry Andric /// subset of the information returned by a regular sys::fs::status() call, and
1360b57cec5SDimitry Andric /// represents the information provided by Windows FileFirstFile/FindNextFile.
1370b57cec5SDimitry Andric class basic_file_status {
1380b57cec5SDimitry Andric protected:
1390b57cec5SDimitry Andric   #if defined(LLVM_ON_UNIX)
1400b57cec5SDimitry Andric   time_t fs_st_atime = 0;
1410b57cec5SDimitry Andric   time_t fs_st_mtime = 0;
1420b57cec5SDimitry Andric   uint32_t fs_st_atime_nsec = 0;
1430b57cec5SDimitry Andric   uint32_t fs_st_mtime_nsec = 0;
1440b57cec5SDimitry Andric   uid_t fs_st_uid = 0;
1450b57cec5SDimitry Andric   gid_t fs_st_gid = 0;
1460b57cec5SDimitry Andric   off_t fs_st_size = 0;
1470b57cec5SDimitry Andric   #elif defined (_WIN32)
1480b57cec5SDimitry Andric   uint32_t LastAccessedTimeHigh = 0;
1490b57cec5SDimitry Andric   uint32_t LastAccessedTimeLow = 0;
1500b57cec5SDimitry Andric   uint32_t LastWriteTimeHigh = 0;
1510b57cec5SDimitry Andric   uint32_t LastWriteTimeLow = 0;
1520b57cec5SDimitry Andric   uint32_t FileSizeHigh = 0;
1530b57cec5SDimitry Andric   uint32_t FileSizeLow = 0;
1540b57cec5SDimitry Andric   #endif
1550b57cec5SDimitry Andric   file_type Type = file_type::status_error;
1560b57cec5SDimitry Andric   perms Perms = perms_not_known;
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric public:
1590b57cec5SDimitry Andric   basic_file_status() = default;
1600b57cec5SDimitry Andric 
basic_file_status(file_type Type)1610b57cec5SDimitry Andric   explicit basic_file_status(file_type Type) : Type(Type) {}
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   #if defined(LLVM_ON_UNIX)
basic_file_status(file_type Type,perms Perms,time_t ATime,uint32_t ATimeNSec,time_t MTime,uint32_t MTimeNSec,uid_t UID,gid_t GID,off_t Size)1640b57cec5SDimitry Andric   basic_file_status(file_type Type, perms Perms, time_t ATime,
1650b57cec5SDimitry Andric                     uint32_t ATimeNSec, time_t MTime, uint32_t MTimeNSec,
1660b57cec5SDimitry Andric                     uid_t UID, gid_t GID, off_t Size)
1670b57cec5SDimitry Andric       : fs_st_atime(ATime), fs_st_mtime(MTime),
1680b57cec5SDimitry Andric         fs_st_atime_nsec(ATimeNSec), fs_st_mtime_nsec(MTimeNSec),
1690b57cec5SDimitry Andric         fs_st_uid(UID), fs_st_gid(GID),
1700b57cec5SDimitry Andric         fs_st_size(Size), Type(Type), Perms(Perms) {}
1710b57cec5SDimitry Andric #elif defined(_WIN32)
basic_file_status(file_type Type,perms Perms,uint32_t LastAccessTimeHigh,uint32_t LastAccessTimeLow,uint32_t LastWriteTimeHigh,uint32_t LastWriteTimeLow,uint32_t FileSizeHigh,uint32_t FileSizeLow)1720b57cec5SDimitry Andric   basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
1730b57cec5SDimitry Andric                     uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
1740b57cec5SDimitry Andric                     uint32_t LastWriteTimeLow, uint32_t FileSizeHigh,
1750b57cec5SDimitry Andric                     uint32_t FileSizeLow)
1760b57cec5SDimitry Andric       : LastAccessedTimeHigh(LastAccessTimeHigh),
1770b57cec5SDimitry Andric         LastAccessedTimeLow(LastAccessTimeLow),
1780b57cec5SDimitry Andric         LastWriteTimeHigh(LastWriteTimeHigh),
1790b57cec5SDimitry Andric         LastWriteTimeLow(LastWriteTimeLow), FileSizeHigh(FileSizeHigh),
1800b57cec5SDimitry Andric         FileSizeLow(FileSizeLow), Type(Type), Perms(Perms) {}
1810b57cec5SDimitry Andric   #endif
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   // getters
type()1840b57cec5SDimitry Andric   file_type type() const { return Type; }
permissions()1850b57cec5SDimitry Andric   perms permissions() const { return Perms; }
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   /// The file access time as reported from the underlying file system.
1880b57cec5SDimitry Andric   ///
1890b57cec5SDimitry Andric   /// Also see comments on \c getLastModificationTime() related to the precision
1900b57cec5SDimitry Andric   /// of the returned value.
1910b57cec5SDimitry Andric   TimePoint<> getLastAccessedTime() const;
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   /// The file modification time as reported from the underlying file system.
1940b57cec5SDimitry Andric   ///
1950b57cec5SDimitry Andric   /// The returned value allows for nanosecond precision but the actual
1960b57cec5SDimitry Andric   /// resolution is an implementation detail of the underlying file system.
1970b57cec5SDimitry Andric   /// There is no guarantee for what kind of resolution you can expect, the
1980b57cec5SDimitry Andric   /// resolution can differ across platforms and even across mountpoints on the
1990b57cec5SDimitry Andric   /// same machine.
2000b57cec5SDimitry Andric   TimePoint<> getLastModificationTime() const;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   #if defined(LLVM_ON_UNIX)
getUser()2030b57cec5SDimitry Andric   uint32_t getUser() const { return fs_st_uid; }
getGroup()2040b57cec5SDimitry Andric   uint32_t getGroup() const { return fs_st_gid; }
getSize()2050b57cec5SDimitry Andric   uint64_t getSize() const { return fs_st_size; }
2060b57cec5SDimitry Andric   #elif defined (_WIN32)
getUser()2070b57cec5SDimitry Andric   uint32_t getUser() const {
2080b57cec5SDimitry Andric     return 9999; // Not applicable to Windows, so...
2090b57cec5SDimitry Andric   }
2100b57cec5SDimitry Andric 
getGroup()2110b57cec5SDimitry Andric   uint32_t getGroup() const {
2120b57cec5SDimitry Andric     return 9999; // Not applicable to Windows, so...
2130b57cec5SDimitry Andric   }
2140b57cec5SDimitry Andric 
getSize()2150b57cec5SDimitry Andric   uint64_t getSize() const {
2160b57cec5SDimitry Andric     return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
2170b57cec5SDimitry Andric   }
2180b57cec5SDimitry Andric   #endif
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // setters
type(file_type v)2210b57cec5SDimitry Andric   void type(file_type v) { Type = v; }
permissions(perms p)2220b57cec5SDimitry Andric   void permissions(perms p) { Perms = p; }
2230b57cec5SDimitry Andric };
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric /// Represents the result of a call to sys::fs::status().
2260b57cec5SDimitry Andric class file_status : public basic_file_status {
2270b57cec5SDimitry Andric   friend bool equivalent(file_status A, file_status B);
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   #if defined(LLVM_ON_UNIX)
2300b57cec5SDimitry Andric   dev_t fs_st_dev = 0;
2310b57cec5SDimitry Andric   nlink_t fs_st_nlinks = 0;
2320b57cec5SDimitry Andric   ino_t fs_st_ino = 0;
2330b57cec5SDimitry Andric   #elif defined (_WIN32)
2340b57cec5SDimitry Andric   uint32_t NumLinks = 0;
2350b57cec5SDimitry Andric   uint32_t VolumeSerialNumber = 0;
2365f757f3fSDimitry Andric   uint64_t PathHash = 0;
2370b57cec5SDimitry Andric   #endif
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric public:
2400b57cec5SDimitry Andric   file_status() = default;
2410b57cec5SDimitry Andric 
file_status(file_type Type)2420b57cec5SDimitry Andric   explicit file_status(file_type Type) : basic_file_status(Type) {}
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   #if defined(LLVM_ON_UNIX)
file_status(file_type Type,perms Perms,dev_t Dev,nlink_t Links,ino_t Ino,time_t ATime,uint32_t ATimeNSec,time_t MTime,uint32_t MTimeNSec,uid_t UID,gid_t GID,off_t Size)2450b57cec5SDimitry Andric   file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino,
2460b57cec5SDimitry Andric               time_t ATime, uint32_t ATimeNSec,
2470b57cec5SDimitry Andric               time_t MTime, uint32_t MTimeNSec,
2480b57cec5SDimitry Andric               uid_t UID, gid_t GID, off_t Size)
2490b57cec5SDimitry Andric       : basic_file_status(Type, Perms, ATime, ATimeNSec, MTime, MTimeNSec,
2500b57cec5SDimitry Andric                           UID, GID, Size),
2510b57cec5SDimitry Andric         fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}
2520b57cec5SDimitry Andric   #elif defined(_WIN32)
file_status(file_type Type,perms Perms,uint32_t LinkCount,uint32_t LastAccessTimeHigh,uint32_t LastAccessTimeLow,uint32_t LastWriteTimeHigh,uint32_t LastWriteTimeLow,uint32_t VolumeSerialNumber,uint32_t FileSizeHigh,uint32_t FileSizeLow,uint64_t PathHash)2530b57cec5SDimitry Andric   file_status(file_type Type, perms Perms, uint32_t LinkCount,
2540b57cec5SDimitry Andric               uint32_t LastAccessTimeHigh, uint32_t LastAccessTimeLow,
2550b57cec5SDimitry Andric               uint32_t LastWriteTimeHigh, uint32_t LastWriteTimeLow,
2560b57cec5SDimitry Andric               uint32_t VolumeSerialNumber, uint32_t FileSizeHigh,
2575f757f3fSDimitry Andric               uint32_t FileSizeLow, uint64_t PathHash)
2580b57cec5SDimitry Andric       : basic_file_status(Type, Perms, LastAccessTimeHigh, LastAccessTimeLow,
2590b57cec5SDimitry Andric                           LastWriteTimeHigh, LastWriteTimeLow, FileSizeHigh,
2600b57cec5SDimitry Andric                           FileSizeLow),
2610b57cec5SDimitry Andric         NumLinks(LinkCount), VolumeSerialNumber(VolumeSerialNumber),
2625f757f3fSDimitry Andric         PathHash(PathHash) {}
2630b57cec5SDimitry Andric   #endif
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   UniqueID getUniqueID() const;
2660b57cec5SDimitry Andric   uint32_t getLinkCount() const;
2670b57cec5SDimitry Andric };
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric /// @}
2700b57cec5SDimitry Andric /// @name Physical Operators
2710b57cec5SDimitry Andric /// @{
2720b57cec5SDimitry Andric 
2730b57cec5SDimitry Andric /// Make \a path an absolute path.
2740b57cec5SDimitry Andric ///
2750b57cec5SDimitry Andric /// Makes \a path absolute using the \a current_directory if it is not already.
2760b57cec5SDimitry Andric /// An empty \a path will result in the \a current_directory.
2770b57cec5SDimitry Andric ///
2780b57cec5SDimitry Andric /// /absolute/path   => /absolute/path
2790b57cec5SDimitry Andric /// relative/../path => <current-directory>/relative/../path
2800b57cec5SDimitry Andric ///
2810b57cec5SDimitry Andric /// @param path A path that is modified to be an absolute path.
2820b57cec5SDimitry Andric void make_absolute(const Twine &current_directory, SmallVectorImpl<char> &path);
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric /// Make \a path an absolute path.
2850b57cec5SDimitry Andric ///
2860b57cec5SDimitry Andric /// Makes \a path absolute using the current directory if it is not already. An
2870b57cec5SDimitry Andric /// empty \a path will result in the current directory.
2880b57cec5SDimitry Andric ///
2890b57cec5SDimitry Andric /// /absolute/path   => /absolute/path
2900b57cec5SDimitry Andric /// relative/../path => <current-directory>/relative/../path
2910b57cec5SDimitry Andric ///
2920b57cec5SDimitry Andric /// @param path A path that is modified to be an absolute path.
2930b57cec5SDimitry Andric /// @returns errc::success if \a path has been made absolute, otherwise a
2940b57cec5SDimitry Andric ///          platform-specific error_code.
2950b57cec5SDimitry Andric std::error_code make_absolute(SmallVectorImpl<char> &path);
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric /// Create all the non-existent directories in path.
2980b57cec5SDimitry Andric ///
2990b57cec5SDimitry Andric /// @param path Directories to create.
3000b57cec5SDimitry Andric /// @returns errc::success if is_directory(path), otherwise a platform
3010b57cec5SDimitry Andric ///          specific error_code. If IgnoreExisting is false, also returns
3020b57cec5SDimitry Andric ///          error if the directory already existed.
3030b57cec5SDimitry Andric std::error_code create_directories(const Twine &path,
3040b57cec5SDimitry Andric                                    bool IgnoreExisting = true,
3050b57cec5SDimitry Andric                                    perms Perms = owner_all | group_all);
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric /// Create the directory in path.
3080b57cec5SDimitry Andric ///
3090b57cec5SDimitry Andric /// @param path Directory to create.
3100b57cec5SDimitry Andric /// @returns errc::success if is_directory(path), otherwise a platform
3110b57cec5SDimitry Andric ///          specific error_code. If IgnoreExisting is false, also returns
3120b57cec5SDimitry Andric ///          error if the directory already existed.
3130b57cec5SDimitry Andric std::error_code create_directory(const Twine &path, bool IgnoreExisting = true,
3140b57cec5SDimitry Andric                                  perms Perms = owner_all | group_all);
3150b57cec5SDimitry Andric 
3160b57cec5SDimitry Andric /// Create a link from \a from to \a to.
3170b57cec5SDimitry Andric ///
3180b57cec5SDimitry Andric /// The link may be a soft or a hard link, depending on the platform. The caller
3190b57cec5SDimitry Andric /// may not assume which one. Currently on windows it creates a hard link since
3200b57cec5SDimitry Andric /// soft links require extra privileges. On unix, it creates a soft link since
3210b57cec5SDimitry Andric /// hard links don't work on SMB file systems.
3220b57cec5SDimitry Andric ///
3230b57cec5SDimitry Andric /// @param to The path to hard link to.
3240b57cec5SDimitry Andric /// @param from The path to hard link from. This is created.
3250b57cec5SDimitry Andric /// @returns errc::success if the link was created, otherwise a platform
3260b57cec5SDimitry Andric /// specific error_code.
3270b57cec5SDimitry Andric std::error_code create_link(const Twine &to, const Twine &from);
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric /// Create a hard link from \a from to \a to, or return an error.
3300b57cec5SDimitry Andric ///
3310b57cec5SDimitry Andric /// @param to The path to hard link to.
3320b57cec5SDimitry Andric /// @param from The path to hard link from. This is created.
3330b57cec5SDimitry Andric /// @returns errc::success if the link was created, otherwise a platform
3340b57cec5SDimitry Andric /// specific error_code.
3350b57cec5SDimitry Andric std::error_code create_hard_link(const Twine &to, const Twine &from);
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric /// Collapse all . and .. patterns, resolve all symlinks, and optionally
3380b57cec5SDimitry Andric ///        expand ~ expressions to the user's home directory.
3390b57cec5SDimitry Andric ///
3400b57cec5SDimitry Andric /// @param path The path to resolve.
3410b57cec5SDimitry Andric /// @param output The location to store the resolved path.
3420b57cec5SDimitry Andric /// @param expand_tilde If true, resolves ~ expressions to the user's home
3430b57cec5SDimitry Andric ///                     directory.
3440b57cec5SDimitry Andric std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output,
3450b57cec5SDimitry Andric                           bool expand_tilde = false);
3460b57cec5SDimitry Andric 
3470b57cec5SDimitry Andric /// Expands ~ expressions to the user's home directory. On Unix ~user
3480b57cec5SDimitry Andric /// directories are resolved as well.
3490b57cec5SDimitry Andric ///
3500b57cec5SDimitry Andric /// @param path The path to resolve.
3510b57cec5SDimitry Andric void expand_tilde(const Twine &path, SmallVectorImpl<char> &output);
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric /// Get the current path.
3540b57cec5SDimitry Andric ///
3550b57cec5SDimitry Andric /// @param result Holds the current path on return.
3560b57cec5SDimitry Andric /// @returns errc::success if the current path has been stored in result,
3570b57cec5SDimitry Andric ///          otherwise a platform-specific error_code.
3580b57cec5SDimitry Andric std::error_code current_path(SmallVectorImpl<char> &result);
3590b57cec5SDimitry Andric 
3600b57cec5SDimitry Andric /// Set the current path.
3610b57cec5SDimitry Andric ///
3620b57cec5SDimitry Andric /// @param path The path to set.
3630b57cec5SDimitry Andric /// @returns errc::success if the current path was successfully set,
3640b57cec5SDimitry Andric ///          otherwise a platform-specific error_code.
3650b57cec5SDimitry Andric std::error_code set_current_path(const Twine &path);
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric /// Remove path. Equivalent to POSIX remove().
3680b57cec5SDimitry Andric ///
3690b57cec5SDimitry Andric /// @param path Input path.
3700b57cec5SDimitry Andric /// @returns errc::success if path has been removed or didn't exist, otherwise a
3710b57cec5SDimitry Andric ///          platform-specific error code. If IgnoreNonExisting is false, also
3720b57cec5SDimitry Andric ///          returns error if the file didn't exist.
3730b57cec5SDimitry Andric std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
3740b57cec5SDimitry Andric 
3750b57cec5SDimitry Andric /// Recursively delete a directory.
3760b57cec5SDimitry Andric ///
3770b57cec5SDimitry Andric /// @param path Input path.
3780b57cec5SDimitry Andric /// @returns errc::success if path has been removed or didn't exist, otherwise a
3790b57cec5SDimitry Andric ///          platform-specific error code.
3800b57cec5SDimitry Andric std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
3810b57cec5SDimitry Andric 
3820b57cec5SDimitry Andric /// Rename \a from to \a to.
3830b57cec5SDimitry Andric ///
3840b57cec5SDimitry Andric /// Files are renamed as if by POSIX rename(), except that on Windows there may
3850b57cec5SDimitry Andric /// be a short interval of time during which the destination file does not
3860b57cec5SDimitry Andric /// exist.
3870b57cec5SDimitry Andric ///
3880b57cec5SDimitry Andric /// @param from The path to rename from.
3890b57cec5SDimitry Andric /// @param to The path to rename to. This is created.
3900b57cec5SDimitry Andric std::error_code rename(const Twine &from, const Twine &to);
3910b57cec5SDimitry Andric 
3920b57cec5SDimitry Andric /// Copy the contents of \a From to \a To.
3930b57cec5SDimitry Andric ///
3940b57cec5SDimitry Andric /// @param From The path to copy from.
3950b57cec5SDimitry Andric /// @param To The path to copy to. This is created.
3960b57cec5SDimitry Andric std::error_code copy_file(const Twine &From, const Twine &To);
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric /// Copy the contents of \a From to \a To.
3990b57cec5SDimitry Andric ///
4000b57cec5SDimitry Andric /// @param From The path to copy from.
4010b57cec5SDimitry Andric /// @param ToFD The open file descriptor of the destination file.
4020b57cec5SDimitry Andric std::error_code copy_file(const Twine &From, int ToFD);
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric /// Resize path to size. File is resized as if by POSIX truncate().
4050b57cec5SDimitry Andric ///
4060b57cec5SDimitry Andric /// @param FD Input file descriptor.
4070b57cec5SDimitry Andric /// @param Size Size to resize to.
4080b57cec5SDimitry Andric /// @returns errc::success if \a path has been resized to \a size, otherwise a
4090b57cec5SDimitry Andric ///          platform-specific error_code.
4100b57cec5SDimitry Andric std::error_code resize_file(int FD, uint64_t Size);
4110b57cec5SDimitry Andric 
412fe6060f1SDimitry Andric /// Resize \p FD to \p Size before mapping \a mapped_file_region::readwrite. On
413fe6060f1SDimitry Andric /// non-Windows, this calls \a resize_file(). On Windows, this is a no-op,
414fe6060f1SDimitry Andric /// since the subsequent mapping (via \c CreateFileMapping) automatically
415fe6060f1SDimitry Andric /// extends the file.
resize_file_before_mapping_readwrite(int FD,uint64_t Size)416fe6060f1SDimitry Andric inline std::error_code resize_file_before_mapping_readwrite(int FD,
417fe6060f1SDimitry Andric                                                             uint64_t Size) {
418fe6060f1SDimitry Andric #ifdef _WIN32
419fe6060f1SDimitry Andric   (void)FD;
420fe6060f1SDimitry Andric   (void)Size;
421fe6060f1SDimitry Andric   return std::error_code();
422fe6060f1SDimitry Andric #else
423fe6060f1SDimitry Andric   return resize_file(FD, Size);
424fe6060f1SDimitry Andric #endif
425fe6060f1SDimitry Andric }
426fe6060f1SDimitry Andric 
4270b57cec5SDimitry Andric /// Compute an MD5 hash of a file's contents.
4280b57cec5SDimitry Andric ///
4290b57cec5SDimitry Andric /// @param FD Input file descriptor.
4300b57cec5SDimitry Andric /// @returns An MD5Result with the hash computed, if successful, otherwise a
4310b57cec5SDimitry Andric ///          std::error_code.
4320b57cec5SDimitry Andric ErrorOr<MD5::MD5Result> md5_contents(int FD);
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric /// Version of compute_md5 that doesn't require an open file descriptor.
4350b57cec5SDimitry Andric ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path);
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric /// @}
4380b57cec5SDimitry Andric /// @name Physical Observers
4390b57cec5SDimitry Andric /// @{
4400b57cec5SDimitry Andric 
4410b57cec5SDimitry Andric /// Does file exist?
4420b57cec5SDimitry Andric ///
4430b57cec5SDimitry Andric /// @param status A basic_file_status previously returned from stat.
4440b57cec5SDimitry Andric /// @returns True if the file represented by status exists, false if it does
4450b57cec5SDimitry Andric ///          not.
4460b57cec5SDimitry Andric bool exists(const basic_file_status &status);
4470b57cec5SDimitry Andric 
4480b57cec5SDimitry Andric enum class AccessMode { Exist, Write, Execute };
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric /// Can the file be accessed?
4510b57cec5SDimitry Andric ///
4520b57cec5SDimitry Andric /// @param Path Input path.
4530b57cec5SDimitry Andric /// @returns errc::success if the path can be accessed, otherwise a
4540b57cec5SDimitry Andric ///          platform-specific error_code.
4550b57cec5SDimitry Andric std::error_code access(const Twine &Path, AccessMode Mode);
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric /// Does file exist?
4580b57cec5SDimitry Andric ///
4590b57cec5SDimitry Andric /// @param Path Input path.
4600b57cec5SDimitry Andric /// @returns True if it exists, false otherwise.
exists(const Twine & Path)4610b57cec5SDimitry Andric inline bool exists(const Twine &Path) {
4620b57cec5SDimitry Andric   return !access(Path, AccessMode::Exist);
4630b57cec5SDimitry Andric }
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric /// Can we execute this file?
4660b57cec5SDimitry Andric ///
4670b57cec5SDimitry Andric /// @param Path Input path.
4680b57cec5SDimitry Andric /// @returns True if we can execute it, false otherwise.
4690b57cec5SDimitry Andric bool can_execute(const Twine &Path);
4700b57cec5SDimitry Andric 
4710b57cec5SDimitry Andric /// Can we write this file?
4720b57cec5SDimitry Andric ///
4730b57cec5SDimitry Andric /// @param Path Input path.
4740b57cec5SDimitry Andric /// @returns True if we can write to it, false otherwise.
can_write(const Twine & Path)4750b57cec5SDimitry Andric inline bool can_write(const Twine &Path) {
4760b57cec5SDimitry Andric   return !access(Path, AccessMode::Write);
4770b57cec5SDimitry Andric }
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric /// Do file_status's represent the same thing?
4800b57cec5SDimitry Andric ///
4810b57cec5SDimitry Andric /// @param A Input file_status.
4820b57cec5SDimitry Andric /// @param B Input file_status.
4830b57cec5SDimitry Andric ///
4840b57cec5SDimitry Andric /// assert(status_known(A) || status_known(B));
4850b57cec5SDimitry Andric ///
4860b57cec5SDimitry Andric /// @returns True if A and B both represent the same file system entity, false
4870b57cec5SDimitry Andric ///          otherwise.
4880b57cec5SDimitry Andric bool equivalent(file_status A, file_status B);
4890b57cec5SDimitry Andric 
4900b57cec5SDimitry Andric /// Do paths represent the same thing?
4910b57cec5SDimitry Andric ///
4920b57cec5SDimitry Andric /// assert(status_known(A) || status_known(B));
4930b57cec5SDimitry Andric ///
4940b57cec5SDimitry Andric /// @param A Input path A.
4950b57cec5SDimitry Andric /// @param B Input path B.
4960b57cec5SDimitry Andric /// @param result Set to true if stat(A) and stat(B) have the same device and
4970b57cec5SDimitry Andric ///               inode (or equivalent).
4980b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
4990b57cec5SDimitry Andric ///          platform-specific error_code.
5000b57cec5SDimitry Andric std::error_code equivalent(const Twine &A, const Twine &B, bool &result);
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric /// Simpler version of equivalent for clients that don't need to
5030b57cec5SDimitry Andric ///        differentiate between an error and false.
equivalent(const Twine & A,const Twine & B)5040b57cec5SDimitry Andric inline bool equivalent(const Twine &A, const Twine &B) {
5050b57cec5SDimitry Andric   bool result;
5060b57cec5SDimitry Andric   return !equivalent(A, B, result) && result;
5070b57cec5SDimitry Andric }
5080b57cec5SDimitry Andric 
5090b57cec5SDimitry Andric /// Is the file mounted on a local filesystem?
5100b57cec5SDimitry Andric ///
5110b57cec5SDimitry Andric /// @param path Input path.
5120b57cec5SDimitry Andric /// @param result Set to true if \a path is on fixed media such as a hard disk,
5130b57cec5SDimitry Andric ///               false if it is not.
5140b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
5150b57cec5SDimitry Andric ///          platform specific error_code.
5160b57cec5SDimitry Andric std::error_code is_local(const Twine &path, bool &result);
5170b57cec5SDimitry Andric 
5180b57cec5SDimitry Andric /// Version of is_local accepting an open file descriptor.
5190b57cec5SDimitry Andric std::error_code is_local(int FD, bool &result);
5200b57cec5SDimitry Andric 
5210b57cec5SDimitry Andric /// Simpler version of is_local for clients that don't need to
5220b57cec5SDimitry Andric ///        differentiate between an error and false.
is_local(const Twine & Path)5230b57cec5SDimitry Andric inline bool is_local(const Twine &Path) {
5240b57cec5SDimitry Andric   bool Result;
5250b57cec5SDimitry Andric   return !is_local(Path, Result) && Result;
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric /// Simpler version of is_local accepting an open file descriptor for
5290b57cec5SDimitry Andric ///        clients that don't need to differentiate between an error and false.
is_local(int FD)5300b57cec5SDimitry Andric inline bool is_local(int FD) {
5310b57cec5SDimitry Andric   bool Result;
5320b57cec5SDimitry Andric   return !is_local(FD, Result) && Result;
5330b57cec5SDimitry Andric }
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric /// Does status represent a directory?
5360b57cec5SDimitry Andric ///
5370b57cec5SDimitry Andric /// @param Path The path to get the type of.
5380b57cec5SDimitry Andric /// @param Follow For symbolic links, indicates whether to return the file type
5390b57cec5SDimitry Andric ///               of the link itself, or of the target.
5400b57cec5SDimitry Andric /// @returns A value from the file_type enumeration indicating the type of file.
5410b57cec5SDimitry Andric file_type get_file_type(const Twine &Path, bool Follow = true);
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric /// Does status represent a directory?
5440b57cec5SDimitry Andric ///
5450b57cec5SDimitry Andric /// @param status A basic_file_status previously returned from status.
5460b57cec5SDimitry Andric /// @returns status.type() == file_type::directory_file.
5470b57cec5SDimitry Andric bool is_directory(const basic_file_status &status);
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric /// Is path a directory?
5500b57cec5SDimitry Andric ///
5510b57cec5SDimitry Andric /// @param path Input path.
5520b57cec5SDimitry Andric /// @param result Set to true if \a path is a directory (after following
5530b57cec5SDimitry Andric ///               symlinks, false if it is not. Undefined otherwise.
5540b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
5550b57cec5SDimitry Andric ///          platform-specific error_code.
5560b57cec5SDimitry Andric std::error_code is_directory(const Twine &path, bool &result);
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric /// Simpler version of is_directory for clients that don't need to
5590b57cec5SDimitry Andric ///        differentiate between an error and false.
is_directory(const Twine & Path)5600b57cec5SDimitry Andric inline bool is_directory(const Twine &Path) {
5610b57cec5SDimitry Andric   bool Result;
5620b57cec5SDimitry Andric   return !is_directory(Path, Result) && Result;
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric /// Does status represent a regular file?
5660b57cec5SDimitry Andric ///
5670b57cec5SDimitry Andric /// @param status A basic_file_status previously returned from status.
5680b57cec5SDimitry Andric /// @returns status_known(status) && status.type() == file_type::regular_file.
5690b57cec5SDimitry Andric bool is_regular_file(const basic_file_status &status);
5700b57cec5SDimitry Andric 
5710b57cec5SDimitry Andric /// Is path a regular file?
5720b57cec5SDimitry Andric ///
5730b57cec5SDimitry Andric /// @param path Input path.
5740b57cec5SDimitry Andric /// @param result Set to true if \a path is a regular file (after following
5750b57cec5SDimitry Andric ///               symlinks), false if it is not. Undefined otherwise.
5760b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
5770b57cec5SDimitry Andric ///          platform-specific error_code.
5780b57cec5SDimitry Andric std::error_code is_regular_file(const Twine &path, bool &result);
5790b57cec5SDimitry Andric 
5800b57cec5SDimitry Andric /// Simpler version of is_regular_file for clients that don't need to
5810b57cec5SDimitry Andric ///        differentiate between an error and false.
is_regular_file(const Twine & Path)5820b57cec5SDimitry Andric inline bool is_regular_file(const Twine &Path) {
5830b57cec5SDimitry Andric   bool Result;
5840b57cec5SDimitry Andric   if (is_regular_file(Path, Result))
5850b57cec5SDimitry Andric     return false;
5860b57cec5SDimitry Andric   return Result;
5870b57cec5SDimitry Andric }
5880b57cec5SDimitry Andric 
5890b57cec5SDimitry Andric /// Does status represent a symlink file?
5900b57cec5SDimitry Andric ///
5910b57cec5SDimitry Andric /// @param status A basic_file_status previously returned from status.
5920b57cec5SDimitry Andric /// @returns status_known(status) && status.type() == file_type::symlink_file.
5930b57cec5SDimitry Andric bool is_symlink_file(const basic_file_status &status);
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric /// Is path a symlink file?
5960b57cec5SDimitry Andric ///
5970b57cec5SDimitry Andric /// @param path Input path.
5980b57cec5SDimitry Andric /// @param result Set to true if \a path is a symlink file, false if it is not.
5990b57cec5SDimitry Andric ///               Undefined otherwise.
6000b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
6010b57cec5SDimitry Andric ///          platform-specific error_code.
6020b57cec5SDimitry Andric std::error_code is_symlink_file(const Twine &path, bool &result);
6030b57cec5SDimitry Andric 
6040b57cec5SDimitry Andric /// Simpler version of is_symlink_file for clients that don't need to
6050b57cec5SDimitry Andric ///        differentiate between an error and false.
is_symlink_file(const Twine & Path)6060b57cec5SDimitry Andric inline bool is_symlink_file(const Twine &Path) {
6070b57cec5SDimitry Andric   bool Result;
6080b57cec5SDimitry Andric   if (is_symlink_file(Path, Result))
6090b57cec5SDimitry Andric     return false;
6100b57cec5SDimitry Andric   return Result;
6110b57cec5SDimitry Andric }
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric /// Does this status represent something that exists but is not a
6140b57cec5SDimitry Andric ///        directory or regular file?
6150b57cec5SDimitry Andric ///
6160b57cec5SDimitry Andric /// @param status A basic_file_status previously returned from status.
6170b57cec5SDimitry Andric /// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
6180b57cec5SDimitry Andric bool is_other(const basic_file_status &status);
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric /// Is path something that exists but is not a directory,
6210b57cec5SDimitry Andric ///        regular file, or symlink?
6220b57cec5SDimitry Andric ///
6230b57cec5SDimitry Andric /// @param path Input path.
6240b57cec5SDimitry Andric /// @param result Set to true if \a path exists, but is not a directory, regular
6250b57cec5SDimitry Andric ///               file, or a symlink, false if it does not. Undefined otherwise.
6260b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
6270b57cec5SDimitry Andric ///          platform-specific error_code.
6280b57cec5SDimitry Andric std::error_code is_other(const Twine &path, bool &result);
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric /// Get file status as if by POSIX stat().
6310b57cec5SDimitry Andric ///
6320b57cec5SDimitry Andric /// @param path Input path.
6330b57cec5SDimitry Andric /// @param result Set to the file status.
6340b57cec5SDimitry Andric /// @param follow When true, follows symlinks.  Otherwise, the symlink itself is
6350b57cec5SDimitry Andric ///               statted.
6360b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
6370b57cec5SDimitry Andric ///          platform-specific error_code.
6380b57cec5SDimitry Andric std::error_code status(const Twine &path, file_status &result,
6390b57cec5SDimitry Andric                        bool follow = true);
6400b57cec5SDimitry Andric 
6410b57cec5SDimitry Andric /// A version for when a file descriptor is already available.
6420b57cec5SDimitry Andric std::error_code status(int FD, file_status &Result);
6430b57cec5SDimitry Andric 
6440b57cec5SDimitry Andric #ifdef _WIN32
6450b57cec5SDimitry Andric /// A version for when a file descriptor is already available.
6460b57cec5SDimitry Andric std::error_code status(file_t FD, file_status &Result);
6470b57cec5SDimitry Andric #endif
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric /// Get file creation mode mask of the process.
6500b57cec5SDimitry Andric ///
6510b57cec5SDimitry Andric /// @returns Mask reported by umask(2)
6520b57cec5SDimitry Andric /// @note There is no umask on Windows. This function returns 0 always
6530b57cec5SDimitry Andric ///       on Windows. This function does not return an error_code because
6540b57cec5SDimitry Andric ///       umask(2) never fails. It is not thread safe.
6550b57cec5SDimitry Andric unsigned getUmask();
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric /// Set file permissions.
6580b57cec5SDimitry Andric ///
6590b57cec5SDimitry Andric /// @param Path File to set permissions on.
6600b57cec5SDimitry Andric /// @param Permissions New file permissions.
6610b57cec5SDimitry Andric /// @returns errc::success if the permissions were successfully set, otherwise
6620b57cec5SDimitry Andric ///          a platform-specific error_code.
6630b57cec5SDimitry Andric /// @note On Windows, all permissions except *_write are ignored. Using any of
6640b57cec5SDimitry Andric ///       owner_write, group_write, or all_write will make the file writable.
6650b57cec5SDimitry Andric ///       Otherwise, the file will be marked as read-only.
6660b57cec5SDimitry Andric std::error_code setPermissions(const Twine &Path, perms Permissions);
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric /// Vesion of setPermissions accepting a file descriptor.
6690b57cec5SDimitry Andric /// TODO Delete the path based overload once we implement the FD based overload
6700b57cec5SDimitry Andric /// on Windows.
6710b57cec5SDimitry Andric std::error_code setPermissions(int FD, perms Permissions);
6720b57cec5SDimitry Andric 
6730b57cec5SDimitry Andric /// Get file permissions.
6740b57cec5SDimitry Andric ///
6750b57cec5SDimitry Andric /// @param Path File to get permissions from.
6760b57cec5SDimitry Andric /// @returns the permissions if they were successfully retrieved, otherwise a
6770b57cec5SDimitry Andric ///          platform-specific error_code.
6780b57cec5SDimitry Andric /// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY
6790b57cec5SDimitry Andric ///       attribute, all_all will be returned. Otherwise, all_read | all_exe
6800b57cec5SDimitry Andric ///       will be returned.
6810b57cec5SDimitry Andric ErrorOr<perms> getPermissions(const Twine &Path);
6820b57cec5SDimitry Andric 
6830b57cec5SDimitry Andric /// Get file size.
6840b57cec5SDimitry Andric ///
6850b57cec5SDimitry Andric /// @param Path Input path.
6860b57cec5SDimitry Andric /// @param Result Set to the size of the file in \a Path.
6870b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
6880b57cec5SDimitry Andric ///          platform-specific error_code.
file_size(const Twine & Path,uint64_t & Result)6890b57cec5SDimitry Andric inline std::error_code file_size(const Twine &Path, uint64_t &Result) {
6900b57cec5SDimitry Andric   file_status Status;
6910b57cec5SDimitry Andric   std::error_code EC = status(Path, Status);
6920b57cec5SDimitry Andric   if (EC)
6930b57cec5SDimitry Andric     return EC;
6940b57cec5SDimitry Andric   Result = Status.getSize();
6950b57cec5SDimitry Andric   return std::error_code();
6960b57cec5SDimitry Andric }
6970b57cec5SDimitry Andric 
6980b57cec5SDimitry Andric /// Set the file modification and access time.
6990b57cec5SDimitry Andric ///
7000b57cec5SDimitry Andric /// @returns errc::success if the file times were successfully set, otherwise a
7010b57cec5SDimitry Andric ///          platform-specific error_code or errc::function_not_supported on
7020b57cec5SDimitry Andric ///          platforms where the functionality isn't available.
7030b57cec5SDimitry Andric std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime,
7040b57cec5SDimitry Andric                                                  TimePoint<> ModificationTime);
7050b57cec5SDimitry Andric 
7060b57cec5SDimitry Andric /// Simpler version that sets both file modification and access time to the same
7070b57cec5SDimitry Andric /// time.
setLastAccessAndModificationTime(int FD,TimePoint<> Time)7080b57cec5SDimitry Andric inline std::error_code setLastAccessAndModificationTime(int FD,
7090b57cec5SDimitry Andric                                                         TimePoint<> Time) {
7100b57cec5SDimitry Andric   return setLastAccessAndModificationTime(FD, Time, Time);
7110b57cec5SDimitry Andric }
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric /// Is status available?
7140b57cec5SDimitry Andric ///
7150b57cec5SDimitry Andric /// @param s Input file status.
7160b57cec5SDimitry Andric /// @returns True if status() != status_error.
7170b57cec5SDimitry Andric bool status_known(const basic_file_status &s);
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric /// Is status available?
7200b57cec5SDimitry Andric ///
7210b57cec5SDimitry Andric /// @param path Input path.
7220b57cec5SDimitry Andric /// @param result Set to true if status() != status_error.
7230b57cec5SDimitry Andric /// @returns errc::success if result has been successfully set, otherwise a
7240b57cec5SDimitry Andric ///          platform-specific error_code.
7250b57cec5SDimitry Andric std::error_code status_known(const Twine &path, bool &result);
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric enum CreationDisposition : unsigned {
7280b57cec5SDimitry Andric   /// CD_CreateAlways - When opening a file:
7290b57cec5SDimitry Andric   ///   * If it already exists, truncate it.
7300b57cec5SDimitry Andric   ///   * If it does not already exist, create a new file.
7310b57cec5SDimitry Andric   CD_CreateAlways = 0,
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric   /// CD_CreateNew - When opening a file:
7340b57cec5SDimitry Andric   ///   * If it already exists, fail.
7350b57cec5SDimitry Andric   ///   * If it does not already exist, create a new file.
7360b57cec5SDimitry Andric   CD_CreateNew = 1,
7370b57cec5SDimitry Andric 
7380b57cec5SDimitry Andric   /// CD_OpenExisting - When opening a file:
7390b57cec5SDimitry Andric   ///   * If it already exists, open the file with the offset set to 0.
7400b57cec5SDimitry Andric   ///   * If it does not already exist, fail.
7410b57cec5SDimitry Andric   CD_OpenExisting = 2,
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric   /// CD_OpenAlways - When opening a file:
7440b57cec5SDimitry Andric   ///   * If it already exists, open the file with the offset set to 0.
7450b57cec5SDimitry Andric   ///   * If it does not already exist, create a new file.
7460b57cec5SDimitry Andric   CD_OpenAlways = 3,
7470b57cec5SDimitry Andric };
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric enum FileAccess : unsigned {
7500b57cec5SDimitry Andric   FA_Read = 1,
7510b57cec5SDimitry Andric   FA_Write = 2,
7520b57cec5SDimitry Andric };
7530b57cec5SDimitry Andric 
7540b57cec5SDimitry Andric enum OpenFlags : unsigned {
7550b57cec5SDimitry Andric   OF_None = 0,
7560b57cec5SDimitry Andric 
757fe6060f1SDimitry Andric   /// The file should be opened in text mode on platforms like z/OS that make
758fe6060f1SDimitry Andric   /// this distinction.
7590b57cec5SDimitry Andric   OF_Text = 1,
760fe6060f1SDimitry Andric 
761fe6060f1SDimitry Andric   /// The file should use a carriage linefeed '\r\n'. This flag should only be
762fe6060f1SDimitry Andric   /// used with OF_Text. Only makes a difference on Windows.
763fe6060f1SDimitry Andric   OF_CRLF = 2,
764fe6060f1SDimitry Andric 
765fe6060f1SDimitry Andric   /// The file should be opened in text mode and use a carriage linefeed '\r\n'.
766fe6060f1SDimitry Andric   /// This flag has the same functionality as OF_Text on z/OS but adds a
767fe6060f1SDimitry Andric   /// carriage linefeed on Windows.
768fe6060f1SDimitry Andric   OF_TextWithCRLF = OF_Text | OF_CRLF,
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric   /// The file should be opened in append mode.
771fe6060f1SDimitry Andric   OF_Append = 4,
7720b57cec5SDimitry Andric 
773349cc55cSDimitry Andric   /// The returned handle can be used for deleting the file. Only makes a
774349cc55cSDimitry Andric   /// difference on windows.
775fe6060f1SDimitry Andric   OF_Delete = 8,
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   /// When a child process is launched, this file should remain open in the
7780b57cec5SDimitry Andric   /// child process.
779fe6060f1SDimitry Andric   OF_ChildInherit = 16,
7800b57cec5SDimitry Andric 
781fe6060f1SDimitry Andric   /// Force files Atime to be updated on access. Only makes a difference on
782fe6060f1SDimitry Andric   /// Windows.
783fe6060f1SDimitry Andric   OF_UpdateAtime = 32,
7840b57cec5SDimitry Andric };
7850b57cec5SDimitry Andric 
7860b57cec5SDimitry Andric /// Create a potentially unique file name but does not create it.
7870b57cec5SDimitry Andric ///
7880b57cec5SDimitry Andric /// Generates a unique path suitable for a temporary file but does not
7890b57cec5SDimitry Andric /// open or create the file. The name is based on \a Model with '%'
7900b57cec5SDimitry Andric /// replaced by a random char in [0-9a-f]. If \a MakeAbsolute is true
7910b57cec5SDimitry Andric /// then the system's temp directory is prepended first. If \a MakeAbsolute
7920b57cec5SDimitry Andric /// is false the current directory will be used instead.
7930b57cec5SDimitry Andric ///
7940b57cec5SDimitry Andric /// This function does not check if the file exists. If you want to be sure
7955f757f3fSDimitry Andric /// that the file does not yet exist, you should use enough '%' characters
7960b57cec5SDimitry Andric /// in your model to ensure this. Each '%' gives 4-bits of entropy so you can
7970b57cec5SDimitry Andric /// use 32 of them to get 128 bits of entropy.
7980b57cec5SDimitry Andric ///
7990b57cec5SDimitry Andric /// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s
8000b57cec5SDimitry Andric ///
8010b57cec5SDimitry Andric /// @param Model Name to base unique path off of.
8020b57cec5SDimitry Andric /// @param ResultPath Set to the file's path.
8030b57cec5SDimitry Andric /// @param MakeAbsolute Whether to use the system temp directory.
8040b57cec5SDimitry Andric void createUniquePath(const Twine &Model, SmallVectorImpl<char> &ResultPath,
8050b57cec5SDimitry Andric                       bool MakeAbsolute);
8060b57cec5SDimitry Andric 
8070b57cec5SDimitry Andric /// Create a uniquely named file.
8080b57cec5SDimitry Andric ///
8090b57cec5SDimitry Andric /// Generates a unique path suitable for a temporary file and then opens it as a
8100b57cec5SDimitry Andric /// file. The name is based on \a Model with '%' replaced by a random char in
8110b57cec5SDimitry Andric /// [0-9a-f]. If \a Model is not an absolute path, the temporary file will be
8120b57cec5SDimitry Andric /// created in the current directory.
8130b57cec5SDimitry Andric ///
8140b57cec5SDimitry Andric /// Example: clang-%%-%%-%%-%%-%%.s => clang-a0-b1-c2-d3-e4.s
8150b57cec5SDimitry Andric ///
8160b57cec5SDimitry Andric /// This is an atomic operation. Either the file is created and opened, or the
8170b57cec5SDimitry Andric /// file system is left untouched.
8180b57cec5SDimitry Andric ///
8190b57cec5SDimitry Andric /// The intended use is for files that are to be kept, possibly after
8200b57cec5SDimitry Andric /// renaming them. For example, when running 'clang -c foo.o', the file can
8210b57cec5SDimitry Andric /// be first created as foo-abc123.o and then renamed.
8220b57cec5SDimitry Andric ///
8230b57cec5SDimitry Andric /// @param Model Name to base unique path off of.
8240b57cec5SDimitry Andric /// @param ResultFD Set to the opened file's file descriptor.
8250b57cec5SDimitry Andric /// @param ResultPath Set to the opened file's absolute path.
826fe6060f1SDimitry Andric /// @param Flags Set to the opened file's flags.
827fe6060f1SDimitry Andric /// @param Mode Set to the opened file's permissions.
8280b57cec5SDimitry Andric /// @returns errc::success if Result{FD,Path} have been successfully set,
8290b57cec5SDimitry Andric ///          otherwise a platform-specific error_code.
8300b57cec5SDimitry Andric std::error_code createUniqueFile(const Twine &Model, int &ResultFD,
8310b57cec5SDimitry Andric                                  SmallVectorImpl<char> &ResultPath,
832fe6060f1SDimitry Andric                                  OpenFlags Flags = OF_None,
8330b57cec5SDimitry Andric                                  unsigned Mode = all_read | all_write);
8340b57cec5SDimitry Andric 
8350b57cec5SDimitry Andric /// Simpler version for clients that don't want an open file. An empty
8360b57cec5SDimitry Andric /// file will still be created.
8370b57cec5SDimitry Andric std::error_code createUniqueFile(const Twine &Model,
8380b57cec5SDimitry Andric                                  SmallVectorImpl<char> &ResultPath,
8390b57cec5SDimitry Andric                                  unsigned Mode = all_read | all_write);
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric /// Represents a temporary file.
8420b57cec5SDimitry Andric ///
8430b57cec5SDimitry Andric /// The temporary file must be eventually discarded or given a final name and
8440b57cec5SDimitry Andric /// kept.
8450b57cec5SDimitry Andric ///
8460b57cec5SDimitry Andric /// The destructor doesn't implicitly discard because there is no way to
8470b57cec5SDimitry Andric /// properly handle errors in a destructor.
8480b57cec5SDimitry Andric class TempFile {
8490b57cec5SDimitry Andric   bool Done = false;
8500b57cec5SDimitry Andric   TempFile(StringRef Name, int FD);
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric public:
8530b57cec5SDimitry Andric   /// This creates a temporary file with createUniqueFile and schedules it for
8540b57cec5SDimitry Andric   /// deletion with sys::RemoveFileOnSignal.
8550b57cec5SDimitry Andric   static Expected<TempFile> create(const Twine &Model,
856fe6060f1SDimitry Andric                                    unsigned Mode = all_read | all_write,
857fe6060f1SDimitry Andric                                    OpenFlags ExtraFlags = OF_None);
8580b57cec5SDimitry Andric   TempFile(TempFile &&Other);
8590b57cec5SDimitry Andric   TempFile &operator=(TempFile &&Other);
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric   // Name of the temporary file.
8620b57cec5SDimitry Andric   std::string TmpName;
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   // The open file descriptor.
8650b57cec5SDimitry Andric   int FD = -1;
8660b57cec5SDimitry Andric 
867349cc55cSDimitry Andric #ifdef _WIN32
868349cc55cSDimitry Andric   // Whether we need to manually remove the file on close.
869349cc55cSDimitry Andric   bool RemoveOnClose = false;
870349cc55cSDimitry Andric #endif
871349cc55cSDimitry Andric 
8720b57cec5SDimitry Andric   // Keep this with the given name.
8730b57cec5SDimitry Andric   Error keep(const Twine &Name);
8740b57cec5SDimitry Andric 
8750b57cec5SDimitry Andric   // Keep this with the temporary name.
8760b57cec5SDimitry Andric   Error keep();
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric   // Delete the file.
8790b57cec5SDimitry Andric   Error discard();
8800b57cec5SDimitry Andric 
8810b57cec5SDimitry Andric   // This checks that keep or delete was called.
8820b57cec5SDimitry Andric   ~TempFile();
8830b57cec5SDimitry Andric };
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric /// Create a file in the system temporary directory.
8860b57cec5SDimitry Andric ///
8870b57cec5SDimitry Andric /// The filename is of the form prefix-random_chars.suffix. Since the directory
8880b57cec5SDimitry Andric /// is not know to the caller, Prefix and Suffix cannot have path separators.
8890b57cec5SDimitry Andric /// The files are created with mode 0600.
8900b57cec5SDimitry Andric ///
8910b57cec5SDimitry Andric /// This should be used for things like a temporary .s that is removed after
8920b57cec5SDimitry Andric /// running the assembler.
8930b57cec5SDimitry Andric std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
8940b57cec5SDimitry Andric                                     int &ResultFD,
895fe6060f1SDimitry Andric                                     SmallVectorImpl<char> &ResultPath,
896fe6060f1SDimitry Andric                                     OpenFlags Flags = OF_None);
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric /// Simpler version for clients that don't want an open file. An empty
8990b57cec5SDimitry Andric /// file will still be created.
9000b57cec5SDimitry Andric std::error_code createTemporaryFile(const Twine &Prefix, StringRef Suffix,
901fe6060f1SDimitry Andric                                     SmallVectorImpl<char> &ResultPath,
902fe6060f1SDimitry Andric                                     OpenFlags Flags = OF_None);
9030b57cec5SDimitry Andric 
9040b57cec5SDimitry Andric std::error_code createUniqueDirectory(const Twine &Prefix,
9050b57cec5SDimitry Andric                                       SmallVectorImpl<char> &ResultPath);
9060b57cec5SDimitry Andric 
9070b57cec5SDimitry Andric /// Get a unique name, not currently exisiting in the filesystem. Subject
9080b57cec5SDimitry Andric /// to race conditions, prefer to use createUniqueFile instead.
9090b57cec5SDimitry Andric ///
9100b57cec5SDimitry Andric /// Similar to createUniqueFile, but instead of creating a file only
9110b57cec5SDimitry Andric /// checks if it exists. This function is subject to race conditions, if you
9120b57cec5SDimitry Andric /// want to use the returned name to actually create a file, use
9130b57cec5SDimitry Andric /// createUniqueFile instead.
9140b57cec5SDimitry Andric std::error_code getPotentiallyUniqueFileName(const Twine &Model,
9150b57cec5SDimitry Andric                                              SmallVectorImpl<char> &ResultPath);
9160b57cec5SDimitry Andric 
9170b57cec5SDimitry Andric /// Get a unique temporary file name, not currently exisiting in the
9180b57cec5SDimitry Andric /// filesystem. Subject to race conditions, prefer to use createTemporaryFile
9190b57cec5SDimitry Andric /// instead.
9200b57cec5SDimitry Andric ///
9210b57cec5SDimitry Andric /// Similar to createTemporaryFile, but instead of creating a file only
9220b57cec5SDimitry Andric /// checks if it exists. This function is subject to race conditions, if you
9230b57cec5SDimitry Andric /// want to use the returned name to actually create a file, use
9240b57cec5SDimitry Andric /// createTemporaryFile instead.
9250b57cec5SDimitry Andric std::error_code
9260b57cec5SDimitry Andric getPotentiallyUniqueTempFileName(const Twine &Prefix, StringRef Suffix,
9270b57cec5SDimitry Andric                                  SmallVectorImpl<char> &ResultPath);
9280b57cec5SDimitry Andric 
9290b57cec5SDimitry Andric inline OpenFlags operator|(OpenFlags A, OpenFlags B) {
9300b57cec5SDimitry Andric   return OpenFlags(unsigned(A) | unsigned(B));
9310b57cec5SDimitry Andric }
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric inline OpenFlags &operator|=(OpenFlags &A, OpenFlags B) {
9340b57cec5SDimitry Andric   A = A | B;
9350b57cec5SDimitry Andric   return A;
9360b57cec5SDimitry Andric }
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric inline FileAccess operator|(FileAccess A, FileAccess B) {
9390b57cec5SDimitry Andric   return FileAccess(unsigned(A) | unsigned(B));
9400b57cec5SDimitry Andric }
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric inline FileAccess &operator|=(FileAccess &A, FileAccess B) {
9430b57cec5SDimitry Andric   A = A | B;
9440b57cec5SDimitry Andric   return A;
9450b57cec5SDimitry Andric }
9460b57cec5SDimitry Andric 
9470b57cec5SDimitry Andric /// @brief Opens a file with the specified creation disposition, access mode,
9480b57cec5SDimitry Andric /// and flags and returns a file descriptor.
9490b57cec5SDimitry Andric ///
9500b57cec5SDimitry Andric /// The caller is responsible for closing the file descriptor once they are
9510b57cec5SDimitry Andric /// finished with it.
9520b57cec5SDimitry Andric ///
9530b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
9540b57cec5SDimitry Andric /// @param ResultFD If the file could be opened successfully, its descriptor
9550b57cec5SDimitry Andric ///                 is stored in this location. Otherwise, this is set to -1.
9560b57cec5SDimitry Andric /// @param Disp Value specifying the existing-file behavior.
9570b57cec5SDimitry Andric /// @param Access Value specifying whether to open the file in read, write, or
9580b57cec5SDimitry Andric ///               read-write mode.
9590b57cec5SDimitry Andric /// @param Flags Additional flags.
9600b57cec5SDimitry Andric /// @param Mode The access permissions of the file, represented in octal.
9610b57cec5SDimitry Andric /// @returns errc::success if \a Name has been opened, otherwise a
9620b57cec5SDimitry Andric ///          platform-specific error_code.
9630b57cec5SDimitry Andric std::error_code openFile(const Twine &Name, int &ResultFD,
9640b57cec5SDimitry Andric                          CreationDisposition Disp, FileAccess Access,
9650b57cec5SDimitry Andric                          OpenFlags Flags, unsigned Mode = 0666);
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric /// @brief Opens a file with the specified creation disposition, access mode,
9680b57cec5SDimitry Andric /// and flags and returns a platform-specific file object.
9690b57cec5SDimitry Andric ///
9700b57cec5SDimitry Andric /// The caller is responsible for closing the file object once they are
9710b57cec5SDimitry Andric /// finished with it.
9720b57cec5SDimitry Andric ///
9730b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
9740b57cec5SDimitry Andric /// @param Disp Value specifying the existing-file behavior.
9750b57cec5SDimitry Andric /// @param Access Value specifying whether to open the file in read, write, or
9760b57cec5SDimitry Andric ///               read-write mode.
9770b57cec5SDimitry Andric /// @param Flags Additional flags.
9780b57cec5SDimitry Andric /// @param Mode The access permissions of the file, represented in octal.
9790b57cec5SDimitry Andric /// @returns errc::success if \a Name has been opened, otherwise a
9800b57cec5SDimitry Andric ///          platform-specific error_code.
9810b57cec5SDimitry Andric Expected<file_t> openNativeFile(const Twine &Name, CreationDisposition Disp,
9820b57cec5SDimitry Andric                                 FileAccess Access, OpenFlags Flags,
9830b57cec5SDimitry Andric                                 unsigned Mode = 0666);
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric /// Converts from a Posix file descriptor number to a native file handle.
9860b57cec5SDimitry Andric /// On Windows, this retreives the underlying handle. On non-Windows, this is a
9870b57cec5SDimitry Andric /// no-op.
9880b57cec5SDimitry Andric file_t convertFDToNativeFile(int FD);
9890b57cec5SDimitry Andric 
9900b57cec5SDimitry Andric #ifndef _WIN32
convertFDToNativeFile(int FD)9910b57cec5SDimitry Andric inline file_t convertFDToNativeFile(int FD) { return FD; }
9920b57cec5SDimitry Andric #endif
9930b57cec5SDimitry Andric 
9940b57cec5SDimitry Andric /// Return an open handle to standard in. On Unix, this is typically FD 0.
9950b57cec5SDimitry Andric /// Returns kInvalidFile when the stream is closed.
9960b57cec5SDimitry Andric file_t getStdinHandle();
9970b57cec5SDimitry Andric 
9980b57cec5SDimitry Andric /// Return an open handle to standard out. On Unix, this is typically FD 1.
9990b57cec5SDimitry Andric /// Returns kInvalidFile when the stream is closed.
10000b57cec5SDimitry Andric file_t getStdoutHandle();
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric /// Return an open handle to standard error. On Unix, this is typically FD 2.
10030b57cec5SDimitry Andric /// Returns kInvalidFile when the stream is closed.
10040b57cec5SDimitry Andric file_t getStderrHandle();
10050b57cec5SDimitry Andric 
10068bcb0991SDimitry Andric /// Reads \p Buf.size() bytes from \p FileHandle into \p Buf. Returns the number
10078bcb0991SDimitry Andric /// of bytes actually read. On Unix, this is equivalent to `return ::read(FD,
10088bcb0991SDimitry Andric /// Buf.data(), Buf.size())`, with error reporting. Returns 0 when reaching EOF.
10090b57cec5SDimitry Andric ///
10100b57cec5SDimitry Andric /// @param FileHandle File to read from.
10110b57cec5SDimitry Andric /// @param Buf Buffer to read into.
10128bcb0991SDimitry Andric /// @returns The number of bytes read, or error.
10138bcb0991SDimitry Andric Expected<size_t> readNativeFile(file_t FileHandle, MutableArrayRef<char> Buf);
10140b57cec5SDimitry Andric 
101504eeddc0SDimitry Andric /// Default chunk size for \a readNativeFileToEOF().
101604eeddc0SDimitry Andric enum : size_t { DefaultReadChunkSize = 4 * 4096 };
101704eeddc0SDimitry Andric 
101804eeddc0SDimitry Andric /// Reads from \p FileHandle until EOF, appending to \p Buffer in chunks of
101904eeddc0SDimitry Andric /// size \p ChunkSize.
102004eeddc0SDimitry Andric ///
102104eeddc0SDimitry Andric /// This calls \a readNativeFile() in a loop. On Error, previous chunks that
102204eeddc0SDimitry Andric /// were read successfully are left in \p Buffer and returned.
102304eeddc0SDimitry Andric ///
102404eeddc0SDimitry Andric /// Note: For reading the final chunk at EOF, \p Buffer's capacity needs extra
102504eeddc0SDimitry Andric /// storage of \p ChunkSize.
102604eeddc0SDimitry Andric ///
102704eeddc0SDimitry Andric /// \param FileHandle File to read from.
102804eeddc0SDimitry Andric /// \param Buffer Where to put the file content.
102904eeddc0SDimitry Andric /// \param ChunkSize Size of chunks.
103004eeddc0SDimitry Andric /// \returns The error if EOF was not found.
103104eeddc0SDimitry Andric Error readNativeFileToEOF(file_t FileHandle, SmallVectorImpl<char> &Buffer,
103204eeddc0SDimitry Andric                           ssize_t ChunkSize = DefaultReadChunkSize);
103304eeddc0SDimitry Andric 
10340b57cec5SDimitry Andric /// Reads \p Buf.size() bytes from \p FileHandle at offset \p Offset into \p
10350b57cec5SDimitry Andric /// Buf. If 'pread' is available, this will use that, otherwise it will use
10368bcb0991SDimitry Andric /// 'lseek'. Returns the number of bytes actually read. Returns 0 when reaching
10378bcb0991SDimitry Andric /// EOF.
10380b57cec5SDimitry Andric ///
10390b57cec5SDimitry Andric /// @param FileHandle File to read from.
10400b57cec5SDimitry Andric /// @param Buf Buffer to read into.
10410b57cec5SDimitry Andric /// @param Offset Offset into the file at which the read should occur.
10428bcb0991SDimitry Andric /// @returns The number of bytes read, or error.
10438bcb0991SDimitry Andric Expected<size_t> readNativeFileSlice(file_t FileHandle,
10448bcb0991SDimitry Andric                                      MutableArrayRef<char> Buf,
10458bcb0991SDimitry Andric                                      uint64_t Offset);
10460b57cec5SDimitry Andric 
10470b57cec5SDimitry Andric /// @brief Opens the file with the given name in a write-only or read-write
10480b57cec5SDimitry Andric /// mode, returning its open file descriptor. If the file does not exist, it
10490b57cec5SDimitry Andric /// is created.
10500b57cec5SDimitry Andric ///
10510b57cec5SDimitry Andric /// The caller is responsible for closing the file descriptor once they are
10520b57cec5SDimitry Andric /// finished with it.
10530b57cec5SDimitry Andric ///
10540b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
10550b57cec5SDimitry Andric /// @param ResultFD If the file could be opened successfully, its descriptor
10560b57cec5SDimitry Andric ///                 is stored in this location. Otherwise, this is set to -1.
10570b57cec5SDimitry Andric /// @param Flags Additional flags used to determine whether the file should be
10580b57cec5SDimitry Andric ///              opened in, for example, read-write or in write-only mode.
10590b57cec5SDimitry Andric /// @param Mode The access permissions of the file, represented in octal.
10600b57cec5SDimitry Andric /// @returns errc::success if \a Name has been opened, otherwise a
10610b57cec5SDimitry Andric ///          platform-specific error_code.
10620b57cec5SDimitry Andric inline std::error_code
10630b57cec5SDimitry Andric openFileForWrite(const Twine &Name, int &ResultFD,
10640b57cec5SDimitry Andric                  CreationDisposition Disp = CD_CreateAlways,
10650b57cec5SDimitry Andric                  OpenFlags Flags = OF_None, unsigned Mode = 0666) {
10660b57cec5SDimitry Andric   return openFile(Name, ResultFD, Disp, FA_Write, Flags, Mode);
10670b57cec5SDimitry Andric }
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric /// @brief Opens the file with the given name in a write-only or read-write
10700b57cec5SDimitry Andric /// mode, returning its open file descriptor. If the file does not exist, it
10710b57cec5SDimitry Andric /// is created.
10720b57cec5SDimitry Andric ///
10730b57cec5SDimitry Andric /// The caller is responsible for closing the freeing the file once they are
10740b57cec5SDimitry Andric /// finished with it.
10750b57cec5SDimitry Andric ///
10760b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
10770b57cec5SDimitry Andric /// @param Flags Additional flags used to determine whether the file should be
10780b57cec5SDimitry Andric ///              opened in, for example, read-write or in write-only mode.
10790b57cec5SDimitry Andric /// @param Mode The access permissions of the file, represented in octal.
10800b57cec5SDimitry Andric /// @returns a platform-specific file descriptor if \a Name has been opened,
10810b57cec5SDimitry Andric ///          otherwise an error object.
10820b57cec5SDimitry Andric inline Expected<file_t> openNativeFileForWrite(const Twine &Name,
10830b57cec5SDimitry Andric                                                CreationDisposition Disp,
10840b57cec5SDimitry Andric                                                OpenFlags Flags,
10850b57cec5SDimitry Andric                                                unsigned Mode = 0666) {
10860b57cec5SDimitry Andric   return openNativeFile(Name, Disp, FA_Write, Flags, Mode);
10870b57cec5SDimitry Andric }
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric /// @brief Opens the file with the given name in a write-only or read-write
10900b57cec5SDimitry Andric /// mode, returning its open file descriptor. If the file does not exist, it
10910b57cec5SDimitry Andric /// is created.
10920b57cec5SDimitry Andric ///
10930b57cec5SDimitry Andric /// The caller is responsible for closing the file descriptor once they are
10940b57cec5SDimitry Andric /// finished with it.
10950b57cec5SDimitry Andric ///
10960b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
10970b57cec5SDimitry Andric /// @param ResultFD If the file could be opened successfully, its descriptor
10980b57cec5SDimitry Andric ///                 is stored in this location. Otherwise, this is set to -1.
10990b57cec5SDimitry Andric /// @param Flags Additional flags used to determine whether the file should be
11000b57cec5SDimitry Andric ///              opened in, for example, read-write or in write-only mode.
11010b57cec5SDimitry Andric /// @param Mode The access permissions of the file, represented in octal.
11020b57cec5SDimitry Andric /// @returns errc::success if \a Name has been opened, otherwise a
11030b57cec5SDimitry Andric ///          platform-specific error_code.
11040b57cec5SDimitry Andric inline std::error_code openFileForReadWrite(const Twine &Name, int &ResultFD,
11050b57cec5SDimitry Andric                                             CreationDisposition Disp,
11060b57cec5SDimitry Andric                                             OpenFlags Flags,
11070b57cec5SDimitry Andric                                             unsigned Mode = 0666) {
11080b57cec5SDimitry Andric   return openFile(Name, ResultFD, Disp, FA_Write | FA_Read, Flags, Mode);
11090b57cec5SDimitry Andric }
11100b57cec5SDimitry Andric 
11110b57cec5SDimitry Andric /// @brief Opens the file with the given name in a write-only or read-write
11120b57cec5SDimitry Andric /// mode, returning its open file descriptor. If the file does not exist, it
11130b57cec5SDimitry Andric /// is created.
11140b57cec5SDimitry Andric ///
11150b57cec5SDimitry Andric /// The caller is responsible for closing the freeing the file once they are
11160b57cec5SDimitry Andric /// finished with it.
11170b57cec5SDimitry Andric ///
11180b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
11190b57cec5SDimitry Andric /// @param Flags Additional flags used to determine whether the file should be
11200b57cec5SDimitry Andric ///              opened in, for example, read-write or in write-only mode.
11210b57cec5SDimitry Andric /// @param Mode The access permissions of the file, represented in octal.
11220b57cec5SDimitry Andric /// @returns a platform-specific file descriptor if \a Name has been opened,
11230b57cec5SDimitry Andric ///          otherwise an error object.
11240b57cec5SDimitry Andric inline Expected<file_t> openNativeFileForReadWrite(const Twine &Name,
11250b57cec5SDimitry Andric                                                    CreationDisposition Disp,
11260b57cec5SDimitry Andric                                                    OpenFlags Flags,
11270b57cec5SDimitry Andric                                                    unsigned Mode = 0666) {
11280b57cec5SDimitry Andric   return openNativeFile(Name, Disp, FA_Write | FA_Read, Flags, Mode);
11290b57cec5SDimitry Andric }
11300b57cec5SDimitry Andric 
11310b57cec5SDimitry Andric /// @brief Opens the file with the given name in a read-only mode, returning
11320b57cec5SDimitry Andric /// its open file descriptor.
11330b57cec5SDimitry Andric ///
11340b57cec5SDimitry Andric /// The caller is responsible for closing the file descriptor once they are
11350b57cec5SDimitry Andric /// finished with it.
11360b57cec5SDimitry Andric ///
11370b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
11380b57cec5SDimitry Andric /// @param ResultFD If the file could be opened successfully, its descriptor
11390b57cec5SDimitry Andric ///                 is stored in this location. Otherwise, this is set to -1.
11400b57cec5SDimitry Andric /// @param RealPath If nonnull, extra work is done to determine the real path
11410b57cec5SDimitry Andric ///                 of the opened file, and that path is stored in this
11420b57cec5SDimitry Andric ///                 location.
11430b57cec5SDimitry Andric /// @returns errc::success if \a Name has been opened, otherwise a
11440b57cec5SDimitry Andric ///          platform-specific error_code.
11450b57cec5SDimitry Andric std::error_code openFileForRead(const Twine &Name, int &ResultFD,
11460b57cec5SDimitry Andric                                 OpenFlags Flags = OF_None,
11470b57cec5SDimitry Andric                                 SmallVectorImpl<char> *RealPath = nullptr);
11480b57cec5SDimitry Andric 
11490b57cec5SDimitry Andric /// @brief Opens the file with the given name in a read-only mode, returning
11500b57cec5SDimitry Andric /// its open file descriptor.
11510b57cec5SDimitry Andric ///
11520b57cec5SDimitry Andric /// The caller is responsible for closing the freeing the file once they are
11530b57cec5SDimitry Andric /// finished with it.
11540b57cec5SDimitry Andric ///
11550b57cec5SDimitry Andric /// @param Name The path of the file to open, relative or absolute.
11560b57cec5SDimitry Andric /// @param RealPath If nonnull, extra work is done to determine the real path
11570b57cec5SDimitry Andric ///                 of the opened file, and that path is stored in this
11580b57cec5SDimitry Andric ///                 location.
11590b57cec5SDimitry Andric /// @returns a platform-specific file descriptor if \a Name has been opened,
11600b57cec5SDimitry Andric ///          otherwise an error object.
11610b57cec5SDimitry Andric Expected<file_t>
11620b57cec5SDimitry Andric openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None,
11630b57cec5SDimitry Andric                       SmallVectorImpl<char> *RealPath = nullptr);
11640b57cec5SDimitry Andric 
1165e8d8bef9SDimitry Andric /// Try to locks the file during the specified time.
1166e8d8bef9SDimitry Andric ///
1167e8d8bef9SDimitry Andric /// This function implements advisory locking on entire file. If it returns
1168e8d8bef9SDimitry Andric /// <em>errc::success</em>, the file is locked by the calling process. Until the
1169e8d8bef9SDimitry Andric /// process unlocks the file by calling \a unlockFile, all attempts to lock the
1170e8d8bef9SDimitry Andric /// same file will fail/block. The process that locked the file may assume that
1171e8d8bef9SDimitry Andric /// none of other processes read or write this file, provided that all processes
1172e8d8bef9SDimitry Andric /// lock the file prior to accessing its content.
1173e8d8bef9SDimitry Andric ///
1174e8d8bef9SDimitry Andric /// @param FD      The descriptor representing the file to lock.
1175e8d8bef9SDimitry Andric /// @param Timeout Time in milliseconds that the process should wait before
1176e8d8bef9SDimitry Andric ///                reporting lock failure. Zero value means try to get lock only
1177e8d8bef9SDimitry Andric ///                once.
1178e8d8bef9SDimitry Andric /// @returns errc::success if lock is successfully obtained,
1179e8d8bef9SDimitry Andric /// errc::no_lock_available if the file cannot be locked, or platform-specific
1180e8d8bef9SDimitry Andric /// error_code otherwise.
1181e8d8bef9SDimitry Andric ///
1182e8d8bef9SDimitry Andric /// @note Care should be taken when using this function in a multithreaded
1183e8d8bef9SDimitry Andric /// context, as it may not prevent other threads in the same process from
1184e8d8bef9SDimitry Andric /// obtaining a lock on the same file, even if they are using a different file
1185e8d8bef9SDimitry Andric /// descriptor.
1186e8d8bef9SDimitry Andric std::error_code
1187e8d8bef9SDimitry Andric tryLockFile(int FD,
1188e8d8bef9SDimitry Andric             std::chrono::milliseconds Timeout = std::chrono::milliseconds(0));
1189e8d8bef9SDimitry Andric 
1190e8d8bef9SDimitry Andric /// Lock the file.
1191e8d8bef9SDimitry Andric ///
1192e8d8bef9SDimitry Andric /// This function acts as @ref tryLockFile but it waits infinitely.
1193e8d8bef9SDimitry Andric std::error_code lockFile(int FD);
1194e8d8bef9SDimitry Andric 
1195e8d8bef9SDimitry Andric /// Unlock the file.
1196e8d8bef9SDimitry Andric ///
1197e8d8bef9SDimitry Andric /// @param FD The descriptor representing the file to unlock.
1198e8d8bef9SDimitry Andric /// @returns errc::success if lock is successfully released or platform-specific
1199e8d8bef9SDimitry Andric /// error_code otherwise.
1200e8d8bef9SDimitry Andric std::error_code unlockFile(int FD);
1201e8d8bef9SDimitry Andric 
12020b57cec5SDimitry Andric /// @brief Close the file object.  This should be used instead of ::close for
12030b57cec5SDimitry Andric /// portability. On error, the caller should assume the file is closed, as is
12040b57cec5SDimitry Andric /// the case for Process::SafelyCloseFileDescriptor
12050b57cec5SDimitry Andric ///
12060b57cec5SDimitry Andric /// @param F On input, this is the file to close.  On output, the file is
12070b57cec5SDimitry Andric /// set to kInvalidFile.
12080b57cec5SDimitry Andric ///
12090b57cec5SDimitry Andric /// @returns An error code if closing the file failed. Typically, an error here
12100b57cec5SDimitry Andric /// means that the filesystem may have failed to perform some buffered writes.
12110b57cec5SDimitry Andric std::error_code closeFile(file_t &F);
12120b57cec5SDimitry Andric 
1213fe6060f1SDimitry Andric #ifdef LLVM_ON_UNIX
1214fe6060f1SDimitry Andric /// @brief Change ownership of a file.
1215fe6060f1SDimitry Andric ///
1216fe6060f1SDimitry Andric /// @param Owner The owner of the file to change to.
1217fe6060f1SDimitry Andric /// @param Group The group of the file to change to.
1218fe6060f1SDimitry Andric /// @returns errc::success if successfully updated file ownership, otherwise an
1219fe6060f1SDimitry Andric ///          error code is returned.
1220fe6060f1SDimitry Andric std::error_code changeFileOwnership(int FD, uint32_t Owner, uint32_t Group);
1221fe6060f1SDimitry Andric #endif
1222fe6060f1SDimitry Andric 
1223e8d8bef9SDimitry Andric /// RAII class that facilitates file locking.
1224e8d8bef9SDimitry Andric class FileLocker {
1225e8d8bef9SDimitry Andric   int FD; ///< Locked file handle.
FileLocker(int FD)1226e8d8bef9SDimitry Andric   FileLocker(int FD) : FD(FD) {}
1227e8d8bef9SDimitry Andric   friend class llvm::raw_fd_ostream;
1228e8d8bef9SDimitry Andric 
1229e8d8bef9SDimitry Andric public:
1230e8d8bef9SDimitry Andric   FileLocker(const FileLocker &L) = delete;
FileLocker(FileLocker && L)1231e8d8bef9SDimitry Andric   FileLocker(FileLocker &&L) : FD(L.FD) { L.FD = -1; }
~FileLocker()1232e8d8bef9SDimitry Andric   ~FileLocker() {
1233e8d8bef9SDimitry Andric     if (FD != -1)
1234e8d8bef9SDimitry Andric       unlockFile(FD);
1235e8d8bef9SDimitry Andric   }
1236e8d8bef9SDimitry Andric   FileLocker &operator=(FileLocker &&L) {
1237e8d8bef9SDimitry Andric     FD = L.FD;
1238e8d8bef9SDimitry Andric     L.FD = -1;
1239e8d8bef9SDimitry Andric     return *this;
1240e8d8bef9SDimitry Andric   }
1241e8d8bef9SDimitry Andric   FileLocker &operator=(const FileLocker &L) = delete;
unlock()1242e8d8bef9SDimitry Andric   std::error_code unlock() {
1243e8d8bef9SDimitry Andric     if (FD != -1) {
1244e8d8bef9SDimitry Andric       std::error_code Result = unlockFile(FD);
1245e8d8bef9SDimitry Andric       FD = -1;
1246e8d8bef9SDimitry Andric       return Result;
1247e8d8bef9SDimitry Andric     }
1248e8d8bef9SDimitry Andric     return std::error_code();
1249e8d8bef9SDimitry Andric   }
1250e8d8bef9SDimitry Andric };
1251e8d8bef9SDimitry Andric 
12520b57cec5SDimitry Andric std::error_code getUniqueID(const Twine Path, UniqueID &Result);
12530b57cec5SDimitry Andric 
12540b57cec5SDimitry Andric /// Get disk space usage information.
12550b57cec5SDimitry Andric ///
12560b57cec5SDimitry Andric /// Note: Users must be careful about "Time Of Check, Time Of Use" kind of bug.
12570b57cec5SDimitry Andric /// Note: Windows reports results according to the quota allocated to the user.
12580b57cec5SDimitry Andric ///
12590b57cec5SDimitry Andric /// @param Path Input path.
12600b57cec5SDimitry Andric /// @returns a space_info structure filled with the capacity, free, and
12610b57cec5SDimitry Andric /// available space on the device \a Path is on. A platform specific error_code
12620b57cec5SDimitry Andric /// is returned on error.
12630b57cec5SDimitry Andric ErrorOr<space_info> disk_space(const Twine &Path);
12640b57cec5SDimitry Andric 
12650b57cec5SDimitry Andric /// This class represents a memory mapped file. It is based on
12660b57cec5SDimitry Andric /// boost::iostreams::mapped_file.
12670b57cec5SDimitry Andric class mapped_file_region {
12680b57cec5SDimitry Andric public:
12690b57cec5SDimitry Andric   enum mapmode {
12700b57cec5SDimitry Andric     readonly, ///< May only access map via const_data as read only.
12710b57cec5SDimitry Andric     readwrite, ///< May access map via data and modify it. Written to path.
12720b57cec5SDimitry Andric     priv ///< May modify via data, but changes are lost on destruction.
12730b57cec5SDimitry Andric   };
12740b57cec5SDimitry Andric 
12750b57cec5SDimitry Andric private:
12760b57cec5SDimitry Andric   /// Platform-specific mapping state.
1277fe6060f1SDimitry Andric   size_t Size = 0;
1278fe6060f1SDimitry Andric   void *Mapping = nullptr;
12790b57cec5SDimitry Andric #ifdef _WIN32
1280fe6060f1SDimitry Andric   sys::fs::file_t FileHandle = nullptr;
12810b57cec5SDimitry Andric #endif
1282fe6060f1SDimitry Andric   mapmode Mode = readonly;
1283fe6060f1SDimitry Andric 
copyFrom(const mapped_file_region & Copied)1284fe6060f1SDimitry Andric   void copyFrom(const mapped_file_region &Copied) {
1285fe6060f1SDimitry Andric     Size = Copied.Size;
1286fe6060f1SDimitry Andric     Mapping = Copied.Mapping;
1287fe6060f1SDimitry Andric #ifdef _WIN32
1288fe6060f1SDimitry Andric     FileHandle = Copied.FileHandle;
1289fe6060f1SDimitry Andric #endif
1290fe6060f1SDimitry Andric     Mode = Copied.Mode;
1291fe6060f1SDimitry Andric   }
1292fe6060f1SDimitry Andric 
moveFromImpl(mapped_file_region & Moved)1293fe6060f1SDimitry Andric   void moveFromImpl(mapped_file_region &Moved) {
1294fe6060f1SDimitry Andric     copyFrom(Moved);
1295fe6060f1SDimitry Andric     Moved.copyFrom(mapped_file_region());
1296fe6060f1SDimitry Andric   }
1297fe6060f1SDimitry Andric 
1298fe6060f1SDimitry Andric   void unmapImpl();
129904eeddc0SDimitry Andric   void dontNeedImpl();
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric   std::error_code init(sys::fs::file_t FD, uint64_t Offset, mapmode Mode);
13020b57cec5SDimitry Andric 
13030b57cec5SDimitry Andric public:
1304fe6060f1SDimitry Andric   mapped_file_region() = default;
mapped_file_region(mapped_file_region && Moved)1305fe6060f1SDimitry Andric   mapped_file_region(mapped_file_region &&Moved) { moveFromImpl(Moved); }
1306fe6060f1SDimitry Andric   mapped_file_region &operator=(mapped_file_region &&Moved) {
1307fe6060f1SDimitry Andric     unmap();
1308fe6060f1SDimitry Andric     moveFromImpl(Moved);
1309fe6060f1SDimitry Andric     return *this;
1310fe6060f1SDimitry Andric   }
1311fe6060f1SDimitry Andric 
1312fe6060f1SDimitry Andric   mapped_file_region(const mapped_file_region &) = delete;
1313fe6060f1SDimitry Andric   mapped_file_region &operator=(const mapped_file_region &) = delete;
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric   /// \param fd An open file descriptor to map. Does not take ownership of fd.
13160b57cec5SDimitry Andric   mapped_file_region(sys::fs::file_t fd, mapmode mode, size_t length, uint64_t offset,
13170b57cec5SDimitry Andric                      std::error_code &ec);
13180b57cec5SDimitry Andric 
~mapped_file_region()1319fe6060f1SDimitry Andric   ~mapped_file_region() { unmapImpl(); }
1320fe6060f1SDimitry Andric 
1321fe6060f1SDimitry Andric   /// Check if this is a valid mapping.
1322fe6060f1SDimitry Andric   explicit operator bool() const { return Mapping; }
1323fe6060f1SDimitry Andric 
1324fe6060f1SDimitry Andric   /// Unmap.
unmap()1325fe6060f1SDimitry Andric   void unmap() {
1326fe6060f1SDimitry Andric     unmapImpl();
1327fe6060f1SDimitry Andric     copyFrom(mapped_file_region());
1328fe6060f1SDimitry Andric   }
dontNeed()132904eeddc0SDimitry Andric   void dontNeed() { dontNeedImpl(); }
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric   size_t size() const;
13320b57cec5SDimitry Andric   char *data() const;
13330b57cec5SDimitry Andric 
13340b57cec5SDimitry Andric   /// Get a const view of the data. Modifying this memory has undefined
13350b57cec5SDimitry Andric   /// behavior.
13360b57cec5SDimitry Andric   const char *const_data() const;
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric   /// \returns The minimum alignment offset must be.
13390b57cec5SDimitry Andric   static int alignment();
13400b57cec5SDimitry Andric };
13410b57cec5SDimitry Andric 
13420b57cec5SDimitry Andric /// Return the path to the main executable, given the value of argv[0] from
13430b57cec5SDimitry Andric /// program startup and the address of main itself. In extremis, this function
13440b57cec5SDimitry Andric /// may fail and return an empty path.
13450b57cec5SDimitry Andric std::string getMainExecutable(const char *argv0, void *MainExecAddr);
13460b57cec5SDimitry Andric 
13470b57cec5SDimitry Andric /// @}
13480b57cec5SDimitry Andric /// @name Iterators
13490b57cec5SDimitry Andric /// @{
13500b57cec5SDimitry Andric 
13510b57cec5SDimitry Andric /// directory_entry - A single entry in a directory.
13520b57cec5SDimitry Andric class directory_entry {
13530b57cec5SDimitry Andric   // FIXME: different platforms make different information available "for free"
13540b57cec5SDimitry Andric   // when traversing a directory. The design of this class wraps most of the
13550b57cec5SDimitry Andric   // information in basic_file_status, so on platforms where we can't populate
13560b57cec5SDimitry Andric   // that whole structure, callers end up paying for a stat().
13570b57cec5SDimitry Andric   // std::filesystem::directory_entry may be a better model.
13580b57cec5SDimitry Andric   std::string Path;
13598bcb0991SDimitry Andric   file_type Type = file_type::type_unknown; // Most platforms can provide this.
13608bcb0991SDimitry Andric   bool FollowSymlinks = true;               // Affects the behavior of status().
13610b57cec5SDimitry Andric   basic_file_status Status;                 // If available.
13620b57cec5SDimitry Andric 
13630b57cec5SDimitry Andric public:
13640b57cec5SDimitry Andric   explicit directory_entry(const Twine &Path, bool FollowSymlinks = true,
13650b57cec5SDimitry Andric                            file_type Type = file_type::type_unknown,
13660b57cec5SDimitry Andric                            basic_file_status Status = basic_file_status())
13670b57cec5SDimitry Andric       : Path(Path.str()), Type(Type), FollowSymlinks(FollowSymlinks),
13680b57cec5SDimitry Andric         Status(Status) {}
13690b57cec5SDimitry Andric 
13700b57cec5SDimitry Andric   directory_entry() = default;
13710b57cec5SDimitry Andric 
13720b57cec5SDimitry Andric   void replace_filename(const Twine &Filename, file_type Type,
13730b57cec5SDimitry Andric                         basic_file_status Status = basic_file_status());
13740b57cec5SDimitry Andric 
path()13750b57cec5SDimitry Andric   const std::string &path() const { return Path; }
13760b57cec5SDimitry Andric   // Get basic information about entry file (a subset of fs::status()).
13770b57cec5SDimitry Andric   // On most platforms this is a stat() call.
13780b57cec5SDimitry Andric   // On windows the information was already retrieved from the directory.
13790b57cec5SDimitry Andric   ErrorOr<basic_file_status> status() const;
13800b57cec5SDimitry Andric   // Get the type of this file.
13810b57cec5SDimitry Andric   // On most platforms (Linux/Mac/Windows/BSD), this was already retrieved.
13820b57cec5SDimitry Andric   // On some platforms (e.g. Solaris) this is a stat() call.
type()13830b57cec5SDimitry Andric   file_type type() const {
13840b57cec5SDimitry Andric     if (Type != file_type::type_unknown)
13850b57cec5SDimitry Andric       return Type;
13860b57cec5SDimitry Andric     auto S = status();
13870b57cec5SDimitry Andric     return S ? S->type() : file_type::type_unknown;
13880b57cec5SDimitry Andric   }
13890b57cec5SDimitry Andric 
13900b57cec5SDimitry Andric   bool operator==(const directory_entry& RHS) const { return Path == RHS.Path; }
13910b57cec5SDimitry Andric   bool operator!=(const directory_entry& RHS) const { return !(*this == RHS); }
13920b57cec5SDimitry Andric   bool operator< (const directory_entry& RHS) const;
13930b57cec5SDimitry Andric   bool operator<=(const directory_entry& RHS) const;
13940b57cec5SDimitry Andric   bool operator> (const directory_entry& RHS) const;
13950b57cec5SDimitry Andric   bool operator>=(const directory_entry& RHS) const;
13960b57cec5SDimitry Andric };
13970b57cec5SDimitry Andric 
13980b57cec5SDimitry Andric namespace detail {
13990b57cec5SDimitry Andric 
14000b57cec5SDimitry Andric   struct DirIterState;
14010b57cec5SDimitry Andric 
14020b57cec5SDimitry Andric   std::error_code directory_iterator_construct(DirIterState &, StringRef, bool);
14030b57cec5SDimitry Andric   std::error_code directory_iterator_increment(DirIterState &);
14040b57cec5SDimitry Andric   std::error_code directory_iterator_destruct(DirIterState &);
14050b57cec5SDimitry Andric 
14060b57cec5SDimitry Andric   /// Keeps state for the directory_iterator.
14070b57cec5SDimitry Andric   struct DirIterState {
~DirIterStateDirIterState14080b57cec5SDimitry Andric     ~DirIterState() {
14090b57cec5SDimitry Andric       directory_iterator_destruct(*this);
14100b57cec5SDimitry Andric     }
14110b57cec5SDimitry Andric 
14120b57cec5SDimitry Andric     intptr_t IterationHandle = 0;
14130b57cec5SDimitry Andric     directory_entry CurrentEntry;
14140b57cec5SDimitry Andric   };
14150b57cec5SDimitry Andric 
14160b57cec5SDimitry Andric } // end namespace detail
14170b57cec5SDimitry Andric 
14180b57cec5SDimitry Andric /// directory_iterator - Iterates through the entries in path. There is no
14190b57cec5SDimitry Andric /// operator++ because we need an error_code. If it's really needed we can make
14200b57cec5SDimitry Andric /// it call report_fatal_error on error.
14210b57cec5SDimitry Andric class directory_iterator {
14220b57cec5SDimitry Andric   std::shared_ptr<detail::DirIterState> State;
14230b57cec5SDimitry Andric   bool FollowSymlinks = true;
14240b57cec5SDimitry Andric 
14250b57cec5SDimitry Andric public:
14260b57cec5SDimitry Andric   explicit directory_iterator(const Twine &path, std::error_code &ec,
14270b57cec5SDimitry Andric                               bool follow_symlinks = true)
FollowSymlinks(follow_symlinks)14280b57cec5SDimitry Andric       : FollowSymlinks(follow_symlinks) {
14290b57cec5SDimitry Andric     State = std::make_shared<detail::DirIterState>();
14300b57cec5SDimitry Andric     SmallString<128> path_storage;
14310b57cec5SDimitry Andric     ec = detail::directory_iterator_construct(
14320b57cec5SDimitry Andric         *State, path.toStringRef(path_storage), FollowSymlinks);
14330b57cec5SDimitry Andric   }
14340b57cec5SDimitry Andric 
14350b57cec5SDimitry Andric   explicit directory_iterator(const directory_entry &de, std::error_code &ec,
14360b57cec5SDimitry Andric                               bool follow_symlinks = true)
FollowSymlinks(follow_symlinks)14370b57cec5SDimitry Andric       : FollowSymlinks(follow_symlinks) {
14380b57cec5SDimitry Andric     State = std::make_shared<detail::DirIterState>();
14390b57cec5SDimitry Andric     ec = detail::directory_iterator_construct(
14400b57cec5SDimitry Andric         *State, de.path(), FollowSymlinks);
14410b57cec5SDimitry Andric   }
14420b57cec5SDimitry Andric 
14430b57cec5SDimitry Andric   /// Construct end iterator.
14440b57cec5SDimitry Andric   directory_iterator() = default;
14450b57cec5SDimitry Andric 
14460b57cec5SDimitry Andric   // No operator++ because we need error_code.
increment(std::error_code & ec)14470b57cec5SDimitry Andric   directory_iterator &increment(std::error_code &ec) {
14480b57cec5SDimitry Andric     ec = directory_iterator_increment(*State);
14490b57cec5SDimitry Andric     return *this;
14500b57cec5SDimitry Andric   }
14510b57cec5SDimitry Andric 
14520b57cec5SDimitry Andric   const directory_entry &operator*() const { return State->CurrentEntry; }
14530b57cec5SDimitry Andric   const directory_entry *operator->() const { return &State->CurrentEntry; }
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric   bool operator==(const directory_iterator &RHS) const {
14560b57cec5SDimitry Andric     if (State == RHS.State)
14570b57cec5SDimitry Andric       return true;
14580b57cec5SDimitry Andric     if (!RHS.State)
14590b57cec5SDimitry Andric       return State->CurrentEntry == directory_entry();
14600b57cec5SDimitry Andric     if (!State)
14610b57cec5SDimitry Andric       return RHS.State->CurrentEntry == directory_entry();
14620b57cec5SDimitry Andric     return State->CurrentEntry == RHS.State->CurrentEntry;
14630b57cec5SDimitry Andric   }
14640b57cec5SDimitry Andric 
14650b57cec5SDimitry Andric   bool operator!=(const directory_iterator &RHS) const {
14660b57cec5SDimitry Andric     return !(*this == RHS);
14670b57cec5SDimitry Andric   }
14680b57cec5SDimitry Andric };
14690b57cec5SDimitry Andric 
14700b57cec5SDimitry Andric namespace detail {
14710b57cec5SDimitry Andric 
14720b57cec5SDimitry Andric   /// Keeps state for the recursive_directory_iterator.
14730b57cec5SDimitry Andric   struct RecDirIterState {
14740b57cec5SDimitry Andric     std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
14750b57cec5SDimitry Andric     uint16_t Level = 0;
14760b57cec5SDimitry Andric     bool HasNoPushRequest = false;
14770b57cec5SDimitry Andric   };
14780b57cec5SDimitry Andric 
14790b57cec5SDimitry Andric } // end namespace detail
14800b57cec5SDimitry Andric 
14810b57cec5SDimitry Andric /// recursive_directory_iterator - Same as directory_iterator except for it
14820b57cec5SDimitry Andric /// recurses down into child directories.
14830b57cec5SDimitry Andric class recursive_directory_iterator {
14840b57cec5SDimitry Andric   std::shared_ptr<detail::RecDirIterState> State;
14850b57cec5SDimitry Andric   bool Follow;
14860b57cec5SDimitry Andric 
14870b57cec5SDimitry Andric public:
14880b57cec5SDimitry Andric   recursive_directory_iterator() = default;
14890b57cec5SDimitry Andric   explicit recursive_directory_iterator(const Twine &path, std::error_code &ec,
14900b57cec5SDimitry Andric                                         bool follow_symlinks = true)
State(std::make_shared<detail::RecDirIterState> ())14910b57cec5SDimitry Andric       : State(std::make_shared<detail::RecDirIterState>()),
14920b57cec5SDimitry Andric         Follow(follow_symlinks) {
14930b57cec5SDimitry Andric     State->Stack.push(directory_iterator(path, ec, Follow));
14940b57cec5SDimitry Andric     if (State->Stack.top() == directory_iterator())
14950b57cec5SDimitry Andric       State.reset();
14960b57cec5SDimitry Andric   }
14970b57cec5SDimitry Andric 
14980b57cec5SDimitry Andric   // No operator++ because we need error_code.
increment(std::error_code & ec)14990b57cec5SDimitry Andric   recursive_directory_iterator &increment(std::error_code &ec) {
15000b57cec5SDimitry Andric     const directory_iterator end_itr = {};
15010b57cec5SDimitry Andric 
15020b57cec5SDimitry Andric     if (State->HasNoPushRequest)
15030b57cec5SDimitry Andric       State->HasNoPushRequest = false;
15040b57cec5SDimitry Andric     else {
15050b57cec5SDimitry Andric       file_type type = State->Stack.top()->type();
15060b57cec5SDimitry Andric       if (type == file_type::symlink_file && Follow) {
15070b57cec5SDimitry Andric         // Resolve the symlink: is it a directory to recurse into?
15080b57cec5SDimitry Andric         ErrorOr<basic_file_status> status = State->Stack.top()->status();
15090b57cec5SDimitry Andric         if (status)
15100b57cec5SDimitry Andric           type = status->type();
15110b57cec5SDimitry Andric         // Otherwise broken symlink, and we'll continue.
15120b57cec5SDimitry Andric       }
15130b57cec5SDimitry Andric       if (type == file_type::directory_file) {
15140b57cec5SDimitry Andric         State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
15150b57cec5SDimitry Andric         if (State->Stack.top() != end_itr) {
15160b57cec5SDimitry Andric           ++State->Level;
15170b57cec5SDimitry Andric           return *this;
15180b57cec5SDimitry Andric         }
15190b57cec5SDimitry Andric         State->Stack.pop();
15200b57cec5SDimitry Andric       }
15210b57cec5SDimitry Andric     }
15220b57cec5SDimitry Andric 
15230b57cec5SDimitry Andric     while (!State->Stack.empty()
15240b57cec5SDimitry Andric            && State->Stack.top().increment(ec) == end_itr) {
15250b57cec5SDimitry Andric       State->Stack.pop();
15260b57cec5SDimitry Andric       --State->Level;
15270b57cec5SDimitry Andric     }
15280b57cec5SDimitry Andric 
15290b57cec5SDimitry Andric     // Check if we are done. If so, create an end iterator.
15300b57cec5SDimitry Andric     if (State->Stack.empty())
15310b57cec5SDimitry Andric       State.reset();
15320b57cec5SDimitry Andric 
15330b57cec5SDimitry Andric     return *this;
15340b57cec5SDimitry Andric   }
15350b57cec5SDimitry Andric 
15360b57cec5SDimitry Andric   const directory_entry &operator*() const { return *State->Stack.top(); }
15370b57cec5SDimitry Andric   const directory_entry *operator->() const { return &*State->Stack.top(); }
15380b57cec5SDimitry Andric 
15390b57cec5SDimitry Andric   // observers
15400b57cec5SDimitry Andric   /// Gets the current level. Starting path is at level 0.
level()15410b57cec5SDimitry Andric   int level() const { return State->Level; }
15420b57cec5SDimitry Andric 
15430b57cec5SDimitry Andric   /// Returns true if no_push has been called for this directory_entry.
no_push_request()15440b57cec5SDimitry Andric   bool no_push_request() const { return State->HasNoPushRequest; }
15450b57cec5SDimitry Andric 
15460b57cec5SDimitry Andric   // modifiers
15470b57cec5SDimitry Andric   /// Goes up one level if Level > 0.
pop()15480b57cec5SDimitry Andric   void pop() {
15490b57cec5SDimitry Andric     assert(State && "Cannot pop an end iterator!");
15500b57cec5SDimitry Andric     assert(State->Level > 0 && "Cannot pop an iterator with level < 1");
15510b57cec5SDimitry Andric 
15520b57cec5SDimitry Andric     const directory_iterator end_itr = {};
15530b57cec5SDimitry Andric     std::error_code ec;
15540b57cec5SDimitry Andric     do {
15550b57cec5SDimitry Andric       if (ec)
15560b57cec5SDimitry Andric         report_fatal_error("Error incrementing directory iterator.");
15570b57cec5SDimitry Andric       State->Stack.pop();
15580b57cec5SDimitry Andric       --State->Level;
15590b57cec5SDimitry Andric     } while (!State->Stack.empty()
15600b57cec5SDimitry Andric              && State->Stack.top().increment(ec) == end_itr);
15610b57cec5SDimitry Andric 
15620b57cec5SDimitry Andric     // Check if we are done. If so, create an end iterator.
15630b57cec5SDimitry Andric     if (State->Stack.empty())
15640b57cec5SDimitry Andric       State.reset();
15650b57cec5SDimitry Andric   }
15660b57cec5SDimitry Andric 
15670b57cec5SDimitry Andric   /// Does not go down into the current directory_entry.
no_push()15680b57cec5SDimitry Andric   void no_push() { State->HasNoPushRequest = true; }
15690b57cec5SDimitry Andric 
15700b57cec5SDimitry Andric   bool operator==(const recursive_directory_iterator &RHS) const {
15710b57cec5SDimitry Andric     return State == RHS.State;
15720b57cec5SDimitry Andric   }
15730b57cec5SDimitry Andric 
15740b57cec5SDimitry Andric   bool operator!=(const recursive_directory_iterator &RHS) const {
15750b57cec5SDimitry Andric     return !(*this == RHS);
15760b57cec5SDimitry Andric   }
15770b57cec5SDimitry Andric };
15780b57cec5SDimitry Andric 
15790b57cec5SDimitry Andric /// @}
15800b57cec5SDimitry Andric 
15810b57cec5SDimitry Andric } // end namespace fs
15820b57cec5SDimitry Andric } // end namespace sys
15830b57cec5SDimitry Andric } // end namespace llvm
15840b57cec5SDimitry Andric 
15850b57cec5SDimitry Andric #endif // LLVM_SUPPORT_FILESYSTEM_H
1586