Skip to main content

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;