[libcxx-commits] [libcxx] 40117b7 - [libcxx] Implement the permissions function for windows

Martin Storsjö via libcxx-commits libcxx-commits at lists.llvm.org
Tue Feb 2 23:28:17 PST 2021


Author: Martin Storsjö
Date: 2021-02-03T09:23:24+02:00
New Revision: 40117b700f723a27b90989a429ceb66c0873b161

URL: https://github.com/llvm/llvm-project/commit/40117b700f723a27b90989a429ceb66c0873b161
DIFF: https://github.com/llvm/llvm-project/commit/40117b700f723a27b90989a429ceb66c0873b161.diff

LOG: [libcxx] Implement the permissions function for windows

Differential Revision: https://reviews.llvm.org/D91171

Added: 
    

Modified: 
    libcxx/src/filesystem/operations.cpp
    libcxx/src/filesystem/posix_compat.h

Removed: 
    


################################################################################
diff  --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index fc18de9e5d80..47cd5e23c092 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -455,10 +455,6 @@ perms posix_get_perms(const StatT& st) noexcept {
   return static_cast<perms>(st.st_mode) & perms::mask;
 }
 
-::mode_t posix_convert_perms(perms prms) {
-  return static_cast< ::mode_t>(prms & perms::mask);
-}
-
 file_status create_file_status(error_code& m_ec, path const& p,
                                const StatT& path_stat, error_code* ec) {
   if (ec)
@@ -530,7 +526,7 @@ bool posix_ftruncate(const FileDescriptor& fd, off_t to_size, error_code& ec) {
 }
 
 bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
-  if (::fchmod(fd.fd, st.st_mode) == -1) {
+  if (detail::fchmod(fd.fd, st.st_mode) == -1) {
     ec = capture_errno();
     return true;
   }
@@ -1212,11 +1208,11 @@ void __permissions(const path& p, perms prms, perm_options opts,
     else if (remove_perms)
       prms = st.permissions() & ~prms;
   }
-  const auto real_perms = detail::posix_convert_perms(prms);
+  const auto real_perms = static_cast<detail::ModeT>(prms & perms::mask);
 
 #if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
   const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
-  if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
+  if (detail::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
     return err.report(capture_errno());
   }
 #else

diff  --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h
index 1adce3a779c2..af4a3691db33 100644
--- a/libcxx/src/filesystem/posix_compat.h
+++ b/libcxx/src/filesystem/posix_compat.h
@@ -349,6 +349,57 @@ wchar_t *realpath(const wchar_t *path, wchar_t *resolved_name) {
   }
   return buff.release();
 }
+
+#define AT_FDCWD -1
+#define AT_SYMLINK_NOFOLLOW 1
+using ModeT = int;
+
+int fchmod_handle(HANDLE h, int perms) {
+  FILE_BASIC_INFO basic;
+  if (!GetFileInformationByHandleEx(h, FileBasicInfo, &basic, sizeof(basic)))
+    return set_errno();
+  DWORD orig_attributes = basic.FileAttributes;
+  basic.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+  if ((perms & 0222) == 0)
+    basic.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+  if (basic.FileAttributes != orig_attributes &&
+      !SetFileInformationByHandle(h, FileBasicInfo, &basic, sizeof(basic)))
+    return set_errno();
+  return 0;
+}
+
+int fchmodat(int fd, const wchar_t *path, int perms, int flag) {
+  DWORD attributes = GetFileAttributesW(path);
+  if (attributes == INVALID_FILE_ATTRIBUTES)
+    return set_errno();
+  if (attributes & FILE_ATTRIBUTE_REPARSE_POINT &&
+      !(flag & AT_SYMLINK_NOFOLLOW)) {
+    // If the file is a symlink, and we are supposed to operate on the target
+    // of the symlink, we need to open a handle to it, without the
+    // FILE_FLAG_OPEN_REPARSE_POINT flag, to open the destination of the
+    // symlink, and operate on it via the handle.
+    detail::WinHandle h(path, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, 0);
+    if (!h)
+      return set_errno();
+    return fchmod_handle(h, perms);
+  } else {
+    // For a non-symlink, or if operating on the symlink itself instead of
+    // its target, we can use SetFileAttributesW, saving a few calls.
+    DWORD orig_attributes = attributes;
+    attributes &= ~FILE_ATTRIBUTE_READONLY;
+    if ((perms & 0222) == 0)
+      attributes |= FILE_ATTRIBUTE_READONLY;
+    if (attributes != orig_attributes && !SetFileAttributesW(path, attributes))
+      return set_errno();
+  }
+  return 0;
+}
+
+int fchmod(int fd, int perms) {
+  HANDLE h = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
+  return fchmod_handle(h, perms);
+}
+
 #else
 int symlink_file(const char *oldname, const char *newname) {
   return ::symlink(oldname, newname);
@@ -358,6 +409,8 @@ int symlink_dir(const char *oldname, const char *newname) {
 }
 using ::chdir;
 using ::close;
+using ::fchmod;
+using ::fchmodat;
 using ::fstat;
 using ::ftruncate;
 using ::getcwd;
@@ -375,6 +428,7 @@ using ::truncate;
 #define O_BINARY 0
 
 using StatVFS = struct statvfs;
+using ModeT = ::mode_t;
 
 #endif
 


        


More information about the libcxx-commits mailing list