Skip to content

fix(libkernel): report ENOTDIR from stat for a file with a trailing slash - #2300

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
reyani-dev:fix/libkernel-stat-trailing-slash
Oct 10, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
reyani-dev:fix/libkernel-stat-trailing-slash

Conversation

@reyani-dev

Copy link
Copy Markdown
Contributor

What

On FreeBSD, stat("file/") fails with ENOTDIR: a trailing slash asks for a directory. On main:

  • Windows: std::filesystem::exists("file/") is true (Win32 ignores the slash), then _wstat64("file/") fails, and File::FillFileStat throws FillFileStat: stat failed for ..., which aborts the title.
  • Linux: stat reports ENOTDIR, which std::filesystem::exists reads as "not found", so the guest got ENOENT.

sceKernelStat now takes the std::filesystem::status once and returns ENOTDIR if the host reports not_a_directory, or if the guest path ends in / and the target exists but isn't a directory. A missing path is still ENOENT, and stat("dir/") still succeeds. stat (the POSIX wrapper) goes through sceKernelStat, so both are covered.

The same trailing slash on other calls returns the wrong error without aborting: open("file/") and unlink("file/") give EINVAL instead of ENOTDIR on Windows. open is being reworked by several open PRs (#1628, #1777, #2144, #2170), and unlink is in my #2289, so I kept this to stat.

Tested

Windows 11, WinLibs GCC 15.2.0 r7, Release, -DBUILD_TESTING=ON:

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); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

🤖 Generated with Claude Code

@reyani-dev

Copy link
Copy Markdown
Contributor Author

Full Linux and Windows builds and tests for this head (d99a6ceb), using the project's Build workflow. I can't start the upstream manual run, so I ran the same build.yml in my fork through a mirror PR. Like the upstream run, the jobs check out the PR head merged into current main (d70b8998):

Job Result
linux success; full build, ctest: 516/516 passed
windows success; full build, ctest: 507/507 passed
relinker (Linux, Windows, macOS) success

Run: https://github.com/AchrafReyani/AnyPS5/actions/runs/37948551554

1 similar comment
@reyani-dev

Copy link
Copy Markdown
Contributor Author

Full Linux and Windows builds and tests for this head (d99a6ceb), using the project's Build workflow. I can't start the upstream manual run, so I ran the same build.yml in my fork through a mirror PR. Like the upstream run, the jobs check out the PR head merged into current main (d70b8998):

Job Result
linux success; full build, ctest: 516/516 passed
windows success; full build, ctest: 507/507 passed
relinker (Linux, Windows, macOS) success

Run: https://github.com/AchrafReyani/AnyPS5/actions/runs/37948551554

oneandonlydean added a commit to oneandonlydean/AnyPS5 that referenced this pull request Oct 10, 2026
reyani-dev and others added 2 commits October 10, 2026 06:14
…lash

On Windows the existence check accepts "file/", then _wstat64 rejects
it and FillFileStat throws, aborting the title. On Linux the host
reports ENOTDIR, which became ENOENT. A trailing slash on something
that is not a directory now returns ENOTDIR on both hosts, as on
FreeBSD.

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

Copy link
Copy Markdown
Collaborator

Checked on Linux merged onto current main: guest_filesystem aborted at the lstat checks, because the new directory check overwrote status, which the lstat checks (added by #1624) reuse. I pushed one commit that uses a separate FileStat dirStatus for it. After that, build and the scoped ctest (73 tests) are green, and the new stat checks fail when the Open.cpp change is reverted.

@adriadam10
adriadam10 force-pushed the fix/libkernel-stat-trailing-slash branch from d99a6ce to c1b714f Compare October 10, 2026 06:15
@adriadam10
adriadam10 merged commit 7d94990 into boykopovar:main Oct 10, 2026
14 checks passed
@reyani-dev

Copy link
Copy Markdown
Contributor Author

Thanks @adriadam10, the separate dirStatus is right.

I checked the Windows (_wstat64) side with your commit (c1b714f) merged onto current main 03bf8ff (Windows 11, WinLibs GCC 15.2.0, Release):

  • guest_filesystem passes 3/3 (--repeat until-fail:3), including the new trailing-slash checks and the lstat ones;
  • ctest -E "^agc_|video_out" passes 335/335.

A fresh full Linux and Windows build of this head is running and will be posted here.

@reyani-dev

Copy link
Copy Markdown
Contributor Author

Full Linux and Windows builds and tests for this head (c1b714f2), using the project's Build workflow. I can't start the upstream manual run, so I ran the same build.yml in my fork through a mirror PR. Like the upstream run, the jobs check out the PR head merged into current main (03bf8ff3):

Job Result
linux success; full build, ctest: 628/628 passed
windows success; full build, ctest: 636/636 passed
relinker (Linux, Windows, macOS) success

Run: https://github.com/AchrafReyani/AnyPS5/actions/runs/38031421856

SleglJan pushed a commit to SleglJan/AnyPS5 that referenced this pull request Oct 10, 2026
…at-trailing-slash

fix(libkernel): report ENOTDIR from stat for a file with a trailing slash
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.

2 participants