Install pipeline
What happens after CyberFoil has a byte stream - container parse, NCA write, tickets, metadata. Transport details: Network.
Overview
All sources converge on the same install orchestrator (install.cpp):
- Prepare - read CNMT NCAs, install content meta to NCM DB, push application record to NS
- Begin - import tickets/certs via ES, stream each content NCA into storage
.nsz / .xcz are not decompressed as whole files - they use the same PFS0/HFS0 layout with .ncz entries instead of .nca.
install.cpp, install_nsp.cpp, install_xci.cpp
NSP / NSZ - PFS0 container
- Magic
PFS0(0x30534650) - File table:
PFS0BaseHeader+ entries + string table - NCA entries:
{id}.nca,{id}.cnmt.nca,{id}.ncz,{id}.cnmt.ncz - Ticket pairs:
.tik+.cert→esImportTicket
Streaming (HTTP / USB)
Dual-thread pipeline in http_nsp.cpp / usb_nsp.cpp:
- Thread 1: HTTP/USB range read →
BufferedPlaceholderWriter - Thread 2: flush 8 MB segments →
NcaWriter→ NCM placeholder - Ring buffer: 8 MB × 128 segments (2 in applet mode)
Per-NCA steps (NSPInstall::InstallNCA)
- Delete stale placeholder
- Optional RSA-PSS signature verify (
validateNCAs) - Stream to placeholder via
NcaWriter Registerplaceholder → final NCA id- Delete placeholder; rollback on error
nsp.cpp, install_nsp.cpp, http_nsp.cpp, buffered_placeholder_writer.cpp
XCI / XCZ - HFS0 container
- Root HFS0 at offset
0xF000or0x10000, magicHFS0(0x30534648) securepartition holds NCAs, tickets, certs- Same Prepare/Begin flow as NSP but reads HFS0 entries
Streaming differences
- HTTP XCI: 4 MB chunks,
NcaWriterdirect (no ring buffer) -http_xci.cpp - SD/USB XCI: same as local NSP pattern via
sdmc_xci.cpp
xci.cpp, install_xci.cpp, http_xci.cpp
NCZ decompression (.nsz / .xcz inner NCAs)
Handled inside NcaWriter / nca_writer.cpp while streaming:
| Magic | Format |
|---|---|
NCZSECTN | Sectioned NCZ - ZSTD or NCZBLOCK per section |
NCZBLOCK | Block-compressed ZSTD stream |
0xFD2FB528 | Raw ZSTD stream |
| (none) | Plain NCA - direct body write |
After decompress, section data is re-encrypted (AES-128-CTR) and written to the NCM placeholder in 8 MB flushes.
nca_writer.cpp
NCM placeholder API
Wrapper around Switch ncmContentStorage* in ncm.cpp:
| Method | API |
|---|---|
CreatePlaceholder | ncmContentStorageCreatePlaceHolder |
WritePlaceholder | ncmContentStorageWritePlaceHolder |
Register | ncmContentStorageRegister - finalize NCA |
DeletePlaceholder | Cleanup incomplete install |
| Content meta | ncmContentMetaDatabase Set + Commit |
| Application | nsPushApplicationRecord |
ncm.cpp, nx/ncm.cpp
NCA signature verification
When validateNCAs is true (default in config):
- Decrypt NCA header (AES-XTS with
headerKey) - Check magic
NCA3 - RSA-2048-PSS verify first 0x200 bytes of header
- On failure: warning dialog - user can abort or continue
install_nsp.cpp, optionsPage.cpp (validateNCAs)
Shop XCI - special HTTP stream
Shop XCI items bypass the generic XCIInstallTask and use InstallXciHttpStream in shopInstall.cpp:
- Detect XCI: extension
.xci/.xczor HFS0 magic at 0xF000/0x10000 - Parse HFS0 via HTTP range with 16 MB read-ahead cache
- Write NCAs through
NcaWriter, commit CNMT incrementally - Import tickets at end - single continuous HTTP connection
NSP/NSZ shop items use standard HTTPNSP + NSPInstall.
shopInstall.cpp - installTitleShop, InstallXciHttpStream