1pub mod newc;
6pub use newc::{NewcHeader, NewcReader};
7pub mod odc;
8pub use odc::{OdcBuilder, OdcHeader, OdcReader};
9
10use {
11 chrono::{DateTime, Utc},
12 std::{
13 fmt::Debug,
14 io::{Chain, Cursor, Read},
15 path::PathBuf,
16 },
17};
18
19#[derive(Debug, thiserror::Error)]
20pub enum Error {
21 #[error("I/O error: {0}")]
22 Io(#[from] std::io::Error),
23
24 #[error("bad magic value encountered")]
25 BadMagic,
26
27 #[error("value in header is not an ASCII string")]
28 BadHeaderString,
29
30 #[error("string value in header is not in hex: {0}")]
31 BadHeaderHex(String),
32
33 #[error("filename could not be decoded")]
34 FilenameDecode,
35
36 #[error("Numeric value too large to be encoded")]
37 ValueTooLarge,
38
39 #[error("Size mismatch between header length and provided data")]
40 SizeMismatch,
41
42 #[error("path is not a file: {0}")]
43 NotAFile(PathBuf),
44}
45
46pub type CpioResult<T> = Result<T, Error>;
48
49pub trait CpioHeader: Debug {
51 fn device(&self) -> u32;
53
54 fn inode(&self) -> u32;
56
57 fn mode(&self) -> u32;
59
60 fn uid(&self) -> u32;
62
63 fn gid(&self) -> u32;
65
66 fn nlink(&self) -> u32;
68
69 fn rdev(&self) -> u32;
71
72 fn mtime(&self) -> u32;
74
75 fn modified_time(&self) -> DateTime<Utc> {
77 DateTime::from_timestamp(self.mtime() as _, 0)
78 .expect("out of range timestamp")
79 .to_utc()
80 }
81
82 fn file_size(&self) -> u64;
84
85 fn name(&self) -> &str;
87}
88
89pub trait CpioReader<T>: Iterator<Item = CpioResult<Box<dyn CpioHeader>>> + Read
100where
101 T: Read + Sized,
102{
103 fn new(reader: T) -> Self
105 where
106 Self: Sized;
107
108 fn read_next(&mut self) -> CpioResult<Option<Box<dyn CpioHeader>>>;
114
115 fn finish(&mut self) -> CpioResult<()>;
120}
121
122pub type ChainedCpioReader<T> = dyn CpioReader<Chain<Cursor<Vec<u8>>, T>>;
123
124pub fn reader<T: 'static + Read + Sized>(mut reader: T) -> CpioResult<Box<ChainedCpioReader<T>>> {
129 let mut magic = vec![0u8; 6];
130 reader.read_exact(&mut magic)?;
131
132 match magic.as_ref() {
133 crate::newc::MAGIC => Ok(Box::new(NewcReader::new(Cursor::new(magic).chain(reader)))),
134 crate::odc::MAGIC => Ok(Box::new(OdcReader::new(Cursor::new(magic).chain(reader)))),
135 _ => Err(Error::BadMagic),
136 }
137}