Skip to content

fix(libkernel): fail open with O_CREAT and O_EXCL on a Windows symbolic link - #9496

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
Gruzzberry:fix/open-excl-symbolic-link
Oct 25, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
Gruzzberry:fix/open-excl-symbolic-link

Conversation

@Gruzzberry

@Gruzzberry Gruzzberry commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

What

On Windows, open with O_CREAT|O_EXCL on a symbolic link whose target is missing succeeded and created the target. FreeBSD 11.4's vn_open_cred only adds FOLLOW when O_EXCL is not set, so the lookup finds the link itself and the call fails with EEXIST whatever the link points to, as POSIX requires for O_CREAT|O_EXCL on a symbolic link.

OpenNative now fails O_CREAT|O_EXCL with EEXIST before the host open when the last component is a reparse point. Any reparse point is an existing name, so the answer does not depend on its kind. A link to an existing file already failed with EEXIST and still does; O_CREAT without O_EXCL still creates the target through a dangling link, as FreeBSD does. Linux already fails in the host open and is unchanged.

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 links can be created.

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 reparse-point handling and the cross-platform regression cases. The check recognizes the link itself before the exclusive create can follow a dangling link to its target; O_CREAT without O_EXCL remains covered as a separate case. The guest_filesystem tests verify both the errno and guest error mapping, ensure no target is created on failure, and clean up the link and target. The PR checks for conventions, intake, eligibility, labels and report pass; hosted product build jobs are skipped.

@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/Open.cpp
PR 6936 core/libs/prx/libkernel/File/src/Open.cpp
PR 7121 core/libs/prx/libkernel/File/src/Open.cpp
PR 7201 core/libs/prx/libkernel/File/src/Open.cpp
PR 8520 core/libs/prx/libkernel/File/src/Open.cpp
core/libs/tests/GuestFilesystem.cpp
PR 9371 core/libs/tests/GuestFilesystem.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.

Rechecked the current head and overlap state. The Windows reparse-point check runs before exclusive create can follow a dangling link; ordinary O_CREAT through that link remains covered. Regression checks verify POSIX and SCE errors, target non-creation, later ordinary creation, and cleanup. The author reports a Windows red/green run and a broader suite; hosted eligibility, conventions, intake, labels and report pass, while product/relinker jobs are skipped. The #5021/#6936/#7201 manual shared-file warnings were not found as concrete overlaps in the reviewed diff. I did not run local tests.

@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 reparse-point check and regression cases are well targeted: they verify EEXIST through both POSIX and SCE entry points, confirm the dangling target is not created, then cover ordinary O_CREAT through the link and cleanup. The earlier manual overlap review also found the #5021/#6936/#7201 warnings were distinct. However, the tests and branch are based on a6dcea9; upstream main is now ab347d1. Please rebase onto current main, rerun the focused guest_filesystem regression and conventions check, and refresh the overlap scan/manual uncomparable-file review. Hosted product jobs are skipped; I did not run local tests.

@Gruzzberry

Copy link
Copy Markdown
Contributor Author

Rebased onto main d6eafa5. guest_filesystem passes 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.

…ic link

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 <noreply@anthropic.com>
@Gruzzberry
Gruzzberry force-pushed the fix/open-excl-symbolic-link branch from fd2c87f to 3cd6a37 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 15:03

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 merged commit 5069919 into boykopovar:main Oct 25, 2026
10 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the O_CREAT|O_EXCL reparse-point check against FreeBSD's vn_open_cred (no FOLLOW with O_EXCL), and that the new guest_filesystem cases fail without the change (dangling link: EEXIST, 0x80020011, no target created; plain O_CREAT still creates through the link); 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