summaryrefslogtreecommitdiff
path: root/include/llvm/Support/FileSystem.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/Support/FileSystem.h')
-rw-r--r--include/llvm/Support/FileSystem.h143
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 &current_directory,
- SmallVectorImpl<char> &path);
+void make_absolute(const Twine &current_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]
};
/// @}