Skip to content

fix(libkernel): fail chflags through a dangling Windows symbolic link with ENOENT - #9469

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
Gruzzberry:fix/chflags-dangling-link
Oct 25, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
Gruzzberry:fix/chflags-dangling-link

Conversation

@Gruzzberry

@Gruzzberry Gruzzberry commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

On Windows, chflags succeeded on a symbolic link whose target is missing and failed dangling/ with ENOTDIR. FreeBSD 11.4's kern_chflagsat looks the path up with FOLLOW, so both fail with ENOENT.

The cause is the lookup in LookupError: under MinGW, std::filesystem::status does not follow a Windows symbolic link and reports a dangling link as an existing regular file. When the last component (or the one before a trailing slash) is a reparse point, the lookup now goes through the target with File::TryFillFileStat, the guest stat, which already follows links: a missing target gives ENOENT, a link to a file followed by a slash gives ENOTDIR, a link to a directory is accepted. Linux is unchanged; chflags is the only caller of LookupError.

Measured on main with a standalone probe, the same dangling link: stat, truncate, utimes and open already fail with ENOENT; chflags returned 0.

Tested

Windows 11 (10.0.26200), WinLibs MinGW-w64 GCC 15.2.0 r7, Ninja, Release, -DBUILD_TESTING=ON, on main 938812d (rebased; since #9109, chflags("dangling/") fails with ENOTDIR from the trailing-slash check before this lookup runs, so that check was dropped from the test; FreeBSD gives ENOENT there), Developer Mode on so links can be created.

#9442 (lchflags) is independent of this PR; its dangling-link check passes with or without it.

Overlaps

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); no silent stubs added
  • No notes, investigation .md files or images added to the repository
  • New third-party code is a submodule built from source: none added
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

AI-assisted (Claude Code).

🤖 Generated with Claude Code

@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.

Reviewed the Windows-only lookup path and focused symlink tests. For reparse-point inputs the change follows the target through the existing guest stat helper, preserving ENOENT for a dangling target and checking directory type for trailing separators; the non-reparse path is unchanged. The debt note and limitations are explicit. Conventions, intake, eligibility, labels, and report pass; hosted Windows/Linux build and test jobs were skipped. The Windows 11 focused runs described in the PR are author-reported; I did not run them locally.

@Gruzzberry

Copy link
Copy Markdown
Contributor Author

Full suite with this PR merged together with #9442, #9469, #9474 and #9487, against main on the same Windows 11 machine (MinGW-w64 GCC 15.2.0 r7, Release): 1875 tests, the same results except agc_import_settle_first_use, which also skips on main when its copies finish before the import returns (5 of 5 runs).

@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 5021 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 6936 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 7121 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 7201 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 7447 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 8520 core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/tests/GuestFilesystem.cpp
PR 9284 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9293 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9297 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9302 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9371 core/libs/tests/GuestFilesystem.cpp
PR 9823 core/libs/prx/libkernel/File/src/Stdio.cpp

@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 Windows-only path and focused symlink cases were reviewed previously, and the reported combined Windows run is useful. The tested commit and the current branch base are still 47 upstream commits behind current main (now 110a18b); the reported baseline is a6dcea9. Please rebase/update onto current main and rerun the focused guest_filesystem checks plus the relevant conventions and overlap checks on that base before treating the earlier results as current. I checked the overlap bot warnings: the listed Stdio.cpp PRs touch other areas, and #6044 does not list GuestFilesystem.cpp, so I found no direct conflict in those warnings. No local test was run for this follow-up.

@Gruzzberry
Gruzzberry force-pushed the fix/chflags-dangling-link branch from 313a0b5 to 9b277bd Compare October 22, 2026 06:43
@Gruzzberry

Copy link
Copy Markdown
Contributor Author

Rebased onto main d6eafa5. guest_filesystem and guest_kernel_sys 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. The overlap scan of the rebased head and a manual check of the pull requests it could not compare are in the description under Overlaps.

@Gruzzberry

Copy link
Copy Markdown
Contributor 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.

@Gruzzberry
Gruzzberry force-pushed the fix/chflags-dangling-link branch from 9b277bd to 5dc1dc1 Compare October 23, 2026 14:17
@Gruzzberry
Gruzzberry marked this pull request as ready for review October 23, 2026 14:18
@Gruzzberry

Copy link
Copy Markdown
Contributor 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.

@adriadam10 adriadam10 self-assigned this Oct 25, 2026
@adriadam10
adriadam10 dismissed MarcZX10’s stale review October 25, 2026 14:40

Dismissing a stale review: the requested changes were addressed after it (new head) and the merge queue blocks on it. Please request changes again if anything is still open.

@adriadam10
adriadam10 force-pushed the fix/chflags-dangling-link branch from 5dc1dc1 to 0de1e4d Compare October 25, 2026 17:08
Gruzzberry and others added 2 commits October 25, 2026 19:58
… with ENOENT

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 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@adriadam10
adriadam10 force-pushed the fix/chflags-dangling-link branch from 0de1e4d to a5c72e0 Compare October 25, 2026 19:00
@adriadam10
adriadam10 merged commit efd368f into boykopovar:main Oct 25, 2026
10 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked LookupError against FreeBSD 11.4 kern_chflagsat (FOLLOW lookup) and the new chflags cases (they fail on main); pushed a commit renaming the test locals that clashed in main() and rebased onto current main (scoped build and 358 tests pass). The earlier Linux CI failures (agc_unit_shadow_completion_store, guest_job_manager_worker_spin_scale_10) are unrelated to this Windows-only change; merged.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants