Merge pull request #2898 from MarcZX100/fix/libkernel-windows-lstat-reparse
fix(libkernel): detect Windows reparse points in lstat
This commit is contained in:
commit
df52ac8354
|
|
@ -44,8 +44,9 @@ static int DoFstat(int fd, NativeStat* st) {
|
|||
return ReadHandleInfo(reinterpret_cast<HANDLE>(::_get_osfhandle(fd)), st);
|
||||
}
|
||||
static int DoLstat(const std::filesystem::path& p, NativeStat* st) {
|
||||
std::error_code error;
|
||||
if (std::filesystem::is_symlink(std::filesystem::symlink_status(p, error))) NotImplemented_nid_no_patch("lstat of a Windows symbolic link");
|
||||
const auto attributes = GetFileAttributesW(p.c_str());
|
||||
if (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
|
||||
NotImplemented_nid_no_patch("lstat of a Windows symbolic link");
|
||||
return DoStat(p, st);
|
||||
}
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
|
@ -227,7 +230,8 @@ int main() {
|
|||
Require(remove_nid_postfix(sized.string().c_str()) == 0);
|
||||
const auto present = root / "present.txt";
|
||||
const auto presentName = present.string();
|
||||
const auto missingName = (root / "missing.txt").string();
|
||||
const auto missing = root / "missing.txt";
|
||||
const auto missingName = missing.string();
|
||||
const auto rootName = root.string();
|
||||
{ std::ofstream stream(present); stream << "posix"; }
|
||||
FileStat status{};
|
||||
|
|
@ -263,6 +267,37 @@ int main() {
|
|||
Require(stat_nid_postfix(dangling.string().c_str(), &status) == -1 && *__error_nid_postfix() == 2);
|
||||
Require(lstat_nid_postfix((root / "present.txt" / "child").string().c_str(), &linkStatus) == -1 && *__error_nid_postfix() == 20);
|
||||
Require(unlink_nid_postfix(link.string().c_str()) == 0 && unlink_nid_postfix(dangling.string().c_str()) == 0);
|
||||
#else
|
||||
const auto targetDirectory = root / "target-directory";
|
||||
Require(std::filesystem::create_directory(targetDirectory));
|
||||
const auto fileLink = root / "file-link";
|
||||
const auto directoryLink = root / "directory-link";
|
||||
const auto danglingLink = root / "dangling-link";
|
||||
Require(CreateSymbolicLinkW(fileLink.c_str(), present.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) != 0);
|
||||
Require(CreateSymbolicLinkW(directoryLink.c_str(), targetDirectory.c_str(),
|
||||
SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) != 0);
|
||||
Require(CreateSymbolicLinkW(danglingLink.c_str(), missing.c_str(), SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) != 0);
|
||||
const auto checkUnsupportedLink = [](const std::filesystem::path& link) {
|
||||
FileStat untouched;
|
||||
std::memset(&untouched, 0x5a, sizeof(untouched));
|
||||
constexpr int sentinelError = 123;
|
||||
*__error_nid_postfix() = sentinelError;
|
||||
bool rejected = false;
|
||||
try {
|
||||
lstat_nid_postfix(link.string().c_str(), &untouched);
|
||||
} catch (const std::runtime_error& error) {
|
||||
rejected = std::strcmp(error.what(), "lstat of a Windows symbolic link not implemented") == 0;
|
||||
}
|
||||
const bool errorUnchanged = *__error_nid_postfix() == sentinelError;
|
||||
const auto* bytes = reinterpret_cast<const unsigned char*>(&untouched);
|
||||
const bool statusUnchanged = std::all_of(bytes, bytes + sizeof(untouched), [](unsigned char value) { return value == 0x5a; });
|
||||
return rejected && errorUnchanged && statusUnchanged;
|
||||
};
|
||||
Require(checkUnsupportedLink(fileLink));
|
||||
Require(checkUnsupportedLink(directoryLink));
|
||||
Require(checkUnsupportedLink(danglingLink));
|
||||
Require(std::filesystem::remove(fileLink) && std::filesystem::remove(directoryLink) &&
|
||||
std::filesystem::remove(danglingLink) && std::filesystem::remove(targetDirectory));
|
||||
#endif
|
||||
FileStat identity{};
|
||||
FileStat byDescriptor{};
|
||||
|
|
|
|||
Loading…
Reference in New Issue