diff options
Diffstat (limited to 'include/llvm/Support/FileSystem.h')
| -rw-r--r-- | include/llvm/Support/FileSystem.h | 143 | 
1 files changed, 85 insertions, 58 deletions
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h index 02db4596bf1c..d2042f51d8c1 100644 --- a/include/llvm/Support/FileSystem.h +++ b/include/llvm/Support/FileSystem.h @@ -160,6 +160,8 @@ protected:    #if defined(LLVM_ON_UNIX)    time_t fs_st_atime = 0;    time_t fs_st_mtime = 0; +  uint32_t fs_st_atime_nsec = 0; +  uint32_t fs_st_mtime_nsec = 0;    uid_t fs_st_uid = 0;    gid_t fs_st_gid = 0;    off_t fs_st_size = 0; @@ -180,9 +182,12 @@ public:    explicit basic_file_status(file_type Type) : Type(Type) {}    #if defined(LLVM_ON_UNIX) -  basic_file_status(file_type Type, perms Perms, time_t ATime, time_t MTime, +  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) -      : fs_st_atime(ATime), fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID), +      : fs_st_atime(ATime), fs_st_mtime(MTime), +        fs_st_atime_nsec(ATimeNSec), fs_st_mtime_nsec(MTimeNSec), +        fs_st_uid(UID), fs_st_gid(GID),          fs_st_size(Size), Type(Type), Perms(Perms) {}  #elif defined(_WIN32)    basic_file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh, @@ -199,7 +204,20 @@ public:    // getters    file_type type() const { return Type; }    perms permissions() const { return Perms; } + +  /// The file access time as reported from the underlying file system. +  /// +  /// Also see comments on \c getLastModificationTime() related to the precision +  /// of the returned value.    TimePoint<> getLastAccessedTime() const; + +  /// The file modification time as reported from the underlying file system. +  /// +  /// The returned value allows for nanosecond precision but the actual +  /// resolution is an implementation detail of the underlying file system. +  /// There is no guarantee for what kind of resolution you can expect, the +  /// resolution can differ across platforms and even across mountpoints on the +  /// same machine.    TimePoint<> getLastModificationTime() const;    #if defined(LLVM_ON_UNIX) @@ -247,8 +265,11 @@ public:    #if defined(LLVM_ON_UNIX)    file_status(file_type Type, perms Perms, dev_t Dev, nlink_t Links, ino_t Ino, -              time_t ATime, time_t MTime, uid_t UID, gid_t GID, off_t Size) -      : basic_file_status(Type, Perms, ATime, MTime, UID, GID, Size), +              time_t ATime, uint32_t ATimeNSec, +              time_t MTime, uint32_t MTimeNSec, +              uid_t UID, gid_t GID, off_t Size) +      : basic_file_status(Type, Perms, ATime, ATimeNSec, MTime, MTimeNSec, +                          UID, GID, Size),          fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino) {}    #elif defined(_WIN32)    file_status(file_type Type, perms Perms, uint32_t LinkCount, @@ -281,10 +302,7 @@ public:  /// relative/../path => <current-directory>/relative/../path  ///  /// @param path A path that is modified to be an absolute path. -/// @returns errc::success if \a path has been made absolute, otherwise a -///          platform-specific error_code. -std::error_code make_absolute(const Twine ¤t_directory, -                              SmallVectorImpl<char> &path); +void make_absolute(const Twine ¤t_directory, SmallVectorImpl<char> &path);  /// Make \a path an absolute path.  /// @@ -349,6 +367,12 @@ std::error_code create_hard_link(const Twine &to, const Twine &from);  std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output,                            bool expand_tilde = false); +/// Expands ~ expressions to the user's home directory. On Unix ~user +/// directories are resolved as well. +/// +/// @param path The path to resolve. +void expand_tilde(const Twine &path, SmallVectorImpl<char> &output); +  /// Get the current path.  ///  /// @param result Holds the current path on return. @@ -666,7 +690,15 @@ inline std::error_code file_size(const Twine &Path, uint64_t &Result) {  /// @returns errc::success if the file times were successfully set, otherwise a  ///          platform-specific error_code or errc::function_not_supported on  ///          platforms where the functionality isn't available. -std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time); +std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, +                                                 TimePoint<> ModificationTime); + +/// Simpler version that sets both file modification and access time to the same +/// time. +inline std::error_code setLastAccessAndModificationTime(int FD, +                                                        TimePoint<> Time) { +  return setLastAccessAndModificationTime(FD, Time, Time); +}  /// Is status available?  /// @@ -693,7 +725,7 @@ enum CreationDisposition : unsigned {    ///   * If it does not already exist, create a new file.    CD_CreateNew = 1, -  /// CD_OpenAlways - When opening a file: +  /// CD_OpenExisting - When opening a file:    ///   * If it already exists, open the file with the offset set to 0.    ///   * If it does not already exist, fail.    CD_OpenExisting = 2, @@ -1092,38 +1124,51 @@ std::string getMainExecutable(const char *argv0, void *MainExecAddr);  /// @name Iterators  /// @{ -/// directory_entry - A single entry in a directory. Caches the status either -/// from the result of the iteration syscall, or the first time status is -/// called. +/// directory_entry - A single entry in a directory.  class directory_entry { +  // FIXME: different platforms make different information available "for free" +  // when traversing a directory. The design of this class wraps most of the +  // information in basic_file_status, so on platforms where we can't populate +  // that whole structure, callers end up paying for a stat(). +  // std::filesystem::directory_entry may be a better model.    std::string Path; -  bool FollowSymlinks; -  basic_file_status Status; +  file_type Type;           // Most platforms can provide this. +  bool FollowSymlinks;      // Affects the behavior of status(). +  basic_file_status Status; // If available.  public: -  explicit directory_entry(const Twine &path, bool follow_symlinks = true, -                           basic_file_status st = basic_file_status()) -      : Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {} +  explicit directory_entry(const Twine &Path, bool FollowSymlinks = true, +                           file_type Type = file_type::type_unknown, +                           basic_file_status Status = basic_file_status()) +      : Path(Path.str()), Type(Type), FollowSymlinks(FollowSymlinks), +        Status(Status) {}    directory_entry() = default; -  void assign(const Twine &path, basic_file_status st = basic_file_status()) { -    Path = path.str(); -    Status = st; -  } - -  void replace_filename(const Twine &filename, -                        basic_file_status st = basic_file_status()); +  void replace_filename(const Twine &Filename, file_type Type, +                        basic_file_status Status = basic_file_status());    const std::string &path() const { return Path; } +  // Get basic information about entry file (a subset of fs::status()). +  // On most platforms this is a stat() call. +  // On windows the information was already retrieved from the directory.    ErrorOr<basic_file_status> status() const; +  // Get the type of this file. +  // On most platforms (Linux/Mac/Windows/BSD), this was already retrieved. +  // On some platforms (e.g. Solaris) this is a stat() call. +  file_type type() const { +    if (Type != file_type::type_unknown) +      return Type; +    auto S = status(); +    return S ? S->type() : file_type::type_unknown; +  } -  bool operator==(const directory_entry& rhs) const { return Path == rhs.Path; } -  bool operator!=(const directory_entry& rhs) const { return !(*this == rhs); } -  bool operator< (const directory_entry& rhs) const; -  bool operator<=(const directory_entry& rhs) const; -  bool operator> (const directory_entry& rhs) const; -  bool operator>=(const directory_entry& rhs) const; +  bool operator==(const directory_entry& RHS) const { return Path == RHS.Path; } +  bool operator!=(const directory_entry& RHS) const { return !(*this == RHS); } +  bool operator< (const directory_entry& RHS) const; +  bool operator<=(const directory_entry& RHS) const; +  bool operator> (const directory_entry& RHS) const; +  bool operator>=(const directory_entry& RHS) const;  };  namespace detail { @@ -1161,7 +1206,6 @@ public:      SmallString<128> path_storage;      ec = detail::directory_iterator_construct(          *State, path.toStringRef(path_storage), FollowSymlinks); -    update_error_code_for_current_entry(ec);    }    explicit directory_iterator(const directory_entry &de, std::error_code &ec, @@ -1170,7 +1214,6 @@ public:      State = std::make_shared<detail::DirIterState>();      ec = detail::directory_iterator_construct(          *State, de.path(), FollowSymlinks); -    update_error_code_for_current_entry(ec);    }    /// Construct end iterator. @@ -1179,7 +1222,6 @@ public:    // No operator++ because we need error_code.    directory_iterator &increment(std::error_code &ec) {      ec = directory_iterator_increment(*State); -    update_error_code_for_current_entry(ec);      return *this;    } @@ -1199,26 +1241,6 @@ public:    bool operator!=(const directory_iterator &RHS) const {      return !(*this == RHS);    } -  // Other members as required by -  // C++ Std, 24.1.1 Input iterators [input.iterators] - -private: -  // Checks if current entry is valid and populates error code. For example, -  // current entry may not exist due to broken symbol links. -  void update_error_code_for_current_entry(std::error_code &ec) { -    // Bail out if error has already occured earlier to avoid overwriting it. -    if (ec) -      return; - -    // Empty directory entry is used to mark the end of an interation, it's not -    // an error. -    if (State->CurrentEntry == directory_entry()) -      return; - -    ErrorOr<basic_file_status> status = State->CurrentEntry.status(); -    if (!status) -      ec = status.getError(); -  }  };  namespace detail { @@ -1256,8 +1278,15 @@ public:      if (State->HasNoPushRequest)        State->HasNoPushRequest = false;      else { -      ErrorOr<basic_file_status> status = State->Stack.top()->status(); -      if (status && is_directory(*status)) { +      file_type type = State->Stack.top()->type(); +      if (type == file_type::symlink_file && Follow) { +        // Resolve the symlink: is it a directory to recurse into? +        ErrorOr<basic_file_status> status = State->Stack.top()->status(); +        if (status) +          type = status->type(); +        // Otherwise broken symlink, and we'll continue. +      } +      if (type == file_type::directory_file) {          State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));          if (State->Stack.top() != end_itr) {            ++State->Level; @@ -1321,8 +1350,6 @@ public:    bool operator!=(const recursive_directory_iterator &RHS) const {      return !(*this == RHS);    } -  // Other members as required by -  // C++ Std, 24.1.1 Input iterators [input.iterators]  };  /// @}  | 
