# znippy decompress — guide
> **Class:** `guide` · audience: a techie restoring bytes from a `.znippy` archive.
> The *what* is in [`decompress-design.md`](decompress-design.md); the *why* in [`decompress-reasoning.md`](decompress-reasoning.md). This file is the workflow.

## f0 — restore an archive (the whole workflow)
Three shapes cover everything you'll do:
```bash
# 1. full restore into a directory
znippy decompress -i archive.znippy -o ./out
# 2. selective restore — only one pkg_type and/or repo (uses the data sub-index)
znippy decompress -i archive.znippy -o ./out --type maven --repo central
# 3. one file, to stdout or to a path
znippy get -i archive.znippy -p org/foo/Bar.class # → stdout
znippy get -i archive.znippy -p org/foo/Bar.class -o Bar.class
# 4. verify every chunk's blake3 without writing files
znippy verify -i archive.znippy
```
An empty `--type`/`--repo` filter equals a full restore. Restore is **core-count-independent**:
the same archive yields byte-identical output on any machine, because each chunk's checksum is
bound to its `chunk_seq`. If a checksum fails, the command errors — it never writes a bad file
and never panics.
## f1 — restore from Rust
Link `znippy-decompress` and call the re-exported top-level functions:
```rust
use std::path::Path;
use znippy_decompress::{decompress_archive, decompress_archive_filtered};
// full restore; returns a VerifyReport (every chunk was blake3-checked)
let report = decompress_archive(Path::new("archive.znippy"), Path::new("out"))?;
// selective: keep only rows whose sub-index matches the filter
let filter = /* (pkg_type, repo) selector */;
let report = decompress_archive_filtered(
Path::new("archive.znippy"), Path::new("out"), filter)?;
```
Under the hood these fan out to `N` workers over a shared atomic row cursor; you get NVMe queue
depth for free (parallel `pread`). Nothing to tune — no reader thread, no channel, no buffer
pool to size. Output paths are sanitized (zip-slip / absolute paths rejected) before any write.
## f2 — pull a single file from Rust
For one or a few files, skip the full restore:
```rust
use std::path::Path;
use znippy_common::get_file;
// resolves the chunk run via the trie/lookup, preads + verifies, returns the bytes
let bytes: Vec<u8> = get_file(Path::new("archive.znippy"), "org/foo/Bar.class")?;
```
`get_file` never materializes the whole index — it locates the file's contiguous chunk run,
`pread`s each blob, decompresses (or copies raw), `blake3`-verifies, and reassembles by
`fdata_offset`. Use it when Holger asks for one path. If you hold one archive and pull *many*
files, prefer `ZnippyArchive::open` + `extract_file` instead — see
[`index-guide.md`](index-guide.md) `f1`.
## f3 — verify, and reading the report
`znippy verify -i <archive>` is the restore engine with writes suppressed: it decompresses
every chunk and checks every `blake3` against the index, producing a `VerifyReport` but no
files. Use it as a cheap integrity gate in CI before shipping an archive: it **exits non-zero**
when the report carries any corrupt file or corrupt byte, so `znippy verify -i A && ship` really
does gate on integrity (it prints the counters either way — read the exit status, not stdout).
From Rust the same `VerifyReport` comes back from `decompress_archive`, which returns `Ok` even
for a corrupt archive — corruption is reported in `report.corrupt_files` / `report.corrupt_bytes`,
so a caller must inspect those counters rather than rely on `?`.
## Selective restore cheatsheet
| you want… | command |
|---|---|
| everything | `znippy decompress -i A -o out` |
| just the maven artifacts | `znippy decompress -i A -o out --type maven` |
| one repo's rust crates | `znippy decompress -i A -o out --type rust --repo crates-io` |
| one file to stdout | `znippy get -i A -p path/to/file` |
| integrity only, no output | `znippy verify -i A` |