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.h274
1 files changed, 200 insertions, 74 deletions
diff --git a/include/llvm/Support/FileSystem.h b/include/llvm/Support/FileSystem.h
index ad21d8af66e99..29515c231bc46 100644
--- a/include/llvm/Support/FileSystem.h
+++ b/include/llvm/Support/FileSystem.h
@@ -33,6 +33,7 @@
#include "llvm/Support/Chrono.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/MD5.h"
#include <cassert>
#include <cstdint>
#include <ctime>
@@ -93,6 +94,7 @@ enum perms {
set_uid_on_exe = 04000,
set_gid_on_exe = 02000,
sticky_bit = 01000,
+ all_perms = all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit,
perms_not_known = 0xFFFF
};
@@ -141,70 +143,61 @@ public:
/// a platform-specific member to store the result.
class file_status
{
+ friend bool equivalent(file_status A, file_status B);
+
#if defined(LLVM_ON_UNIX)
- dev_t fs_st_dev;
- ino_t fs_st_ino;
- time_t fs_st_atime;
- time_t fs_st_mtime;
- uid_t fs_st_uid;
- gid_t fs_st_gid;
- off_t fs_st_size;
+ dev_t fs_st_dev = 0;
+ nlink_t fs_st_nlinks = 0;
+ ino_t fs_st_ino = 0;
+ time_t fs_st_atime = 0;
+ time_t fs_st_mtime = 0;
+ uid_t fs_st_uid = 0;
+ gid_t fs_st_gid = 0;
+ off_t fs_st_size = 0;
#elif defined (LLVM_ON_WIN32)
- uint32_t LastAccessedTimeHigh;
- uint32_t LastAccessedTimeLow;
- uint32_t LastWriteTimeHigh;
- uint32_t LastWriteTimeLow;
- uint32_t VolumeSerialNumber;
- uint32_t FileSizeHigh;
- uint32_t FileSizeLow;
- uint32_t FileIndexHigh;
- uint32_t FileIndexLow;
+ uint32_t NumLinks = 0;
+ uint32_t LastAccessedTimeHigh = 0;
+ uint32_t LastAccessedTimeLow = 0;
+ uint32_t LastWriteTimeHigh = 0;
+ uint32_t LastWriteTimeLow = 0;
+ uint32_t VolumeSerialNumber = 0;
+ uint32_t FileSizeHigh = 0;
+ uint32_t FileSizeLow = 0;
+ uint32_t FileIndexHigh = 0;
+ uint32_t FileIndexLow = 0;
#endif
- friend bool equivalent(file_status A, file_status B);
- file_type Type;
- perms Perms;
+ file_type Type = file_type::status_error;
+ perms Perms = perms_not_known;
public:
#if defined(LLVM_ON_UNIX)
- file_status()
- : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
- fs_st_uid(0), fs_st_gid(0), fs_st_size(0),
- Type(file_type::status_error), Perms(perms_not_known) {}
-
- file_status(file_type Type)
- : fs_st_dev(0), fs_st_ino(0), fs_st_atime(0), fs_st_mtime(0),
- fs_st_uid(0), fs_st_gid(0), fs_st_size(0), Type(Type),
- Perms(perms_not_known) {}
-
- file_status(file_type Type, perms Perms, dev_t Dev, ino_t Ino, time_t ATime,
- time_t MTime, uid_t UID, gid_t GID, off_t Size)
- : fs_st_dev(Dev), fs_st_ino(Ino), fs_st_atime(ATime), fs_st_mtime(MTime),
- fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size), Type(Type),
- Perms(Perms) {}
+ file_status() = default;
+
+ file_status(file_type Type) : Type(Type) {}
+
+ 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)
+ : fs_st_dev(Dev), fs_st_nlinks(Links), fs_st_ino(Ino), fs_st_atime(ATime),
+ fs_st_mtime(MTime), fs_st_uid(UID), fs_st_gid(GID), fs_st_size(Size),
+ Type(Type), Perms(Perms) {}
#elif defined(LLVM_ON_WIN32)
- file_status()
- : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
- LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
- FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0),
- Type(file_type::status_error), Perms(perms_not_known) {}
-
- file_status(file_type Type)
- : LastAccessedTimeHigh(0), LastAccessedTimeLow(0), LastWriteTimeHigh(0),
- LastWriteTimeLow(0), VolumeSerialNumber(0), FileSizeHigh(0),
- FileSizeLow(0), FileIndexHigh(0), FileIndexLow(0), Type(Type),
- Perms(perms_not_known) {}
-
- file_status(file_type Type, uint32_t LastAccessTimeHigh,
- uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
- uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
- uint32_t FileSizeHigh, uint32_t FileSizeLow,
- uint32_t FileIndexHigh, uint32_t FileIndexLow)
- : LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow),
+ file_status() = default;
+
+ file_status(file_type Type) : Type(Type) {}
+
+ 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, uint32_t FileIndexHigh,
+ uint32_t FileIndexLow)
+ : NumLinks(LinkCount), LastAccessedTimeHigh(LastAccessTimeHigh),
+ LastAccessedTimeLow(LastAccessTimeLow),
LastWriteTimeHigh(LastWriteTimeHigh),
LastWriteTimeLow(LastWriteTimeLow),
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
- FileIndexLow(FileIndexLow), Type(Type), Perms(perms_not_known) {}
+ FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {}
#endif
// getters
@@ -213,6 +206,7 @@ public:
TimePoint<> getLastAccessedTime() const;
TimePoint<> getLastModificationTime() const;
UniqueID getUniqueID() const;
+ uint32_t getLinkCount() const;
#if defined(LLVM_ON_UNIX)
uint32_t getUser() const { return fs_st_uid; }
@@ -222,9 +216,11 @@ public:
uint32_t getUser() const {
return 9999; // Not applicable to Windows, so...
}
+
uint32_t getGroup() const {
return 9999; // Not applicable to Windows, so...
}
+
uint64_t getSize() const {
return (uint64_t(FileSizeHigh) << 32) + FileSizeLow;
}
@@ -271,12 +267,12 @@ struct file_magic {
return V != unknown;
}
- file_magic() : V(unknown) {}
+ file_magic() = default;
file_magic(Impl V) : V(V) {}
operator Impl() const { return V; }
private:
- Impl V;
+ Impl V = unknown;
};
/// @}
@@ -350,6 +346,16 @@ std::error_code create_link(const Twine &to, const Twine &from);
/// specific error_code.
std::error_code create_hard_link(const Twine &to, const Twine &from);
+/// @brief Collapse all . and .. patterns, resolve all symlinks, and optionally
+/// expand ~ expressions to the user's home directory.
+///
+/// @param path The path to resolve.
+/// @param output The location to store the resolved path.
+/// @param expand_tilde If true, resolves ~ expressions to the user's home
+/// directory.
+std::error_code real_path(const Twine &path, SmallVectorImpl<char> &output,
+ bool expand_tilde = false);
+
/// @brief Get the current path.
///
/// @param result Holds the current path on return.
@@ -357,6 +363,13 @@ std::error_code create_hard_link(const Twine &to, const Twine &from);
/// otherwise a platform-specific error_code.
std::error_code current_path(SmallVectorImpl<char> &result);
+/// @brief Set the current path.
+///
+/// @param path The path to set.
+/// @returns errc::success if the current path was successfully set,
+/// otherwise a platform-specific error_code.
+std::error_code set_current_path(const Twine &path);
+
/// @brief Remove path. Equivalent to POSIX remove().
///
/// @param path Input path.
@@ -365,6 +378,13 @@ std::error_code current_path(SmallVectorImpl<char> &result);
/// returns error if the file didn't exist.
std::error_code remove(const Twine &path, bool IgnoreNonExisting = true);
+/// @brief Recursively delete a directory.
+///
+/// @param path Input path.
+/// @returns errc::success if path has been removed or didn't exist, otherwise a
+/// platform-specific error code.
+std::error_code remove_directories(const Twine &path, bool IgnoreErrors = true);
+
/// @brief Rename \a from to \a to. Files are renamed as if by POSIX rename().
///
/// @param from The path to rename from.
@@ -385,6 +405,16 @@ std::error_code copy_file(const Twine &From, const Twine &To);
/// platform-specific error_code.
std::error_code resize_file(int FD, uint64_t Size);
+/// @brief Compute an MD5 hash of a file's contents.
+///
+/// @param FD Input file descriptor.
+/// @returns An MD5Result with the hash computed, if successful, otherwise a
+/// std::error_code.
+ErrorOr<MD5::MD5Result> md5_contents(int FD);
+
+/// @brief Version of compute_md5 that doesn't require an open file descriptor.
+ErrorOr<MD5::MD5Result> md5_contents(const Twine &Path);
+
/// @}
/// @name Physical Observers
/// @{
@@ -457,6 +487,40 @@ inline bool equivalent(const Twine &A, const Twine &B) {
return !equivalent(A, B, result) && result;
}
+/// @brief Is the file mounted on a local filesystem?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is on fixed media such as a hard disk,
+/// false if it is not.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform specific error_code.
+std::error_code is_local(const Twine &path, bool &result);
+
+/// @brief Version of is_local accepting an open file descriptor.
+std::error_code is_local(int FD, bool &result);
+
+/// @brief Simpler version of is_local for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_local(const Twine &Path) {
+ bool Result;
+ return !is_local(Path, Result) && Result;
+}
+
+/// @brief Simpler version of is_local accepting an open file descriptor for
+/// clients that don't need to differentiate between an error and false.
+inline bool is_local(int FD) {
+ bool Result;
+ return !is_local(FD, Result) && Result;
+}
+
+/// @brief Does status represent a directory?
+///
+/// @param Path The path to get the type of.
+/// @param Follow For symbolic links, indicates whether to return the file type
+/// of the link itself, or of the target.
+/// @returns A value from the file_type enumeration indicating the type of file.
+file_type get_file_type(const Twine &Path, bool Follow = true);
+
/// @brief Does status represent a directory?
///
/// @param status A file_status previously returned from status.
@@ -466,8 +530,8 @@ bool is_directory(file_status status);
/// @brief Is path a directory?
///
/// @param path Input path.
-/// @param result Set to true if \a path is a directory, false if it is not.
-/// Undefined otherwise.
+/// @param result Set to true if \a path is a directory (after following
+/// symlinks, false if it is not. Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code is_directory(const Twine &path, bool &result);
@@ -488,8 +552,8 @@ bool is_regular_file(file_status status);
/// @brief Is path a regular file?
///
/// @param path Input path.
-/// @param result Set to true if \a path is a regular file, false if it is not.
-/// Undefined otherwise.
+/// @param result Set to true if \a path is a regular file (after following
+/// symlinks), false if it is not. Undefined otherwise.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
std::error_code is_regular_file(const Twine &path, bool &result);
@@ -503,8 +567,32 @@ inline bool is_regular_file(const Twine &Path) {
return Result;
}
+/// @brief Does status represent a symlink file?
+///
+/// @param status A file_status previously returned from status.
+/// @returns status_known(status) && status.type() == file_type::symlink_file.
+bool is_symlink_file(file_status status);
+
+/// @brief Is path a symlink file?
+///
+/// @param path Input path.
+/// @param result Set to true if \a path is a symlink file, false if it is not.
+/// Undefined otherwise.
+/// @returns errc::success if result has been successfully set, otherwise a
+/// platform-specific error_code.
+std::error_code is_symlink_file(const Twine &path, bool &result);
+
+/// @brief Simpler version of is_symlink_file for clients that don't need to
+/// differentiate between an error and false.
+inline bool is_symlink_file(const Twine &Path) {
+ bool Result;
+ if (is_symlink_file(Path, Result))
+ return false;
+ return Result;
+}
+
/// @brief Does this status represent something that exists but is not a
-/// directory, regular file, or symlink?
+/// directory or regular file?
///
/// @param status A file_status previously returned from status.
/// @returns exists(s) && !is_regular_file(s) && !is_directory(s)
@@ -524,13 +612,37 @@ std::error_code is_other(const Twine &path, bool &result);
///
/// @param path Input path.
/// @param result Set to the file status.
+/// @param follow When true, follows symlinks. Otherwise, the symlink itself is
+/// statted.
/// @returns errc::success if result has been successfully set, otherwise a
/// platform-specific error_code.
-std::error_code status(const Twine &path, file_status &result);
+std::error_code status(const Twine &path, file_status &result,
+ bool follow = true);
/// @brief A version for when a file descriptor is already available.
std::error_code status(int FD, file_status &Result);
+/// @brief Set file permissions.
+///
+/// @param Path File to set permissions on.
+/// @param Permissions New file permissions.
+/// @returns errc::success if the permissions were successfully set, otherwise
+/// a platform-specific error_code.
+/// @note On Windows, all permissions except *_write are ignored. Using any of
+/// owner_write, group_write, or all_write will make the file writable.
+/// Otherwise, the file will be marked as read-only.
+std::error_code setPermissions(const Twine &Path, perms Permissions);
+
+/// @brief Get file permissions.
+///
+/// @param Path File to get permissions from.
+/// @returns the permissions if they were successfully retrieved, otherwise a
+/// platform-specific error_code.
+/// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY
+/// attribute, all_all will be returned. Otherwise, all_read | all_exe
+/// will be returned.
+ErrorOr<perms> getPermissions(const Twine &Path);
+
/// @brief Get file size.
///
/// @param Path Input path.
@@ -735,12 +847,13 @@ std::string getMainExecutable(const char *argv0, void *MainExecAddr);
/// called.
class directory_entry {
std::string Path;
+ bool FollowSymlinks;
mutable file_status Status;
public:
- explicit directory_entry(const Twine &path, file_status st = file_status())
- : Path(path.str())
- , Status(st) {}
+ explicit directory_entry(const Twine &path, bool follow_symlinks = true,
+ file_status st = file_status())
+ : Path(path.str()), FollowSymlinks(follow_symlinks), Status(st) {}
directory_entry() = default;
@@ -763,9 +876,10 @@ public:
};
namespace detail {
+
struct DirIterState;
- std::error_code directory_iterator_construct(DirIterState &, StringRef);
+ std::error_code directory_iterator_construct(DirIterState &, StringRef, bool);
std::error_code directory_iterator_increment(DirIterState &);
std::error_code directory_iterator_destruct(DirIterState &);
@@ -778,6 +892,7 @@ namespace detail {
intptr_t IterationHandle = 0;
directory_entry CurrentEntry;
};
+
} // end namespace detail
/// directory_iterator - Iterates through the entries in path. There is no
@@ -785,18 +900,24 @@ namespace detail {
/// it call report_fatal_error on error.
class directory_iterator {
std::shared_ptr<detail::DirIterState> State;
+ bool FollowSymlinks = true;
public:
- explicit directory_iterator(const Twine &path, std::error_code &ec) {
+ explicit directory_iterator(const Twine &path, std::error_code &ec,
+ bool follow_symlinks = true)
+ : FollowSymlinks(follow_symlinks) {
State = std::make_shared<detail::DirIterState>();
SmallString<128> path_storage;
- ec = detail::directory_iterator_construct(*State,
- path.toStringRef(path_storage));
+ ec = detail::directory_iterator_construct(
+ *State, path.toStringRef(path_storage), FollowSymlinks);
}
- explicit directory_iterator(const directory_entry &de, std::error_code &ec) {
+ explicit directory_iterator(const directory_entry &de, std::error_code &ec,
+ bool follow_symlinks = true)
+ : FollowSymlinks(follow_symlinks) {
State = std::make_shared<detail::DirIterState>();
- ec = detail::directory_iterator_construct(*State, de.path());
+ ec =
+ detail::directory_iterator_construct(*State, de.path(), FollowSymlinks);
}
/// Construct end iterator.
@@ -829,24 +950,29 @@ public:
};
namespace detail {
+
/// Keeps state for the recursive_directory_iterator.
struct RecDirIterState {
std::stack<directory_iterator, std::vector<directory_iterator>> Stack;
uint16_t Level = 0;
bool HasNoPushRequest = false;
};
+
} // end namespace detail
/// recursive_directory_iterator - Same as directory_iterator except for it
/// recurses down into child directories.
class recursive_directory_iterator {
std::shared_ptr<detail::RecDirIterState> State;
+ bool Follow;
public:
recursive_directory_iterator() = default;
- explicit recursive_directory_iterator(const Twine &path, std::error_code &ec)
- : State(std::make_shared<detail::RecDirIterState>()) {
- State->Stack.push(directory_iterator(path, ec));
+ explicit recursive_directory_iterator(const Twine &path, std::error_code &ec,
+ bool follow_symlinks = true)
+ : State(std::make_shared<detail::RecDirIterState>()),
+ Follow(follow_symlinks) {
+ State->Stack.push(directory_iterator(path, ec, Follow));
if (State->Stack.top() == directory_iterator())
State.reset();
}
@@ -861,7 +987,7 @@ public:
file_status st;
if ((ec = State->Stack.top()->status(st))) return *this;
if (is_directory(st)) {
- State->Stack.push(directory_iterator(*State->Stack.top(), ec));
+ State->Stack.push(directory_iterator(*State->Stack.top(), ec, Follow));
if (ec) return *this;
if (State->Stack.top() != end_itr) {
++State->Level;