From 8839f6a1ba2cc32e14c98a3fd7f0289bcf84cc4a Mon Sep 17 00:00:00 2001 From: Tharun Balaji Date: Fri, 9 Oct 2026 15:06:23 +0530 Subject: [PATCH 1/3] feat(libkernel): implement sceKernelFdatasync --- core/libs/prx/libkernel/File/src/Stdio.cpp | 8 ++++++++ core/libs/tests/GuestFilesystem.cpp | 3 +++ 2 files changed, 11 insertions(+) diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index 711b9f388..cad87ab6f 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -463,6 +463,14 @@ int APS5_VABI sceKernelFsync(int fd) { #endif } +int APS5_VABI sceKernelFdatasync(int fd) { +#ifdef _WIN32 + return ::_commit(fd); +#else + return ::fdatasync(fd); +#endif +} + int APS5_VABI sceKernelWriteThrottlingStatus(std::uint64_t* status) { if (status == nullptr) throw std::invalid_argument("sceKernelWriteThrottlingStatus: status is null"); status[0] = std::numeric_limits::max(); diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index bd0f598b7..d55e41e93 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -21,6 +21,7 @@ int APS5_VABI futimes_nid_postfix(int, const KernelTimeval*); int APS5_VABI socket_nid_postfix(int, int, int); int APS5_VABI sceKernelFsync(int); int APS5_VABI fdatasync_nid_postfix(int); +int APS5_VABI sceKernelFdatasync(int); int APS5_VABI sceKernelWriteThrottlingStatus(std::uint64_t*); int APS5_VABI sceKernelFtruncate(int, long long); int APS5_VABI sceKernelTruncate_nid_postfix(const char*, long long); @@ -140,6 +141,7 @@ int main() { #endif Require(descriptor >= 0 && sceKernelFsync(descriptor) == 0); Require(fdatasync_nid_postfix(descriptor) == 0); + Require(sceKernelFdatasync(descriptor) == 0); const auto ownerWrite = [&] { return (std::filesystem::status(sized).permissions() & std::filesystem::perms::owner_write) != std::filesystem::perms::none; }; @@ -163,6 +165,7 @@ int main() { Require(fchmod_nid_postfix(descriptor, 0600) == -1 && *__error_nid_postfix() == 9); Require(futimes_nid_postfix(descriptor, nullptr) == -1 && *__error_nid_postfix() == 9); Require(fdatasync_nid_postfix(descriptor) == -1 && *__error_nid_postfix() == 9); + Require(sceKernelFdatasync(descriptor) == -1); #endif const int socket = socket_nid_postfix(2, 2, 0); Require(socket >= 0); From 36bc9214cf05b91f8c52b72a118142a34a7b5b4b Mon Sep 17 00:00:00 2001 From: Tharun Balaji Date: Sat, 10 Oct 2026 13:42:48 +0530 Subject: [PATCH 2/3] fix(libkernel): return SCE errors from sceKernelFdatasync --- core/libs/prx/libkernel/File/src/Stdio.cpp | 5 +++-- core/libs/tests/GuestFilesystem.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index cad87ab6f..983528a93 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -465,10 +465,11 @@ int APS5_VABI sceKernelFsync(int fd) { int APS5_VABI sceKernelFdatasync(int fd) { #ifdef _WIN32 - return ::_commit(fd); + if (::_commit(fd) != 0) return SceErrorFromErrno(errno); #else - return ::fdatasync(fd); + if (::fdatasync(fd) != 0) return SceErrorFromErrno(errno); #endif + return 0; } int APS5_VABI sceKernelWriteThrottlingStatus(std::uint64_t* status) { diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index d55e41e93..86c8c5b22 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -165,7 +165,7 @@ int main() { Require(fchmod_nid_postfix(descriptor, 0600) == -1 && *__error_nid_postfix() == 9); Require(futimes_nid_postfix(descriptor, nullptr) == -1 && *__error_nid_postfix() == 9); Require(fdatasync_nid_postfix(descriptor) == -1 && *__error_nid_postfix() == 9); - Require(sceKernelFdatasync(descriptor) == -1); + Require(sceKernelFdatasync(descriptor) == static_cast(0x80020009u)); #endif const int socket = socket_nid_postfix(2, 2, 0); Require(socket >= 0); From 57be03a4c1cb52f7ee3ca0bec3b4b6874cea1a60 Mon Sep 17 00:00:00 2001 From: Tharun Balaji Date: Sat, 10 Oct 2026 20:42:36 +0530 Subject: [PATCH 3/3] fix: guard sceKernelFdatasync against guest socket descriptors Add the guest socket descriptor guard to sceKernelFdatasync before any native syscall, matching the existing sceKernelFchmod pattern. This prevents high guest socket descriptors (e.g. 0x10000000) from reaching the Windows CRT _commit, which would trigger the invalid-parameter handler, and ensures the correct SCE error is returned on all platforms. Refactor fdatasync_nid_postfix to delegate to sceKernelFdatasync via PosixResult, removing the duplicated socket guard and native syscall. Extend GuestFilesystem tests to cover: - sceKernelFdatasync on a valid guest socket returns SCE EINVAL (0x80020016) - sceKernelFdatasync on a closed guest socket returns SCE EBADF (0x80020009) - sceKernelFdatasync on a high invalid descriptor (0x7fffffff) returns SCE EBADF - closed-ordinary-descriptor tests now run on Windows (verified _commit on a closed descriptor returns EBADF without provoking the CRT handler) --- core/libs/prx/libkernel/File/src/Stdio.cpp | 15 +++++---------- core/libs/tests/GuestFilesystem.cpp | 5 +++-- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index 983528a93..f31ffaa8a 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -464,12 +464,13 @@ int APS5_VABI sceKernelFsync(int fd) { } int APS5_VABI sceKernelFdatasync(int fd) { + if (fd >= GuestSockets::FirstDescriptor) return SceErrorFromErrno(GuestSockets::IsOpen(fd) ? GUEST_EINVAL : GUEST_EBADF); #ifdef _WIN32 - if (::_commit(fd) != 0) return SceErrorFromErrno(errno); + if (::_commit(fd) != 0) return SceErrorFromErrno(errno); #else - if (::fdatasync(fd) != 0) return SceErrorFromErrno(errno); + if (::fdatasync(fd) != 0) return SceErrorFromErrno(errno); #endif - return 0; + return 0; } int APS5_VABI sceKernelWriteThrottlingStatus(std::uint64_t* status) { @@ -801,13 +802,7 @@ int APS5_VABI fsync_nid_postfix(int fd) { } int APS5_VABI fdatasync_nid_postfix(int fd) { - if (fd >= GuestSockets::FirstDescriptor) return PosixFailure(GuestSockets::IsOpen(fd) ? GUEST_EINVAL : GUEST_EBADF); -#ifdef _WIN32 - if (::_commit(fd) != 0) return PosixResult(SceErrorFromErrno(errno)); -#else - if (::fdatasync(fd) != 0) return PosixResult(SceErrorFromErrno(errno)); -#endif - return 0; + return PosixResult(sceKernelFdatasync(fd)); } } diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index 86c8c5b22..93551d5f6 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -160,23 +160,24 @@ int main() { Require(futimes_nid_postfix(descriptor, negative) == -1 && *__error_nid_postfix() == 22); Require(std::fclose(native) == 0); Require(std::filesystem::file_size(sized) == 3); -#ifndef _WIN32 Require(sceKernelFchmod(descriptor, 0600) == static_cast(0x80020009u)); Require(fchmod_nid_postfix(descriptor, 0600) == -1 && *__error_nid_postfix() == 9); Require(futimes_nid_postfix(descriptor, nullptr) == -1 && *__error_nid_postfix() == 9); Require(fdatasync_nid_postfix(descriptor) == -1 && *__error_nid_postfix() == 9); Require(sceKernelFdatasync(descriptor) == static_cast(0x80020009u)); -#endif const int socket = socket_nid_postfix(2, 2, 0); Require(socket >= 0); Require(sceKernelFchmod(socket, 0600) == static_cast(0x80020016u)); Require(fchmod_nid_postfix(socket, 0600) == -1 && *__error_nid_postfix() == 22); Require(futimes_nid_postfix(socket, nullptr) == -1 && *__error_nid_postfix() == 22); Require(fdatasync_nid_postfix(socket) == -1 && *__error_nid_postfix() == 22); + Require(sceKernelFdatasync(socket) == static_cast(0x80020016u)); Require(close_nid_postfix(socket) == 0); Require(fchmod_nid_postfix(socket, 0600) == -1 && *__error_nid_postfix() == 9); Require(futimes_nid_postfix(socket, nullptr) == -1 && *__error_nid_postfix() == 9); Require(fdatasync_nid_postfix(socket) == -1 && *__error_nid_postfix() == 9); + Require(sceKernelFdatasync(socket) == static_cast(0x80020009u)); + Require(sceKernelFdatasync(0x7fffffff) == static_cast(0x80020009u)); Require(remove_nid_postfix(sized.string().c_str()) == 0); const auto present = root / "present.txt"; const auto presentName = present.string();