summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Support/FileSystem.h26
-rw-r--r--llvm/lib/Support/Path.cpp8
-rw-r--r--llvm/lib/Support/Unix/Path.inc11
-rw-r--r--llvm/lib/Support/Windows/Path.inc47
-rw-r--r--llvm/unittests/Support/Path.cpp171
5 files changed, 253 insertions, 10 deletions
diff --git a/llvm/include/llvm/Support/FileSystem.h b/llvm/include/llvm/Support/FileSystem.h
index 7fa969dfcc7..ab8cbf7567d 100644
--- a/llvm/include/llvm/Support/FileSystem.h
+++ b/llvm/include/llvm/Support/FileSystem.h
@@ -93,6 +93,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
};
@@ -181,7 +182,7 @@ public:
file_status(file_type Type) : Type(Type) {}
- file_status(file_type Type, uint32_t LastAccessTimeHigh,
+ file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
uint32_t FileSizeHigh, uint32_t FileSizeLow,
@@ -191,7 +192,7 @@ public:
LastWriteTimeLow(LastWriteTimeLow),
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
- FileIndexLow(FileIndexLow), Type(Type) {}
+ FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {}
#endif
// getters
@@ -605,6 +606,27 @@ std::error_code status(const Twine &path, file_status &result,
/// @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.
diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp
index fc3cf525c93..26b3eadb289 100644
--- a/llvm/lib/Support/Path.cpp
+++ b/llvm/lib/Support/Path.cpp
@@ -1192,6 +1192,14 @@ std::error_code directory_entry::status(file_status &result) const {
return fs::status(Path, result, FollowSymlinks);
}
+ErrorOr<perms> getPermissions(const Twine &Path) {
+ file_status Status;
+ if (std::error_code EC = status(Path, Status))
+ return EC;
+
+ return Status.permissions();
+}
+
} // end namespace fs
} // end namespace sys
} // end namespace llvm
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index cdc692b8f1f..c1ffd1eeb29 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -547,7 +547,7 @@ static std::error_code fillStatus(int StatRet, const struct stat &Status,
else if (S_ISLNK(Status.st_mode))
Type = file_type::symlink_file;
- perms Perms = static_cast<perms>(Status.st_mode);
+ perms Perms = static_cast<perms>(Status.st_mode) & all_perms;
Result =
file_status(Type, Perms, Status.st_dev, Status.st_ino, Status.st_atime,
Status.st_mtime, Status.st_uid, Status.st_gid,
@@ -571,6 +571,15 @@ std::error_code status(int FD, file_status &Result) {
return fillStatus(StatRet, Status, Result);
}
+std::error_code setPermissions(const Twine &Path, perms Permissions) {
+ SmallString<128> PathStorage;
+ StringRef P = Path.toNullTerminatedStringRef(PathStorage);
+
+ if (::chmod(P.begin(), Permissions))
+ return std::error_code(errno, std::generic_category());
+ return std::error_code();
+}
+
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
#if defined(HAVE_FUTIMENS)
timespec Times[2];
diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index d8a14b41cb2..f8a75a21e48 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -530,13 +530,15 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
? file_type::directory_file
: file_type::regular_file;
- Result =
- file_status(Type, Info.ftLastAccessTime.dwHighDateTime,
- Info.ftLastAccessTime.dwLowDateTime,
- Info.ftLastWriteTime.dwHighDateTime,
- Info.ftLastWriteTime.dwLowDateTime,
- Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
- Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
+ perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ ? (all_read | all_exe)
+ : all_all;
+ Result = file_status(
+ Type, Permissions, Info.ftLastAccessTime.dwHighDateTime,
+ Info.ftLastAccessTime.dwLowDateTime,
+ Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime,
+ Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow,
+ Info.nFileIndexHigh, Info.nFileIndexLow);
return std::error_code();
}
@@ -589,6 +591,37 @@ std::error_code status(int FD, file_status &Result) {
return getStatus(FileHandle, Result);
}
+std::error_code setPermissions(const Twine &Path, perms Permissions) {
+ SmallVector<wchar_t, 128> PathUTF16;
+ if (std::error_code EC = widenPath(Path, PathUTF16))
+ return EC;
+
+ DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin());
+ if (Attributes == INVALID_FILE_ATTRIBUTES)
+ return mapWindowsError(GetLastError());
+
+ // There are many Windows file attributes that are not to do with the file
+ // permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve
+ // them.
+ if (Permissions & all_write) {
+ Attributes &= ~FILE_ATTRIBUTE_READONLY;
+ if (Attributes == 0)
+ // FILE_ATTRIBUTE_NORMAL indicates no other attributes are set.
+ Attributes |= FILE_ATTRIBUTE_NORMAL;
+ }
+ else {
+ Attributes |= FILE_ATTRIBUTE_READONLY;
+ // FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so
+ // remove it, if it is present.
+ Attributes &= ~FILE_ATTRIBUTE_NORMAL;
+ }
+
+ if (!::SetFileAttributesW(PathUTF16.begin(), Attributes))
+ return mapWindowsError(GetLastError());
+
+ return std::error_code();
+}
+
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
FILETIME FT = toFILETIME(Time);
HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp
index b79586b9946..8068b320306 100644
--- a/llvm/unittests/Support/Path.cpp
+++ b/llvm/unittests/Support/Path.cpp
@@ -1335,4 +1335,175 @@ TEST_F(FileSystemTest, set_current_path) {
ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path;
}
+TEST_F(FileSystemTest, permissions) {
+ int FD;
+ SmallString<64> TempPath;
+ ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
+ FileRemover Cleanup(TempPath);
+
+ // Make sure it exists.
+ ASSERT_TRUE(fs::exists(Twine(TempPath)));
+
+ auto CheckPermissions = [&](fs::perms Expected) {
+ ErrorOr<fs::perms> Actual = fs::getPermissions(TempPath);
+ return Actual && *Actual == Expected;
+ };
+
+ std::error_code NoError;
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe));
+
+#if defined(LLVM_ON_WIN32)
+ fs::perms ReadOnly = fs::all_read | fs::all_exe;
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, ReadOnly | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(ReadOnly));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all));
+#else
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::no_perms));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::owner_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::group_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::others_all));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_write));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe | fs::set_gid_on_exe |
+ fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe |
+ fs::set_gid_on_exe | fs::sticky_bit));
+
+ EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_perms));
+#endif
+}
+
} // anonymous namespace
OpenPOWER on IntegriCloud