Skip the space after ERROR in sscanf and preserve the signed native
error code instead of negating it. Previously a native failure parsed
as 0 and was negated into a positive value that api_games_uninstall
treated as success.
zhttp can now uninstall a title natively, reusing the same embedded
helper that drives installs. Three changes make it work on 13.60:
- install_helper.c escalates to the SYSTEM_PROCESS auth id
(0x4800000000000006) by writing cr_sceAuthID at ucred+0x58 via
kernel_copyin; the SDKs
Treat `instance.pid` as a control identity instead of a hard lock by authenticating shutdown requests with the saved token, ignoring stale/reused/malformed identities, and only blocking when a verified payload (or authenticated prior instance) is still alive. Add PS4/PS5 `sendfile` safety gating that uses buffered `pread`+`send` on incompatible or unknown mount types (exFAT/FAT/nullfs/PFS, or mount lookup failure) while keeping zero-copy on safe filesystems, and wire in README/Makefile updates plus new host-side tests and stubs for both paths.
The macOS/Linux ftp jobs rejected pal_dns_filter.c with
-Wunused-but-set-global: g_dns_stop is only read by the console resolver
loops, so on hosts it was written for nothing. The control port carried the
same kind of dead state (g_control_thread_started, and a thread id only ever
passed to pthread_create) because the thread is detached and never joined.
Guard the DNS stop flag with the console builds and drop the unused control
port variables; an audit of every release configuration on preprocessed
sources now reports no set-but-unread file-scope statics.
The PS5 ftp build (ENABLE_ZHTTPD=0) did not compile: main.c evaluated
ENABLE_ZHTTPD before defaulting it (-Wundef) and the PS5 shutdown helpers sat
inside the web-only block even though the main loop and the control port rely
on them. Default the switch at the top of the file, keep the shutdown helpers
in every PS5 build, and let the Makefile define ENABLE_ZHTTPD=0 explicitly so
no translation unit ever sees the macro undefined.
Console-format PS5 packages (magic 0x7F "FIH") hold no readable param.sfo, so
native PS5 titles kept showing their title id twice while PS4 ones resolved.
Fall back to the system metadata when the package cannot be parsed:
/user/appmeta/<TITLE>/param.json and then /system_data/priv/appmeta, whose
localizedParameters carry the display name as plain UTF-8 (first entry = the
default language). The format is pinned by a fixture in test_http_games.
With ENABLE_PKG_INSTALL=0 the helper was still compiled and its 115 KB blob
linked into the payload even though no code referenced it. Gate the helper
build and blob on the flag so release artifacts carry the installer neither in
code nor in data.
- copy.c: replace the 2x4 MB ping-pong with a 4-slot ring of 8 MB chunks
(PS4: 1 MB), filled by concurrent pread() readers (2 on PS5, 1 on PS4)
and drained by a single in-order writer. The progress callback now runs
without holding the pipeline mutex, and mmap pressure degrades to fewer
slots/smaller chunks before falling back to the serial copy.
- Fix a source fd leak on the pre-flight ENOSPC path.
- /api/copy?move=1: rename() when source and destination share a
filesystem, otherwise copy and remove the source entries (keep_src=0).
Moves merging into an existing folder rename file by file.
- web: moves use the server-side mode instead of copy + recursive delete.
Builds without ENABLE_PKG_INSTALL now report it in /api/status
(features.pkg_install) and the web interface hides every installer entry point
— the Games action, the file explorer item and the progress pollers — instead
of offering actions that only answer 409. The release workflow already builds
with the flag off, so this release ships without the remote PKG installer.
Extend the HTTP suite with the archive extraction fixtures (good, traversal
and symlink cases) and the system endpoints, so the split APIs keep their
behavior pinned.
Bring the file manager, transfers, settings and games views in line with the
split HTTP APIs (dump jobs, copy/extract progress, DNS filter and system
status), refresh the styling and document the API, pkg install flow and
architecture, together with the repository issue and pull request templates.
tools/fetch_pacbrew_ps4.sh unpacks the pinned PacBrew portlibs (libcurl,
mbedTLS, zlib) with a Mozilla CA bundle; the Makefile detects that prefix and
enables ENABLE_LIBCURL for PS4, bridging the three libc symbols the OpenOrbis
build expects. Console payloads now always link as PIE (GoldHEN's payloader
rejects ET_EXEC), which is what made the plain `make deploy` flow work, and
the release workflow installs the same portlibs for PS4 zhttp artifacts.
Titles delivered as one package keep no sce_sys/param.sfo on disk, so the
Games view fell back to the title id and showed the content id twice. Read
the param.sfo entry from app.pkg when the loose file is missing (magic probe,
encrypted entries skipped), cover CONTENT_ID/CATEGORY lookups too, and let the
web UI hide the id line when it would repeat the name. Regression test builds
a minimal package image and checks the catalog reports the SFO title.
The PS4 entry point never ignored SIGPIPE (the shared handler is compiled out
there), so a browser cancelling a download killed the payload with signal 13.
Ignore SIGPIPE on PS4 like PS5 and POSIX do, and set SO_NOSIGPIPE on the HTTP
listener and client sockets (FTP sockets follow through pal_socket_configure)
so a vanished peer only breaks its own connection. test_http_server aborts a
streamed download mid-flight and checks the server keeps answering.
Add removable-volume detection that ignores empty slots, disc eject/state
helpers, the userland DNS filter, PS5 firmware offset lookup with the optional
kernel net filter, and a control port a new payload uses to retire the
previous instance.
List installed titles with icons, start them through LncUtil (with the
no-logged-in-user guard), install and uninstall packages, and repair missing
home screen entries through the shell's app.db. PS5 package installs are
driven by an embedded helper delivered to elfldr on loopback.
Dump an installed title's running sandbox (already decrypted by the kernel)
to the browser as a streamed ZIP or to console storage as a file tree or ZIP.
The job launches the title when needed, reports entries/size/source through
the status endpoint, honours POST /api/dump/cancel and keeps the decrypt flag
configurable. Documented in docs/game-dumping.md, covered by test_dump_job.
Add a ZIP64 writer that streams entries straight into the HTTP response (and
decrypts SELF containers on consoles), archive path validation helpers and a
reworked builtin unzip, all covered by fixtures and unit tests.
Move copy, sendfile and directory helpers behind one platform layer, let the
FTP server run beside the HTTP stack with its own instance bookkeeping, and
keep the transfer command on the shared pipeline.
One manager owns remote downloads: libcurl for HTTP/HTTPS/FTP (with ranged
parallel fetches), libnfs for nfs:// URLs and an optional libtorrent engine
for magnet links. Jobs survive payload re-injections, support pause, cancel
and retry, and report per-job progress through the HTTP API.
The HTTP stack had grown into a single file that owned sockets, parsing,
uploads and every API domain. Split it into focused modules (listener,
response stream, upload, json helpers) with the domain handlers next to the
APIs they serve, and cover framing, streaming and uploads with unit tests.
Replace the embedded UI with a file manager: sidebar, details table, keyboard shortcuts, uploads, copy/move and extraction. Games, System, Transfers and Settings use the same components. The previous UI is archived in web/legacy/ and left out of the embedded resources.
The restyle is flat: donation banner, credits with the maintainer photo, and no gradients or card shadows. JavaScript stays ES5.
Survive console Rest Mode by recreating FTP/HTTP listeners with backoff and exposing daemon instance_id; implement real SITE CHMOD (#9) and fix atomic-copy temp paths that broke dashboard moves (#7).
curlftpfs sends 'LIST -a' by default. zftpd treated '-a' as a
path argument, causing 550 errors and empty directory listings
on FUSE-based FTP mounts (e.g. fnOS remote mount).
Add ftp_path_has_list_flag() / ftp_path_skip_list_flag() to
ftp_path.c with stat()-based flag-vs-path disambiguation.
Only well-known flags (-a/-l/-la/-al) are recognised; unknown
flag patterns pass through as paths to preserve access to files
whose names start with '-'.
- PS4/PS5: upload .elf and .bin files directly (no tar.gz) for payload injection
- macOS: create .app bundle with Info.plist (extracts VERSION from ftp_config.h)
- Linux: keep standard tar.gz with BUILD_INFO
- Upload step: use dist/* to handle all artifact types
- Release assets: collect .elf, .bin, and .tar.gz files
- Fix Info.plist heredoc: remove single quotes so VERSION expands correctly
- Fix sha256sum: remove || true (if ls guard already handles missing files)