Change the type of iterator for cpio-decoder

This commit is contained in:
LI Qing
2023-03-01 14:54:29 +08:00
committed by Tate, Hongliang Tian
parent 7326eb87a0
commit 9606119028
2 changed files with 57 additions and 16 deletions

View File

@ -2,12 +2,12 @@
//! //!
//! # Example //! # Example
//! //!
//! ```rust,should_panic //! ```rust
//! use cpio_decoder::CpioDecoder; //! use cpio_decoder::CpioDecoder;
//! //!
//! let decoder = CpioDecoder::new(&[]); //! let decoder = CpioDecoder::new(&[]);
//! for entry in decoder.entries() { //! for entry_result in decoder.decode_entries() {
//! println!("{:?}", entry); //! println!("The entry_result is: {:?}", entry_result);
//! } //! }
//! ``` //! ```
@ -41,18 +41,19 @@ impl<'a> CpioDecoder<'a> {
Self { buffer } Self { buffer }
} }
/// Return an iterator for all entries in the CPIO. /// Return an iterator trying to decode the entries in the CPIO.
/// pub fn decode_entries(&'a self) -> CpioEntryIter<'a> {
/// It will panic if fails to decode some entries.
pub fn entries(&'a self) -> CpioEntryIter<'a> {
CpioEntryIter::new(self) CpioEntryIter::new(self)
} }
} }
/// A file entry iterator. /// An iterator over the results of CPIO entries.
///
/// It stops if reaches to the trailer entry or encounters an error.
pub struct CpioEntryIter<'a> { pub struct CpioEntryIter<'a> {
buffer: &'a [u8], buffer: &'a [u8],
offset: usize, offset: usize,
is_error: bool,
} }
impl<'a> CpioEntryIter<'a> { impl<'a> CpioEntryIter<'a> {
@ -60,20 +61,38 @@ impl<'a> CpioEntryIter<'a> {
Self { Self {
buffer: decoder.buffer, buffer: decoder.buffer,
offset: 0, offset: 0,
is_error: false,
} }
} }
} }
impl<'a> Iterator for CpioEntryIter<'a> { impl<'a> Iterator for CpioEntryIter<'a> {
type Item = CpioEntry<'a>; type Item = Result<CpioEntry<'a>>;
fn next(&mut self) -> Option<CpioEntry<'a>> { fn next(&mut self) -> Option<Result<CpioEntry<'a>>> {
let entry = CpioEntry::new(&self.buffer[self.offset..]).unwrap(); // Stop to iterate entries if encounters an error.
if entry.is_trailer() { if self.is_error {
return None; return None;
} }
self.offset += entry.archive_offset();
Some(entry) let entry_result = if self.offset >= self.buffer.len() {
Err(Error::BufferShortError)
} else {
CpioEntry::new(&self.buffer[self.offset..])
};
match &entry_result {
Ok(entry) => {
// A correct CPIO buffer must end with a trailer.
if entry.is_trailer() {
return None;
}
self.offset += entry.archive_offset();
}
Err(_) => {
self.is_error = true;
}
}
Some(entry_result)
} }
} }

View File

@ -1,3 +1,4 @@
use super::error::*;
use super::{CpioDecoder, FileType}; use super::{CpioDecoder, FileType};
#[test] #[test]
@ -24,8 +25,10 @@ fn test_decoder() {
}; };
let decoder = CpioDecoder::new(&buffer); let decoder = CpioDecoder::new(&buffer);
assert!(decoder.entries().count() > 3); assert!(decoder.decode_entries().count() > 3);
for (idx, entry) in decoder.entries().enumerate() { for (idx, entry_result) in decoder.decode_entries().enumerate() {
assert!(entry_result.is_ok());
let entry = entry_result.unwrap();
if idx == 0 { if idx == 0 {
assert!(entry.name() == "."); assert!(entry.name() == ".");
assert!(entry.metadata().file_type() == FileType::Dir); assert!(entry.metadata().file_type() == FileType::Dir);
@ -43,3 +46,22 @@ fn test_decoder() {
} }
} }
} }
#[test]
fn test_short_buffer() {
let decoder = CpioDecoder::new(&[]);
for entry_result in decoder.decode_entries() {
assert!(entry_result.is_err());
assert!(entry_result.err() == Some(Error::BufferShortError));
}
}
#[test]
fn test_invalid_buffer() {
let buffer: &[u8] = b"invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic";
let decoder = CpioDecoder::new(buffer);
for entry_result in decoder.decode_entries() {
assert!(entry_result.is_err());
assert!(entry_result.err() == Some(Error::MagicError));
}
}