diff --git a/docs/RPCS3_PORT.md b/docs/RPCS3_PORT.md index 2bd8260..d6f1ff1 100644 --- a/docs/RPCS3_PORT.md +++ b/docs/RPCS3_PORT.md @@ -425,7 +425,7 @@ unloaded, so the next load finds its addresses free. handler it replaced (the title's crash reporter), and the title's handlers return when the core is unloaded. -**Platform gaps closed in the SDK (a9fbb6a).** Each is aliased in +**Platform gaps closed in the SDK (8160289).** Each is aliased in `tools/core-imports.py`. - No export at all: `accept4`, `getpagesizes`, `in6addr_any`. @@ -437,6 +437,12 @@ return when the core is unloaded. - Answered differently on the console: `pthread_getaffinity_np` and `pthread_setaffinity_np` (the 64-bit mask), `sysconf` (13 CPUs, not 16), `pthread_exit` (a thread's `thread_local` destructors first). +- Refused: `realpath` answers EPERM, even for `/app0`, so libc++'s + `std::filesystem::canonical` and `weakly_canonical` came back empty and the + package installer could not normalise its path. `ps5_realpath` makes the path + absolute, resolves `.` and `..` by name and checks each component with + `stat`; it keeps a symbolic link's name. The title links it too + (`--wrap=realpath`). - Memory: committed ranges (`ps5_vrange_commit`), exact reservations, zeroing of reused direct memory, and placement up to 1 TiB. diff --git a/src/platform_wraps.c b/src/platform_wraps.c index 7493785..f46451b 100644 --- a/src/platform_wraps.c +++ b/src/platform_wraps.c @@ -45,6 +45,13 @@ DIR *__wrap_fdopendir(int fd) return ps5_fdopendir(fd); } +/* A title's realpath is refused (EPERM); libc++'s std::filesystem canonical + * paths are built on it. */ +char *__wrap_realpath(const char *path, char *resolved) +{ + return ps5_realpath(path, resolved); +} + DIR *__wrap_opendir(const char *path) { return ps5_opendir(path); diff --git a/tests/test_core_imports.py b/tests/test_core_imports.py index e074b4d..2427b34 100644 --- a/tests/test_core_imports.py +++ b/tests/test_core_imports.py @@ -29,16 +29,20 @@ class CoreImports(unittest.TestCase): self.assertIn('asm("ps5_rewinddir")', generated) self.assertIn('asm("ps5_opendir")', generated) - def test_aligned_new_and_getcwd_bind_to_the_title(self): + def test_aligned_new_getcwd_and_realpath_bind_to_the_title(self): # Over-aligned operator new comes from direct memory, as plain new does, - # and getcwd from the platform layer (libc's faults for a title). + # and getcwd and realpath from the platform layer (libc's fault or are + # refused for a title). generated = imports.generate({'_ZnwmSt11align_val_t': ('FUNC', False), '_ZnamSt11align_val_t': ('FUNC', False), '_ZnwmSt11align_val_tRKSt9nothrow_t': ('FUNC', False), - 'getcwd': ('FUNC', False)}) + 'getcwd': ('FUNC', False), + 'realpath': ('FUNC', False)}) self.assertIn('asm("ps5_core_new_aligned")', generated) self.assertIn('asm("ps5_core_new_aligned_nothrow")', generated) self.assertIn('asm("ps5_getcwd")', generated) + self.assertIn('asm("ps5_realpath")', generated) + self.assertNotIn('asm("realpath")', generated) self.assertNotIn('asm("_ZnwmSt11align_val_t")', generated) def test_weak_only_when_every_core_imports_weakly(self): diff --git a/tools/build-title.sh b/tools/build-title.sh index ada7b50..e1ada37 100755 --- a/tools/build-title.sh +++ b/tools/build-title.sh @@ -274,6 +274,9 @@ PY # payload SDK fork), and src/platform_wraps.c binds these links to it. A core's # own imports of the same calls are bound to it by tools/core-imports.py. directory_wrap_flags="--wrap=opendir --wrap=readdir --wrap=closedir --wrap=fdopendir --wrap=openat --wrap=unlinkat --wrap=fchmodat" +# realpath is refused to a title, so std::filesystem::canonical and +# weakly_canonical (RPCS3's package installer) came back empty. +directory_wrap_flags+=" --wrap=realpath" # Folders the title or a core creates are 0777 and files at least 0666, so FTP, # which runs as another user, can reach them (src/permissions_ps5.cpp). directory_wrap_flags+=" --wrap=mkdir --wrap=open --wrap=fopen" diff --git a/tools/core-imports.py b/tools/core-imports.py index 22cfdb0..c3b86a5 100644 --- a/tools/core-imports.py +++ b/tools/core-imports.py @@ -98,7 +98,9 @@ def generate(imports): # src/core_loader_ps5.cpp: the console's, plus dlopen(NULL), the # process handle LLVM's JIT asks for. 'dlopen': 'ps5_cores_dlopen', 'dlsym': 'ps5_cores_dlsym', - 'dlclose': 'ps5_cores_dlclose', 'dlerror': 'ps5_cores_dlerror'} + 'dlclose': 'ps5_cores_dlclose', 'dlerror': 'ps5_cores_dlerror', + # Refused to a title (EPERM), even for /app0. + 'realpath': 'ps5_realpath'} for index, (name, (kind, weak)) in enumerate(sorted(imports.items())): target = aliases.get(name, name) declaration = f'void core_import_{index}()' if kind == 'FUNC' else f'char core_import_{index}[]' diff --git a/tools/setup-native-dependencies.sh b/tools/setup-native-dependencies.sh index f082f8d..c3bee63 100644 --- a/tools/setup-native-dependencies.sh +++ b/tools/setup-native-dependencies.sh @@ -23,7 +23,7 @@ zlib_stamp="$zlib_root/.source-version" # there). The pinned revision is exported with git archive, so a build never # depends on the fork's working tree, and the SDK directory records it. sdk_fork="${PS5_PAYLOAD_SDK_FORK:-$root/../PS5_PayloadSDK}" -sdk_revision=a9fbb6a9c9c67567ef5561c74075ce5e2ee9b21b +sdk_revision=8160289a132263853f4c7cff542d9d6edc0c7c12 zlib_url="https://zlib.net/fossils/zlib-$zlib_version.tar.gz" zlib_hash="bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16" skip_sdk=false