You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
libkernel/libc: rmdir, sceKernelRmdir and remove delete the directory for "dir/." instead of failing with EINVAL; fix branch ready #3116
Guest paths are normalized lexically (Resolve in libc/src/General.cpp), so dir/. reaches the host as dir/ and the directory is removed. FreeBSD's kern_rmdirat rejects a final . with EINVAL ("No rmdir "." please."), and POSIX requires rmdir to fail with EINVAL when the last component is dot. remove calls rmdir for a directory (FreeBSD lib/libc/stdio/remove.c).
On main (Linux), each of these returns 0 and the directory is gone: rmdir("probe_dir/."), sceKernelRmdir("probe_dir/."), remove("probe_dir/.").
Fix on my fork: milescoviello/AnyPS5:fix/rmdir-dot-component (one commit, 9aaf6240, rebased onto mainec77a61 after #3395): sceKernelRmdir (and therefore rmdir) and remove return EINVAL (0x80020016) and keep the directory. A missing path or a file before the dot keeps its current error. guest_filesystem gains checks that fail on main and pass with the fix. Linux only; Windows was not built or tested. The check runs on the guest path before any host call, so the code is portable.
Setup: Gentoo, Linux 7.2.8, GCC 15.3.0, Release with CI's configure flags, main4d27834.
Tested: the new checks fail on main and pass with the fix. Full ctest with the fix on Linux (RTX 5090 Laptop GPU): no new failures; the only failures are the known agc_driver_dcc_keys_first_write (#2767) and two guest_video_out_* tests that time out with the displays powered off. tools/check_conventions.py passes. All five fixes I am filing today also pass their tests merged together on the current main.
Not opened as a PR because intake is paused for new contributors; a maintainer is welcome to carry the commit.
changed the title [-]libkernel/libc: rmdir, sceKernelRmdir and remove delete the directory for "dir/." instead of failing with EINVAL[/-][+]libkernel/libc: rmdir, sceKernelRmdir and remove delete the directory for "dir/." instead of failing with EINVAL; fix branch ready[/+]on Oct 11, 2026
Windows run, since the issue says it wasn't built or tested there: Windows 11, WinLibs GCC 15.2.0 r7, Release, fix/rmdir-dot-component (a43ccf41) merged onto main06da117 together with #3117, #3181 and #3169 (#3169 is needed here because guest_filesystem otherwise stops at the symlink checks on a machine without the symlink privilege).
The bug is on Windows too: RemoveDirectoryW collapses the dot itself, so a plain rmdir of dir\. removes dir (checked directly with Python's os.rmdir).
With the branch, the new checks in guest_filesystem sit outside the non-Windows block and pass: rmdir, sceKernelRmdir and remove of dir/. and dir/./ return EINVAL (0x80020016 for sceKernelRmdir) and the directory stays. The backslash paths the test builds on Windows work since FinalPathComponentIsDot_nid_no_patch splits on both separators.
All 421 non-GPU tests (ctest -E "^agc_") pass with the four branches merged.
AI-assisted (Claude Code); I ran this on my machine.
Thanks @Silverash-i8 for the Windows runs on this and #3117, and for checking RemoveDirectoryW directly. Good to know the dot case is fixed on Windows too. The \\?\ idea for .. on Windows is useful as well.
Rebased onto mainec77a61: #3395 changed the same lines of sceKernelRmdir. The dot check now runs right after its ENOTDIR/ENOENT block, which keeps FreeBSD's order (lookup errors first, then EINVAL, then ENOTEMPTY). New commit 9aaf6240. The 33 file, path and save-data tests pass, including #3395's new checks, and guest_filesystem fails with the check reverted.
Windows recheck of the rebased 9aaf6240 on mainec77a61 (Windows 11, WinLibs GCC 15.2.0 r7, Release): guest_filesystem passes, now all the way through since #3169 is in, and the non-GPU suite (ctest -E "^agc_") is 453/454. The one failure is windows_exceptions, which fails the same way on plain main (#3411), so nothing from this branch.
AI-assisted (Claude Code); I ran this on my machine.
Activity
[-]libkernel/libc: rmdir, sceKernelRmdir and remove delete the directory for "dir/." instead of failing with EINVAL[/-][+]libkernel/libc: rmdir, sceKernelRmdir and remove delete the directory for "dir/." instead of failing with EINVAL; fix branch ready[/+]Silverash-i8 commentedon Oct 11, 2026
Windows run, since the issue says it wasn't built or tested there: Windows 11, WinLibs GCC 15.2.0 r7, Release,
fix/rmdir-dot-component(a43ccf41) merged ontomain06da117 together with #3117, #3181 and #3169 (#3169 is needed here becauseguest_filesystemotherwise stops at the symlink checks on a machine without the symlink privilege).RemoveDirectoryWcollapses the dot itself, so a plainrmdirofdir\.removesdir(checked directly with Python'sos.rmdir).guest_filesystemsit outside the non-Windows block and pass:rmdir,sceKernelRmdirandremoveofdir/.anddir/./return EINVAL (0x80020016 forsceKernelRmdir) and the directory stays. The backslash paths the test builds on Windows work sinceFinalPathComponentIsDot_nid_no_patchsplits on both separators.ctest -E "^agc_") pass with the four branches merged.AI-assisted (Claude Code); I ran this on my machine.
milescoviello commentedon Oct 11, 2026
Thanks @Silverash-i8 for the Windows runs on this and #3117, and for checking
RemoveDirectoryWdirectly. Good to know the dot case is fixed on Windows too. The\\?\idea for..on Windows is useful as well.milescoviello commentedon Oct 11, 2026
Rebased onto
mainec77a61: #3395 changed the same lines ofsceKernelRmdir. The dot check now runs right after its ENOTDIR/ENOENT block, which keeps FreeBSD's order (lookup errors first, then EINVAL, then ENOTEMPTY). New commit9aaf6240. The 33 file, path and save-data tests pass, including #3395's new checks, andguest_filesystemfails with the check reverted.AI-assisted: yes
Silverash-i8 commentedon Oct 11, 2026
Windows recheck of the rebased
9aaf6240onmainec77a61 (Windows 11, WinLibs GCC 15.2.0 r7, Release):guest_filesystempasses, now all the way through since #3169 is in, and the non-GPU suite (ctest -E "^agc_") is 453/454. The one failure iswindows_exceptions, which fails the same way on plainmain(#3411), so nothing from this branch.AI-assisted (Claude Code); I ran this on my machine.