Skip to content

fix(libSceLibcInternal): start fdopendir at the descriptor position and set FD_CLOEXEC - #4810

Closed
xXPBSXx wants to merge 2 commits into
boykopovar:mainfrom
xXPBSXx:feat/fdopendir-position
Closed

xXPBSXx wants to merge 2 commits into
boykopovar:mainfrom
xXPBSXx:feat/fdopendir-position

Conversation

@xXPBSXx

@xXPBSXx xXPBSXx commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What

fdopendir (added in #4569) opens the directory stream at the first entry and does not set FD_CLOEXEC; its TechnicalDebt entry lists both as differences from FreeBSD. FreeBSD 11's fdopendir first calls _fcntl(fd, F_SETFD, FD_CLOEXEC) and then __opendir_common(fd, ..., true); with use_current_pos it reads the first batch of entries from the descriptor's current offset ("For the fdopendir() case, the initial seek position must be preserved", same file). This PR does both:

  • fdopendir sets FD_CLOEXEC through the existing fcntl (F_SETFD, which stores the one flag the word has) before anything else, so a descriptor that is not open still fails with EBADF, and a non-directory still fails with ENOTDIR with the flag set, as in FreeBSD.

  • On Windows the guest directory descriptor already keeps a cursor (lseek; the test covers lseek only, not getdirentries); the stream now skips that many entries of the host listing, which assumes the descriptor and the stream list the directory in the same order (both come from the same host enumeration, with . and .. first).

  • On Linux the stream is opened with the host fdopendir on a duplicate of the descriptor, which shares its position. This assumes the guest descriptor number is the host descriptor number there.

The debt entry is updated in docs/dev/debt/libSceLibcInternal.md (the two differences are removed; the Windows ordering assumption and the untested Linux path are stated).

Tested

  • Windows 10, MinGW GCC 15.2.0, Ninja Release, -j2: the test-only commit fails (guest_fdopendir aborts with exit code 0xc0000409 at the new checks); with the change guest_directory, guest_statvfs, guest_fstatvfs_conversion, guest_fstatvfs, guest_fdopendir, guest_posix_filesystem, guest_directory_buffer, guest_directory_rewind and guest_directory_close pass (9 of 9); python tools/check_conventions.py --base upstream/main passes.

  • Built with the 3rdparty/libusb-cmake submodule checked out locally at the pinned commit bea6567b (current main requires it; it was empty in my checkout). The branch is based on 584cc4c57; git merge-tree against main 43e3a70f8 reports no conflict.

  • The nine tests were rerun on the final commit (8e99582f6, base 584cc4c57): build without errors, 9 of 9 pass, check_conventions passes.

  • Not tested by me: Linux (see the validation below). The Linux path (dup + host fdopendir) was not built or run. The "starts at the current position" check in the test is Windows-only (#ifdef _WIN32); the FD_CLOEXEC and error checks run on both.

  • Linux validation by coltken95 in the comments (13 October, 11:12Z; Ubuntu 24.04, GCC 13.3, Release; this PR's commits on main at 77b9f7270): guest_fdopendir passes, and with main's sources and this PR's test it aborts. That covers the Linux path that the line above says was not run by me.

  • git merge-tree of the current head 8e99582f6 against main 068ab2aba (13 October) is clean.

  • Not measured on a console: the behavior follows the FreeBSD 11.0 source, not a PS5 run.

Checklist

  • Merges onto current main without conflict (checked with git merge-tree against 43e3a70f8; the branch is based on 584cc4c57); 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

  • New third-party code is a submodule built from source (n/a, none added; the local libusb-cmake clone is build infrastructure and not part of this PR)

  • Generic behaviour, not specific to one title

  • Depends on: none

  • Unblocks: none

  • AI-assisted: yes (Claude Code)

AI-assisted (Claude Code).

🤖 Generated with Claude Code

xXPBSXx and others added 2 commits October 12, 2026 23:44
…rt at the descriptor position

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…nd set FD_CLOEXEC

FreeBSD 11's fdopendir sets FD_CLOEXEC and reads the first batch of entries from the
descriptor's current offset (lib/libc/gen/opendir.c, __opendir_common with use_current_pos).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@coltken95

Copy link
Copy Markdown

Linux validation (Ubuntu 24.04, GCC 13.3, Release), this PR's commits on main at 77b9f72: guest_fdopendir passes. With main's sources and this PR's test, it aborts, so the test catches the old position and FD_CLOEXEC behaviour on Linux too. OliSe Player (PPSA01153) imports fdopendir; it starts and runs on Linux with this behaviour, though it does not exercise a moved descriptor position.

AI-assisted: yes

@xXPBSXx

xXPBSXx commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the Linux validation, @coltken95 (guest_fdopendir passes, and the test aborts with main's sources). It is quoted in the description now, which previously said Linux was not tested.

AI-assisted (Claude Code).

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Closing: no title is known to reach this. With the queue at 700+ open PRs, please hold off on new PRs that don't name a title needing the change until it's down. If a title stops on this on current main, reopen with the title ID and the log line.

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