| Crates.io | exarch-core |
| lib.rs | exarch-core |
| version | 0.2.2 |
| created_at | 2025-12-30 21:40:06.976593+00 |
| updated_at | 2026-01-03 18:34:45.266343+00 |
| description | Memory-safe archive extraction library with security validation |
| homepage | https://github.com/bug-ops/exarch |
| repository | https://github.com/bug-ops/exarch |
| max_upload_size | |
| id | 2013356 |
| size | 767,320 |
Memory-safe archive extraction and creation library with security validation.
This crate is part of the exarch workspace.
[dependencies]
exarch-core = "0.2"
[!IMPORTANT] Requires Rust 1.89.0 or later (Edition 2024).
use exarch_core::{extract_archive, SecurityConfig};
fn main() -> Result<(), exarch_core::ExtractionError> {
let config = SecurityConfig::default();
let report = extract_archive("archive.tar.gz", "/output/dir", &config)?;
println!("Extracted {} files ({} bytes)",
report.files_extracted,
report.bytes_written);
Ok(())
}
use exarch_core::SecurityConfig;
let config = SecurityConfig {
max_file_size: 100 * 1024 * 1024, // 100 MB per file
max_total_size: 1024 * 1024 * 1024, // 1 GB total
max_file_count: 10_000, // Max 10k files
max_compression_ratio: 50.0, // 50x compression limit
..Default::default()
};
use exarch_core::ArchiveBuilder;
let mut archive = ArchiveBuilder::new()
.max_file_size(50 * 1024 * 1024)
.max_compression_ratio(100.0)
.open("archive.tar.gz")?;
let report = archive.extract("/output/path")?;
exarch-core provides defense-in-depth protection against common archive vulnerabilities:
| Protection | Description | Default |
|---|---|---|
| Path traversal | Blocks ../ and absolute paths |
Enabled |
| Symlink attacks | Prevents symlinks escaping extraction directory | Blocked |
| Hardlink attacks | Validates hardlink targets within extraction directory | Blocked |
| Zip bombs | Detects high compression ratios | Enabled (100x limit) |
| Permission sanitization | Strips setuid/setgid bits | Enabled |
| Size limits | Configurable file and total size limits | 50 MB / 10 GB |
[!CAUTION] Default configuration blocks symlinks and hardlinks. Enable only when you trust the archive source.
Create archives with secure defaults:
use exarch_core::{create_archive, CreationConfig};
// Simple creation with defaults
let config = CreationConfig::default();
let report = create_archive("backup.tar.gz", &["src/", "Cargo.toml"], &config)?;
println!("Created {} files", report.files_added);
use exarch_core::ArchiveCreator;
let report = ArchiveCreator::new()
.output("project.tar.gz")
.add_source("src/")
.add_source("Cargo.toml")
.add_source("README.md")
.compression_level(9)
.exclude("*.log")
.exclude("target/")
.create()?;
| Option | Default | Description |
|---|---|---|
follow_symlinks |
false |
Follow symbolic links |
include_hidden |
false |
Include hidden files (.*) |
compression_level |
6 |
Compression level (1-9) |
exclude_patterns |
[".git", ".DS_Store", "*.tmp"] |
Glob patterns to exclude |
strip_prefix |
None |
Strip prefix from paths |
preserve_permissions |
true |
Preserve Unix permissions |
| Extension | Format | Compression | Extraction | Creation |
|---|---|---|---|---|
.tar |
TAR | None | ✅ | ✅ |
.tar.gz, .tgz |
TAR | Gzip | ✅ | ✅ |
.tar.bz2, .tbz2 |
TAR | Bzip2 | ✅ | ✅ |
.tar.xz, .txz |
TAR | XZ | ✅ | ✅ |
.tar.zst, .tzst |
TAR | Zstd | ✅ | ✅ |
.zip |
ZIP | Deflate | ✅ | ✅ |
.7z |
7z | LZMA/LZMA2 | ✅ | — |
[!NOTE] 7z creation is not yet supported. Solid and encrypted 7z archives are rejected for security reasons.
| Type | Description |
|---|---|
extract_archive |
High-level extraction function |
Archive |
Archive handle with typestate pattern |
ArchiveBuilder |
Builder for configuring extraction |
SecurityConfig |
Security configuration options |
ExtractionReport |
Extraction statistics and results |
ExtractionError |
Error types for extraction failures |
use exarch_core::{extract_archive, ExtractionError, SecurityConfig};
match extract_archive("archive.tar.gz", "/output", &SecurityConfig::default()) {
Ok(report) => println!("Extracted {} files", report.files_extracted),
Err(ExtractionError::PathTraversal { path, .. }) => {
eprintln!("Blocked path traversal: {}", path.display());
}
Err(ExtractionError::QuotaExceeded { resource }) => {
eprintln!("Resource limit exceeded: {:?}", resource);
}
Err(e) => eprintln!("Extraction failed: {}", e),
}
Optimized for throughput with:
SmallVec for hardlink tracking (avoids heap allocation for typical archives)Throughput targets:
exarch-python — Python bindings via PyO3exarch-node — Node.js bindings via napi-rs[!NOTE] Minimum Supported Rust Version: 1.89.0. MSRV increases are minor version bumps.
Licensed under either of:
at your option.