Merge pull request #4688 from eliyarson/fix/kernel-stat-relinked-prx
fix(libkernel): resolve original .prx names to relinked .guest.prx in stat, open and reachability
This commit is contained in:
commit
88f48fddef
|
|
@ -18,6 +18,7 @@ extern "C" int HostStandardError_nid_no_patch();
|
|||
#endif
|
||||
|
||||
extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path);
|
||||
extern "C" std::filesystem::path RelinkedModulePath_nid_no_patch(const std::filesystem::path& path);
|
||||
extern "C" int SetWorkingDirectory_nid_no_patch(const char* resolved);
|
||||
extern "C" bool FinalPathComponentIsDot_nid_no_patch(const char* path);
|
||||
// Guest path aliases: a guest prefix such as "/savedata0" (a save-data mount point) resolves to a host
|
||||
|
|
|
|||
|
|
@ -379,6 +379,13 @@ extern "C" std::filesystem::path ResolvePath_nid_no_patch(const char* path) {
|
|||
return Resolve(state, path);
|
||||
}
|
||||
|
||||
extern "C" std::filesystem::path RelinkedModulePath_nid_no_patch(const std::filesystem::path& path) {
|
||||
auto relinked = path;
|
||||
relinked += ".guest.prx";
|
||||
std::error_code error;
|
||||
return std::filesystem::is_regular_file(relinked, error) ? relinked : path;
|
||||
}
|
||||
|
||||
extern "C" int SetWorkingDirectory_nid_no_patch(const char* resolved) {
|
||||
if (resolved == nullptr) return 14;
|
||||
auto& state = Directories();
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
namespace File {
|
||||
|
||||
std::filesystem::path PathOrRelinkedModule(const std::filesystem::path& nativePath);
|
||||
void FillFileStat(const std::filesystem::path& nativePath, FileStat* sb);
|
||||
void FillFileStat(int nativeDescriptor, FileStat* sb);
|
||||
bool FillFileStatFromDescriptor(int fd, FileStat* sb);
|
||||
|
|
|
|||
|
|
@ -125,6 +125,12 @@ static void CopyNativeStat(const NativeStat& st, FileStat* sb) {
|
|||
|
||||
namespace File {
|
||||
|
||||
std::filesystem::path PathOrRelinkedModule(const std::filesystem::path& nativePath) {
|
||||
std::error_code error;
|
||||
if (std::filesystem::exists(std::filesystem::symlink_status(nativePath, error))) return nativePath;
|
||||
return RelinkedModulePath_nid_no_patch(nativePath);
|
||||
}
|
||||
|
||||
void FillFileStat(const std::filesystem::path& nativePath, FileStat* sb) {
|
||||
NativeStat st{};
|
||||
if (DoStat(nativePath, &st) != 0) {
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ int APS5_VABI sceKernelOpen(const char* path, int flags, std::uint16_t mode) {
|
|||
}
|
||||
std::filesystem::path native;
|
||||
if (const int error = ResolvePathError_nid_no_patch(path, native)) return SceKernelError(error);
|
||||
if ((flags & (SCE_KERNEL_O_ACCMODE | SCE_KERNEL_O_CREAT)) == SCE_KERNEL_O_RDONLY) native = File::PathOrRelinkedModule(native);
|
||||
return OpenNative(native, flags, mode);
|
||||
}
|
||||
|
||||
|
|
@ -291,6 +292,7 @@ int APS5_VABI sceKernelStat(const char* path, FileStat* sb) {
|
|||
if (*path == '\0') return SceErrorFromErrno(2);
|
||||
std::filesystem::path native;
|
||||
if (const int error = ResolvePathError_nid_no_patch(path, native)) return SceKernelError(error);
|
||||
native = File::PathOrRelinkedModule(native);
|
||||
std::error_code error;
|
||||
constexpr int GuestEnotdir = 20;
|
||||
const auto status = std::filesystem::status(native, error);
|
||||
|
|
|
|||
|
|
@ -795,6 +795,7 @@ int APS5_VABI sceKernelCheckReachability(const char* path) {
|
|||
if (std::strlen(path) > 255) return SCE_KERNEL_ERROR_ENAMETOOLONG;
|
||||
std::filesystem::path native;
|
||||
if (const int error = ResolvePathError_nid_no_patch(path, native)) return SceKernelError(error);
|
||||
native = File::PathOrRelinkedModule(native);
|
||||
std::error_code error;
|
||||
return std::filesystem::exists(native, error) ? 0 : SCE_KERNEL_ERROR_ENOENT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,13 +162,6 @@ static void InitializeDeferredModule(HMODULE native) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static std::filesystem::path RelinkedModulePath(const std::filesystem::path& path) {
|
||||
auto relinked = path;
|
||||
relinked += ".guest.prx";
|
||||
std::error_code error;
|
||||
return std::filesystem::is_regular_file(relinked, error) ? relinked : path;
|
||||
}
|
||||
|
||||
void* APS5_VABI dlopen_nid_postfix(const char* path, int flags) {
|
||||
if ((flags & ~0x103) || (flags & 3) == 0 || (flags & 3) == 3) {
|
||||
Error("dlopen: unsupported flags"); return nullptr;
|
||||
|
|
@ -182,7 +175,7 @@ void* APS5_VABI dlopen_nid_postfix(const char* path, int flags) {
|
|||
module->owned = false;
|
||||
} else {
|
||||
if (!*path) { Error("dlopen: empty module path"); return nullptr; }
|
||||
const auto resolved = RelinkedModulePath(ResolvePath_nid_no_patch(path));
|
||||
const auto resolved = RelinkedModulePath_nid_no_patch(ResolvePath_nid_no_patch(path));
|
||||
module->native = LoadLibraryExW(resolved.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
|
||||
if (module->native) InitializeDeferredModule(static_cast<HMODULE>(module->native));
|
||||
}
|
||||
|
|
@ -192,7 +185,7 @@ void* APS5_VABI dlopen_nid_postfix(const char* path, int flags) {
|
|||
Error(message); return nullptr;
|
||||
}
|
||||
#else
|
||||
const auto resolved = path ? RelinkedModulePath(ResolvePath_nid_no_patch(path)).string() : std::string{};
|
||||
const auto resolved = path ? RelinkedModulePath_nid_no_patch(ResolvePath_nid_no_patch(path)).string() : std::string{};
|
||||
const int nativeFlags = ((flags & 3) == 1 ? RTLD_LAZY : RTLD_NOW) |
|
||||
((flags & 0x100) ? RTLD_GLOBAL : RTLD_LOCAL);
|
||||
module->native = ::dlopen(path ? resolved.c_str() : nullptr, nativeFlags);
|
||||
|
|
|
|||
|
|
@ -174,8 +174,36 @@ static void TestParentTraversal() {
|
|||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
static void TestRelinkedModuleNames() {
|
||||
const auto root = std::filesystem::path("anyps5-relinked-names-" +
|
||||
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
||||
Require(std::filesystem::create_directories(root));
|
||||
const auto original = (root / "Plugin.prx").generic_string();
|
||||
const auto relinked = original + ".guest.prx";
|
||||
FileStat status{};
|
||||
Require(sceKernelStat(original.c_str(), &status) == static_cast<int>(0x80020002u));
|
||||
Require(sceKernelCheckReachability(original.c_str()) == static_cast<int>(0x80020002u));
|
||||
Require(sceKernelOpen(original.c_str(), 0, 0) == static_cast<int>(0x80020002u));
|
||||
{ std::ofstream file(relinked); file << "relinked"; }
|
||||
Require(sceKernelStat(original.c_str(), &status) == 0 && status.st_size == 8);
|
||||
Require(stat_nid_postfix(original.c_str(), &status) == 0 && status.st_size == 8);
|
||||
Require(sceKernelCheckReachability(original.c_str()) == 0);
|
||||
const int opened = sceKernelOpen(original.c_str(), 0, 0);
|
||||
Require(opened >= 0 && sceKernelClose(opened) == 0);
|
||||
Require(sceKernelStat((root / "Other.prx").generic_string().c_str(), &status) == static_cast<int>(0x80020002u));
|
||||
Require(!std::filesystem::exists(original));
|
||||
{ std::ofstream file(original); file << "original-bytes"; }
|
||||
Require(sceKernelStat(original.c_str(), &status) == 0 && status.st_size == 14);
|
||||
Require(std::filesystem::remove(original));
|
||||
const int created = sceKernelOpen(original.c_str(), 0x601, 0600);
|
||||
Require(created >= 0 && sceKernelClose(created) == 0);
|
||||
Require(std::filesystem::file_size(original) == 0 && std::filesystem::file_size(relinked) == 8);
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
int main() {
|
||||
TestParentTraversal();
|
||||
TestRelinkedModuleNames();
|
||||
Require(chmod_nid_postfix(nullptr, 0600) == -1 && *__error_nid_postfix() == 14);
|
||||
Require(sceKernelChmod_nid_postfix(nullptr, 0600) == static_cast<int>(0x8002000eu));
|
||||
Require(chmod_nid_postfix("", 0600) == -1 && *__error_nid_postfix() == 2);
|
||||
|
|
|
|||
Loading…
Reference in New Issue