Skip to content

feat(libSceLibcInternal): implement fdopendir - #4569

Merged
adriadam10 merged 1 commit into
boykopovar:mainfrom
pipe1os:feat/libkernel-fdopendir
Oct 12, 2026
Merged

adriadam10 merged 1 commit into
boykopovar:mainfrom
pipe1os:feat/libkernel-fdopendir

Conversation

@pipe1os

@pipe1os pipe1os commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What

fdopendir (j+XjoRSIvwU) is not exported, and three catalog homebrew titles stop on it:

These titles import fdopendir from libSceLibcInternal.prx, as does the ps5-payload-dev SDK (its sce_stubs list it only in libSceLibcInternal.c). On Windows the import builder only looks in libSceLibcInternal.prx and then libc.prx for such an import, so the export lives in libSceLibcInternal. It can't sit next to opendir in libc: it needs libkernel's descriptor lookup, and libc doesn't link libkernel, while libSceLibcInternal links both.

The semantics follow FreeBSD 11's fdopendir and closedir:

  • fdopendir (libSceLibcInternal). It looks up the descriptor's directory with libkernel's GetDirectoryDescriptorPath_nid_no_patch. A descriptor that isn't open fails with EBADF, as FreeBSD's F_SETFD call does, and one that isn't a directory fails with ENOTDIR; both leave the descriptor open.
  • OpenDescriptorDirectory_nid_no_patch (libc). It opens the stream on that directory the way opendir does and keeps the descriptor. closedir then closes it through libkernel's close, as FreeBSD's closedir does with _close(fdclosedir(dirp)).
  • docs/dev/debt/libSceLibcInternal.md. Two differences from FreeBSD are recorded:
    • The stream starts at the directory's first entry, where FreeBSD reads from the descriptor's current offset.
    • FD_CLOEXEC isn't set on the descriptor.

Tested

Windows 11, WinLibs GCC 15.2.0 r7, Release, on main 682ef0c.

  • New guest_fdopendir test. It links libSceLibcInternal, libkernel and libc.
    • It opens a directory with open(O_DIRECTORY), and fdopendir and readdir list a file (type 8) and a subdirectory (type 4).
    • closedir returns 0 and closes the descriptor.
    • The closed descriptor and -1 then fail with EBADF.
    • A regular file's descriptor fails with ENOTDIR and stays open.
  • The Windows import lookup. I rebuilt @babyhuey's test/verify-sx5 stack with this commit in place of the earlier libkernel export. j+XjoRSIvwU is now exported by libSceLibcInternal.prx only. PS5SX2, relinked with --trap-sdk-syscall-stubs, gets past the loader on Windows and runs guest code ([notification] PS5SX2: starting, its HEN config checks, [elevate] already root), as it does on Linux. Before, it failed with FAIL: unresolved ELF import j+XjoRSIvwU (fdopendir) from libSceLibcInternal.prx.
  • Full ctest: 993 of 993 pass. guest_np_auth_authorized_app_dialog and two AGC execution tests aren't built here, because their object paths exceed Windows MAX_PATH in my checkout. The same happens on main.
  • Checks. tools/check_conventions.py, tools/check_test_registration.py and tools/pr_overlap.py --branch pass. The new source line in libSceLibcInternal/CMakeLists.txt and the libc helper are placed away from the lines that feat(libc): implement readdir_r #3635, feat(libSceLibcInternal): implement posix_spawn actions #3651, feat(libSceLibcInternal): implement getopt and getopt_long #3694 and feat(libc): query filesystem statistics by guest path #4653 change.

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

@github-actions

github-actions Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Progress report (2f4cc89 → f3b8ef7)

📈 System libraries: 86.37% (+0.01%, +1 implemented functions)

✅ 1 implemented
Library Name
libSceLibcInternal fdopendir_nid_postfix

@babyhuey

Copy link
Copy Markdown
Contributor

I ran PS5SX2 (PPSA99203) with this PR. Its earlier stops come from open PRs, so I stacked them on main d592d54: #4466, #4382, #4530, #3787, #4426 and #3658 (statvfs), all with --trap-sdk-syscall-stubs. Without this PR, that stack stops at fdopendir on both systems. With it (fork branch test/verify-sx5, a7efa4a), the two systems differ:

  • Linux: the import resolves. PS5SX2 runs guest code for the first time ([notification] PS5SX2: starting, its USB and HEN checks, [elevate] already root) and then stops at sysctlbyname("hw.model"), which AnyPS5 doesn't support yet.
  • Windows 11 (WinLibs GCC 15.2): still FAIL: unresolved ELF import j+XjoRSIvwU (fdopendir) from libSceLibcInternal.prx.

The cause is the module. The title imports fdopendir from libSceLibcInternal.prx, and so does the ps5-payload-dev SDK: its sce_stubs list fdopendir only in libSceLibcInternal.c, not libkernel.c. This PR exports it from libkernel.prx (objdump -p shows j+XjoRSIvwU only there). The Linux loader finds the symbol in any loaded library. The Windows import builder only searches libSceLibcInternal.prx and then libc.prx for a libSceLibcInternal import (WindowsEntryStubBuilder.cpp L146-L156, WindowsImportBuilder.cpp L55), so it never looks in libkernel.

So the export probably belongs in libc, next to opendir in Directory.cpp. That would also match 2 Ship 2 Harkinian on Windows (#4553), assuming it imports fdopendir from libSceLibcInternal like the SDK does. Your guest_fdopendir passes 5/5 on Windows with no warnings in the PR's files, but that test links libkernel directly, so it can't show the module lookup.

@overlordxrz-source

Copy link
Copy Markdown
Contributor

Another title for this one: OliSe Player (PPSA01153). Tested on Linux (Ubuntu 24.04, lavapipe) with main b538b28 + #4452 + this PR + #4470, relinked with --trap-sdk-syscall-stubs.

  • Without this PR: ./app.elf: symbol lookup error: ./app.elf: undefined symbol: j+XjoRSIvwU
  • With this PR: it gets past fdopendir and now stops at: ./app.elf: symbol lookup error: ./app.elf: undefined symbol: ayTeobcoGj8.

AI-assisted: yes

@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed labels Oct 12, 2026
@babyhuey

Copy link
Copy Markdown
Contributor

Windows result for the OliSe Player (PPSA01153) run above: on main 682ef0c + this PR (e3e796c) + #4653, relinked with --trap-sdk-syscall-stubs, Windows 11 (WinLibs GCC 15.2) still stops at the import:

FAIL: unresolved ELF import j+XjoRSIvwU (fdopendir) from libSceLibcInternal.prx

OliSe imports fdopendir from libSceLibcInternal, as PS5SX2 does. j+XjoRSIvwU is exported only by libkernel.prx in that build, and Windows resolves a libSceLibcInternal import only from libSceLibcInternal and libc.prx. So both titles pass on Linux and stop on Windows until the export moves into libc.

@pipe1os
pipe1os force-pushed the feat/libkernel-fdopendir branch from e3e796c to f3b8ef7 Compare October 12, 2026 19:39
@pipe1os pipe1os changed the title feat(libkernel): implement fdopendir feat(libSceLibcInternal): implement fdopendir Oct 12, 2026
@pipe1os

pipe1os commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor Author

The Windows import builder only searches libSceLibcInternal.prx and then libc.prx for a libSceLibcInternal import (WindowsEntryStubBuilder.cpp L146-L156, WindowsImportBuilder.cpp L55), so it never looks in libkernel.

Thanks for testing it on both, that was the bug. The title and the SDK both import fdopendir from libSceLibcInternal, so my libkernel export was invisible on Windows.

So the export probably belongs in libc, next to opendir in Directory.cpp.

It lives in libSceLibcInternal now (core/libs/prx/libSceLibcInternal/Directory.cpp). I'd have put it next to opendir in libc, but it needs libkernel's descriptor lookup and libc doesn't link libkernel. libSceLibcInternal links both, and the DIR is still libc's, so closedir works the same. The import builder checks libSceLibcInternal first, so that's enough for Windows.

I rebuilt your test/verify-sx5 stack on Windows, reverted the old commit and put this one on top. PS5SX2 gets past the loader now and runs guest code ([notification] PS5SX2: starting, the HEN config checks, [elevate] already root), same as your Linux run. The test links libSceLibcInternal too.

So both titles pass on Linux and stop on Windows until the export moves into libc.

Your OliSe run used e3e796c, the old head. f3b8ef7 exports j+XjoRSIvwU from libSceLibcInternal.prx, the module OliSe imports it from, so it should resolve there the same way. I haven't run OliSe on Windows myself, though.

@github-actions github-actions Bot added prx and removed needs rebase Conflicts with main, rebase needed labels Oct 12, 2026
@babyhuey

Copy link
Copy Markdown
Contributor

Retested the new head f3b8ef7 on Windows 11 (WinLibs GCC 15.2), with --trap-sdk-syscall-stubs: j+XjoRSIvwU now resolves from libSceLibcInternal.

OliSe Player (PPSA01153) on main 9f8a108 + this PR + #4653 (statvfs) gets past both imports and renders. It creates its swapchain, holds fps: 59.9, and was still running at the 60 s limit. The only failure in its log is its music radio's HTTP fetch (radio: DOWNLOAD FAILED (-2)), not a throw. Without this PR, that build stopped at FAIL: unresolved ELF import j+XjoRSIvwU (fdopendir) from libSceLibcInternal.prx.

PS5SX2 (PPSA99203), stacked with its other open PRs (#4382, #4530, #3787, #4653), also resolves fdopendir now on Windows and starts running.

@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on the PR merged onto current main: build and the 96 libs/libc/LibcInternal tests pass, guest_fdopendir included (it can't even build without the change). fdopendir errors (EBADF, ENOTDIR, descriptor left open) and the closedir closing the descriptor match FreeBSD 11 opendir.c/closedir.c; the two differences are in the debt file. Windows import resolution is confirmed by @babyhuey's runs (OliSe Player, PS5SX2); merging.

@adriadam10
adriadam10 merged commit 28c9dae into boykopovar:main Oct 12, 2026
14 of 15 checks passed
@pipe1os
pipe1os deleted the feat/libkernel-fdopendir branch October 12, 2026 21:44
pipe1os added a commit to pipe1os/personal-portfolio that referenced this pull request Oct 12, 2026
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.

4 participants