Skip to content

fix(libkernel): report ENOTDIR from mkdir and rmdir when a path component is a file - #3395

Merged
adriadam10 merged 2 commits into
boykopovar:mainfrom
LeandroLP23:fix/kernel-mkdir-enotdir
Oct 11, 2026
Merged

adriadam10 merged 2 commits into
boykopovar:mainfrom
LeandroLP23:fix/kernel-mkdir-enotdir

Conversation

@LeandroLP23

Copy link
Copy Markdown
Contributor

Carrying @husseinkad's fix for #3097 (they can't open PRs yet). The change is theirs: ec46ae8d and 4af85eb9 cherry-picked onto main, authorship kept. main had meanwhile fixed part of it with #2743 (mkdir("file/child") already reports ENOTDIR), so the conflicts in Stdio.cpp were resolved by keeping main's helpers and taking husseinkad's version of the sceKernelMkdir check, which covers both the direct-parent case and the deeper one; their test block sits next to main's read-only unlink/rmdir checks.

What

On Windows, mkdir and rmdir returned ENOENT when a component further up the path is a regular file (mkdir("file/a/b"), rmdir("file/x"), rmdir("file/")), where FreeBSD returns ENOTDIR. The POSIX and sceKernel forms now report ENOTDIR in those cases, and sceKernelMkdir no longer returns a Win32 error number as an errno.

Tested

Windows 11 (26300), WinLibs GCC 15.2.0 r7, Release: guest_filesystem and guest_kernel_sync (which holds #2743's cases) pass 3/3; guest_filesystem fails with main's Stdio.cpp (guest errno 2, Win32 error 3 at the new deep-path check); ctest -E agc_ 445/445; conventions pass.

Fork CI (run): Windows and the three relinker jobs pass. Linux fails agc_driver_image_plane_address_on_line_implicit_lod and guest_kernel_stack_protect, the same two in all three runs of this batch (#3111, #3076 and #3097 fixes, unrelated changes), so they come from main.

Fixes #3097

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 (Claude Code, for carrying, the conflict resolution and the Windows run; see the issue for the author's disclosure)

…nent is a file

On Windows mkdir_nid_postfix returned ENOENT and sceKernelMkdir and
sceKernelRmdir returned ENOENT or EIO when a regular file was used as a
directory in the path. FreeBSD mkdir(2) and rmdir(2) return ENOTDIR for
a path component that is not a directory.
…s in sceKernelMkdir

Capture errno before the ENOTDIR lookup, translate EINVAL from a name
under a regular file to ENOTDIR, check the parent only once and strip a
trailing separator before taking it, and split the dense rmdir return.
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on Linux: build and ctest green, guest_filesystem passes and fails when the Stdio.cpp change is reverted. The ENOTDIR cases (direct and deeper components), ENOENT for a missing parent, trailing separators and the invalid-name-under-file case are pinned by the new test, and the logic matches FreeBSD's mkdir(2)/rmdir(2). The Windows-specific behaviour relies on the author's Windows 11 run. Merging.

@adriadam10
adriadam10 merged commit ec77a61 into boykopovar:main Oct 11, 2026
15 checks passed
@LeandroLP23
LeandroLP23 deleted the fix/kernel-mkdir-enotdir branch October 11, 2026 10:03
@husseinkad

husseinkad commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Thank you @LeandroLP23 for carrying this, and the %p and signal() changes as well, and thank you @MarcZX100 for the earlier ones: keeping the authorship is much appreciated.

One small, optional ask for the remaining fixes from my fork (#2711 fgets, #2725 strtod, #2679 rwlock, #2680 directory lseek, #2702 strftime, #2694 UDP errno, #2703 equeue, #2698 ctype, #2768 inet, #2676 strtol): if it is just as easy, reopening my own PR instead of carrying the commits would help, because the intake check counts merged PRs by author, and the carried ones do not move my count. Carrying is still completely fine and very welcome if reopening is not practical, and I understand the intake limit is there for a reason.

AI-assisted: yes.

@LeandroLP23

Copy link
Copy Markdown
Contributor Author

@husseinkad that makes sense. Reopening another author's PR is something only maintainers can do, so I'll stop carrying the remaining fixes from your fork and leave them for your original PRs; if a maintainer reopens them, I'm happy to run them on Windows (Radeon 860M) and post the results there. #3452 is already under review with the requested changes in, so I'll see that one through.

@husseinkad

husseinkad commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Thank you @LeandroLP23, that is clear, and thank you for seeing #3452 through. To avoid holding anything up on my account: if the maintainers would rather not reopen the closed ones, carrying the remaining fixes is still welcome and I would not mind at all; the authorship is what matters, and I am happy with either route. Your offer to run reopened PRs on the Radeon 860M would be very useful too.

AI-assisted: yes.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

libkernel: mkdir and rmdir return ENOENT instead of ENOTDIR on Windows when a path component is a regular file

3 participants