diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/Support/FileSystem.h | 61 | ||||
-rw-r--r-- | llvm/lib/Support/Path.cpp | 20 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Path.inc | 21 | ||||
-rw-r--r-- | llvm/lib/Support/Windows/Path.inc | 71 | ||||
-rw-r--r-- | llvm/unittests/Support/Path.cpp | 186 |
5 files changed, 304 insertions, 55 deletions
diff --git a/llvm/include/llvm/Support/FileSystem.h b/llvm/include/llvm/Support/FileSystem.h index 7fa969dfcc7..e684c5a2390 100644 --- a/llvm/include/llvm/Support/FileSystem.h +++ b/llvm/include/llvm/Support/FileSystem.h @@ -178,23 +178,23 @@ public: Perms(Perms) {} #elif defined(LLVM_ON_WIN32) file_status() = default; - - file_status(file_type Type) : Type(Type) {} - - 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, +
+ file_status(file_type Type) : Type(Type) {}
+
+ 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,
uint32_t FileIndexHigh, uint32_t FileIndexLow) : LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow), LastWriteTimeHigh(LastWriteTimeHigh), - LastWriteTimeLow(LastWriteTimeLow), - VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh), - FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh), - FileIndexLow(FileIndexLow), Type(Type) {} - #endif - - // getters + LastWriteTimeLow(LastWriteTimeLow),
+ VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
+ FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
+ FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {}
+ #endif
+
+ // getters
file_type type() const { return Type; } perms permissions() const { return Perms; } TimePoint<> getLastAccessedTime() const; @@ -602,12 +602,33 @@ std::error_code is_other(const Twine &path, bool &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 Get file size. -/// -/// @param Path Input path. +/// @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.
/// @param Result Set to the size of the file in \a Path. /// @returns errc::success if result has been successfully set, otherwise a /// platform-specific error_code. diff --git a/llvm/lib/Support/Path.cpp b/llvm/lib/Support/Path.cpp index fc3cf525c93..5ac60e8dc3e 100644 --- a/llvm/lib/Support/Path.cpp +++ b/llvm/lib/Support/Path.cpp @@ -1189,12 +1189,20 @@ std::error_code identify_magic(const Twine &Path, file_magic &Result) { } std::error_code directory_entry::status(file_status &result) const { - return fs::status(Path, result, FollowSymlinks); -} - -} // end namespace fs -} // end namespace sys -} // end namespace llvm + 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
// Include the truly platform-specific parts. #if defined(LLVM_ON_UNIX) diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc index cdc692b8f1f..b2669d51eb8 100644 --- a/llvm/lib/Support/Unix/Path.inc +++ b/llvm/lib/Support/Unix/Path.inc @@ -568,12 +568,21 @@ std::error_code status(const Twine &Path, file_status &Result, bool Follow) { std::error_code status(int FD, file_status &Result) { struct stat Status; int StatRet = ::fstat(FD, &Status); - return fillStatus(StatRet, Status, Result); -} - -std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { -#if defined(HAVE_FUTIMENS) - timespec Times[2]; + 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];
Times[0] = Times[1] = sys::toTimeSpec(Time); if (::futimens(FD, Times)) return std::error_code(errno, std::generic_category()); diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index d8a14b41cb2..8ad1edd12e9 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -527,19 +527,21 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) { goto handle_status_error; { - 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); - return std::error_code(); - } - + file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ? file_type::directory_file
+ : file_type::regular_file;
+ 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();
+ }
+
handle_status_error: DWORD LastError = ::GetLastError(); if (LastError == ERROR_FILE_NOT_FOUND || @@ -586,12 +588,43 @@ std::error_code status(const Twine &path, file_status &result, bool Follow) { std::error_code status(int FD, file_status &Result) { HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); - return getStatus(FileHandle, Result); -} - -std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) { - FILETIME FT = toFILETIME(Time); - HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD)); + 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));
if (!SetFileTime(FileHandle, NULL, &FT, &FT)) return mapWindowsError(::GetLastError()); return std::error_code(); diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp index c9c98f5d70b..fd54c1284b0 100644 --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -1253,7 +1253,185 @@ TEST_F(FileSystemTest, set_current_path) { fs::UniqueID D1, D2; ASSERT_NO_ERROR(fs::getUniqueID(TestDirectory, D1)); ASSERT_NO_ERROR(fs::getUniqueID(path, D2)); - ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path; -} - -} // anonymous namespace + 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_all | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ 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_all | fs::set_uid_on_exe |
+ fs::set_gid_on_exe |
+ fs::sticky_bit),
+ NoError);
+ EXPECT_TRUE(CheckPermissions(fs::all_all | fs::set_uid_on_exe |
+ fs::set_gid_on_exe | fs::sticky_bit));
+#endif
+}
+
+} // anonymous namespace
|