From 8254d3be9f5f55bafbe3532fca7deb4889b72617 Mon Sep 17 00:00:00 2001 From: Maksim Moisiuk Date: Thu, 16 Jul 2020 00:13:54 +0200 Subject: [PATCH] [vcpkg] implement copy_symlink working for non-elevated processes (#12400) * [vcpkg] implement copy_symlink working for non-elevated processes * [vcpkg] read_symlink Windows implementation * [vcpkg] normalize_path on Windows only * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * remove normalization * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * Update toolsrc/src/vcpkg/base/files.cpp Co-authored-by: nicole mazzuca * use unique_ptr * comments Co-authored-by: nicole mazzuca --- toolsrc/src/vcpkg/base/files.cpp | 57 +++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/toolsrc/src/vcpkg/base/files.cpp b/toolsrc/src/vcpkg/base/files.cpp index 4e3531c22..704f5c24f 100644 --- a/toolsrc/src/vcpkg/base/files.cpp +++ b/toolsrc/src/vcpkg/base/files.cpp @@ -102,6 +102,61 @@ namespace vcpkg::Files return status_implementation(false, p, ec); } + fs::path read_symlink_implementation(const fs::path& oldpath, std::error_code& ec) + { +#if defined(_WIN32) && !VCPKG_USE_STD_FILESYSTEM + ec.clear(); + auto handle = CreateFileW(oldpath.c_str(), + 0, // open just the metadata + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr /* no security attributes */, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + nullptr /* no template file */); + if (handle == INVALID_HANDLE_VALUE) + { + ec.assign(GetLastError(), std::system_category()); + return oldpath; + } + fs::path target; + const DWORD maxsize = 32768; + const std::unique_ptr buffer(new wchar_t[maxsize]); + const auto rc = GetFinalPathNameByHandleW(handle, buffer.get(), maxsize, 0); + if (rc > 0 && rc < maxsize) + { + target = buffer.get(); + } + else + { + ec.assign(GetLastError(), std::system_category()); + } + CloseHandle(handle); + return target; +#else // ^^^ defined(_WIN32) && !VCPKG_USE_STD_FILESYSTEM // !defined(_WIN32) || VCPKG_USE_STD_FILESYSTEM vvv + return fs::stdfs::read_symlink(oldpath, ec); +#endif // ^^^ !defined(_WIN32) || VCPKG_USE_STD_FILESYSTEM + } + + void copy_symlink_implementation(const fs::path& oldpath, const fs::path& newpath, std::error_code& ec) + { +#if defined(_WIN32) && !VCPKG_USE_STD_FILESYSTEM + const auto target = read_symlink_implementation(oldpath, ec); + if (ec) return; + + const DWORD flags = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + if (!CreateSymbolicLinkW(newpath.c_str(), target.c_str(), flags)) + { + const auto err = GetLastError(); + ec.assign(err, std::system_category()); + return; + } + ec.clear(); + return; +#else // ^^^ defined(_WIN32) && !VCPKG_USE_STD_FILESYSTEM // !defined(_WIN32) || VCPKG_USE_STD_FILESYSTEM vvv + return fs::stdfs::copy_symlink(oldpath, newpath, ec); +#endif // ^^^ !defined(_WIN32) || VCPKG_USE_STD_FILESYSTEM + } + // does _not_ follow symlinks void set_writeable(const fs::path& path, std::error_code& ec) noexcept { @@ -800,7 +855,7 @@ namespace vcpkg::Files } virtual void copy_symlink(const fs::path& oldpath, const fs::path& newpath, std::error_code& ec) override { - return fs::stdfs::copy_symlink(oldpath, newpath, ec); + return Files::copy_symlink_implementation(oldpath, newpath, ec); } virtual fs::file_status status(const fs::path& path, std::error_code& ec) const override