Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vcpkg] implement copy_symlink working for non-elevated processes #12400

Merged
merged 14 commits into from
Jul 15, 2020
57 changes: 56 additions & 1 deletion toolsrc/src/vcpkg/base/files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,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
Maximus5 marked this conversation as resolved.
Show resolved Hide resolved
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<wchar_t[]> 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
{
Expand Down Expand Up @@ -799,7 +854,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
Expand Down