61 Commits
Author SHA1 Message Date
blu 9897260c6e Merge branch 'boykopovar:main' into pr/windows-reparse-non-link 2026-10-21 19:08:16 -07:00
Adrià 38d3c0858a Merge pull request #8522 from xXPBSXx/fix/enotdir-through-file-4
fix(libkernel_sys): fail link, symlink, pathconf and fchmodat through a regular file with ENOTDIR
2026-10-21 20:47:51 +02:00
blu 04b1d6e5b5 Merge branch 'boykopovar:main' into pr/windows-reparse-non-link 2026-10-20 23:38:51 -07:00
bluandClaude Fable 5.1 338e2cbe97 test(libkernel): skip the reparse point checks when setting one is refused for rights
Both fixtures required FSCTL_SET_REPARSE_POINT to succeed; a user without the right would have
aborted guest_filesystem and guest_kernel_sys. They now print that the checks are skipped and carry
on, as the symbolic link checks do without Developer Mode. On this PC the control succeeds at
medium integrity, so the checks ran both elevated and unelevated.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-20 18:46:51 -07:00
Dean bfd6c27d65 Merge pull request #8312 from altuux/fix/libkernel-sys-readlink-notdir
fix(libkernel_sys): fail readlink through a regular file with ENOTDIR on Windows
2026-10-21 12:06:42 +13:00
altuuxandAntigravity a685523018 fix(libkernel_sys): fail readlink through a regular file with ENOTDIR on Windows
A path whose directory part is a regular file, such as file/child, failed
with ENOENT in readlink and readlinkat on Windows, where FreeBSD 11.4 fails
it with ENOTDIR (vfs_cache_lookup, sys/kern/vfs_cache.c). The not-found
error now checks whether the nearest existing ancestor is not a directory,
as was previously done for chmod, truncate, utimes, rename, remove, chdir,
opendir, and fopen.

Co-Authored-By: Antigravity <noreply@google.com>
2026-10-20 20:25:13 +02:00
xXPBSXxandClaude Sonnet 5.5 994fb42929 fix(libkernel_sys): check the readlink size before the path
FreeBSD 11.4 kern_readlinkat returns EINVAL for a count above IOSIZE_MAX
before namei looks at the path. readlink and readlinkat checked a NULL or
empty path first, so readlink(NULL, buf, SIZE_MAX) returned EFAULT and
readlink("", buf, SIZE_MAX) returned ENOENT where FreeBSD returns EINVAL.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 20:02:22 +02:00
bluandClaude Opus 5.5 0ecef87c4c fix(libkernel): answer Windows reparse points that are not links
lstat and readlink threw NotImplemented for every Windows reparse point
other than a symbolic link or a drive junction. A tag without the name
surrogate bit (cloud files, deduplication) does not stand for another path,
so lstat now answers as stat does and readlink returns EINVAL, as FreeBSD
does for a file that is not a link and as CPython's os.lstat and os.readlink
do (bpo-37834). A name surrogate that is neither a symbolic link nor a
junction (a mounted volume, a WSL link) is reported as the reparse point
itself with the mode of its attributes, and readlink returns EINVAL.

The tests set reparse tags with FSCTL_SET_REPARSE_POINT, one without the
name surrogate bit and one with it. A compact /exe (WOF) file cannot serve
as the fixture: on Windows 11 24H2 the WOF filter hides the reparse point
from GetFileAttributesW and FileAttributeTagInfo alike. Windows refuses
every open of an unhandled tag without FILE_FLAG_OPEN_REPARSE_POINT, so the
test requires lstat to agree with stat rather than to succeed.

mashingaan's boykopovar/AnyPS5#6447 returned EINVAL for other reparse
points without the tag check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-20 08:21:33 -07:00
xXPBSXxandClaude Sonnet 5.5 923a32c9c9 fix(libkernel_sys): fail link, symlink, pathconf and fchmodat through a regular file with ENOTDIR
FreeBSD 11.4 vfs_cache_lookup answers ENOTDIR when the directory it searches
is not a directory (sys/kern/vfs_cache.c:2104-2105), the lookup behind the
calls fixed in the earlier ENOTDIR changes. These four calls answered ENOENT
for a path such as file/child on Windows.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 16:48:47 +02:00
Adrià 5f7aa5570c Merge pull request #7563 from babyhuey/feat/libkernel_sys-fstatat
feat(libkernel_sys): implement fstatat
2026-10-20 16:08:26 +02:00
Adrià 48790e0233 Merge pull request #7039 from nabil88/fix/windows-libkernel-and-tests
feat(libkernel): implement getdtablesize and fix Windows host-tree removal
2026-10-19 19:36:18 +02:00
Dean 0b6486704b Merge pull request #7915 from root-over/fix/libkernel-open-flags-before-path-v2
fix(libkernel): check open flags before the path in open, _open and openat
2026-10-20 05:52:06 +13:00
Giuseppe Magliano ff688b2146 fix(libkernel): check open flags before the path in open, _open and openat
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.
2026-10-19 15:34:43 +02:00
UAQ Taxi a968336825 fix(libc): remove Windows trees without the remove_all symlink hang
MinGW libstdc++ up to GCC 16 does not treat a reparse point as a link in
std::filesystem::remove_all, so a host tree that holds a symlink is walked
through the link and never returns. Add RemoveTree, which removes the tree
itself on Windows, and use it where save data, app content and the shader
disk cache removed host trees. The libstdc++ fix is in GCC 17 (88856ad855ae).
2026-10-19 14:49:49 +02:00
Rajkamalcode 2224903528 test(libkernel_sys): remove links and the fixture without std::filesystem on Windows
The MinGW libstdc++ reports a dangling symbolic link as missing and clears
the error, so std::filesystem::remove neither deletes it nor fails, and
remove_all loops forever over a tree that contains one. Remove reparse
points with DeleteFileW and RemoveDirectoryW and the fixture through the
shell; record the gap in the libs technical debt.
2026-10-19 14:34:35 +05:30
Adrià 408455bdac Merge pull request #6667 from DavidSamir/fix/libkernel-sys-macos-posix
fix(libkernel_sys): build and check fchdir search permission on macOS
2026-10-19 10:18:13 +02:00
Dean 0a3ba87dcc Merge pull request #6200 from valenciana-nc/fix/symlink-parent-escape
fix(libkernel_sys): reject parent-directory components in symlink targets
2026-10-19 15:22:00 +13:00
valenciana-nc 1a200a1e14 test(libkernel_sys): read accepted symlink targets back through readlink and remove them 2026-10-18 19:04:07 -06:00
Hannah Lyons 15649b702f feat(libkernel_sys): implement fstatat 2026-10-18 20:39:35 -04:00
Adrià ce8c71a78e Merge pull request #6411 from Nixitov/feat/fchown
feat(libkernel_sys): implement fchown
2026-10-19 01:56:48 +02:00
valenciana-nc 84d77798c2 fix(libkernel_sys): reject root names in symlink targets and test target restrictions
Replace the leading-slash absolute-target check with a root-name/root-directory
check so Windows targets like C:/ or \\server\share are rejected too, and
add guest tests covering rejected (.. , ../x, a/../b, a/../../x, /abs, plus
C:/ and UNC paths on Windows) and accepted (sub/dir, a..b, ...) targets.
2026-10-18 21:21:40 +00:00
Adrià ccf0f58785 Merge pull request #6228 from Ondra97/codex/fix-windows-directory-renames
fix(libkernel): preserve directory identity across Windows renames
2026-10-18 22:20:22 +02:00
Maz 7212dae71a fix(libkernel): reject Windows volume mount points in junction reads
A mounted folder uses the junction reparse tag and would otherwise be returned as a relative Volume GUID path. Only a drive path is reported, through the absolute-link text helpers.
2026-10-18 12:53:48 +04:00
Maz e964264d23 Merge branch fix/windows-absolute-symlink into fix/windows-junction
Keep the junction reader and try the absolute symbolic-link reader first.
2026-10-18 12:50:08 +04:00
Ondra97 739e451332 fix(libkernel): preserve directory identity across Windows renames 2026-10-17 23:17:39 +02:00
Maz 01f3938fe1 fix(libkernel): report Windows directory junctions from lstat and readlink 2026-10-18 01:05:40 +04:00
Maz dd70ca83fe test(libkernel): read absolute links into a buffer that fits 2026-10-17 17:06:37 +04:00
Maz 6e331b3823 test(libkernel): compare absolute links by the file they name 2026-10-17 16:46:55 +04:00
Maz 6ad392dad3 fix(libkernel): report absolute Windows symbolic links
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.
2026-10-17 16:03:12 +04:00
Hussein Kadhim fd407e34a0 fix(libkernel): fail open with EINVAL for an invalid access mode or O_CREAT|O_EXCL|O_DIRECTORY
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)
2026-10-16 14:21:23 +00:00
David f9bc7d18e2 test(libkernel_sys): run the fchdir search permission check on macOS
The case that removes search permission from a directory and expects
fchdir to fail with EACCES, leave the working directory unchanged and
succeed again once search is allowed ran only on Linux. It now runs on
every host but Windows, with the POSIX headers it needs.
2026-10-16 07:20:14 +04:00
Nixitov 443df0551b feat(libkernel_sys): implement fchown
Morrowind imports fchown and stops at it once rtprio_thread and the pthread concurrency controls are in. Accept the guest's own owner and group (0) or unchanged (-1), fail an invalid descriptor with EBADF, and throw for another owner or group, since ownership is not modelled.
2026-10-15 16:02:36 +02:00
Dean f40b6930ff Merge pull request #4914 from MarcZX100/codex/carry-link-follow-symlink-4026
fix(libkernel_sys): follow symbolic links in link
2026-10-14 17:05:05 +13:00
Adrià d67a9e5a45 Merge pull request #4553 from Nixitov/feat/fchmodat
feat(libkernel_sys): implement fchmodat
2026-10-13 17:03:44 +02:00
Adrià Franch 603d94a53f test(libkernel_sys): reuse longName in the fchmodat check 2026-10-13 16:14:56 +02:00
Nixitov e3c1d01815 feat(libkernel_sys): implement fchmodat
2 Ship 2 Harkinian (PPSA99621) imports fchmodat through std::filesystem::permissions and stops at start-up on main. Resolve AT_FDCWD and absolute paths as usual and join other relative paths to the directory descriptor like openat, accept 0 and AT_SYMLINK_NOFOLLOW, and mask the mode to 07777.
2026-10-13 16:14:53 +02:00
screammandClaude Fable 5.1 41b0ca597b feat(libkernel_sys): let chroot keep the guest root
Porpoise (PPSA99764) stops on its weak chroot import (#3632, #4497).
Run 5 on main c2565f014, and again on a copy of that runtime:

  FAIL: unresolved ELF import AKknh8Cx-V8 from libkernel_sys.prx

Its only call is in put_root_back (src/porpoise_jailbreak.cpp,
elripalda/Porpoise-Dolphin-Emulator-for-PS5 2ed1ab5a06995aa1): after a
jailbreak daemon has made the console's root its root and /app0 is
gone, it calls fchdir on the descriptor of "/" it opened at start, then
chroot("."), and checks the result. So it only ever puts back the root
it started in, and it does not use paths under any other root.

On top of the lookup errors of the previous commit, chroot now follows
FreeBSD 11.4 sys_chroot and pwd_chroot (8c639945, vfs_syscalls.c and
kern_descrip.c) for that case: a directory that is the guest root
("/", "/..", "." after fchdir to "/") succeeds without a change, since
fd_rdir would be set to the vnode it already is. The guest is taken
never to have changed its root, so with chroot_allow_open_directories 1
an open directory does not give EPERM. ENAMETOOLONG is added as in
pathconf, and a ".." through a file reports ENOTDIR instead of
escaping as a filesystem_error. Any other directory still throws: the
resolver's root and mount aliases are fixed, and no title is known that
needs a real new root.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:11:08 +01:00
screammandClaude Fable 5.1 dc0d316fda feat(libkernel_sys): add chroot with FreeBSD lookup errors
Porpoise (PPSA99764) imports chroot (AKknh8Cx-V8) from
libkernel_sys.prx, not libkernel.prx, one reference. Predicted stop
once pathconf, the pthread_attr calls and ftrylockfile ahead of it are
covered (not a run):

  FAIL: unresolved ELF import AKknh8Cx-V8 from libkernel_sys.prx

The NID is computed with tools/nid_names.py and matches aerolib.

Follows FreeBSD 11.4 sys/kern/vfs_syscalls.c sys_chroot and change_dir
(8c639945a44588f6cfdddfb057bb5aad88735da0) for a root caller up to the
lookup: EFAULT for a null path, ENOENT for an empty or missing one,
ENOTDIR for a file or a path through a file. A directory that is found
throws with the path named: the resolver's root is fixed and the mount
aliases (/app0, /savedata0) are host paths that do not move with it,
so it cannot be re-based, and a real chroot is not modelled. Nothing
shows that Porpoise calls it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-13 15:11:08 +01:00
jagrat Singh 2a8e745267 feat(libkernel_sys): implement renameat 2026-10-13 10:19:35 +02:00
jagrat Singh 55ddffe269 feat(libkernel_sys): implement unlinkat 2026-10-13 10:11:24 +02:00
milescoviello 7cba4ce60a fix(libkernel_sys): let link follow a symbolic link like FreeBSD
link threw "a symbolic link as the existing path is not supported" when
its first argument named a symbolic link, so a valid call aborted the
title. FreeBSD's link follows that link (sys/kern/vfs_syscalls.c,
sys_link: "kern_linkat(td, AT_FDCWD, AT_FDCWD, uap->path, uap->link,
UIO_USERSPACE, FOLLOW)") and hard-links the file it points to; a link to
a directory then fails with EPERM ("if (vp->v_type == VDIR) ... return
(EPERM);") and a dangling one with ENOENT from namei.

link now checks the followed status of the existing path and, when it
is a symbolic link, creates the hard link to the file it resolves to.
std::filesystem::create_hard_link would otherwise link the symbolic
link itself on Linux.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit a521101b77)
2026-10-13 03:46:17 +00:00
jagrat Singh ec0d61e58e feat(libkernel_sys): implement mkdirat 2026-10-13 06:11:56 +05:30
DavidandClaude Fable 5.1 62f6764cc2 feat(libkernel_sys): implement pathconf
Porpoise 2.7 (PPSA99764) stops at load on main 0f863c10:

    FAIL: unresolved ELF import oc98+zOImus from libkernel_sys.prx

oc98+zOImus is pathconf (tools/nid_names.py, aerolib.csv at
zecoxao/sce_symbols 2883963a). It is exported from libkernel_sys next to
link and readlink.

The lookup follows FreeBSD 11's kern_pathconf and namei (release/11.0.0,
671fb7df): links are followed, a path of 1024 bytes or more or a
component over 255 fails with ENAMETOOLONG, a missing path with ENOENT.
The values are the constants of FreeBSD 11's UFS ufs_pathconf, which
vop_stdpathconf shares where both answer. Names whose UFS value depends
on the mount, the kernel options or the page size, or on which UFS and
vop_stdpathconf disagree, throw; other names fail with EINVAL. The
console's filesystem values are unverified and recorded in
TechnicalDebt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-12 22:56:28 +02:00
jagrat Singh 20243b81e4 feat(libkernel_sys): implement readlinkat 2026-10-13 02:09:59 +05:30
codingreapermapsandClaude Opus 5.5 c6be0e95cc fix(libkernel_sys): read relative symbolic links on Windows
readlink threw for every Windows reparse point, including the links
symlink creates. Read the target of a relative symbolic link from its
reparse data and return it with forward slashes. Absolute targets,
junctions and other reparse points still throw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 04:39:39 +01:00
Hannah Lyons c154b8bff3 feat(libkernel_sys): implement openat 2026-10-11 18:01:11 -04:00
Adrià 562149d750 Merge pull request #3685 from zmeizy/claude/kernel-sys-errno-translation
fix(libkernel_sys): translate host errors to guest errno numbers
2026-10-11 23:50:40 +02:00
Santhosh KumarandClaude Opus 5.5 2ad916566f fix(libkernel_sys): return the resolver's error from symlink
symlink, added in #3491 while this branch was open, still resolved its
new path with ResolvePath_nid_no_patch, which now throws for an invalid
"..". Use ResolvePathError_nid_no_patch as link does, so
"missing/../x" returns ENOENT and "file/../x" ENOTDIR.

Reported by @Silverash-i8 on #3485.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 01:25:02 +05:30
Santhosh Kumar 17827dd9ab fix(filesystem): reject invalid parent traversal on Windows 2026-10-12 01:25:02 +05:30
Claude 4a419397cb fix(libkernel_sys): translate host errors to guest errno numbers
GuestError passed host error values up to 34 through and reported every
other value as EIO, so readlink failed with EIO for a name that is too
long or a symbolic link loop, and a host EAGAIN would have been reported
as the guest's EDEADLK. The values whose numbering differs are now
mapped to FreeBSD's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ha6Tsy62AFUyp9a5Mf7vjA
2026-10-11 19:50:38 +00:00