Skip to content

feat(libkernel_sys): implement lchflags - #9442

Open
Gruzzberry wants to merge 1 commit into
boykopovar:mainfrom
Gruzzberry:feat/lchflags
Open

Gruzzberry wants to merge 1 commit into
boykopovar:mainfrom
Gruzzberry:feat/lchflags

Conversation

@Gruzzberry

@Gruzzberry Gruzzberry commented Oct 21, 2026 •

Copy link
Copy Markdown

What

lchflags was a throwing stub in libkernel_sys. FreeBSD 11.4 implements it as chflags without following a symbolic link in the last component: sys_lchflags calls kern_chflagsat with AT_SYMLINK_NOFOLLOW, and kern_chflagsat only switches namei from FOLLOW to NOFOLLOW.

chflags in Stdio.cpp now goes through ChangeFileFlags_nid_no_patch, which takes the same follow choice. When not following, a symbolic link in the last component is the target, so a dangling link is accepted instead of failing the lookup. The link is recognised with File::FillLinkStat, the guest lstat, because under MinGW std::filesystem::symlink_status reports a Windows symbolic link as the file or directory it names. A trailing slash still follows, as in FreeBSD. The flag checks are the existing ones, unchanged: unknown bits EOPNOTSUPP, SF_SNAPSHOT EPERM, any other non-zero flag throws because the host keeps no BSD file flags. chflags itself behaves as before.

Tested

Windows 11 (10.0.26200), WinLibs MinGW-w64 GCC 15.2.0 r7, Ninja, Release, -DBUILD_TESTING=ON, on main d6eafa5 (rebased), Developer Mode on so the link cases run.

Overlaps

Checklist

AI-assisted (Claude Code).

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Progress report (db6af9e → 47ea711)

📈 System libraries: 48.54% (+0.01%, +1 implemented functions)

✅ 1 implemented
Library Name
libkernel_sys lchflags_nid_postfix

@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 4630 docs/dev/debt/libkernel.md
PR 5021 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.cpp
docs/dev/debt/libkernel.md
PR 6149 docs/dev/debt/libkernel.md
PR 6740 docs/dev/debt/libkernel.md
PR 6830 docs/dev/debt/libkernel.md
PR 6936 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 7049 docs/dev/debt/libkernel.md
PR 7088 docs/dev/debt/libkernel.md
PR 7090 docs/dev/debt/libkernel.md
PR 7105 docs/dev/debt/libkernel.md
PR 7121 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 7135 docs/dev/debt/libkernel.md
PR 7149 docs/dev/debt/libkernel.md
PR 7192 docs/dev/debt/libkernel.md
PR 7201 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.cpp
PR 7447 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 7464 docs/dev/debt/libkernel.md
PR 7509 docs/dev/debt/libkernel.md
PR 7511 docs/dev/debt/libkernel.md
PR 7530 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 7532 docs/dev/debt/libkernel.md
PR 7565 docs/dev/debt/libkernel.md
PR 7804 docs/dev/debt/libkernel.md
PR 8010 docs/dev/debt/libkernel.md
PR 8457 core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 8520 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 8553 docs/dev/debt/libkernel.md
PR 8605 docs/dev/debt/libkernel.md
PR 8725 docs/dev/debt/libkernel.md
PR 8726 docs/dev/debt/libkernel.md
PR 8916 docs/dev/debt/libkernel.md
PR 9019 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
PR 9095 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
docs/dev/debt/libkernel.md
PR 9097 core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 9133 docs/dev/debt/libkernel.md
PR 9156 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9161 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
PR 9162 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9171 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9172 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9187 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9195 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9199 docs/dev/debt/libkernel.md
PR 9239 docs/dev/debt/libkernel.md
PR 9242 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9263 docs/dev/debt/libkernel.md
PR 9284 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9293 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9297 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9298 docs/dev/debt/libkernel.md
PR 9302 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9326 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9359 docs/dev/debt/libkernel.md
PR 9363 docs/dev/debt/libkernel.md
PR 9365 docs/dev/debt/libkernel.md
PR 9374 core/libs/tests/GuestKernelSys.cpp
PR 9378 docs/dev/debt/libkernel.md
PR 9379 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9383 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9389 core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
docs/dev/debt/libkernel.md
PR 9461 docs/dev/debt/libkernel.md
PR 9473 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9477 docs/dev/debt/libkernel.md
PR 9478 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9482 docs/dev/debt/libkernel.md
PR 9491 docs/dev/debt/libkernel.md
PR 9499 docs/dev/debt/libkernel.md
PR 9502 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9509 docs/dev/debt/libkernel.md
PR 9512 docs/dev/debt/libkernel.md
PR 9515 docs/dev/debt/libkernel.md
PR 9537 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 9555 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9557 docs/dev/debt/libkernel.md
PR 9561 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 9566 docs/dev/debt/libkernel.md
PR 9573 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9575 docs/dev/debt/libkernel.md
PR 9578 docs/dev/debt/libkernel.md
PR 9618 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9632 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9669 docs/dev/debt/libkernel.md
PR 9684 docs/dev/debt/libkernel.md
PR 9713 core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 9732 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 9823 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9826 core/libs/prx/libkernel_sys/Export.cpp
PR 9843 docs/dev/debt/libkernel.md
PR 9882 docs/dev/debt/libkernel.md
PR 9938 docs/dev/debt/libkernel.md
PR 9947 docs/dev/debt/libkernel.md
PR 9962 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 9994 core/libs/tests/GuestKernelSys.cpp
PR 10014 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 10016 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 10025 docs/dev/debt/libkernel.md
PR 10061 docs/dev/debt/libkernel.md
PR 10089 docs/dev/debt/libkernel.md
PR 10105 docs/dev/debt/libkernel.md
PR 10121 docs/dev/debt/libkernel.md
PR 10130 docs/dev/debt/libkernel.md
PR 10132 docs/dev/debt/libkernel.md
PR 10133 docs/dev/debt/libkernel.md
PR 10137 docs/dev/debt/libkernel.md
PR 10162 docs/dev/debt/libkernel.md
PR 10177 docs/dev/debt/libkernel.md
PR 10179 docs/dev/debt/libkernel.md
PR 10192 docs/dev/debt/libkernel.md
PR 10198 docs/dev/debt/libkernel.md
PR 10243 docs/dev/debt/libkernel.md
PR 10299 docs/dev/debt/libkernel.md
PR 10305 docs/dev/debt/libkernel.md
PR 10310 docs/dev/debt/libkernel.md
PR 10319 docs/dev/debt/libkernel.md
PR 10332 core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 10335 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 10385 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 10421 core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 10425 docs/dev/debt/libkernel.md
PR 10427 core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 10434 core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 10442 docs/dev/debt/libkernel.md
PR 10456 docs/dev/debt/libkernel.md
PR 10499 docs/dev/debt/libkernel.md
PR 10501 docs/dev/debt/libkernel.md
PR 10509 core/libs/prx/libkernel_sys/Export.cpp
PR 10524 core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
PR 10543 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 10552 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 10558 docs/dev/debt/libkernel.md
PR 10621 docs/dev/debt/libkernel.md
PR 10645 docs/dev/debt/libkernel.md
PR 10657 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 10666 docs/dev/debt/libkernel.md
PR 10671 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 10695 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 10725 docs/dev/debt/libkernel.md
PR 10734 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 10741 core/libs/prx/libkernel_sys/Export.Discovery.cpp
PR 10745 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 10749 docs/dev/debt/libkernel.md
PR 10755 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 10767 docs/dev/debt/libkernel.md
PR 10789 docs/dev/debt/libkernel.md
PR 10794 core/libs/prx/libkernel_sys/Export.Discovery.cpp
docs/dev/debt/libkernel.md
PR 10799 core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/tests/GuestKernelSys.cpp
PR 10809 docs/dev/debt/libkernel.md
PR 10826 docs/dev/debt/libkernel.md
PR 10830 docs/dev/debt/libkernel.md
PR 10838 core/libs/prx/libkernel_sys/Export.Discovery.cpp
core/libs/prx/libkernel_sys/Export.cpp
core/libs/tests/GuestKernelSys.cpp
PR 10848 docs/dev/debt/libkernel.md
PR 10855 docs/dev/debt/libkernel.md

@Gruzzberry

Copy link
Copy Markdown
Author

Updated: the link check now uses File::FillLinkStat (the guest lstat) instead of std::filesystem::symlink_status. Measured on Windows 11 with MinGW-w64 GCC 15.2.0 r7: symlink_status and status both report a symbolic link, dangling or not, as the regular file or directory it names, so the earlier check was never true on Windows and the dangling-link test only passed because chflags does not follow links there either. With chflags fixed to follow links (separate PR), the earlier version fails the dangling-link check and this one passes. guest_kernel_sys and guest_filesystem pass.

@jotitadev jotitadev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux run of the current change, since the description lists only Windows ("Not tested: Linux").

Machine: Linux x86_64, i7-8700 (6 cores / 12 threads), Ubuntu 26.04, GCC 15.2, Release, BUILD_TESTING=ON. Head e5d6ec946 merged onto main a6dcea927 (the merge touches Stdio.cpp, libkernel_sys/Export.Discovery.cpp, libkernel_sys/Export.cpp and GuestKernelSys.cpp).

  • Build ok. guest_kernel_sys passes with the change, including the new lchflags cases (regular file, EFAULT, ENOENT, ENOTDIR, EOPNOTSUPP, EPERM, the dangling and working link cases and the UF_IMMUTABLE throw).
  • Restoring the three implementation files to main and keeping the test aborts guest_kernel_sys:
    terminate called after throwing an instance of 'std::runtime_error'
    what(): lchflags_nid_postfix not implemented
    so the regression reproduces on Linux as well and the test covers the change.
  • The export moves from the discovery stub (Export.Discovery.cpp) to a real entry in Export.cpp; the patched/unpatched libkernel_sys libraries build and the NID/convention tests pass, so the NID patching stays intact.

Written with AI assistance (Claude Code). I ran the builds and tests above on my machine.

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the lchflags implementation and its source/test context. The cited FreeBSD syscall uses AT_SYMLINK_NOFOLLOW; the helper uses guest lstat so a dangling final-component link is recognized on MinGW, while chflags retains follow behavior. The existing unsupported-flag results are preserved. The author reports Windows tests and an independent reviewer reports Linux build/regression results; hosted eligibility, conventions, labels and report pass, while product/relinker jobs were skipped. I did not run local tests.

The current overlap results need author coordination before merge:

  • #9423 changes the PathError contract and the chflags code in Stdio.cpp; this PR refactors that same chflags implementation and calls the old PathError signature. The branches must be reconciled so checked guest-path copying and the new no-follow helper both remain.
  • #9103 inserts chown/lchown/fchownat exports in libkernel_sys/Export.cpp at the same fstatat/unlink insertion area where this PR adds lchflags.
  • #6044 renames GuestKernelSys.cpp to tests/process/GuestKernelSys.cpp, while this PR adds the regression cases to the old path. Coordinate so the final registered test target includes the new coverage after the move.

Please agree the order with these authors, rebase/compose the changes, and record Depends on for any prerequisite. The present none entries do not document these direct overlaps. The scan also listed #9040, #9097 and #6525 at nearby test lines; I manually compared their hunks and found their helper/call insertions separate from the lchflags additions, so I am not requesting changes for those.

@Gruzzberry

Copy link
Copy Markdown
Author

Rebased onto main d6eafa5. guest_kernel_sys and guest_filesystem pass on the new head, the new checks fail on that main without the change, and check_conventions.py passes. Full suite on main d6eafa5 and on main with #9442, #9469, #9474, #9487 and #9496 merged together: 1890 tests each, identical results.

Overlaps, now listed in the description under Overlaps: I asked on #9423 to land it first and will then rebase this PR so ChangeFileFlags_nid_no_patch takes the copied path for chflags and lchflags. #9200, #9097 and #9103 are adjacent text only, and the new cases follow GuestKernelSys.cpp if #6044 moves it first. Thanks @jotitadev for the Linux run; it is credited in the description.

@Gruzzberry

Copy link
Copy Markdown
Author

Holding this as a draft, following the direction on #5239: the open queue is above 700 and no named title needs this change on current main. I will only mark it ready again with a current-main title ID, its Game bring-up discussion and the log line where it stops on this, or once the queue is below 700. Thanks for the reviews so far; the requested fixes are being made on the branch in the meantime.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
@Gruzzberry
Gruzzberry marked this pull request as ready for review October 23, 2026 14:18
@Gruzzberry

Copy link
Copy Markdown
Author

Rebased onto main 938812d and marked ready for review, as @MarcZX10 noted the #5239 hold does not need to apply here. On Windows (MinGW GCC 15.2.0): the focused tests pass, check_conventions.py passes, and the full suite (2029 tests) on main merged with #9442, #9469, #9474, #9487, #9496, #9661 and #9682 matches main itself, apart from parallel-run flakes that pass when run alone.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 23, 2026

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation and reported Windows/Linux checks look well-supported. One documentation follow-up: please update the existing chflags debt entry in docs/dev/debt/libkernel.md to include lchflags and its no-follow behavior, including that this behavior and the console filesystem/flag handling have not been measured on a PS5. The entry currently documents the same shared flag limitations for chflags/fchflags, but does not name the newly implemented API or its symlink-specific path behavior. No blocking code issue found in this review.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
@Gruzzberry

Copy link
Copy Markdown
Author

@MarcZX10 thanks, added in f120c81: a lchflags entry in docs/dev/debt/libkernel.md right after fchflags, which names the no-follow behaviour (a link in the last component is the file whose flags are set, so a dangling link is accepted, as FreeBSD 11.4's sys_lchflags passes AT_SYMLINK_NOFOLLOW) and says that this and the console's filesystem and flag handling have not been measured on a PS5. I kept it as its own entry like fchflags rather than extending the chflags one, since that entry is already over the 1000-character debt-length limit on main (the one warning check_conventions.py still prints for this file). Also rebased onto main 11e8ad2 to clear the GuestKernelSys.cpp conflict with the new fpathconf checks (both kept); guest_kernel_sys and guest_filesystem pass, alone and merged with #9682.

lchflags is chflags without following a symbolic link in the last path
component, as FreeBSD 11.4's sys_lchflags calls kern_chflagsat with
AT_SYMLINK_NOFOLLOW. chflags now goes through a shared helper that takes
the follow choice; a link in the last component is accepted as the
target when not following, and the flag checks are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Gruzzberry

Copy link
Copy Markdown
Author

Follow-up in 47ea711: the lchflags entry now links File/src/Stdio.cpp, where the shared chflags path lives, so it passes the debt-file check and stays next to chflags in libkernel.md (the conventions job failed on the earlier head, which linked the libkernel_sys export first). Also rebased onto main 9232ee9 for the lchown/linkat stub removal beside it. check_conventions.py passes; guest_kernel_sys and guest_filesystem pass, two runs out of two.

@github-actions github-actions Bot added docs and removed needs rebase Conflicts with main, rebase needed labels Oct 24, 2026
@MarcZX10

Copy link
Copy Markdown
Contributor

A PR overlap check shows #10625 also edits the declaration block in GuestKernelSys.cpp: this PR adds lchflags_nid_postfix, while #10625 adds the two path-alias helper declarations next to it. Each branch merges with current main, but combining the old heads reports a conflict at that insertion block; both independent declarations need to be retained. Could you and #10625's author agree on an order/rebase plan? The requested overlap update is on #10625; no implementation conflict is indicated.

@Dom3005

Dom3005 commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

Hi, #10625 (symlink .. targets) touches the same declaration block in core/libs/tests/GuestKernelSys.cpp. The two changes don't depend on each other. I suggest #9442 goes first. I'll mark #10625 Depends on: #9442 and rebase it once yours merges. Does that work for you?

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 24, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 25, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs libkernel needs rebase Conflicts with main, rebase needed prx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants