JujuforceandClaude Opus 4.8 cd02c09ad0 fix: skip NTFS DOS (8.3) short-name entries when extracting
When a file or directory has a separate 8.3 short name, it appears in the NTFS
directory index twice: once under its Win32 long name and once under the Dos
short name. The extractor iterated all index entries, so every such item was
written a second time under its mangled NAME~1.EXT alias — and short-named
directories had their entire subtree re-extracted.

Skip index entries in the Dos namespace (the file is still extracted via its
Win32 entry). Add unit tests for the skip decision.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 14:03:30 +02:00
2026-06-28 11:18:27 +02:00
2026-06-28 11:18:27 +02:00
2024-07-21 23:59:02 +07:00

fsdecrypt

Decryptor and extractor for SEGA arcade filesystem containers (fscrypt format). Works on Windows and Linux, no admin privileges required.

Installation

Requires Rust.

cargo build --release

The binary will be at target/release/fsdecrypt (or fsdecrypt.exe on Windows).

Usage

fsdecrypt <FILES>...

Examples

# Extract a game APP container
fsdecrypt ABCD_1.00.00_20240101120000_0.app

# Extract an OPTION/DLC container
fsdecrypt ABCD_A001_20240101120000_0.opt

# Extract multiple files at once
fsdecrypt game_v1.app game_v2.app extras.opt

# Decrypt only (outputs raw .ntfs/.exfat image, no extraction)
fsdecrypt --no-extract ABCD_1.00.00_20240101120000_0.app

Delta Updates

Games often ship incremental updates as a separate .app file. Just pass the update file — fsdecrypt will automatically find the base in the same folder and merge them:

fsdecrypt ABCD_1.01.00_20240215143000_1_1.00.00.app

You can also pass both explicitly:

fsdecrypt ABCD_1.00.00_20240101120000_0.app ABCD_1.01.00_20240215143000_1_1.00.00.app

The output folder is named after the input file (e.g. ABCD_1.01.00_20240215143000_1_1.00.00/).

External Key Files

For games not in the built-in key database, place a file named {GAME_ID}.bin in the working directory:

  • 16 bytes for key only (IV derived automatically)
  • 32 bytes for key + IV

Testing

Tests run locally (there is no hosted CI). The unit tests are plain cargo test; the Linux x86_64-musl release target is exercised via Docker when you need it.

cargo test            # unit tests (IV derivation, timestamp decoding, key lookup)
scripts/test.sh       # native tests + smoke test, then the same in a musl container
scripts/test.sh --no-docker   # skip the Docker/Linux step

scripts/test.sh uses the clux/muslrust image to build and test the static Linux binary — the same way release artifacts are produced — so both targets can be validated from any host.

End-to-end fixtures

The tests/e2e.rs test decrypts real containers placed in a fixtures/ directory at the repo root and checks that each extracts successfully. That folder is git-ignored — the proprietary sample containers are never committed — and the test is a no-op when it is empty, so just drop a few .app/.opt files in fixtures/ and run cargo test (or scripts/test.sh) to exercise the full decrypt-and-extract path.

License

BSD Zero Clause License (0BSD)

S
Description
No description provided
Readme 0BSD
10 MiB
Languages
Erlang 97.9%
Rust 2%