diff --git a/core/libs/prx/libc/src/Directory.cpp b/core/libs/prx/libc/src/Directory.cpp index 69d3670e80..3f84ac2eb3 100644 --- a/core/libs/prx/libc/src/Directory.cpp +++ b/core/libs/prx/libc/src/Directory.cpp @@ -54,7 +54,16 @@ int NativeOpenError(DWORD error) { NativeDirectory* OpenNative(const std::filesystem::path& path) { const DWORD attributes = GetFileAttributesW(path.c_str()); if (attributes == INVALID_FILE_ATTRIBUTES) { errno = NativeOpenError(GetLastError()); return nullptr; } - if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { errno = ENOTDIR; return nullptr; } + if ((attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) { + errno = ENOTDIR; + if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) { + const HANDLE followed = CreateFileW(path.c_str(), FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + if (followed != INVALID_HANDLE_VALUE) CloseHandle(followed); + else if (GetLastError() == ERROR_CANT_RESOLVE_FILENAME) errno = ELOOP; + } + return nullptr; + } auto native = std::make_unique_for_overwrite(); native->handle = CreateFileW(path.c_str(), FILE_LIST_DIRECTORY | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); diff --git a/core/libs/tests/GuestDirectory.cpp b/core/libs/tests/GuestDirectory.cpp index f5646097dc..5f6096246e 100644 --- a/core/libs/tests/GuestDirectory.cpp +++ b/core/libs/tests/GuestDirectory.cpp @@ -173,8 +173,20 @@ int main() { Require(closedir_nid_postfix(directory) == 0); Require(opendir_nid_postfix((root / "missing").string().c_str()) == nullptr); Require(*__error_nid_postfix() == 2); -#ifndef _WIN32 const auto symlinkLoop = root / "symlink-loop"; +#ifdef _WIN32 + if (links) { + Require(CreateSymbolicLinkW(symlinkLoop.c_str(), L"symlink-loop", SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) != 0); + Require(opendir_nid_postfix(symlinkLoop.string().c_str()) == nullptr); + Require(*__error_nid_postfix() == 62); + Require(DeleteFileW(symlinkLoop.c_str()) != 0); + const auto directoryLoop = root / "directory-loop"; + Require(CreateSymbolicLinkW(directoryLoop.c_str(), L"directory-loop", SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) != 0); + Require(opendir_nid_postfix(directoryLoop.string().c_str()) == nullptr); + Require(*__error_nid_postfix() == 62); + Require(RemoveDirectoryW(directoryLoop.c_str()) != 0); + } +#else std::filesystem::create_symlink("symlink-loop", symlinkLoop); Require(opendir_nid_postfix(symlinkLoop.string().c_str()) == nullptr); Require(*__error_nid_postfix() == 62);