From 9ceb6d144d5f35994f4d8488bffb751550c3823e Mon Sep 17 00:00:00 2001 From: Rick <99503318+0xRickx@users.noreply.github.com> Date: Tue, 13 Oct 2026 10:47:52 +0200 Subject: [PATCH] fix(libkernel_sys): reach rename through a _nid_no_patch export renameat (2a8e7452) calls rename_nid_postfix when both paths are AT_FDCWD-relative or absolute. Rename.cpp is built into both libc and libkernel, and on Windows libkernel_sys bound that import to libkernel, which comes first on its link line. The NID patcher then rewrote the import to rename's NID, which only libc exports, as libkernel keeps its copy under the plain name. So libkernel_sys.prx fails to load with error 127 on Windows, and with it every title that imports it. Linux resolves the symbol globally and was not affected. rename's body is now RenameGuestPath_nid_no_patch, which both libraries export under that name, and renameat calls it, the way libkernel_sys already reaches libkernel's other helpers. rename_nid_postfix forwards to it, so its behaviour is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) --- core/libs/prx/libc/include/General.hpp | 1 + core/libs/prx/libc/src/Rename.cpp | 6 +++++- core/libs/prx/libkernel_sys/Export.cpp | 4 +--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/libs/prx/libc/include/General.hpp b/core/libs/prx/libc/include/General.hpp index 3fce094f1..654f5c78c 100644 --- a/core/libs/prx/libc/include/General.hpp +++ b/core/libs/prx/libc/include/General.hpp @@ -21,6 +21,7 @@ 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); +extern "C" int RenameGuestPath_nid_no_patch(const char* from, const char* to); // Guest path aliases: a guest prefix such as "/savedata0" (a save-data mount point) resolves to a host // directory instead of the run directory; the prefix matches whole path components only. extern "C" void AddPathAlias_nid_no_patch(const char* guestPrefix, const char* hostPath); diff --git a/core/libs/prx/libc/src/Rename.cpp b/core/libs/prx/libc/src/Rename.cpp index b5bb04527..1261e3df3 100644 --- a/core/libs/prx/libc/src/Rename.cpp +++ b/core/libs/prx/libc/src/Rename.cpp @@ -66,7 +66,7 @@ static int RenamePath_nid_no_patch(const std::filesystem::path& source, const st return error ? FilesystemError(error) : 0; } -extern "C" int APS5_VABI rename_nid_postfix(const char* from, const char* to) { +extern "C" int RenameGuestPath_nid_no_patch(const char* from, const char* to) { if (!from || !to) { errno = 14; return -1; } if (!*from || !*to) { errno = 2; return -1; } try { @@ -83,3 +83,7 @@ extern "C" int APS5_VABI rename_nid_postfix(const char* from, const char* to) { return -1; } } + +extern "C" int APS5_VABI rename_nid_postfix(const char* from, const char* to) { + return RenameGuestPath_nid_no_patch(from, to); +} diff --git a/core/libs/prx/libkernel_sys/Export.cpp b/core/libs/prx/libkernel_sys/Export.cpp index 2b4024dde..238aca391 100644 --- a/core/libs/prx/libkernel_sys/Export.cpp +++ b/core/libs/prx/libkernel_sys/Export.cpp @@ -544,13 +544,11 @@ int APS5_VABI unlinkat_nid_postfix(int fd, const char* path, int flag) { return 0; } -int APS5_VABI rename_nid_postfix(const char* from, const char* to); - int APS5_VABI renameat_nid_postfix(int oldfd, const char* from, int newfd, const char* to) { if (from == nullptr || to == nullptr) return static_cast(Fail(GuestEfault)); if (*from == '\0' || *to == '\0') return static_cast(Fail(GuestEnoent)); if ((oldfd == GuestAtFdcwd || *from == '/') && (newfd == GuestAtFdcwd || *to == '/')) - return rename_nid_postfix(from, to); + return RenameGuestPath_nid_no_patch(from, to); if (std::strlen(from) >= GuestPathMax || HasLongComponent(from) || std::strlen(to) >= GuestPathMax || HasLongComponent(to)) return static_cast(Fail(GuestEnametoolong));