Repository navigation
feat(libSceLibcInternal): handle every __opendir2 flag - #12977
Conversation
Follow FreeBSD 11.4's __opendir2: __DTF_READALL or __DTF_SKIPREAD returns NULL with errno unchanged, and every other value opens the directory as opendir does, since the remaining flags only act on union mounts and whiteout entries.
Progress report (bb04a4f → 03fc7bb)📈 System libraries: 46.5% (+0.01%, +1 implemented functions) ✅ 1 implemented
Changed libraries (implemented exports)
|
rooklz
left a comment
There was a problem hiding this comment.
Reviewed head 03fc7bbca3 against main bb04a4f1ea, on macOS arm64. I only checked it on the host. I did not build or run anything on the console.
Gates
tools/check_conventions.py --base upstream/mainpasses.git diff --checkis clean, andgit merge-treeagainstbb04a4f1eais clean.pr_overlapmerged 12 of 12 PRs. The only shared file is the debt file: #5021 and #10749 already conflict with main on it, so neither could be compared.
Source check (FreeBSD d106002967)
__opendir2(opendir.c L83-84) returns NULL with errno untouched for__DTF_READALL|__DTF_SKIPREADbefore_open, so a null name never gets dereferenced. This matches the PR's null-name rows.__opendir_commonstoresdd_flags(L293) and branches only onDTF_NODUP, and only for unionfs/MNT_UNION(L312-317).- In readdir.c,
DTF_HIDEWis read only forDT_WHT(L85). The__DTF_*bits are internal state that readdir, rewinddir and telldir set and clear. Nothing reads bits above 0x10. opendiris__opendir2(name, DTF_HIDEW|DTF_NODUP)(L61).
So "every value without 0x8/0x10 is opendir" holds as long as there is no union mount and the DIR stays opaque.
Standalone harness
I used the verbatim PR body and main body over host opendir, with the PR's test rows ported 1:1, built with clang++ -O1 and ASan+UBSan:
-
PR head: PASS.
-
main: aborts at the first new flag (0x20 → NotImplemented). This matches the author's negative control.
-
Mutants:
- only 0x8 checked: KILLED (0x10 row)
- only 0x10 checked: KILLED
- sets errno=EINVAL: KILLED (errno sentinel row)
- rejects all of
~0x7: KILLED (0x20/0x100 rows) - requires both bits: KILLED
All 5 mutants were killed.
Not run
- The real
guest_opendir2target. Submodules are not initialised in my lane. The PR's windows check passed, and linux was skipped by CI. - The device's answer for any flag. The debt line says this openly, which is the right call.
Verdict: APPROVE.
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Windows run of this head (
AI-assisted: yes (Claude Code). |
|
Checked |
What
__opendir2no longer throws for flags outsideDTF_HIDEW | DTF_NODUP | DTF_REWIND. It now handles every flag value the way FreeBSD 11.4 does.Source of the behaviour. FreeBSD 11.4 libc, the release the libSceUsbd and libScePosixForWebKit debt entries already pin:
__opendir2returnsNULLbefore it opens anything, witherrnounchanged, when__DTF_READALL(0x8) or__DTF_SKIPREAD(0x10) is set. Any other value goes to__opendir_common.__opendir_commonstores the flags indd_flagsand acts only onDTF_NODUP, and only whenfstatfsreportsunionfsorMNT_UNION. No guest filesystem reports either.DTF_REWINDis defined but never read by libc.DTF_HIDEWonly makesreaddirskipDT_WHTentries, and host filesystems never produce those. Bits above 0x10 are stored and never read. The flag values are indirent.h.opendiris__opendir2(name, DTF_HIDEW|DTF_NODUP). So every value without 0x8 or 0x10 opens the same stream as the in-treeopendir_nid_postfix.DIRis opaque: FreeBSD declaresstruct _dirdesconly ingen-private.h, and the AnyPS5 stream is a host record. That leaves no guest-visibledd_flagsto fill.Lines that change on
main:Directory.cppL26-L32, which throws for any other flag;GuestOpendir2.cppL32-L42.The device's answer was not measured, and the debt entry still says so.
Changes:
libSceLibcInternal/Directory.cpp:__opendir2returns null witherrnountouched when 0x8 or 0x10 is set. Otherwise it callsopendir. TheNotImplemented_nid_no_patchpath is gone.guest_opendir2:opendir;errnoat a sentinel, both for an existing directory and for a null name;opendir's errno.docs/dev/debt/libSceLibcInternal.md: the entry is cut to what stays open, which is that the device's answer is not measured.Tested
Linux (GitHub Codespace, native build of this branch on
bb04a4f1ea):guest_opendir2passes.Directory.cppfrommain,guest_opendir2aborts (flag 0x20 reachesNotImplemented_nid_no_patch).Checks:
python3 tools/check_conventions.py --base origin/mainpasses.tools/progress.py --comparegives libSceLibcInternal 72/75 to 73/75 (+1,__opendir2_nid_postfix).Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)