From a4e755ccb1abb77b174668e48c6a9ba7ee482ccf Mon Sep 17 00:00:00 2001 From: asimplestray <304690168+asimplestray@users.noreply.github.com> Date: Tue, 29 Sep 2026 22:27:51 +0000 Subject: [PATCH] feat(kernel): implement file metadata ops and address conversion --- core/libs/CMakeLists.txt | 4 +- core/libs/prx/libkernel/File/src/Stdio.cpp | 38 ++++++++++++++----- core/libs/prx/libkernel/Socket/src/Socket.cpp | 16 +++----- core/libs/prx/libkernel/Unimplemented.cpp | 10 ----- core/libs/tests/GuestFilesystem.cpp | 26 +++++++++++++ core/libs/tests/GuestUdp.cpp | 14 +++++++ 6 files changed, 75 insertions(+), 33 deletions(-) diff --git a/core/libs/CMakeLists.txt b/core/libs/CMakeLists.txt index ee1485b69..7feb18633 100644 --- a/core/libs/CMakeLists.txt +++ b/core/libs/CMakeLists.txt @@ -281,12 +281,12 @@ if(BUILD_TESTING) endif() add_executable(guest_filesystem_tests tests/GuestFilesystem.cpp) target_include_directories(guest_filesystem_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - target_link_libraries(guest_filesystem_tests PRIVATE libc) + target_link_libraries(guest_filesystem_tests PRIVATE libkernel libc) configure_windows_unwind(guest_filesystem_tests) add_test(NAME guest_filesystem COMMAND guest_filesystem_tests) if(WIN32) set_tests_properties(guest_filesystem PROPERTIES ENVIRONMENT_MODIFICATION - "PATH=path_list_prepend:$") + "PATH=path_list_prepend:$") endif() add_executable(guest_directory_tests tests/GuestDirectory.cpp) target_include_directories(guest_directory_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index 4e35b2dd9..0846da2ae 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -20,6 +20,7 @@ #include #include #include +#include static int NativeRmdir(const std::filesystem::path& path) { return ::_wrmdir(path.wstring().c_str()); } @@ -33,6 +34,11 @@ static int NativeChmod(const std::filesystem::path& path, int mode) { static int NativeFtruncate(int descriptor, std::int64_t length) { return static_cast(::_chsize_s(descriptor, length)); } +static int NativeUtimes(const std::filesystem::path& path, const KernelTimeval* times) { + if (times == nullptr) return ::_wutime(path.wstring().c_str(), nullptr); + struct _utimbuf values{static_cast(times[0].tv_sec), static_cast(times[1].tv_sec)}; + return ::_wutime(path.wstring().c_str(), &values); +} static int NativeFlock(int descriptor, int operation) { HANDLE handle = reinterpret_cast(::_get_osfhandle(descriptor)); if (handle == INVALID_HANDLE_VALUE) { @@ -79,6 +85,7 @@ static std::int64_t NativePwrite(int descriptor, const void* buf, std::size_t nb #include #include #include +#include #include #include #include @@ -94,6 +101,12 @@ static int NativeChmod(const std::filesystem::path& path, int mode) { static int NativeFtruncate(int descriptor, std::int64_t length) { return ::ftruncate(descriptor, static_cast(length)); } +static int NativeUtimes(const std::filesystem::path& path, const KernelTimeval* times) { + if (times == nullptr) return ::utimes(path.c_str(), nullptr); + struct timeval values[2]{{static_cast(times[0].tv_sec), static_cast(times[0].tv_usec)}, + {static_cast(times[1].tv_sec), static_cast(times[1].tv_usec)}}; + return ::utimes(path.c_str(), values); +} static int NativeFlock(int descriptor, int operation) { return ::flock(descriptor, operation); } @@ -180,6 +193,10 @@ int APS5_VABI ftruncate_nid_postfix(int d, int64_t length) { return 0; } +int APS5_VABI sceKernelFtruncate(int d, int64_t length) { + return ftruncate_nid_postfix(d, length); +} + int64_t APS5_VABI lseek_nid_postfix(int d, int64_t offset, int whence) { return static_cast(sceKernelLseek(d, offset, whence)); } @@ -423,23 +440,24 @@ int APS5_VABI rmdir_nid_postfix(const char* path) { extern "C" { int APS5_VABI sceKernelChmod_nid_postfix(const char* path, std::uint16_t mode) { - (void)path; - (void)mode; - NotImplemented_nid_no_patch(__func__); - return 0; + return chmod_nid_postfix(path, mode); } int APS5_VABI sceKernelTruncate_nid_postfix(const char* path, std::int64_t length) { - (void)path; - (void)length; - NotImplemented_nid_no_patch(__func__); + if (path == nullptr) throw std::invalid_argument("sceKernelTruncate: path is null"); + if (length < 0) return SceErrorFromErrno(GUEST_EINVAL); + const auto native = ResolvePath_nid_no_patch(path); + std::error_code error; + if (!std::filesystem::exists(native, error)) return SceErrorFromErrno(GUEST_ENOENT); + std::filesystem::resize_file(native, static_cast(length), error); + if (error) return SceErrorFromErrno(GUEST_EIO); return 0; } int APS5_VABI sceKernelUtimes_nid_postfix(const char* path, const KernelTimeval* times) { - (void)path; - (void)times; - NotImplemented_nid_no_patch(__func__); + if (path == nullptr) throw std::invalid_argument("sceKernelUtimes: path is null"); + const auto native = ResolvePath_nid_no_patch(path); + if (NativeUtimes(native, times) != 0) return SceErrorFromErrno(errno); return 0; } diff --git a/core/libs/prx/libkernel/Socket/src/Socket.cpp b/core/libs/prx/libkernel/Socket/src/Socket.cpp index 89b612603..1568af931 100644 --- a/core/libs/prx/libkernel/Socket/src/Socket.cpp +++ b/core/libs/prx/libkernel/Socket/src/Socket.cpp @@ -5,6 +5,9 @@ extern "C" { +const char* APS5_VABI __inet_ntop_nid_postfix(int family, const void* source, char* destination, std::uint32_t capacity); +int APS5_VABI __inet_pton_nid_postfix(int family, const char* text, void* destination); + int APS5_VABI accept_nid_postfix(int s, void* addr, uint32_t* addrlen) { (void)s; (void)addr; @@ -54,20 +57,11 @@ int64_t APS5_VABI recv_nid_postfix(int s, void* buf, uint64_t len, int flags) { const char* APS5_VABI inet_ntop_nid_postfix(int af, const void* src, char* dst, uint32_t size) { - (void)af; - (void)src; - (void)dst; - (void)size; - NotImplemented_nid_no_patch(__func__); - return nullptr; + return __inet_ntop_nid_postfix(af, src, dst, size); } int APS5_VABI inet_pton_nid_postfix(int af, const char* src, void* dst) { - (void)af; - (void)src; - (void)dst; - NotImplemented_nid_no_patch(__func__); - return 0; + return __inet_pton_nid_postfix(af, src, dst); } int APS5_VABI select_nid_postfix(int nfds, void* readfds, void* writefds, void* exceptfds, const void* timeout) { diff --git a/core/libs/prx/libkernel/Unimplemented.cpp b/core/libs/prx/libkernel/Unimplemented.cpp index f5401a80b..69a80905d 100644 --- a/core/libs/prx/libkernel/Unimplemented.cpp +++ b/core/libs/prx/libkernel/Unimplemented.cpp @@ -5,11 +5,6 @@ extern "C" { -int APS5_VABI rename_nid_postfix() { - NotImplemented_nid_no_patch(__func__); - return 0; -} - int APS5_VABI sceCoredumpWriteUserData() { NotImplemented_nid_no_patch(__func__); return 0; @@ -35,9 +30,4 @@ int APS5_VABI sceKernelAprResolveFilepathsWithPrefixToIdsForEach() { return 0; } -int APS5_VABI sceKernelFtruncate() { - NotImplemented_nid_no_patch(__func__); - return 0; -} - } diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index 0a5b998cc..2bf530e32 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -7,6 +7,11 @@ extern "C" { int APS5_VABI remove_nid_postfix(const char*); int APS5_VABI rename_nid_postfix(const char*, const char*); +int APS5_VABI sceKernelChmod_nid_postfix(const char*, unsigned short); +int APS5_VABI sceKernelFsync(int); +int APS5_VABI sceKernelFtruncate(int, long long); +int APS5_VABI sceKernelTruncate_nid_postfix(const char*, long long); +int APS5_VABI sceKernelUtimes_nid_postfix(const char*, const void*); int* APS5_VABI __error_nid_postfix(); } static void Check(bool value, int line) { @@ -41,6 +46,27 @@ int main() { Require(remove_nid_postfix(file.string().c_str()) == 0); Require(!std::filesystem::exists(file)); Require(remove_nid_postfix(file.string().c_str()) == -1 && *__error_nid_postfix() == 2); + const auto sized = root / "sized.txt"; + { std::ofstream stream(sized); stream << "0123456789abcdef"; } + Require(sceKernelChmod_nid_postfix(sized.string().c_str(), 0600) == 0); + Require(sceKernelTruncate_nid_postfix(sized.string().c_str(), 6) == 0); + Require(std::filesystem::file_size(sized) == 6); + { std::ifstream stream(sized); std::string contents; std::getline(stream, contents); + Require(contents == "012345"); } + Require(sceKernelTruncate_nid_postfix((sized / "missing").string().c_str(), 6) == static_cast(0x80020002u)); + Require(sceKernelUtimes_nid_postfix(sized.string().c_str(), nullptr) == 0); + std::FILE* native = std::fopen(sized.string().c_str(), "r+b"); + Require(native != nullptr); +#ifdef _WIN32 + const int descriptor = _fileno(native); +#else + const int descriptor = ::fileno(native); +#endif + Require(descriptor >= 0 && sceKernelFsync(descriptor) == 0); + Require(sceKernelFtruncate(descriptor, 3) == 0); + Require(std::fclose(native) == 0); + Require(std::filesystem::file_size(sized) == 3); + Require(remove_nid_postfix(sized.string().c_str()) == 0); Require(remove_nid_postfix(root.string().c_str()) == 0); Require(!std::filesystem::exists(root)); } diff --git a/core/libs/tests/GuestUdp.cpp b/core/libs/tests/GuestUdp.cpp index 572e8dc3a..df2c4e3c3 100644 --- a/core/libs/tests/GuestUdp.cpp +++ b/core/libs/tests/GuestUdp.cpp @@ -16,6 +16,8 @@ int APS5_VABI ioctl_nid_postfix(int, std::uint64_t, void*); std::int64_t APS5_VABI sendto_nid_postfix(int, const void*, std::uint64_t, int, const void*, std::uint32_t); std::int64_t APS5_VABI recvfrom_nid_postfix(int, void*, std::uint64_t, int, void*, std::uint32_t*); int APS5_VABI close_nid_postfix(int); +const char* APS5_VABI inet_ntop_nid_postfix(int, const void*, char*, std::uint32_t); +int APS5_VABI inet_pton_nid_postfix(int, const char*, void*); int* APS5_VABI __error_nid_postfix(); } static void Require(bool value) { if (!value) std::abort(); } @@ -65,5 +67,17 @@ int main() { Require(close_nid_postfix(receiver) == -1 && *__error_nid_postfix() == 9); Require(ioctl_nid_postfix(receiver, 0x4004667f, &queued) == -1); Require(close_nid_postfix(sender) == 0); + unsigned char parsed[16]{}; + Require(inet_pton_nid_postfix(2, "127.0.0.1", parsed) == 1); + Require(parsed[0] == 127 && parsed[1] == 0 && parsed[2] == 0 && parsed[3] == 1); + char text[64]{}; + Require(inet_ntop_nid_postfix(2, parsed, text, sizeof(text)) == text); + Require(std::strcmp(text, "127.0.0.1") == 0); + Require(inet_pton_nid_postfix(28, "::1", parsed) == 1); + Require(inet_ntop_nid_postfix(28, parsed, text, sizeof(text)) == text); + Require(std::strcmp(text, "::1") == 0); + Require(inet_pton_nid_postfix(99, "127.0.0.1", parsed) == -1 && *__error_nid_postfix() == 47); + Require(inet_pton_nid_postfix(2, "not-an-address", parsed) == 0); + Require(inet_ntop_nid_postfix(2, parsed, text, 4) == nullptr && *__error_nid_postfix() == 28); Require(socket_nid_postfix(2, 1, 0) == -1); // unsupported TCP must not appear to work }