std::filesystem::status does not follow a Windows symbolic link under
MinGW, so the lookup chflags makes saw a link whose target is missing as
an existing file and returned 0. A reparse point in the last component
is now looked up through the target with the guest stat, as FreeBSD 11.4's
namei follows it: a missing target gives ENOENT, and a trailing slash
after a link to a file gives ENOTDIR.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Main's #9618 has lstat fill a local FileStat and copy it out to the guest.
The merge keeps that and this branch's module lookup in the same call, so an
original .prx name still resolves to its relinked .guest.prx.
fcntl(fd, F_DUPFD, min) with min at or above RLIMIT_NOFILE duplicated the
descriptor repeatedly until the CRT table was full and then failed with
EMFILE, after opening thousands of descriptors. FreeBSD checks the minimum
first: kern_dup returns EINVAL for FDDUP_FCNTL when new < 0 or
new >= maxfd (sys/kern/kern_descrip.c:836-840). Linux already answers
EINVAL through the host fcntl. Check the minimum against the guest
RLIMIT_NOFILE before the Windows loop.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
fstat, _fstat, sceKernelFstat, stat, lstat, sceKernelStat and _fstatfs
filled the caller's struct in place, or copied into it after a check that
only tests for null, so a pointer into unmapped memory crashed the host.
Fill a local struct and copy it out with a checked write that fails with
EFAULT. FreeBSD 11.4 does the same after the lookup has succeeded:
copyout(&ub, uap->sb) in sys_fstat (sys/kern/kern_descrip.c:1328),
copyout(&sb, uap->ub) in sys_stat (sys/kern/vfs_syscalls.c:2066) and
copyout(sfp, uap->buf) in sys_fstatfs (sys/kern/vfs_syscalls.c:337).
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
fcntl(F_SETFL) threw when it changed O_APPEND on a Windows file. The
guest flag already chooses WriteAtEnd, but a descriptor opened with
O_APPEND also carries the CRT's append flag, so _write kept appending
after the guest cleared it. F_SETFL now replaces the CRT descriptor of
every descriptor sharing the open file's status with a duplicate handle
opened with or without _O_APPEND, as libc fdopen does for append mode.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FreeBSD 11.4's vn_open_cred does not follow the last component when
O_EXCL is set, so O_CREAT|O_EXCL on a symbolic link fails with EEXIST
whatever it points to. On Windows the host open followed a dangling link
and created its target. A reparse point in the last component now fails
O_CREAT|O_EXCL with EEXIST before the host open.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
_wchmod changes the read-only attribute of the path it is given, so on
Windows chmod through a symbolic link changed the link and left the file
it names unchanged, and a dangling link succeeded. A reparse point is now
opened through its target and the target's path is changed, as FreeBSD
11.4's sys_chmod passes FOLLOW: a missing target fails with ENOENT and a
link loop with ELOOP. The path lookup of a handle moves out of
WindowsDescriptorPath_nid_no_patch so both use it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FreeBSD resolves the descriptor with getvnode in sys_fchflags
(vfs_syscalls.c:2403), which fails with EINVAL for a descriptor that has no
vnode. fchflags threw for a kqueue descriptor instead.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
FreeBSD keeps every character device on devfs, whose devfs_statfs reports
512-byte blocks, 2 blocks and nothing free. Windows threw for any console,
NUL or the guest random device, and Linux described the host's /dev mount.
A kqueue now returns EINVAL, as getvnode does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The EINVAL for a descriptor without a vnode now applies only to a pipe or socket. A character device is a vnode on FreeBSD, so getvnode succeeds and change_dir fails with ENOTDIR; File::IsCharacterDevice keeps that answer for the host character devices (a tty, NUL or /dev/null) and the guest random device. guest_kernel_sys pins it with /dev/random.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
fchmod and sceKernelFchmod on either end of a pipe answered ENOENT on
Windows, where the pipe has no path, and changed the pipe's mode on Linux.
FreeBSD 11's pipe_chmod sends an unnamed pipe to invfo_chmod, which
returns EINVAL, as sockets already get here.
FreeBSD 11.4's vn_seek fails SEEK_CUR and SEEK_END with EOVERFLOW when the base offset plus a positive offset does not fit in an off_t, and with EINVAL only when the result is negative. The host lseek reports EINVAL for the overflow, so the guest saw EINVAL. When the host call fails with EINVAL for a positive offset on SEEK_CUR or SEEK_END, the base position is read back and the call fails with EOVERFLOW if the sum would overflow; the file position is left unchanged.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>