hadris_cpio/lib.rs
1//! # Hadris CPIO
2//!
3//! A Rust implementation of the CPIO archive format (newc/SVR4) with support for
4//! no-std environments, streaming reads, and archive creation from in-memory trees
5//! or the host filesystem.
6//!
7//! CPIO archives are commonly used for Linux initramfs images, RPM packages, and
8//! general-purpose file archiving. This crate supports the "new" (newc) ASCII format
9//! (`070701`) and its CRC variant (`070702`), which are the formats used by modern
10//! Linux tools.
11//!
12//! ## Quick Start
13//!
14//! ### Reading an Archive
15//!
16//! ```rust,no_run
17//! use std::fs::File;
18//! use std::io::BufReader;
19//! use hadris_cpio::CpioArchiveReader;
20//!
21//! let file = File::open("archive.cpio").unwrap();
22//! let mut reader = CpioArchiveReader::new(BufReader::new(file));
23//!
24//! while let Some(entry) = reader.next_entry_alloc().unwrap() {
25//! let name = entry.name_str().unwrap();
26//! println!("{} ({} bytes)", name, entry.file_size());
27//! reader.skip_entry_data_owned(&entry).unwrap();
28//! }
29//! ```
30//!
31//! ### Creating an Archive
32//!
33//! ```rust,no_run
34//! use std::fs::File;
35//! use std::io::BufWriter;
36//! use hadris_cpio::{CpioArchiveWriter, CpioWriteOptions, FileTree};
37//!
38//! let tree = FileTree::from_fs(std::path::Path::new("./my-directory")).unwrap();
39//! let out = BufWriter::new(File::create("archive.cpio").unwrap());
40//! let _out = CpioArchiveWriter::new(out, CpioWriteOptions::default())
41//! .finish(&tree)
42//! .unwrap();
43//! ```
44//!
45//! ## Feature Flags
46//!
47//! | Feature | Description | Dependencies |
48//! |---------|-------------|--------------|
49//! | `read` | Streaming archive reader | None |
50//! | `alloc` | Heap allocation without full std | `alloc` crate |
51//! | `std` | Full standard library support | `std`, `alloc` |
52//! | `sync` | Synchronous archive API | `hadris-io/sync` |
53//! | `async` | Asynchronous archive API | `hadris-io/async` |
54//! | `write` | Archive creation | `alloc`, `read` |
55//!
56//! Default features: `std`, `sync`, `read`, `write`
57//!
58//! `std` does not select an I/O mode. Custom configurations should enable
59//! `sync`, `async`, or both explicitly.
60//!
61//! ### For Bootloaders / Kernels (minimal footprint)
62//!
63//! ```toml
64//! [dependencies]
65//! hadris-cpio = { version = "2.1.0", default-features = false, features = ["read", "sync"] }
66//! ```
67//!
68//! ### For Kernels with Heap (no-std + alloc)
69//!
70//! ```toml
71//! [dependencies]
72//! hadris-cpio = { version = "2.1.0", default-features = false, features = ["read", "alloc", "sync"] }
73//! ```
74//!
75//! ### For Desktop Applications (full features)
76//!
77//! ```toml
78//! [dependencies]
79//! hadris-cpio = "2.1.0"
80//! ```
81//!
82//! ## Archive Format
83//!
84//! The newc format stores entries sequentially. Each entry consists of:
85//!
86//! 1. A 110-byte ASCII header (all numeric fields in uppercase hex)
87//! 2. The filename (NUL-terminated, padded to 4-byte boundary)
88//! 3. The file data (padded to 4-byte boundary)
89//!
90//! The archive ends with a special `TRAILER!!!` sentinel entry.
91//!
92//! Two magic numbers are supported:
93//! - `070701` — Standard newc format
94//! - `070702` — newc with per-file CRC checksums
95//!
96//! ## Architecture
97//!
98//! - [`error`] — Error types and result alias
99//! - [`header`] — Raw 110-byte header parsing and construction
100//! - [`entry`] — Decoded entry header with typed fields
101//! - [`mode`] — Unix file type extraction from mode bits
102//! - [`read`] — Streaming archive reader (`CpioArchiveReader`)
103//! - [`mod@write`] — Archive writer and in-memory file tree
104//!
105//! ## Specification References
106//!
107//! - `cpio(5)` man page — newc format definition
108//! - Linux kernel `usr/gen_init_cpio.c` — Reference implementation
109//! - RPM file format specification — CPIO payload format
110
111#![no_std]
112#![cfg_attr(docsrs, feature(doc_cfg))]
113#![allow(async_fn_in_trait)]
114#![deny(missing_docs)]
115// Sync and async APIs intentionally compile the same source modules twice.
116#![allow(clippy::duplicate_mod)]
117
118#[cfg(feature = "std")]
119extern crate std;
120
121#[cfg(feature = "alloc")]
122extern crate alloc;
123
124// ---------------------------------------------------------------------------
125// Shared types (compiled once, not duplicated by sync/async modules)
126// ---------------------------------------------------------------------------
127
128/// Error types for CPIO operations.
129pub mod error;
130/// Unix file type constants and mode bit manipulation.
131pub mod mode;
132
133// ---------------------------------------------------------------------------
134// Sync module
135// ---------------------------------------------------------------------------
136
137#[cfg(feature = "sync")]
138#[path = ""]
139pub mod sync {
140 //! Synchronous CPIO archive API.
141 //!
142 //! All I/O operations use synchronous `Read`/`Write`/`Seek` traits.
143
144 pub use hadris_io::Result as IoResult;
145 pub use hadris_io::sync::{Parsable, Read, ReadExt, Seek, Writable, Write};
146 pub use hadris_io::{Error, ErrorKind, SeekFrom};
147
148 macro_rules! io_transform {
149 ($($item:tt)*) => { hadris_macros::strip_async!{ $($item)* } };
150 }
151
152 #[allow(unused_macros)]
153 macro_rules! sync_only {
154 ($($item:tt)*) => { $($item)* };
155 }
156
157 #[allow(unused_macros)]
158 macro_rules! async_only {
159 ($($item:tt)*) => {};
160 }
161
162 #[path = "."]
163 mod __inner {
164 /// Decoded entry header with typed fields.
165 pub mod entry;
166 /// Raw 110-byte ASCII newc header parsing and construction.
167 pub mod header;
168 /// Streaming CPIO archive reader.
169 #[cfg(feature = "read")]
170 pub mod read;
171 /// CPIO archive writer and in-memory file tree.
172 #[cfg(feature = "write")]
173 pub mod write;
174 }
175 pub use __inner::*;
176
177 // Convenience re-exports
178 pub use __inner::entry::CpioEntryHeader;
179 pub use __inner::header::{
180 CpioMagic, HEADER_SIZE, MAGIC_NEWC, MAGIC_NEWC_CRC, RawNewcHeader, TRAILER_NAME,
181 };
182 #[cfg(all(feature = "read", feature = "alloc"))]
183 pub use __inner::read::CpioEntryOwned;
184 #[cfg(feature = "read")]
185 pub use __inner::read::{CpioArchiveReader, CpioEntry};
186 #[cfg(feature = "write")]
187 pub use __inner::write::file_tree::{FileNode, FileTree};
188 #[cfg(feature = "write")]
189 pub use __inner::write::{CpioArchiveWriter, CpioWriteOptions};
190}
191
192// ---------------------------------------------------------------------------
193// Async module
194// ---------------------------------------------------------------------------
195
196#[cfg(feature = "async")]
197#[path = ""]
198pub mod r#async {
199 //! Asynchronous CPIO archive API.
200 //!
201 //! All I/O operations use async `Read`/`Write`/`Seek` traits.
202
203 pub use hadris_io::Result as IoResult;
204 pub use hadris_io::r#async::{Parsable, Read, ReadExt, Seek, Writable, Write};
205 pub use hadris_io::{Error, ErrorKind, SeekFrom};
206
207 macro_rules! io_transform {
208 ($($item:tt)*) => { $($item)* };
209 }
210
211 #[allow(unused_macros)]
212 macro_rules! sync_only {
213 ($($item:tt)*) => {};
214 }
215
216 #[allow(unused_macros)]
217 macro_rules! async_only {
218 ($($item:tt)*) => { $($item)* };
219 }
220
221 #[path = "."]
222 mod __inner {
223 /// Decoded CPIO entry metadata.
224 pub mod entry;
225 /// Raw newc header constants and parsing.
226 pub mod header;
227 #[cfg(feature = "read")]
228 /// Streaming archive reader.
229 pub mod read;
230 #[cfg(feature = "write")]
231 /// Archive writer and in-memory input tree.
232 pub mod write;
233 }
234 pub use __inner::*;
235
236 pub use __inner::entry::CpioEntryHeader;
237 pub use __inner::header::{
238 CpioMagic, HEADER_SIZE, MAGIC_NEWC, MAGIC_NEWC_CRC, RawNewcHeader, TRAILER_NAME,
239 };
240 #[cfg(all(feature = "read", feature = "alloc"))]
241 pub use __inner::read::CpioEntryOwned;
242 #[cfg(feature = "read")]
243 pub use __inner::read::{CpioArchiveReader, CpioEntry};
244 #[cfg(feature = "write")]
245 pub use __inner::write::file_tree::{FileNode, FileTree};
246 #[cfg(feature = "write")]
247 pub use __inner::write::{CpioArchiveWriter, CpioWriteOptions};
248}
249
250// ---------------------------------------------------------------------------
251// Default re-exports for backwards compatibility (sync)
252// ---------------------------------------------------------------------------
253
254#[cfg(feature = "sync")]
255pub use sync::*;
256
257// Re-exports from shared types
258pub use error::{Error, Result};
259pub use mode::FileType;