[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