fix(libkernel): open directories whose host path ends in a separator on Windows

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
winstrex 2026-10-12 10:06:44 -03:00
parent 33ae282e4e
commit a47178b86f
2 changed files with 17 additions and 3 deletions

View File

@ -169,12 +169,14 @@ static int OpenNative(const std::filesystem::path& native, int flags, std::uint1
#endif
int fd = NativeOpen(native, MapFlags(flags), mode);
#ifdef _WIN32
if (fd < 0 && errno != ENOENT) {
if (fd < 0 && (errno != ENOENT || !native.has_filename())) {
auto directory = native;
while (!directory.has_filename() && directory.has_relative_path()) directory = directory.parent_path();
std::error_code error;
if (std::filesystem::is_directory(native, error)) {
if (std::filesystem::is_directory(directory, error)) {
if ((flags & (SCE_KERNEL_O_CREAT | SCE_KERNEL_O_EXCL)) == (SCE_KERNEL_O_CREAT | SCE_KERNEL_O_EXCL)) errno = EEXIST;
else if ((flags & SCE_KERNEL_O_ACCMODE) != SCE_KERNEL_O_RDONLY || (flags & (SCE_KERNEL_O_CREAT | SCE_KERNEL_O_TRUNC))) errno = EISDIR;
else fd = File::OpenDirectoryDescriptor(native);
else fd = File::OpenDirectoryDescriptor(directory);
}
}
#endif

View File

@ -12,6 +12,8 @@
#include <cstdio>
#include <cstring>
#include <stdexcept>
#include <string>
#include <vector>
#ifdef _WIN32
#include <io.h>
#include <windows.h>
@ -48,6 +50,7 @@ int APS5_VABI rmdir_nid_postfix(const char*);
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);
int APS5_VABI sceKernelStat(const char*, FileStat*);
int APS5_VABI sceKernelCheckReachability(const char*);
int APS5_VABI sceKernelFstat(int, FileStat*);
@ -567,6 +570,15 @@ int main() {
Require(directoryDescriptor >= 0 && close_nid_postfix(directoryDescriptor) == 0);
const int flaggedDirectory = sceKernelOpen(rootName.c_str(), 0x20000, 0);
Require(flaggedDirectory >= 0 && sceKernelClose(flaggedDirectory) == 0);
std::vector<char> entries(4096);
for (const auto& directoryName : {std::string("/"), std::string("."), rootName + "/", rootName + "/.."}) {
const int listed = sceKernelOpen(directoryName.c_str(), 0x20000, 0);
Require(listed >= 0);
int read = sceKernelGetdents(listed, entries.data(), static_cast<int>(entries.size()));
Require(read > 0);
while (read > 0) read = sceKernelGetdents(listed, entries.data(), static_cast<int>(entries.size()));
Require(read == 0 && sceKernelClose(listed) == 0);
}
Require(open_nid_postfix(presentName.c_str(), 0x20000, 0) == -1 && *__error_nid_postfix() == 20);
Require(sceKernelOpen(presentName.c_str(), 0x20000, 0) == static_cast<int>(0x80020014u));
Require(sceKernelOpen(presentName.c_str(), 0x20402, 0) == static_cast<int>(0x80020014u));