From 2f1eb100a03a0782bf6dba912936f371151e1a1b Mon Sep 17 00:00:00 2001 From: David Date: Tue, 13 Oct 2026 06:59:08 +0400 Subject: [PATCH] fix(libkernel): fail reads on a directory descriptor with EISDIR on Windows (cherry picked from commit d7ef271ef7eeb1d82a337a0b0a9767ce68721bd4) --- core/libs/prx/libkernel/File/src/Open.cpp | 4 ++++ core/libs/prx/libkernel/File/src/Stdio.cpp | 3 ++- core/libs/tests/GuestFilesystem.cpp | 18 +++++++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/core/libs/prx/libkernel/File/src/Open.cpp b/core/libs/prx/libkernel/File/src/Open.cpp index 2a1edd018..1155960dd 100644 --- a/core/libs/prx/libkernel/File/src/Open.cpp +++ b/core/libs/prx/libkernel/File/src/Open.cpp @@ -53,6 +53,10 @@ static int NativeRead(int fd, void* buf, std::size_t n) { } const int result = ::_read(fd, buf, static_cast(n)); if (result < 0 && _doserrno == ERROR_NO_DATA) errno = EAGAIN; + if (result == 0 && File::DirectoryDescriptorPath(fd)) { + errno = EISDIR; + return -1; + } return result; } static int NativeWrite(int fd, const void* buf, std::size_t n) { diff --git a/core/libs/prx/libkernel/File/src/Stdio.cpp b/core/libs/prx/libkernel/File/src/Stdio.cpp index f42248503..58e25ea3d 100644 --- a/core/libs/prx/libkernel/File/src/Stdio.cpp +++ b/core/libs/prx/libkernel/File/src/Stdio.cpp @@ -184,7 +184,7 @@ std::int64_t NativePositioned_nid_no_patch(int descriptor, void* buf, std::size_ } LARGE_INTEGER position{}; if (::GetFileType(handle) != FILE_TYPE_DISK || !::SetFilePointerEx(handle, LARGE_INTEGER{}, &position, FILE_CURRENT)) { - errno = ESPIPE; + errno = !File::DirectoryDescriptorPath(descriptor) ? ESPIPE : write ? EBADF : EISDIR; return -1; } OVERLAPPED overlapped{}; @@ -991,6 +991,7 @@ static std::int64_t TransferIovecs(int d, const KernelIovec* iov, int iovcnt, co const auto result = offset != nullptr ? NativePositioned_nid_no_patch(d, &none, 0, *offset, write) : NativeTransfer(d, &none, 0, write); return result < 0 ? SceErrorFromErrno(errno) : 0; } + if (!write && offset == nullptr && File::DirectoryDescriptorPath(d)) return SceErrorFromErrno(GUEST_EISDIR); const bool whole = write || offset != nullptr || NativeIsDisk(d); std::int64_t done = 0; for (int i = 0; i < iovcnt; ++i) { diff --git a/core/libs/tests/GuestFilesystem.cpp b/core/libs/tests/GuestFilesystem.cpp index d32843235..18822eeb2 100644 --- a/core/libs/tests/GuestFilesystem.cpp +++ b/core/libs/tests/GuestFilesystem.cpp @@ -51,6 +51,11 @@ int APS5_VABI mkdir_nid_postfix(const char*, unsigned short); int APS5_VABI sceKernelOpen(const char*, int, unsigned short); int APS5_VABI sceKernelClose(int); int APS5_VABI sceKernelGetdents(int, char*, int); +std::int64_t APS5_VABI sceKernelRead(int, void*, std::size_t); +std::int64_t APS5_VABI sceKernelReadv(int, const void*, int); +std::int64_t APS5_VABI sceKernelPread(int, void*, std::size_t, std::int64_t); +std::int64_t APS5_VABI sceKernelPreadv(int, const void*, int, std::int64_t); +std::int64_t APS5_VABI sceKernelPwrite(int, const void*, std::size_t, std::int64_t); int APS5_VABI sceKernelStat(const char*, FileStat*); int APS5_VABI sceKernelCheckReachability(const char*); int APS5_VABI sceKernelFstat(int, FileStat*); @@ -602,7 +607,18 @@ int main() { Require(syncedLocked >= 0 && sceKernelFsync(syncedLocked) == 0 && close_nid_postfix(syncedLocked) == 0); Require(sceKernelChmod_nid_postfix(presentName.c_str(), 0600) == 0); const int directoryDescriptor = open_nid_postfix(rootName.c_str(), 0, 0); - Require(directoryDescriptor >= 0 && close_nid_postfix(directoryDescriptor) == 0); + Require(directoryDescriptor >= 0); + char directoryBytes[8]{}; + struct { void* base; std::size_t length; } directoryVector[2] = {{directoryBytes, 3}, {directoryBytes + 3, 5}}; + Require(read_nid_postfix(directoryDescriptor, directoryBytes, sizeof(directoryBytes)) == -1 && *__error_nid_postfix() == 21); + Require(sceKernelRead(directoryDescriptor, directoryBytes, sizeof(directoryBytes)) == static_cast(0x80020015u)); + Require(sceKernelReadv(directoryDescriptor, directoryVector, 2) == static_cast(0x80020015u)); + Require(sceKernelPread(directoryDescriptor, directoryBytes, sizeof(directoryBytes), 0) == static_cast(0x80020015u)); + Require(sceKernelPreadv(directoryDescriptor, directoryVector, 2, 0) == static_cast(0x80020015u)); + Require(sceKernelPwrite(directoryDescriptor, "x", 1, 0) == static_cast(0x80020009u)); + std::vector listing(4096); + Require(sceKernelGetdents(directoryDescriptor, listing.data(), static_cast(listing.size())) > 0); + Require(close_nid_postfix(directoryDescriptor) == 0); const int flaggedDirectory = sceKernelOpen(rootName.c_str(), 0x20000, 0); Require(flaggedDirectory >= 0 && sceKernelClose(flaggedDirectory) == 0); std::vector entries(4096);