Skip to content

Commit 565edc0

Browse files
committed
Add support for getting file system permissions and implement sys::fs::permissions to set them.
Patch by James Henderson. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297617 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 61b9140 commit 565edc0

File tree

5 files changed

+304
-55
lines changed

5 files changed

+304
-55
lines changed

include/llvm/Support/FileSystem.h

+41-20
Original file line numberDiff line numberDiff line change
@@ -178,23 +178,23 @@ class file_status
178178
Perms(Perms) {}
179179
#elif defined(LLVM_ON_WIN32)
180180
file_status() = default;
181-
182-
file_status(file_type Type) : Type(Type) {}
183-
184-
file_status(file_type Type, uint32_t LastAccessTimeHigh,
185-
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
186-
uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
187-
uint32_t FileSizeHigh, uint32_t FileSizeLow,
181+
182+
file_status(file_type Type) : Type(Type) {}
183+
184+
file_status(file_type Type, perms Perms, uint32_t LastAccessTimeHigh,
185+
uint32_t LastAccessTimeLow, uint32_t LastWriteTimeHigh,
186+
uint32_t LastWriteTimeLow, uint32_t VolumeSerialNumber,
187+
uint32_t FileSizeHigh, uint32_t FileSizeLow,
188188
uint32_t FileIndexHigh, uint32_t FileIndexLow)
189189
: LastAccessedTimeHigh(LastAccessTimeHigh), LastAccessedTimeLow(LastAccessTimeLow),
190190
LastWriteTimeHigh(LastWriteTimeHigh),
191-
LastWriteTimeLow(LastWriteTimeLow),
192-
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
193-
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
194-
FileIndexLow(FileIndexLow), Type(Type) {}
195-
#endif
196-
197-
// getters
191+
LastWriteTimeLow(LastWriteTimeLow),
192+
VolumeSerialNumber(VolumeSerialNumber), FileSizeHigh(FileSizeHigh),
193+
FileSizeLow(FileSizeLow), FileIndexHigh(FileIndexHigh),
194+
FileIndexLow(FileIndexLow), Type(Type), Perms(Perms) {}
195+
#endif
196+
197+
// getters
198198
file_type type() const { return Type; }
199199
perms permissions() const { return Perms; }
200200
TimePoint<> getLastAccessedTime() const;
@@ -602,12 +602,33 @@ std::error_code is_other(const Twine &path, bool &result);
602602
std::error_code status(const Twine &path, file_status &result,
603603
bool follow = true);
604604

605-
/// @brief A version for when a file descriptor is already available.
606-
std::error_code status(int FD, file_status &Result);
607-
608-
/// @brief Get file size.
609-
///
610-
/// @param Path Input path.
605+
/// @brief A version for when a file descriptor is already available.
606+
std::error_code status(int FD, file_status &Result);
607+
608+
/// @brief Set file permissions.
609+
///
610+
/// @param Path File to set permissions on.
611+
/// @param Permissions New file permissions.
612+
/// @returns errc::success if the permissions were successfully set, otherwise
613+
/// a platform-specific error_code.
614+
/// @note On Windows, all permissions except *_write are ignored. Using any of
615+
/// owner_write, group_write, or all_write will make the file writable.
616+
/// Otherwise, the file will be marked as read-only.
617+
std::error_code setPermissions(const Twine &Path, perms Permissions);
618+
619+
/// @brief Get file permissions.
620+
///
621+
/// @param Path File to get permissions from.
622+
/// @returns the permissions if they were successfully retrieved, otherwise a
623+
/// platform-specific error_code.
624+
/// @note On Windows, if the file does not have the FILE_ATTRIBUTE_READONLY
625+
/// attribute, all_all will be returned. Otherwise, all_read | all_exe
626+
/// will be returned.
627+
ErrorOr<perms> getPermissions(const Twine &Path);
628+
629+
/// @brief Get file size.
630+
///
631+
/// @param Path Input path.
611632
/// @param Result Set to the size of the file in \a Path.
612633
/// @returns errc::success if result has been successfully set, otherwise a
613634
/// platform-specific error_code.

lib/Support/Path.cpp

+14-6
Original file line numberDiff line numberDiff line change
@@ -1189,12 +1189,20 @@ std::error_code identify_magic(const Twine &Path, file_magic &Result) {
11891189
}
11901190

11911191
std::error_code directory_entry::status(file_status &result) const {
1192-
return fs::status(Path, result, FollowSymlinks);
1193-
}
1194-
1195-
} // end namespace fs
1196-
} // end namespace sys
1197-
} // end namespace llvm
1192+
return fs::status(Path, result, FollowSymlinks);
1193+
}
1194+
1195+
ErrorOr<perms> getPermissions(const Twine &Path) {
1196+
file_status Status;
1197+
if (std::error_code EC = status(Path, Status))
1198+
return EC;
1199+
1200+
return Status.permissions();
1201+
}
1202+
1203+
} // end namespace fs
1204+
} // end namespace sys
1205+
} // end namespace llvm
11981206

11991207
// Include the truly platform-specific parts.
12001208
#if defined(LLVM_ON_UNIX)

lib/Support/Unix/Path.inc

+15-6
Original file line numberDiff line numberDiff line change
@@ -568,12 +568,21 @@ std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
568568
std::error_code status(int FD, file_status &Result) {
569569
struct stat Status;
570570
int StatRet = ::fstat(FD, &Status);
571-
return fillStatus(StatRet, Status, Result);
572-
}
573-
574-
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
575-
#if defined(HAVE_FUTIMENS)
576-
timespec Times[2];
571+
return fillStatus(StatRet, Status, Result);
572+
}
573+
574+
std::error_code setPermissions(const Twine &Path, perms Permissions) {
575+
SmallString<128> PathStorage;
576+
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
577+
578+
if (::chmod(P.begin(), Permissions))
579+
return std::error_code(errno, std::generic_category());
580+
return std::error_code();
581+
}
582+
583+
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
584+
#if defined(HAVE_FUTIMENS)
585+
timespec Times[2];
577586
Times[0] = Times[1] = sys::toTimeSpec(Time);
578587
if (::futimens(FD, Times))
579588
return std::error_code(errno, std::generic_category());

lib/Support/Windows/Path.inc

+52-19
Original file line numberDiff line numberDiff line change
@@ -527,19 +527,21 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
527527
goto handle_status_error;
528528

529529
{
530-
file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
531-
? file_type::directory_file
532-
: file_type::regular_file;
533-
Result =
534-
file_status(Type, Info.ftLastAccessTime.dwHighDateTime,
535-
Info.ftLastAccessTime.dwLowDateTime,
536-
Info.ftLastWriteTime.dwHighDateTime,
537-
Info.ftLastWriteTime.dwLowDateTime,
538-
Info.dwVolumeSerialNumber, Info.nFileSizeHigh,
539-
Info.nFileSizeLow, Info.nFileIndexHigh, Info.nFileIndexLow);
540-
return std::error_code();
541-
}
542-
530+
file_type Type = (Info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
531+
? file_type::directory_file
532+
: file_type::regular_file;
533+
perms Permissions = (Info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
534+
? (all_read | all_exe)
535+
: all_all;
536+
Result = file_status(
537+
Type, Permissions, Info.ftLastAccessTime.dwHighDateTime,
538+
Info.ftLastAccessTime.dwLowDateTime,
539+
Info.ftLastWriteTime.dwHighDateTime, Info.ftLastWriteTime.dwLowDateTime,
540+
Info.dwVolumeSerialNumber, Info.nFileSizeHigh, Info.nFileSizeLow,
541+
Info.nFileIndexHigh, Info.nFileIndexLow);
542+
return std::error_code();
543+
}
544+
543545
handle_status_error:
544546
DWORD LastError = ::GetLastError();
545547
if (LastError == ERROR_FILE_NOT_FOUND ||
@@ -586,12 +588,43 @@ std::error_code status(const Twine &path, file_status &result, bool Follow) {
586588

587589
std::error_code status(int FD, file_status &Result) {
588590
HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
589-
return getStatus(FileHandle, Result);
590-
}
591-
592-
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
593-
FILETIME FT = toFILETIME(Time);
594-
HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
591+
return getStatus(FileHandle, Result);
592+
}
593+
594+
std::error_code setPermissions(const Twine &Path, perms Permissions) {
595+
SmallVector<wchar_t, 128> PathUTF16;
596+
if (std::error_code EC = widenPath(Path, PathUTF16))
597+
return EC;
598+
599+
DWORD Attributes = ::GetFileAttributesW(PathUTF16.begin());
600+
if (Attributes == INVALID_FILE_ATTRIBUTES)
601+
return mapWindowsError(GetLastError());
602+
603+
// There are many Windows file attributes that are not to do with the file
604+
// permissions (e.g. FILE_ATTRIBUTE_HIDDEN). We need to be careful to preserve
605+
// them.
606+
if (Permissions & all_write) {
607+
Attributes &= ~FILE_ATTRIBUTE_READONLY;
608+
if (Attributes == 0)
609+
// FILE_ATTRIBUTE_NORMAL indicates no other attributes are set.
610+
Attributes |= FILE_ATTRIBUTE_NORMAL;
611+
}
612+
else {
613+
Attributes |= FILE_ATTRIBUTE_READONLY;
614+
// FILE_ATTRIBUTE_NORMAL is not compatible with any other attributes, so
615+
// remove it, if it is present.
616+
Attributes &= ~FILE_ATTRIBUTE_NORMAL;
617+
}
618+
619+
if (!::SetFileAttributesW(PathUTF16.begin(), Attributes))
620+
return mapWindowsError(GetLastError());
621+
622+
return std::error_code();
623+
}
624+
625+
std::error_code setLastModificationAndAccessTime(int FD, TimePoint<> Time) {
626+
FILETIME FT = toFILETIME(Time);
627+
HANDLE FileHandle = reinterpret_cast<HANDLE>(_get_osfhandle(FD));
595628
if (!SetFileTime(FileHandle, NULL, &FT, &FT))
596629
return mapWindowsError(::GetLastError());
597630
return std::error_code();

0 commit comments

Comments
 (0)