[libcxx-commits] [PATCH] D91172: [17/N] [libcxx] Implement the read_symlink function for windows

Martin Storsjö via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Mon Dec 7 03:12:00 PST 2020


mstorsjo updated this revision to Diff 309855.
mstorsjo marked 4 inline comments as done.
mstorsjo set the repository for this revision to rG LLVM Github Monorepo.
mstorsjo added a comment.

Updated according to suggestions.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D91172/new/

https://reviews.llvm.org/D91172

Files:
  libcxx/src/filesystem/operations.cpp


Index: libcxx/src/filesystem/operations.cpp
===================================================================
--- libcxx/src/filesystem/operations.cpp
+++ libcxx/src/filesystem/operations.cpp
@@ -22,6 +22,7 @@
 #define NOMINMAX
 #include <windows.h>
 #include <io.h>
+#include <winioctl.h>
 #else
 #include <unistd.h>
 #include <sys/stat.h>
@@ -49,6 +50,36 @@
 # pragma comment(lib, "rt")
 #endif
 
+#if defined(_LIBCPP_WIN32API)
+// This struct isn't defined in the normal Windows SDK, but only in the
+// Windows Driver Kit.
+struct LIBCPP_REPARSE_DATA_BUFFER {
+  unsigned long  ReparseTag;
+  unsigned short ReparseDataLength;
+  unsigned short Reserved;
+  union {
+    struct {
+      unsigned short SubstituteNameOffset;
+      unsigned short SubstituteNameLength;
+      unsigned short PrintNameOffset;
+      unsigned short PrintNameLength;
+      unsigned long  Flags;
+      wchar_t        PathBuffer[1];
+    } SymbolicLinkReparseBuffer;
+    struct {
+      unsigned short SubstituteNameOffset;
+      unsigned short SubstituteNameLength;
+      unsigned short PrintNameOffset;
+      unsigned short PrintNameLength;
+      wchar_t        PathBuffer[1];
+    } MountPointReparseBuffer;
+    struct {
+      unsigned char DataBuffer[1];
+    } GenericReparseBuffer;
+  };
+};
+#endif
+
 _LIBCPP_BEGIN_NAMESPACE_FILESYSTEM
 
 namespace {
@@ -1475,6 +1506,38 @@
 path __read_symlink(const path& p, error_code* ec) {
   ErrorHandler<path> err("read_symlink", ec, &p);
 
+#if defined(_LIBCPP_WIN32API)
+  uint8_t buf[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+  detail::WinHandle h(p.c_str(), FILE_READ_ATTRIBUTES,
+                      FILE_FLAG_OPEN_REPARSE_POINT);
+  if (!h)
+    return err.report(detail::make_windows_error(GetLastError()));
+  DWORD out;
+  if (!DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, nullptr, 0, buf, sizeof(buf),
+                       &out, 0))
+    return err.report(detail::make_windows_error(GetLastError()));
+  const auto *reparse = reinterpret_cast<LIBCPP_REPARSE_DATA_BUFFER *>(buf);
+  size_t path_buf_offset = offsetof(LIBCPP_REPARSE_DATA_BUFFER,
+                                    SymbolicLinkReparseBuffer.PathBuffer[0]);
+  if (out < path_buf_offset)
+    return err.report(make_error_code(errc::invalid_argument));
+  if (reparse->ReparseTag != IO_REPARSE_TAG_SYMLINK)
+    return err.report(make_error_code(errc::invalid_argument));
+  const auto &symlink = reparse->SymbolicLinkReparseBuffer;
+  unsigned short name_offset, name_length;
+  if (symlink.PrintNameLength == 0) {
+    name_offset = symlink.SubstituteNameOffset;
+    name_length = symlink.SubstituteNameLength;
+  } else {
+    name_offset = symlink.PrintNameOffset;
+    name_length = symlink.PrintNameLength;
+  }
+  // name_offset/length are expressed in bytes, not in wchar_t
+  if (path_buf_offset + name_offset + name_length > out)
+    return err.report(make_error_code(errc::invalid_argument));
+  return {wstring(&symlink.PathBuffer[name_offset / sizeof(wchar_t)],
+                  name_length / sizeof(wchar_t))};
+#else
 #ifdef PATH_MAX
   struct NullDeleter { void operator()(void*) const {} };
   const size_t size = PATH_MAX + 1;
@@ -1496,6 +1559,7 @@
     return err.report(errc::value_too_large);
   buff[ret] = 0;
   return {buff.get()};
+#endif
 }
 
 bool __remove(const path& p, error_code* ec) {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D91172.309855.patch
Type: text/x-patch
Size: 3334 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20201207/10ae21ce/attachment.bin>


More information about the libcxx-commits mailing list