lseek on a descriptor that is not open with an invalid whence answered EINVAL.
FreeBSD 11.4 kern_lseek looks the descriptor up first and only then lets the
file's seek operation judge the whence, so the answer is EBADF.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A path whose directory part is a regular file, such as file/child, failed
with ENOENT in chdir, remove, opendir, fopen and freopen on Windows, where
FreeBSD 11.4 fails it with ENOTDIR (vfs_cache_lookup, sys/kern/vfs_cache.c).
The not-found error of these calls now asks whether the nearest existing
ancestor is not a directory, as open, stat, lstat, access and unlink do.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A path whose directory part is a regular file, such as file/child, failed
with ENOENT in chmod, truncate, utimes and rename on Windows, where FreeBSD
11.4 fails it with ENOTDIR (vfs_cache_lookup, sys/kern/vfs_cache.c). The
not-found error of these calls now asks whether the nearest existing
ancestor is not a directory, as open, stat, lstat, access and unlink do.
For rename the source ancestor is checked first and the destination ancestor
only while the source exists. A test line that expected ENOENT for truncate
of a path below a regular file now expects ENOTDIR.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A path whose directory part is a regular file, such as file/child, failed
with ENOENT in open, stat, lstat, access and unlink on Windows, where
FreeBSD 11.4 lookup fails it with ENOTDIR (vfs_cache_lookup, sys/kern/vfs_cache.c).
mkdir and rmdir already did. A not-found error of these calls now asks whether the
nearest existing ancestor is not a directory and reports ENOTDIR then.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fopen and freopen of a directory in a write mode failed with EACCES on
Windows, the host's answer. FreeBSD 11.4 fopen opens the path with open(2),
which fails a directory opened for writing with EISDIR (kern_openat, vn_open_cred).
A failed write-mode open of a directory now reports EISDIR.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
On Windows fsync and fdatasync of a pipe descriptor answered EBADF for the
read end and 0 for the write end. FreeBSD 11.4 kern_fsync reaches the
descriptor through getvnode, which fails a descriptor that is not a vnode
with EINVAL. NativeSync now refuses a pipe handle with EINVAL before it
commits.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
flock on a descriptor that is not open threw a runtime_error from the failed
Windows lock call, ending the title. FreeBSD 11.4 sys_flock fails it with
EBADF (fget) and a descriptor that is not a vnode, such as a pipe, with
EOPNOTSUPP. The guest flock now checks the descriptor first, on Windows
through the OS handle and elsewhere through fstat.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
FreeBSD 11.4 kern_truncate returns EINVAL for a negative length before it
looks up the path, and getutimes rejects an out-of-range tv_usec before
namei in utimes and lutimes. The guest calls checked a NULL or empty path
first, so truncate(NULL, -1) and utimes("", {usec -1}) returned EFAULT or
ENOENT where FreeBSD returns EINVAL.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
FreeBSD 11.4 rejects access mode 3 in kern_openat and
O_CREAT|O_EXCL|O_DIRECTORY in vn_open_cred before namei reads the path
or resolves the directory descriptor. open, _open and openat checked a
NULL or empty path first and returned EFAULT or ENOENT for those flags.
InvalidOpenFlags moves to FileFlags.hpp and runs first in all three.
sceKernelFstat and fstat passed any descriptor to the UCRT's _fstat64, which
raises the invalid-parameter handler for one that is not open. The crash
report installs that handler as fatal, so the calling thread died where the
console returns EBADF. Dying Light 2 (PPSA02262) hits it on a loading thread
right after sign-in.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Open.cpp passed host errno values 1 to 34 through and turned every
other one into EIO. On Linux, ENAMETOOLONG (36) and ELOOP (40) are above
that range, so sceKernelOpen and sceKernelUnlink returned EIO for a name
longer than 255 bytes or a symbolic link loop, where FreeBSD returns
ENAMETOOLONG (63) and ELOOP (62). sceKernelStat returned ENOENT for
both. sceKernelMkdir already reported them through the mapping in
Stdio.cpp.
Values above 34 now go through FilesystemError, the std::errc mapping
that path resolution already uses. sceKernelStat returns ENAMETOOLONG
and ELOOP when the status query fails with them. The POSIX open, unlink
and stat wrappers set the same errno values.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fopen resolved the random device paths to a host file that does not
exist and failed with ENOENT, while open and sceKernelOpen already serve
them from host entropy. A read-only fopen of either path now returns a
stream whose fread fills the buffer with host entropy. setvbuf, feof,
ferror, clearerr, the stream locks and fclose work on it, fflush returns
0 as on a FreeBSD stream that is not writing, other stream functions
throw, and opening the paths for writing throws as in libkernel.
ProsperoTV (PPSA99003) reads its phone pairing code this way and showed
"Code expired or unavailable".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceKernelGetdirentries on a descriptor that is not a directory returned
ENOTDIR from the host getdents64 on Linux, and ENOTDIR for every descriptor
missing from the directory table on Windows, including invalid ones.
FreeBSD 11.4's kern_getdirentries returns EINVAL when the vnode is not a
directory.
Return EINVAL for a regular file on both hosts and EBADF for an invalid
descriptor on Windows. Test getdents and getdirentries on a regular file and
list the pipe case, which still fails with ESPIPE on Linux, in the library's
technical debt file.
Written with AI assistance (Claude).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
lstat and readlink aborted on an absolute symbolic link because only a relative reparse point was accepted. Read the link text, and still refuse reparse points that are not symbolic links.
FreeBSD rejects an access mode of 3 in kern_openat and the combination of O_CREAT, O_EXCL and O_DIRECTORY in vn_open_cred before it looks the path up. sceKernelOpen, open and openat threw std::invalid_argument for access mode 3 and, on Windows, created the file for the second combination.
(cherry picked from commit 038a07098ef38e95fade52154847b579dcb0f9d0)
A read-only open, stat or reachability check of a missing path listed its
directory twice: once for a case-insensitive match of the name and again for
a case-insensitive match of the relinked <name>.guest.prx (#5434). Both
names are now matched in the same listing. Precedence and the ambiguous-name
errors are unchanged.
stat of a dangling link reaches FillFileStat and throws on the CI toolchain; it is not part of this change.
Co-Authored-By: Claude <noreply@anthropic.com>
lstat of a Windows symbolic link threw, although symlink creates links
with relative targets on Windows and readlink reads them. Report such a
link as S_IFLNK with its own identity and times and the length of its
target as st_size, through the reparse reader readlink already used,
now shared from libkernel. Links with absolute targets, junctions and
other reparse points still throw, as for readlink.
Borderlands 4 (PPSA01494) loads its UI library with
sceKernelLoadStartModule("/app0/prx/libRenoirCore.PS5.prx"), but ships
the module as prx/librenoircore.ps5.prx. On Linux the call fails:
Could not load /app0/prx/libRenoirCore.PS5.prx result 0, handle result -2147352574
(0x80020002, ENOENT). Guest paths are resolved case-insensitively, but
that only finds a component that exists. With the documented layout,
app0/prx holds only the converted librenoircore.ps5.prx.guest.prx,
so the requested name resolves to itself and RelinkedModulePath then
looks for "libRenoirCore.PS5.prx.guest.prx" with its exact spelling.
Windows and macOS hosts ignore the case, so only Linux is affected.
RelinkedModulePath now falls back to the same ASCII case-insensitive
match as ResolveHostPath when the exact <name>.guest.prx is missing,
and throws for an ambiguous match as that does. dlopen,
sceKernelLoadStartModule, stat, open and sceKernelCheckReachability all
go through it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>