From ef373416f30080dbe9b714f24e552a0015ff77f9 Mon Sep 17 00:00:00 2001
From: Tobias Kloss <tobias.kloss@draeger.com>
Date: Fri, 18 Jan 2019 08:04:58 -0500
Subject: [PATCH] SystemTools: Fix FileIsSymlink with Windows data
 deduplication

On Windows machines with enabled data deduplication files duplicates are
incorrectly recognized as symlinks and therefore install fails with
"file COPY cannot read symlink".

Similar issues can be found here:

* https://github.com/Microsoft/vcpkg/issues/2488
* https://github.com/puppetlabs/puppet/pull/6513

From the later fix this commit is mainly influenced.
---
 SystemTools.cxx | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/SystemTools.cxx b/SystemTools.cxx
index c5160a9..e78d95e 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -2982,7 +2982,28 @@ bool SystemTools::FileIsSymlink(const std::string& name)
   DWORD attr =
     GetFileAttributesW(Encoding::ToWindowsExtendedPath(name).c_str());
   if (attr != INVALID_FILE_ATTRIBUTES) {
-    return (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+    if ((attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
+      HANDLE hFile = CreateFileW(Encoding::ToWide(name).c_str(), GENERIC_READ,
+                                 FILE_SHARE_READ, NULL, OPEN_EXISTING,
+                                 FILE_FLAG_BACKUP_SEMANTICS, NULL);
+      if (hFile == INVALID_HANDLE_VALUE) {
+        return false;
+      }
+      byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+      DWORD bytesReturned = 0;
+      if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer,
+                           MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned,
+                           NULL)) {
+        CloseHandle(hFile);
+        return false;
+      }
+      CloseHandle(hFile);
+      ULONG reparseTag =
+        reinterpret_cast<PREPARSE_GUID_DATA_BUFFER>(&buffer[0])->ReparseTag;
+      return (reparseTag == IO_REPARSE_TAG_SYMLINK) ||
+        (reparseTag == IO_REPARSE_TAG_MOUNT_POINT);
+    }
+    return false;
   } else {
     return false;
   }
-- 
GitLab