Commit Graph
61 Commits
Author SHA1 Message Date
Dean 5b5d2a8636 Merge pull request #8626 from xXPBSXx/carry/6226-relinker-stem
fix(libc): find a relinked module by stem when the exact name misses (carries #6226)
2026-10-21 19:52:46 +13:00
Dean GalvinandxXPBSXx 8cb7251b2e Merge origin/main into PR 8626
Co-authored-by: xXPBSXx <20614131+xXPBSXx@users.noreply.github.com>
2026-10-21 14:56:22 +13:00
xXPBSXxandClaude Sonnet 5.5 035d82b571 fix(libc): fail a path that ends in a dot component below a regular file with ENOTDIR on Windows
FreeBSD looks the "." up in the directory before it, so "file/." fails with
ENOTDIR and "missing/." with ENOENT (sys/kern/vfs_cache.c vfs_cache_lookup,
`dvp->v_type != VDIR`). Resolve() dropped a trailing "." and handed the
host "file/", which stat, access, open and mkdir answered with ENOENT,
EINVAL or EEXIST. The ".." branch already checks the directory first;
do the same for a path whose last component is ".".

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 03:08:16 +02:00
Dean 46c7538777 Merge pull request #7467 from Dripl1x/codex/windows-path-component-lookup
perf(libc): avoid repeated Windows path component scans
2026-10-21 13:57:05 +13:00
Dom3005andClaude Opus 5.5 1af777afb1 fix(libc): map a Windows symbolic link loop to ELOOP when opening
CreateFileW fails a symbolic link that resolves to itself with
ERROR_CANT_RESOLVE_FILENAME (1921). WindowsOpenError_nid_no_patch had no
case for it, so sceKernelOpen, open and fopen reported EINVAL where
FreeBSD reports ELOOP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 22:18:21 +02:00
bfd1d5b568 fix(libc): compare the relinked module stem without the last extension only
The stem of a request and of a relinked module name was cut at the first dot,
so a request for Engine.Render.prx that missed could load Engine.Core.prx.guest.prx.
Only the last extension is removed now, as the review of the stem lookup asked,
and the variant-names test requests a dotted name that must not load the sibling
fixture module.

Co-Authored-By: lendinglibrary <340867775+lendinglibrary@users.noreply.github.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 20:50:03 +02:00
lendinglibrary a3c4cdcdbb fix(libc): find a relinked module by stem when the exact name misses
A title asks for a module by its console name and the relinker names the
converted module after the ELF it was built from: Unity IL2CPP titles load
Media/Modules/<name>.prx and Media/Plugins/<name>.prx while the dump holds
<name>.elf.guest.prx, so sceKernelLoadStartModule failed with 0x80020002
and the title stopped 3 s after start. After the exact and the
case-insensitive <name>.guest.prx lookups miss, take the sibling whose stem
matches the request and ends with .guest.prx, shortest name first.
2026-10-20 20:42:59 +02:00
mazen c03168fb47 fix(libc): keep guest stdio on a dup2 of descriptors 1 and 2
Host logging opens its own FILE on the saved descriptor. The guest FILE stays on the replaced descriptor, so guest printf, puts and fprintf still reach the pipe.
2026-10-20 13:38:07 +04:00
mazen 715fe9ca26 fix(libkernel): keep host stdout off a guest dup2 onto descriptor 1
The same guest dup2 that fills the stderr pipe also replaces descriptor 1, so host stdout was still writing into the guest pipe.
2026-10-20 13:38:07 +04:00
xXPBSXxandClaude Sonnet 5.5 972fb84988 fix(libc): fail chdir, remove, opendir and fopen through a regular file with ENOTDIR on Windows
A path whose directory part is a regular file, such as file/child, failed
with ENOENT in chdir, remove, opendir, fopen and freopen on Windows, where
FreeBSD 11.4 fails it with ENOTDIR (vfs_cache_lookup, sys/kern/vfs_cache.c).
The not-found error of these calls now asks whether the nearest existing
ancestor is not a directory, as open, stat, lstat, access and unlink do.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 07:54:18 +02:00
xXPBSXxandClaude Sonnet 5.5 6bc6c444e0 fix(libc): fail an oversized guest path name with ENAMETOOLONG
stat, open, mkdir, rename and the other calls that resolve a guest path answered ENOENT (or EIO for rename) for a name longer than 255 bytes or a path of 1024 bytes or more, because the host path just did not exist. FreeBSD 11.4's namei fails a component above NAME_MAX and a path of MAXPATHLEN bytes with ENAMETOOLONG. Check both limits on the guest string before it is resolved; FilesystemError already maps the error to 63.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 02:46:53 +02:00
Adrià d047690c63 Merge pull request #6967 from CrimsonMac/fix/libc-u8path-deprecation
fix(libc): build the working directory path without deprecated u8path
2026-10-19 17:40:22 +02:00
Adrià ccf0f58785 Merge pull request #6228 from Ondra97/codex/fix-windows-directory-renames
fix(libkernel): preserve directory identity across Windows renames
2026-10-18 22:20:22 +02:00
Evgeniy Kazarin 5a1590c9f8 fix(libc): resolve the final Windows path component 2026-10-18 13:15:04 -04:00
Adrià f03a2da5ee Merge pull request #5668 from babyhuey/fix/libc-keep-host-standard-streams
fix(libc): keep the host standard stream when a guest freopen of it fails
2026-10-18 19:11:47 +02:00
Evgeniy Kazarin 87a486fb30 fix(libc): preserve lookup in case-sensitive Windows directories 2026-10-18 13:03:41 -04:00
Evgeniy Kazarin cabd834bc5 perf(libc): avoid repeated Windows path component scans 2026-10-18 13:03:41 -04:00
Adrià 81cb863394 Merge pull request #6061 from wachi35676/fix/libc-drive-component-under-mount
fix(libc): keep a drive-letter component of a guest path under its mount on Windows
2026-10-18 17:51:46 +02:00
babyhuey 2d8d3b9dc1 fix(libc): keep the host standard stream when a guest freopen of it fails 2026-10-18 09:12:17 -04:00
MarcZX100 f96cdc1e7e fix(libc): mark unimplemented NID handler as non-returning 2026-10-18 01:10:16 +00:00
Ondra97 739e451332 fix(libkernel): preserve directory identity across Windows renames 2026-10-17 23:17:39 +02:00
Muhammad Wasif Ali WasifandClaude Opus 5.5 78cabf5dcd fix(libc): keep a drive-letter component of a guest path under its mount on Windows
A guest path is resolved by appending its components to the host root or
to a mount alias directory through std::filesystem::path. On Windows a
component such as "C:" that came first in the appended part was parsed as
a root name, so operator/ replaced the host directory instead of
appending: "/savedata0/C:/Windows/win.ini" and "/app0/../C:/Windows/win.ini"
resolved to "C:\Windows\win.ini", and "/C:/x" lost the component and
resolved to "<root>\x". A colon is an ordinary character in a FreeBSD
file name, so those names belong under the mount.

Guest paths are now split into component names and joined to the host
directory as text. Explicit native drive paths are still passed through.
On NTFS a name containing ":" still opens an alternate data stream; the
libc debt list now records it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:22:08 +05:00
Santhosh Kumar eb26fb97f8 fix(libkernel): filter sandbox TLS roots and preserve path overrides 2026-10-17 02:25:41 +00:00
screammandClaude Fable 5.1 9f4a8d6ec5 feat(libkernel): serve the console CA list from the host trust store
Titles that bundle OpenSSL load the console's CA file from the sandbox
directory and fail every HTTPS request without it. ProsperoRadio
(PPSA99001, libcurl 8.18.0 + OpenSSL 3.5.2) on main + #4796 + #4525:

  [ProsperoRadio][http] https://all.api.radio-browser.info/json/servers: Problem with the SSL CA cert (path? access rights?) (error adding trust anchors from file: /gkbHtXc3Wq/common/cert/CA_LIST.cer)

SwanStation (PPSA98510) stops on the same file (#5001).

The guest path resolver now accepts exact-path providers, and libkernel
registers one for /<sceKernelGetFsSandboxRandomWord()>/common/cert/CA_LIST.cer.
On first use it writes a PEM bundle once per process to
cert_cache/CA_LIST.cer in the run directory, read-only: on Windows the
current user's ROOT and CA system stores, elsewhere SSL_CERT_FILE or the
first distro bundle that exists. Without a certificate the path keeps
resolving under the guest root and does not exist, as before. Every other
path under the sandbox word is unchanged. The console file's format and
the rest of its common/cert directory are unverified and recorded in
docs/dev/debt/libkernel.md.

With this change, #4796, #4525 and #5025 on Windows 11, 60 s each:

  [ProsperoRadio][http] 11846160 bytes in 1458 ms: 1161 passes, 803 waits (679 woken) for 1428 ms
  [ProsperoRadio][catalog] page offset=0 bytes=11846160 objects=10000 accepted=9549 total=9549
  ...
  [ProsperoRadio][catalog] page offset=60000 bytes=1712035 objects=1494 accepted=1436 total=59371

  [SwanStationPS5] update: latest 1.2.5, this 1.1.3, available
  [SwanStationPS5] gamedb: index written

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-17 02:24:02 +00:00
Crimson e55144bfe5 fix(libc): build the working directory path without deprecated u8path 2026-10-17 01:18:48 +03:00
Alexej Szpevák b71434d9b7 feat(libc): read app0.zar beside app0 and refuse archive-only paths elsewhere
A ZArchive named app0.zar beside app0/ is a read-only layer under it. libc opens it at the first path resolution, looks paths missing from app0/ up case-insensitively, reads files across compressed blocks and keeps the archived descriptor table with shared positions.

Resolving an archive-only path through a call that does not read the archive throws instead of failing with ENOENT, as do opendir of a directory present in both places, fdopen of an archived descriptor and chdir into the archive. A path through .. in an archive-only directory resolves.
2026-10-16 20:03:26 +02:00
Adrià 120615bc73 Merge pull request #4927 from QRMOE/fix-libc-getcwd-allocated-size
fix(libc): ignore getcwd size when allocating a buffer
2026-10-15 16:59:41 +02:00
Dean Galvin eac8bfcfc0 fix(libc): list the directory once for a missing path that may be a relinked module
A read-only open, stat or reachability check of a missing path listed its
directory twice: once for a case-insensitive match of the name and again for
a case-insensitive match of the relinked <name>.guest.prx (#5434). Both
names are now matched in the same listing. Precedence and the ambiguous-name
errors are unchanged.
2026-10-15 13:59:12 +13:00
Adrià f7628decf2 Merge pull request #4994 from krishalivaibhav/codex/path-service-lifetime
fix(libc): preserve path services through process exit
2026-10-14 19:52:39 +02:00
Dean c3bad39372 Merge pull request #5434 from milescoviello/fix/relinked-module-name-case
fix(libc): find a relinked module whose name differs in case
2026-10-14 22:41:23 +13:00
milescovielloandClaude Opus 5.5 f0c3a5c85e fix(libc): find a relinked module whose name differs in case
Borderlands 4 (PPSA01494) loads its UI library with
sceKernelLoadStartModule("/app0/prx/libRenoirCore.PS5.prx"), but ships
the module as prx/librenoircore.ps5.prx. On Linux the call fails:

    Could not load /app0/prx/libRenoirCore.PS5.prx result 0, handle result -2147352574

(0x80020002, ENOENT). Guest paths are resolved case-insensitively, but
that only finds a component that exists. With the documented layout,
app0/prx holds only the converted librenoircore.ps5.prx.guest.prx,
so the requested name resolves to itself and RelinkedModulePath then
looks for "libRenoirCore.PS5.prx.guest.prx" with its exact spelling.
Windows and macOS hosts ignore the case, so only Linux is affected.

RelinkedModulePath now falls back to the same ASCII case-insensitive
match as ResolveHostPath when the exact <name>.guest.prx is missing,
and throws for an ambiguous match as that does. dlopen,
sceKernelLoadStartModule, stat, open and sceKernelCheckReachability all
go through it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:31:24 +00:00
milescovielloandClaude Opus 5.5 ccfadfbeef fix(libc): keep a trailing slash on paths under a mount alias
Guest path resolution trimmed the trailing slash of a path under a
mount alias (/savedata0, /download0, /app0 and the others), so the host
saw "file" for "file/": unlink, remove, sceKernelUnlink and rename
removed or moved the file, open opened it, and chmod and access
succeeded on it. The same path outside an alias already failed with
ENOTDIR, because the host got the slash.

FreeBSD 11.4 rejects it in lookup() (sys/kern/vfs_lookup.c):

	/*
	 * If we're processing a path with a trailing slash,
	 * check that the end result is a directory.
	 */
	if ((cnp->cn_flags & TRAILINGSLASH) && dp->v_type != VDIR) {
		error = ENOTDIR;
		goto bad2;
	}

On Linux and macOS a path under an alias now keeps its trailing slash
on the host path, as paths outside an alias do, so the host fails with
ENOTDIR for a file and directories with a trailing slash still work.
Windows keeps the previous behaviour; TechnicalDebt records it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 01:31:01 +00:00
krishalivaibhav 99ae2e812b fix(libc): preserve path services through process exit 2026-10-13 13:04:10 +05:30
Dean 4fe3123627 Merge pull request #4640 from MarcZX100/codex/win-host-standard-handles-4631
fix(libc): preserve host standard handles on Windows redirects
2026-10-13 17:49:02 +13:00
Dean 88f48fddef Merge pull request #4688 from eliyarson/fix/kernel-stat-relinked-prx
fix(libkernel): resolve original .prx names to relinked .guest.prx in stat, open and reachability
2026-10-13 17:48:42 +13:00
QRMOE 6571007d63 fix(libc): ignore getcwd size when allocating a buffer 2026-10-13 06:35:54 +02:00
marshmll 438d410824 fix(libc): keep host diagnostics on stderr when a guest redirects it on Linux
On Linux a guest stderr redirect also moves the host's: guest
descriptors are host descriptors, and the guest stderr stream wraps the
host stderr FILE. After dup2(fd, 2), or freopen(path, mode, stderr) with
full buffering, the libc terminate report, the host fprintf(stderr)
diagnostics and libstdc++'s terminate message go into the title's pipe
or file, and abort() discards what is still buffered. RetroArch
(PPSA99169) reopens stderr onto app0/trace.txt with full buffering, so
its stop on main left no message anywhere.

Before the first guest redirect of descriptor 2 (libkernel dup2, libc
freopen of a stream on descriptor 2), keep a close-on-exec duplicate of
the host descriptor 2 and point the host stderr at an unbuffered stream
on it. The guest stream keeps its own FILE and follows the redirect.
The libc terminate report writes to the kept descriptor with write()
instead of the stderr stream, and libkernel's sceKernelDebugOutText uses
the same kept descriptor.
2026-10-12 19:00:08 -03:00
David c22654102b fix(libc): keep the host standard handles when a guest replaces descriptor 0, 1 or 2 on Windows 2026-10-12 21:23:00 +00:00
Eli Yarson f80a2f5535 fix(libkernel): resolve original .prx names to relinked .guest.prx in stat, open and reachability
Titles check for a plugin with sceKernelStat before loading it through the engine path. The relinker emits only X.prx.guest.prx, so the check failed and PSNCore started with the raw (0, NULL) arguments. Share the dlopen mapping with sceKernelStat, read-only sceKernelOpen and sceKernelCheckReachability when the original name is absent.
2026-10-12 16:02:14 -03:00
Yunus Shaikh 0245ba7d88 fix(libc): open fopen streams with delete sharing on Windows
fopen opened its stream with _wfopen, which shares read and write
access but not delete access. While the guest held a stream open,
rename of its file failed with EIO and remove with EBUSY. POSIX rename
and remove work on open files, as on Linux and FreeBSD, and since
#3677 the descriptors sceKernelOpen returns share delete access.

fopen now creates the handle with CreateFileW sharing read, write and
delete, with the access and creation disposition of the mode, and
wraps it with _open_osfhandle and _wfdopen, keeping append mode. A
failed CreateFileW sets errno through the error mapping #3677 added to
libkernel's NativeOpen, which moves to libc as
WindowsOpenError_nid_no_patch so that both use it. freopen still
reopens through _wfreopen; TechnicalDebt records it.
2026-10-11 15:56:20 -07:00
Santhosh Kumar 17827dd9ab fix(filesystem): reject invalid parent traversal on Windows 2026-10-12 01:25:02 +05:30
milescovielloandClaude Opus 5.5 ad14190c13 fix(libc): resolve ".." in guest paths against the directory before it
Guest paths were normalized lexically before they reached the host, so
"missing/../file" and "file/../x" dropped the component before "..":
stat and open succeeded on the file, unlink deleted it and rmdir removed
a directory, where FreeBSD's lookup() resolves ".." with VOP_LOOKUP in
the directory reached so far and fails with ENOENT for a missing
component and ENOTDIR for a file. POSIX path resolution (XBD 4.13) says
the same.

".." is still collapsed lexically when the path before it is an existing
directory, so case-insensitive matching and aliases behave as before.
When it is not, the rest of the path is passed to the host unchanged and
the host resolves it. Linux then reports ENOENT or ENOTDIR as FreeBSD
does; Windows collapses ".." itself, so its results are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XYhZu5HokHMo9mfi8QU83m
2026-10-12 01:24:53 +05:30
MarcZX100andmilescoviello 8c06d20f6a fix(filesystem): reject final dot removal paths
Co-authored-by: milescoviello <kitslayer29@gmail.com>
2026-10-11 10:42:14 +00:00
MarcZX100 1a73d0165e fix(libkernel_sys): use C ABI for fchdir helpers 2026-10-11 10:26:53 +00:00
MarcZX100 dc818b3ca6 fix(libc): keep chdir resolution atomic 2026-10-11 10:26:53 +00:00
Tharun Balaji 5a8091fafd feat(libkernel_sys): implement fchdir
FreeBSD fchdir(2) changes the working directory to the directory referenced by a descriptor. The guest imports fchdir from libkernel_sys (PPSA99764, issue #1578) and the module did not export it.

The descriptor's directory is resolved from the path recorded when the directory was opened on Windows, and from the /proc/self/fd link target on Linux. The guest working directory is then set through the libc routine shared with chdir. A descriptor that is not open returns EBADF and one that is not a directory returns ENOTDIR.

AI-assisted: yes
(cherry picked from commit 76329cbb08781e13d757c3ff955acf71f8bd506f)
2026-10-11 10:26:53 +00:00
22alfbassett b2b71cd213 fix(libkernel): flush only recorded paths in sceKernelSync on Linux
On Linux, sceKernelSync called sync(2), which blocks until all
dirty pages are written back. Unrelated host I/O can stall guest's
sceKernelSync, causing the guest_kernel_sync test to stall for minutes.

Share the Windows implementation instead.
Fsync each recorded path and its changed parent directories.
Use st_mtim and coarse realtime mark on Linux in place of FILETIME.
2026-10-09 23:55:38 -05:00
Achraf ReyaniandClaude Opus 5.5 d8c5d142b6 fix(libc): allocate getcwd's buffer from the application heap
getcwd(NULL, size) returned memory from the guest heap directly, while
the caller frees it with free(), which goes to the application heap.
With a title's malloc replacement registered, that free reached the
replacement with a pointer it never returned. Allocate from the
application heap like strdup, and report ENOMEM when it returns null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 00:26:48 +09:00
TibixDev 4f23830d89 fix(libc): resolve guest filename case on host filesystems
Resolve ASCII case differences in guest paths and mount aliases while preferring exact names and rejecting ambiguous fallback matches. Preserve new filenames and host roots. Five filesystem tests pass; Skyrim now loads its INI and shader archives, initializes Vulkan and uploads intro textures instead of dereferencing null shader metadata. Written with AI assistance.
2026-10-08 14:33:17 +02:00
TibixDev 33555244c3 fix(appcontent): track temporary storage mounts
Preserve files across unmount, block new lookups until remount, and validate mount-dependent operations. Keep prior-run storage inaccessible after initialization.

Written with AI assistance.
2026-10-08 13:00:00 +02:00