jlevere/psf
GitHub: jlevere/psf
纯 Rust 编写的 Microsoft PSTREAM 补丁存储文件(.psf)及其 CIX 索引的解析库,提供 Sans-IO 零拷贝的数据流读取能力。
Stars: 0 | Forks: 0
# psf
[](https://github.com/jlevere/psf/actions/workflows/ci.yml)
[](#许可证)
纯 Rust 编写的读取器,用于读取 Microsoft **PSTREAM** 补丁存储文件 (Patch Storage Files) —— 即 Windows Update 所使用的“快速
下载” payload 容器 (LCU `.psf`, FoD `.psf`, MSU
PSTREAM) —— 以及与之配对的 **容器索引** (`*.psf.cix.xml`)。
PSTREAM 文件包含一个简小的头部,其后紧跟多个拼接在一起的 payload 流 (通常每一个是 `PA30`/`PA31` MSDelta 差异流)。该容器本身并不
具备自索引功能:从目标文件到其 `(offset, length)` 流的映射关系存放
在 CIX 清单中。本 crate 解析这二者并按范围产生流的字节;将这些数据传递给 [`msdelta`](https://github.com/jlevere/msdelta) 即可
重构目标文件。
Sans-IO 且零拷贝:输入为 `&[u8]`,输出为字节切片。
```
use psf::{Psf, cix::ContainerIndex};
let cix = ContainerIndex::parse(cix_xml)?;
let psf = Psf::parse(psf_bytes)?;
for file in cix.files() {
if let Some(stream) = file.psf_stream() {
let blob = psf.stream(stream)?; // PA30 delta or RAW bytes
// -> msdelta::pa30::apply(base, blob)
}
}
# Ok::<(), psf::Error>(())
```
## 大型容器
上面的示例借用了整个 `.psf`。对于因体积过大而无法读入
`Vec` 的本地文件,可以使用 `mmap` 并将映射作为 `&[u8]` 传递:该切片 API 是
惰性的 —— 操作系统只会为你切片的特定范围进行分页加载。
当数据源无法被内存映射时 (例如网络下载,或者包含在
按顺序读取的归档文件中的 `.psf`),可以启用 `io` feature 以获取一个 `Read + Seek`
适配器,该适配器能按范围拉取数据流,而无需将整个容器保留在内存中:
```
psf = { version = "0.1", features = ["io"] }
```
```
# #[cfg(feature = "io")] {
use std::fs::File;
use psf::{PsfStream, reader::PsfReader};
let mut psf = PsfReader::new(File::open("express.psf")?)?;
let blob = psf.stream(PsfStream { offset: 128, length: 4595 })?; // PA30 delta or RAW
# Ok::<(), psf::reader::ReadError>(())
# }
```
默认构建版本依然保持 sans-IO;该适配器属于按需启用 (opt-in) 功能。
## 开发说明
```
nix develop # stable toolchain + cargo-nextest
cargo build
cargo nextest run # or: cargo test --all-features
```
这些解析器需要在由攻击者可控的输入上运行 (因为 `.psf` 及其 CIX 清单
内嵌在更新程序中),因此使用了 `cargo-fuzz` 对其进行模糊测试:
```
nix develop .#fuzz # nightly + cargo-fuzz
./fuzz/seed_corpus.sh # valid artifacts -> corpora
cargo fuzz run fuzz_cix_structured # generative CIX (round-trip oracle)
cargo fuzz run fuzz_cix -- -dict=fuzz/cix.dict # CIX XML parser (mutates real manifests)
cargo fuzz run fuzz_psf -- -dict=fuzz/psf.dict # PSTREAM header + scanner
cargo fuzz run fuzz_reader -- -dict=fuzz/psf.dict # reader vs in-memory (differential)
```
真实的 `.psf`/CIX 测试夹具 (fixtures) 被 git-ignore 了;在缺少这些文件时,依赖夹具的测试将会自动跳过
(`UUP_PSF_FIXTURE`, `UUP_CIX`)。
## 许可证
根据你的选择,采用 [MIT](LICENSE-MIT) 或 [Apache-2.0](LICENSE-APACHE) 许可证授权。
被 [`uup`](https://github.com/jlevere/uup) 和
[`msu`](https://github.com/jlevere/msu) 所使用。
标签:Rust, Sans-IO, Windows Update, 可视化界面, 差分数据, 文件解析, 系统工具, 网络流量审计, 通知系统