Переглянути джерело

Merge branch 'upstream-KWSys' into update-kwsys

# By KWSys Upstream
* upstream-KWSys:
  KWSys 2021-05-07 (979d7db0)
Brad King 4 роки тому
батько
коміт
ba87a84339

+ 4 - 4
Source/kwsys/ProcessUNIX.c

@@ -2894,10 +2894,10 @@ static void kwsysProcessesSignalHandler(int signum
   /* Re-Install our handler.  Repeat call until it is not interrupted.  */
   {
     struct sigaction newSigAction;
-    struct sigaction& oldSigAction;
+    struct sigaction* oldSigAction;
     memset(&newSigAction, 0, sizeof(struct sigaction));
-    newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
-    newSigChldAction.sa_flags = SA_NOCLDSTOP;
+    newSigAction.sa_handler = kwsysProcessesSignalHandler;
+    newSigAction.sa_flags = SA_NOCLDSTOP;
     sigemptyset(&newSigAction.sa_mask);
     switch (signum) {
       case SIGCHLD:
@@ -2912,7 +2912,7 @@ static void kwsysProcessesSignalHandler(int signum
         oldSigAction = &kwsysProcessesOldSigTermAction;
         break;
       default:
-        return 0;
+        return;
     }
     while ((sigaction(signum, &newSigAction, oldSigAction) < 0) &&
            (errno == EINTR))

+ 1 - 1
Source/kwsys/Status.hxx.in

@@ -70,7 +70,7 @@ public:
 #ifdef _WIN32
   /** If the kind is "Windows", returns the GetLastError()-style value.
       Otherwise, returns 0.  */
-  int GetWindows() const
+  unsigned int GetWindows() const
   {
     return this->Kind_ == Kind::Windows ? this->Windows_ : 0;
   }

+ 108 - 15
Source/kwsys/SystemTools.cxx

@@ -93,9 +93,43 @@
 #  ifndef INVALID_FILE_ATTRIBUTES
 #    define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
 #  endif
+#  ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+#    define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
+#  endif
 #  if defined(_MSC_VER) && _MSC_VER >= 1800
 #    define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
 #  endif
+// from ntifs.h, which can only be used by drivers
+typedef struct _REPARSE_DATA_BUFFER
+{
+  ULONG ReparseTag;
+  USHORT ReparseDataLength;
+  USHORT Reserved;
+  union
+  {
+    struct
+    {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      ULONG Flags;
+      WCHAR PathBuffer[1];
+    } SymbolicLinkReparseBuffer;
+    struct
+    {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      WCHAR PathBuffer[1];
+    } MountPointReparseBuffer;
+    struct
+    {
+      UCHAR DataBuffer[1];
+    } GenericReparseBuffer;
+  } DUMMYUNIONNAME;
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
 #endif
 
 #if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
@@ -3008,7 +3042,7 @@ bool SystemTools::FileIsSymlink(const std::string& name)
       }
       CloseHandle(hFile);
       ULONG reparseTag =
-        reinterpret_cast<PREPARSE_GUID_DATA_BUFFER>(&buffer[0])->ReparseTag;
+        reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0])->ReparseTag;
       return (reparseTag == IO_REPARSE_TAG_SYMLINK) ||
         (reparseTag == IO_REPARSE_TAG_MOUNT_POINT);
     }
@@ -3048,31 +3082,90 @@ bool SystemTools::FileIsFIFO(const std::string& name)
 #endif
 }
 
-#if defined(_WIN32) && !defined(__CYGWIN__)
-Status SystemTools::CreateSymlink(std::string const&, std::string const&)
-{
-  return Status::Windows(ERROR_NOT_SUPPORTED);
-}
-#else
 Status SystemTools::CreateSymlink(std::string const& origName,
                                   std::string const& newName)
 {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  DWORD flags;
+  if (FileIsDirectory(origName)) {
+    flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
+  } else {
+    flags = 0;
+  }
+
+  std::wstring origPath = Encoding::ToWindowsExtendedPath(origName);
+  std::wstring newPath = Encoding::ToWindowsExtendedPath(newName);
+
+  Status status;
+  if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(),
+                           flags |
+                             SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) {
+    status = Status::Windows_GetLastError();
+  }
+  // Older Windows versions do not understand
+  // SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+  if (status.GetWindows() == ERROR_INVALID_PARAMETER) {
+    status = Status::Success();
+    if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(), flags)) {
+      status = Status::Windows_GetLastError();
+    }
+  }
+
+  return status;
+#else
   if (symlink(origName.c_str(), newName.c_str()) < 0) {
     return Status::POSIX_errno();
   }
   return Status::Success();
-}
 #endif
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-Status SystemTools::ReadSymlink(std::string const&, std::string&)
-{
-  return Status::Windows(ERROR_NOT_SUPPORTED);
 }
-#else
+
 Status SystemTools::ReadSymlink(std::string const& newName,
                                 std::string& origName)
 {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  std::wstring newPath = Encoding::ToWindowsExtendedPath(newName);
+  // FILE_ATTRIBUTE_REPARSE_POINT means:
+  // * a file or directory that has an associated reparse point, or
+  // * a file that is a symbolic link.
+  HANDLE hFile = CreateFileW(
+    newPath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+    FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+  if (hFile == INVALID_HANDLE_VALUE) {
+    return Status::Windows_GetLastError();
+  }
+  byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+  DWORD bytesReturned = 0;
+  Status status;
+  if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer,
+                       MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned,
+                       nullptr)) {
+    status = Status::Windows_GetLastError();
+  }
+  CloseHandle(hFile);
+  if (!status) {
+    return status;
+  }
+  PREPARSE_DATA_BUFFER data =
+    reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0]);
+  USHORT substituteNameLength;
+  PCWSTR substituteNameData;
+  if (data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+    substituteNameLength =
+      data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
+    substituteNameData = data->SymbolicLinkReparseBuffer.PathBuffer +
+      data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
+  } else if (data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+    substituteNameLength =
+      data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
+    substituteNameData = data->MountPointReparseBuffer.PathBuffer +
+      data->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
+  } else {
+    return Status::Windows(ERROR_REPARSE_TAG_MISMATCH);
+  }
+  std::wstring substituteName(substituteNameData, substituteNameLength);
+  origName = Encoding::ToNarrow(substituteName);
+#else
   char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1];
   int count = static_cast<int>(
     readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH));
@@ -3082,9 +3175,9 @@ Status SystemTools::ReadSymlink(std::string const& newName,
   // Add null-terminator.
   buf[count] = 0;
   origName = buf;
+#endif
   return Status::Success();
 }
-#endif
 
 Status SystemTools::ChangeDirectory(std::string const& dir)
 {

+ 19 - 11
Source/kwsys/testSystemTools.cxx

@@ -29,6 +29,7 @@
 #  ifdef _MSC_VER
 #    define umask _umask
 #  endif
+#  include <windows.h>
 #endif
 #include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */
 // Visual C++ does not define mode_t.
@@ -425,21 +426,28 @@ static bool CheckFileOperations()
     res = false;
   }
 
-#if !defined(_WIN32)
   std::string const testBadSymlink(testNewDir + "/badSymlink.txt");
   std::string const testBadSymlinkTgt(testNewDir + "/missing/symlinkTgt.txt");
-  if (!kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink)) {
-    std::cerr << "Problem with CreateSymlink for: " << testBadSymlink << " -> "
-              << testBadSymlinkTgt << std::endl;
-    res = false;
-  }
+  kwsys::Status const symlinkStatus =
+    kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink);
+#if defined(_WIN32)
+  // Under Windows, the user may not have enough privileges to create symlinks
+  if (symlinkStatus.GetWindows() != ERROR_PRIVILEGE_NOT_HELD)
+#endif
+  {
+    if (!symlinkStatus) {
+      std::cerr << "CreateSymlink for: " << testBadSymlink << " -> "
+                << testBadSymlinkTgt
+                << " failed: " << symlinkStatus.GetString() << std::endl;
+      res = false;
+    }
 
-  if (!kwsys::SystemTools::Touch(testBadSymlink, false)) {
-    std::cerr << "Problem with Touch (no create) for: " << testBadSymlink
-              << std::endl;
-    res = false;
+    if (!kwsys::SystemTools::Touch(testBadSymlink, false)) {
+      std::cerr << "Problem with Touch (no create) for: " << testBadSymlink
+                << std::endl;
+      res = false;
+    }
   }
-#endif
 
   if (!kwsys::SystemTools::Touch(testNewDir, false)) {
     std::cerr << "Problem with Touch (no create) for: " << testNewDir