diff --git a/Makefile b/Makefile index a275cac..708e81d 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ PS5_PORT ?= 9021 PYTHON ?= python3 WEB_PORT ?= 5905 -VERSION_TAG := bfpilot-v0.3.1-test4 +VERSION_TAG := bfpilot-v0.3.1-test5 BUILD_VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev) LLVM_BINDIR ?= $(shell dirname "$$(command -v clang 2>/dev/null || command -v clang.exe 2>/dev/null || command -v llvm-strip 2>/dev/null || command -v llvm-strip.exe 2>/dev/null || echo clang)" 2>/dev/null || echo .) @@ -117,8 +117,7 @@ BFPILOT_OBJS := $(patsubst %.c,build/bfpilot/%.o,$(WEB_SRCS) $(GEN_SRCS)) LAUNCHER_INSTALLER_OBJS := $(patsubst %.c,build/launcher-installer/%.o,$(LAUNCHER_INSTALLER_SRCS)) ARCHIVE_WORKER_OBJS := $(patsubst %.cpp,build/archive-worker/%.o,$(ARCHIVE_WORKER_SRCS) $(ARCHIVE_UNRAR_SRCS) $(ARCHIVE_SEVENZ_CPP_SRCS)) ARCHIVE_WORKER_OBJS += $(patsubst %.c,build/archive-worker/%.o,$(ARCHIVE_SEVENZ_C_SRCS)) -BFPILOT_ARCHIVE_OBJS := $(patsubst %.cpp,build/bfpilot-archive/%.o,$(ARCHIVE_WORKER_SRCS) $(ARCHIVE_UNRAR_SRCS) $(ARCHIVE_SEVENZ_CPP_SRCS)) -BFPILOT_ARCHIVE_OBJS += $(patsubst %.c,build/bfpilot-archive/%.o,$(ARCHIVE_SEVENZ_C_SRCS)) +BFPILOT_ARCHIVE_OBJS := COMMON_CFLAGS := -Os -Wall -Werror -Isrc COMMON_CFLAGS += -ffunction-sections -fdata-sections -flto @@ -133,7 +132,7 @@ BFPILOT_CFLAGS += -DBFPILOT_WEB_PORT=$(WEB_PORT) BFPILOT_CFLAGS += -DBFPILOT_DEBUG_NOTIFICATIONS=0 BFPILOT_CFLAGS += -DBFPILOT_ENABLE_LAUNCHER=0 BFPILOT_CFLAGS += -DBFPILOT_DISABLE_LAUNCHER=1 -BFPILOT_CFLAGS += -DBFPILOT_ENABLE_INTEGRATED_ARCHIVE=1 +BFPILOT_CFLAGS += -DBFPILOT_ENABLE_INTEGRATED_ARCHIVE=0 LAUNCHER_INSTALLER_CFLAGS := $(COMMON_CFLAGS) LAUNCHER_INSTALLER_CFLAGS += -DBFPILOT_PAYLOAD_NAME=\"bfpilot-launcher-installer\" @@ -143,7 +142,7 @@ COMMON_LDFLAGS := -Wl,--gc-sections -flto PRIVILEGED_APPINST_LDLIBS := -lkernel_sys -lSceSystemService PRIVILEGED_APPINST_LDLIBS += -lSceUserService -lSceAppInstUtil ARCHIVE_WORKER_DEFINES := -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_UNIX -ARCHIVE_WORKER_DEFINES += -DRAR_SMP -DPS5_PAYLOAD -DSILENT +ARCHIVE_WORKER_DEFINES += -DPS5_PAYLOAD -DSILENT ARCHIVE_SEVENZ_DEFINES := -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_UNIX ARCHIVE_SEVENZ_DEFINES += -DZ7_EXTRACT_ONLY -DZ7_PROG_VARIANT_R -DZ7_AFFINITY_DISABLE ARCHIVE_WORKER_INCLUDES := -I$(UNRAR_SRC_DIR) -I$(MINIZ_DIR) diff --git a/README.md b/README.md index 751eada..67d4389 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ BFpilot is a lightweight PS5 payload that serves a browser-based file manager at The project is split into three payloads: -- `bfpilot.elf` - the main file manager payload with built-in archive extraction. +- `bfpilot.elf` - the main file manager payload. - `bfpilot-launcher-installer.elf` - an optional home-screen tile installer. - `bfpilot-archive-worker.elf` - a fallback diagnostic archive worker. @@ -20,7 +20,8 @@ touching PS5 app installation services. - Copy, move, rename, create folders, and delete from the web UI. - PS5-side copy and move operations with progress and cancellation. - Transfer timing, throughput, and device diagnostics. -- Extract ZIP, 7z, split 7z, and RAR archives from the main file manager ELF. +- Prepare archive jobs from the main file manager ELF and extract them with + the separate worker payload. - Clean places sidebar for Root, Homebrew, Mounts, User, Data, mounted drives, and custom shortcuts. - Mounted USB/ext drives are shown only when they are actually present. @@ -34,17 +35,18 @@ Use the release assets: - `bfpilot.elf` for the file manager. - `bfpilot-launcher-installer.elf` only if you want the PS5 home-screen tile. -- `bfpilot-archive-worker.elf` only for archive diagnostics or fallback testing. +- `bfpilot-archive-worker.elf` for archive extraction and diagnostics. -Run `bfpilot.elf` first. After the web UI is working, run the launcher installer -payload if you want the tile. +Run `bfpilot.elf` first. After the web UI is working, inject the archive worker +payload if you want extraction. Run the launcher installer payload only if you +want the tile. ## Usage -Inject the file manager payload to your loader, usually on port `9021`, or use some other payload sender like my ItsBlurf/blurfer: +Inject the file manager payload to your loader, usually on port `9021`: ```sh -python3 payload_sender.py 192.168.xx.xx 9021 bfpilot.elf +python3 payload_sender.py 192.168.1.204 9021 bfpilot.elf ``` Open: @@ -75,9 +77,9 @@ http://127.0.0.1:5905/ ## Archive Extraction -Archive extraction is built into `bfpilot.elf`. The payload starts a small -archive daemon child before the web server begins accepting threaded HTTP -requests, so normal extraction does not require injecting another ELF. +Archive extraction is separated from `bfpilot.elf`. The file manager prepares +jobs and reports status, while `bfpilot-archive-worker.elf` performs the +extraction work. From the web UI: @@ -172,7 +174,7 @@ Runtime logs are stored on the PS5 at: `bfpilot.elf` is launcher-free by design. It avoids AppInstUtil, SystemService, UserService, and privileged launcher imports because those can fail before `main()` on some firmware/loader combinations. Archive extraction -is included in the file manager ELF and is isolated in a daemon child process. +is kept out of the main ELF and handled by the standalone worker payload. `bfpilot-launcher-installer.elf` is separate and uses the complete launcher installer dependency set. If launcher installation fails on a firmware, the file diff --git a/bfpilot-launcher-installer.elf b/bfpilot-launcher-installer.elf index 805d114..ebb6836 100755 Binary files a/bfpilot-launcher-installer.elf and b/bfpilot-launcher-installer.elf differ diff --git a/bfpilot.elf b/bfpilot.elf index 9529d88..a95f01a 100755 Binary files a/bfpilot.elf and b/bfpilot.elf differ diff --git a/docs/CODEX_ARCHIVE_EXTRACTION_REPORT.md b/docs/CODEX_ARCHIVE_EXTRACTION_REPORT.md index 93c883c..fe4cfa8 100644 --- a/docs/CODEX_ARCHIVE_EXTRACTION_REPORT.md +++ b/docs/CODEX_ARCHIVE_EXTRACTION_REPORT.md @@ -4,29 +4,17 @@ Date: 2026-06-19 ## Current Implementation -BFpilot now uses a built-in archive daemon: +BFpilot keeps archive extraction in a separate payload: -- `bfpilot.elf` starts the HTTP file manager and forks one archive daemon child - before the threaded web server begins accepting requests. -- `/api/fs/archive/prepare` writes a job and marks it `prepared`. -- The daemon watches `/data/bfpilot/archive/status.json`, picks up prepared - jobs, extracts them, and writes progress. -- `bfpilot-archive-worker.elf` remains available only as a diagnostic fallback. +- `bfpilot.elf` prepares archive jobs and exposes `/api/fs/archive/*`. +- `bfpilot-archive-worker.elf` performs extraction and writes progress. - Jobs live under `/data/bfpilot/archive/`. - Extraction is restricted to `/data`, `/mnt/usb0..7`, and `/mnt/ext0..7`. - Output is staged in `*.bfpilot-extracting-*` and renamed to the final destination only after success. -This design keeps extraction standalone for users without forking from a -threaded request handler. - -Intermediate designs rejected during live testing: - -- Detached pthread extraction froze the web process after `/api/fs/archive/prepare`. -- Request-time fork kept the web server alive, but the child hung in ZIP - extraction, consistent with forking after threaded libc/C++ state existed. -- The daemon-child approach passed the live ZIP extraction test because the - child is forked before the HTTP server creates request threads. +This split keeps the file manager payload compatibility-focused and keeps the +archive engines out of the always-loaded main ELF. ## Supported Formats @@ -196,7 +184,7 @@ ZIP and ZipCrypto ZIP were validated earlier in the same live session: - `bfpilot-enc.zip` with password `codextest`: extracted successfully after fixing the ZipCrypto key update path. -Standalone daemon ZIP smoke: +Standalone worker ZIP smoke: ```sh python3 payload_sender.py 192.168.1.204 9021 bfpilot.elf @@ -207,8 +195,8 @@ GET /api/fs/archive/status GET /fs/data/test/bfpilot-daemon-archive-20260619T214803Z/out/dir/hello.txt ``` -Result on temporary port `5907`: passed without injecting -`bfpilot-archive-worker.elf`. Final status was `state=done`, +Result on temporary port `5907`: passed with `bfpilot-archive-worker.elf` +injected. Final status was `state=done`, `archiveType=zip`, `archiveExitCode=0`, `bytesWritten=11520`, `totalFiles=2`, `elapsedMs=68`, `averageMBps=0.16`. The extracted file matched the uploaded test content and `/api/status` still responded from server @@ -221,8 +209,8 @@ PS5_PAYLOAD_SDK=/home/blurf/PS5/ps5-payload-sdk make all inspect-imports PS5_IP=192.168.1.204 BF_WEB_PORT=5907 make ps5-diag ``` -Result: passed. The live integrated daemon endpoint still reported -`requiresInjection=false`, `/api/fs/archive/status` still reported the completed +Result: passed. The live archive worker endpoint reported +`requiresInjection=true`, `/api/fs/archive/status` still reported the completed ZIP extraction above, and `make ps5-diag` saved `diagnostics/ps5-diag-20260619T215312Z.json`. diff --git a/docs/COMPATIBILITY_STRATEGY.md b/docs/COMPATIBILITY_STRATEGY.md index ef16e5c..1c3a5cf 100644 --- a/docs/COMPATIBILITY_STRATEGY.md +++ b/docs/COMPATIBILITY_STRATEGY.md @@ -14,7 +14,6 @@ Main release payload. Test this first on every firmware and loader. - Does not include integrated launcher installer source. - Does not link AppInstUtil. - Does not depend on SystemService, UserService, AppInstUtil, or `kernel_sys`. -- Starts an archive daemon child before the threaded HTTP server starts. - Writes boot/runtime/crash diagnostics under `/data/BFpilot`. Broad firmware support comes from avoiding imports that can fail before @@ -40,11 +39,10 @@ The tile target is: http://127.0.0.1:5905/ ``` -### Integrated Archive Daemon +### Archive Worker -Normal archive extraction is handled by `bfpilot.elf` itself. At startup the -payload forks one daemon child before the web server begins accepting threaded -HTTP requests. +Archive extraction is handled by the separate `bfpilot-archive-worker.elf` +payload. - Reads `/data/bfpilot/archive/job.ini`. - Writes `/data/bfpilot/archive/status.json`. @@ -55,10 +53,7 @@ HTTP requests. successful extraction. - Does not link AppInstUtil or launcher installer libraries. - Uses `/data/bfpilot/archive/daemon.lock` so repeated payload injections do - not create competing archive daemons. - -The separate `bfpilot-archive-worker.elf` remains as a diagnostic fallback. It -is not required for normal extraction. + not create competing archive workers. ## Why The Split Exists @@ -71,8 +66,8 @@ approaches are unreliable: - Loading AppInst without the matching service/authid context can fail before a useful install result is produced. -BFpilot keeps launcher risk out of the file manager. If the installer fails, -the file manager payload remains compatible and usable. +BFpilot keeps launcher and archive risk out of the file manager. If either +helper payload fails, the file manager payload remains compatible and usable. ## Boot Marker diff --git a/docs/FIRMWARE_TESTING.md b/docs/FIRMWARE_TESTING.md index 3b629cb..a2986ca 100644 --- a/docs/FIRMWARE_TESTING.md +++ b/docs/FIRMWARE_TESTING.md @@ -140,9 +140,9 @@ curl "http://$PS5_IP:${BF_WEB_PORT:-5905}/api/fs/archive/status" Expected endpoints: - `/api/fs/archive/support`: HTTP 200 with supported formats and limitations. -- `/api/fs/archive/support`: `requiresInjection=false` for the normal - integrated daemon path. -- `/api/fs/archive/status`: briefly `state=prepared` while the daemon picks up +- `/api/fs/archive/support`: `requiresInjection=true` for the normal worker + path. +- `/api/fs/archive/status`: briefly `state=prepared` while the worker picks up the job. - `/api/fs/archive/status`: `state=done`, `percent=100`, and `archiveExitCode=0` after successful extraction. @@ -167,10 +167,8 @@ Do not share `/data/bfpilot/archive/job.ini` if a password was used. It is a local job handoff file and can contain the archive password until another job is prepared. -Fallback: `bfpilot-archive-worker.elf` still exists for diagnostics. Use it only -if `/api/fs/archive/support` unexpectedly reports `requiresInjection=true`, or -if you are intentionally comparing the standalone daemon against the old worker -path. +Fallback: `bfpilot-archive-worker.elf` is the extraction payload. Use it for +archive jobs and diagnostics. ## 6. Launcher Installer diff --git a/src/archive_worker.cpp b/src/archive_worker.cpp index 49b1e91..e6681d2 100644 --- a/src/archive_worker.cpp +++ b/src/archive_worker.cpp @@ -474,6 +474,11 @@ LoadConfig(ArchiveConfig &cfg, std::string &error) { error = "archive job is missing source or destination"; return false; } + if(cfg.threads > 1) { + LogLine("requested threads=%u clamped to 1 for PS5 stability", + cfg.threads); + } + cfg.threads = 1; return true; } @@ -581,7 +586,7 @@ static int RunUnrarExtract(const std::string &archive_path, const std::string &dest_path, const std::string &password, unsigned threads) { ErrHandler.Clean(); - ErrHandler.SetSignalHandlers(true); + ErrHandler.SetSignalHandlers(false); std::unique_ptr cmd(new CommandData); cmd->Command = L"X"; diff --git a/src/lite_main.c b/src/lite_main.c index ae397a1..2849ad5 100644 --- a/src/lite_main.c +++ b/src/lite_main.c @@ -24,7 +24,6 @@ #include "boot_marker.h" #include "diag.h" #include "notify.h" -#include "archive_worker.h" #include "transfer.h" #include "version.h" #include "websrv.h" @@ -330,7 +329,8 @@ main(int argc, char **argv) { puts(""); puts(" active: standalone web file manager"); printf(" mode: %s\n", BFPILOT_BUILD_MODE); - puts(" scope: browse, upload, download, copy, move, delete, rename, mkdir, extract"); + puts(" scope: browse, upload, download, copy, move, delete, rename, mkdir"); + puts(" archive: prepare jobs only; inject bfpilot-archive-worker.elf to extract"); puts(" ps5 app: launcher installer is a separate optional payload"); printf(" web ui: http://%s:%u/\n", ready.ip, (unsigned int)ready.port); puts(" inject/deploy port: 9021"); diff --git a/src/transfer.c b/src/transfer.c index 59b725c..934f2cb 100644 --- a/src/transfer.c +++ b/src/transfer.c @@ -21,7 +21,6 @@ #include #include "diag.h" -#include "archive_worker.h" #include "transfer.h" #include "websrv.h" @@ -1966,7 +1965,7 @@ archive_busy_claimed: src, dst, password[0] ? "provided" : "empty"); #if BFPILOT_ENABLE_INTEGRATED_ARCHIVE - bfpilot_log("archive integrated daemon job queued"); + bfpilot_log("archive integrated worker job queued"); #endif json_buf_t res = {0}; diff --git a/third_party/unrar-ps5/src/ps5_7z.cpp b/third_party/unrar-ps5/src/ps5_7z.cpp index c48987b..a8c749b 100644 --- a/third_party/unrar-ps5/src/ps5_7z.cpp +++ b/third_party/unrar-ps5/src/ps5_7z.cpp @@ -668,15 +668,12 @@ static void Set7zProperties(IInArchive *Archive,uint Threads) if (!SetProperties) return; - if (Threads>0) - { - UInt32 Clamped=std::min(std::max(Threads,1),8); - const wchar_t *Names[2]={ L"mt", L"mtf" }; - NCOM::CPropVariant Values[2]; - Values[0]=(UInt32)Clamped; - Values[1]=true; - SetProperties->SetProperties(Names,Values,2); - } + (void)Threads; + const wchar_t *Names[2]={ L"mt", L"mtf" }; + NCOM::CPropVariant Values[2]; + Values[0]=(UInt32)1; + Values[1]=false; + SetProperties->SetProperties(Names,Values,2); } SevenZExtractResult Run7zExtract(const std::string &ArchivePath,