mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 09:53:24 +00:00
Optimize the CpioEntry to send data to the Write trait
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
4b3cf8daeb
commit
13c4c614b5
112
Cargo.lock
generated
112
Cargo.lock
generated
@ -177,6 +177,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"core2",
|
"core2",
|
||||||
"int-to-c-enum",
|
"int-to-c-enum",
|
||||||
|
"lending-iterator",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -285,6 +286,35 @@ version = "1.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ext-trait"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d772df1c1a777963712fb68e014235e80863d6a91a85c4e06ba2d16243a310e5"
|
||||||
|
dependencies = [
|
||||||
|
"ext-trait-proc_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ext-trait-proc_macros"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ab7934152eaf26aa5aa9f7371408ad5af4c31357073c9e84c3b9d7f11ad639a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "extension-traits"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a296e5a895621edf9fa8329c83aa1cb69a964643e36cf54d8d7a69b789089537"
|
||||||
|
dependencies = [
|
||||||
|
"ext-trait",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@ -575,6 +605,7 @@ dependencies = [
|
|||||||
"ascii",
|
"ascii",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"controlled",
|
"controlled",
|
||||||
|
"core2",
|
||||||
"cpio-decoder",
|
"cpio-decoder",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"int-to-c-enum",
|
"int-to-c-enum",
|
||||||
@ -589,6 +620,7 @@ dependencies = [
|
|||||||
"jinux-util",
|
"jinux-util",
|
||||||
"keyable-arc",
|
"keyable-arc",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"lending-iterator",
|
||||||
"libflate",
|
"libflate",
|
||||||
"log",
|
"log",
|
||||||
"lru",
|
"lru",
|
||||||
@ -661,6 +693,31 @@ dependencies = [
|
|||||||
"spin 0.5.2",
|
"spin 0.5.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lending-iterator"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bc07588c853b50689205fb5c00498aa681d89828e0ce8cbd965ebc7a5d8ae260"
|
||||||
|
dependencies = [
|
||||||
|
"extension-traits",
|
||||||
|
"lending-iterator-proc_macros",
|
||||||
|
"macro_rules_attribute",
|
||||||
|
"never-say-never",
|
||||||
|
"nougat",
|
||||||
|
"polonius-the-crab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lending-iterator-proc_macros"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5445dd1c0deb1e97b8a16561d17fc686ca83e8411128fb036e9668a72d51b1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.146"
|
version = "0.2.146"
|
||||||
@ -725,6 +782,22 @@ dependencies = [
|
|||||||
"hashbrown 0.13.1",
|
"hashbrown 0.13.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "macro_rules_attribute"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf0c9b980bf4f3a37fd7b1c066941dd1b1d0152ce6ee6e8fe8c49b9f6810d862"
|
||||||
|
dependencies = [
|
||||||
|
"macro_rules_attribute-proc_macro",
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "macro_rules_attribute-proc_macro"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "58093314a45e00c77d5c508f76e77c3396afbbc0d01506e7fae47b018bac2b1d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "managed"
|
name = "managed"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@ -746,12 +819,45 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "never-say-never"
|
||||||
|
version = "6.6.666"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf5a574dadd7941adeaa71823ecba5e28331b8313fb2e1c6a5c7e5981ea53ad6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nougat"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97b57b9ced431322f054fc673f1d3c7fa52d80efd9df74ad2fc759f044742510"
|
||||||
|
dependencies = [
|
||||||
|
"macro_rules_attribute",
|
||||||
|
"nougat-proc_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nougat-proc_macros"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c84f77a45e99a2f9b492695d99e1c23844619caa5f3e57647cffacad773ca257"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.17.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pod"
|
name = "pod"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -770,6 +876,12 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "polonius-the-crab"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c2a69ee997a6282f8462abf1e0d8c38c965e968799e912b3bed8c9e8a28c2f9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -7,4 +7,5 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
int-to-c-enum = { path = "../../libs/int-to-c-enum" }
|
int-to-c-enum = { path = "../../libs/int-to-c-enum" }
|
||||||
core2 = { version = "0.4", default_features = false, features = ["alloc"] }
|
core2 = { version = "0.4", default_features = false, features = ["alloc"] }
|
||||||
|
lending-iterator = "0.1.7"
|
@ -9,4 +9,17 @@ pub enum Error {
|
|||||||
FileTypeError,
|
FileTypeError,
|
||||||
FileNameError,
|
FileNameError,
|
||||||
BufferShortError,
|
BufferShortError,
|
||||||
|
IoError,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<core2::io::Error> for Error {
|
||||||
|
#[inline]
|
||||||
|
fn from(err: core2::io::Error) -> Self {
|
||||||
|
use core2::io::ErrorKind;
|
||||||
|
|
||||||
|
match err.kind() {
|
||||||
|
ErrorKind::UnexpectedEof => Self::BufferShortError,
|
||||||
|
_ => Self::IoError,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use cpio_decoder::CpioDecoder;
|
//! use cpio_decoder::CpioDecoder;
|
||||||
|
//! use lending_iterator::LendingIterator;
|
||||||
//!
|
//!
|
||||||
//! let short_buffer: Vec<u8> = Vec::new();
|
//! let short_buffer: Vec<u8> = Vec::new();
|
||||||
//! let mut decoder = CpioDecoder::new(short_buffer.as_slice());
|
//! let mut decoder = CpioDecoder::new(short_buffer.as_slice());
|
||||||
//! for entry_result in decoder.decode_entries() {
|
//! if let Some(entry_result) = decoder.next() {
|
||||||
//! println!("The entry_result is: {:?}", entry_result);
|
//! println!("The entry_result is: {:?}", entry_result);
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
@ -21,16 +22,17 @@ extern crate alloc;
|
|||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use core::cmp::min;
|
||||||
use core2::io::Read;
|
use core2::io::{Read, Write};
|
||||||
use int_to_c_enum::TryFromInt;
|
use int_to_c_enum::TryFromInt;
|
||||||
|
use lending_iterator::prelude::*;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
/// A CPIO (the newc format) decoder.
|
/// A CPIO (the newc format) decoder to iterator over the results of CPIO entries.
|
||||||
///
|
///
|
||||||
/// "newc" is the new portable format and CRC format.
|
/// "newc" is the new portable format and CRC format.
|
||||||
///
|
///
|
||||||
@ -41,37 +43,16 @@ mod test;
|
|||||||
/// All the fields in the header are ISO 646 (approximately ASCII) strings
|
/// All the fields in the header are ISO 646 (approximately ASCII) strings
|
||||||
/// of hexadecimal numbers, left padded, not NULL terminated.
|
/// of hexadecimal numbers, left padded, not NULL terminated.
|
||||||
pub struct CpioDecoder<R> {
|
pub struct CpioDecoder<R> {
|
||||||
inner: R,
|
reader: R,
|
||||||
|
is_error: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> CpioDecoder<R>
|
impl<R> CpioDecoder<R>
|
||||||
where
|
where
|
||||||
R: Read,
|
R: Read,
|
||||||
{
|
{
|
||||||
/// create a decoder to decode the CPIO.
|
/// Create a decoder.
|
||||||
pub fn new(inner: R) -> Self {
|
pub fn new(reader: R) -> Self {
|
||||||
Self { inner }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return an iterator trying to decode the entries in the CPIO.
|
|
||||||
pub fn decode_entries(&mut self) -> CpioEntryIter<R> {
|
|
||||||
CpioEntryIter::new(&mut self.inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator over the results of CPIO entries.
|
|
||||||
///
|
|
||||||
/// It stops if reaches to the trailer entry or encounters an error.
|
|
||||||
pub struct CpioEntryIter<'a, R> {
|
|
||||||
reader: &'a mut R,
|
|
||||||
is_error: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, R> CpioEntryIter<'a, R>
|
|
||||||
where
|
|
||||||
R: Read,
|
|
||||||
{
|
|
||||||
fn new(reader: &'a mut R) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
reader,
|
reader,
|
||||||
is_error: false,
|
is_error: false,
|
||||||
@ -79,19 +60,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, R> Iterator for CpioEntryIter<'a, R>
|
#[gat]
|
||||||
|
impl<R> LendingIterator for CpioDecoder<R>
|
||||||
where
|
where
|
||||||
R: Read,
|
R: Read,
|
||||||
{
|
{
|
||||||
type Item = Result<CpioEntry>;
|
type Item<'a> = Result<CpioEntry<'a, R>>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Result<CpioEntry>> {
|
/// Stops if reaches to the trailer entry or encounters an error.
|
||||||
|
fn next<'a>(self: &'a mut Self) -> Option<Self::Item<'a>> {
|
||||||
// Stop to iterate entries if encounters an error.
|
// Stop to iterate entries if encounters an error.
|
||||||
if self.is_error {
|
if self.is_error {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry_result = CpioEntry::new(self.reader);
|
let entry_result = CpioEntry::new(&mut self.reader);
|
||||||
match &entry_result {
|
match &entry_result {
|
||||||
Ok(entry) => {
|
Ok(entry) => {
|
||||||
// A correct CPIO buffer must end with a trailer.
|
// A correct CPIO buffer must end with a trailer.
|
||||||
@ -109,25 +92,24 @@ where
|
|||||||
|
|
||||||
/// A file entry in the CPIO.
|
/// A file entry in the CPIO.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CpioEntry {
|
pub struct CpioEntry<'a, R> {
|
||||||
metadata: FileMetadata,
|
metadata: FileMetadata,
|
||||||
name: String,
|
name: String,
|
||||||
data: Vec<u8>,
|
reader: &'a mut R,
|
||||||
|
data_padding_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CpioEntry {
|
impl<'a, R> CpioEntry<'a, R>
|
||||||
fn new<R>(reader: &mut R) -> Result<Self>
|
where
|
||||||
where
|
R: Read,
|
||||||
R: Read,
|
{
|
||||||
{
|
fn new(reader: &'a mut R) -> Result<Self> {
|
||||||
let (metadata, name, data) = {
|
let (metadata, name, data_padding_len) = {
|
||||||
let header = Header::new(reader)?;
|
let header = Header::new(reader)?;
|
||||||
let name = {
|
let name = {
|
||||||
let name_size = read_hex_bytes_to_u32(&header.name_size)? as usize;
|
let name_size = read_hex_bytes_to_u32(&header.name_size)? as usize;
|
||||||
let mut name_bytes = vec![0u8; name_size];
|
let mut name_bytes = vec![0u8; name_size];
|
||||||
reader
|
reader.read_exact(&mut name_bytes)?;
|
||||||
.read_exact(&mut name_bytes)
|
|
||||||
.map_err(|_| Error::BufferShortError)?;
|
|
||||||
let name = core::ffi::CStr::from_bytes_with_nul(&name_bytes)
|
let name = core::ffi::CStr::from_bytes_with_nul(&name_bytes)
|
||||||
.map_err(|_| Error::FileNameError)?;
|
.map_err(|_| Error::FileNameError)?;
|
||||||
name.to_str().map_err(|_| Error::Utf8Error)?.to_string()
|
name.to_str().map_err(|_| Error::Utf8Error)?.to_string()
|
||||||
@ -137,38 +119,22 @@ impl CpioEntry {
|
|||||||
} else {
|
} else {
|
||||||
FileMetadata::new(&header)?
|
FileMetadata::new(&header)?
|
||||||
};
|
};
|
||||||
let data = {
|
let data_padding_len = {
|
||||||
let pad_header_len = align_up_pad(header.len() + name.len() + 1, 4);
|
let header_padding_len = align_up_pad(header.len() + name.len() + 1, 4);
|
||||||
if pad_header_len > 0 {
|
if header_padding_len > 0 {
|
||||||
let mut pad_buf = vec![0u8; pad_header_len];
|
let mut pad_buf = vec![0u8; header_padding_len];
|
||||||
reader
|
reader.read_exact(&mut pad_buf)?;
|
||||||
.read_exact(&mut pad_buf)
|
|
||||||
.map_err(|_| Error::BufferShortError)?;
|
|
||||||
}
|
}
|
||||||
let mut data: Vec<u8> = Vec::new();
|
align_up_pad(metadata.size() as usize, 4)
|
||||||
let data_size = metadata.size as usize;
|
|
||||||
if data_size > 0 {
|
|
||||||
data.resize_with(data_size, Default::default);
|
|
||||||
reader
|
|
||||||
.read_exact(&mut data)
|
|
||||||
.map_err(|_| Error::BufferShortError)?;
|
|
||||||
}
|
|
||||||
data
|
|
||||||
};
|
};
|
||||||
let pad_data_len = align_up_pad(data.len(), 4);
|
|
||||||
if pad_data_len > 0 {
|
|
||||||
let mut pad_buf = vec![0u8; pad_data_len];
|
|
||||||
reader
|
|
||||||
.read_exact(&mut pad_buf)
|
|
||||||
.map_err(|_| Error::BufferShortError)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
(metadata, name, data)
|
(metadata, name, data_padding_len)
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
metadata,
|
metadata,
|
||||||
name,
|
name,
|
||||||
data,
|
reader,
|
||||||
|
data_padding_len,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,12 +148,28 @@ impl CpioEntry {
|
|||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The data of the file.
|
/// Read all data to the writer.
|
||||||
pub fn data(&self) -> &[u8] {
|
pub fn read_all<W>(&mut self, mut writer: W) -> Result<()>
|
||||||
&self.data
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
let data_len = self.metadata().size() as usize;
|
||||||
|
let mut send_len = 0;
|
||||||
|
let mut buffer = vec![0u8; 0x1000];
|
||||||
|
while send_len < data_len {
|
||||||
|
let len = min(buffer.len(), data_len - send_len);
|
||||||
|
self.reader.read_exact(&mut buffer[..len])?;
|
||||||
|
writer.write_all(&mut buffer[..len])?;
|
||||||
|
send_len += len;
|
||||||
|
}
|
||||||
|
if self.data_padding_len > 0 {
|
||||||
|
self.reader
|
||||||
|
.read_exact(&mut buffer[..self.data_padding_len])?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_trailer(&self) -> bool {
|
pub fn is_trailer(&self) -> bool {
|
||||||
&self.name == TRAILER_NAME
|
&self.name == TRAILER_NAME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,9 +326,7 @@ impl Header {
|
|||||||
R: Read,
|
R: Read,
|
||||||
{
|
{
|
||||||
let mut buf = vec![0u8; core::mem::size_of::<Self>()];
|
let mut buf = vec![0u8; core::mem::size_of::<Self>()];
|
||||||
reader
|
reader.read_exact(&mut buf)?;
|
||||||
.read_exact(&mut buf)
|
|
||||||
.map_err(|_| Error::BufferShortError)?;
|
|
||||||
|
|
||||||
let header = Self {
|
let header = Self {
|
||||||
magic: <[u8; 6]>::try_from(&buf[0..6]).unwrap(),
|
magic: <[u8; 6]>::try_from(&buf[0..6]).unwrap(),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::error::*;
|
use super::error::*;
|
||||||
use super::{CpioDecoder, FileType};
|
use super::{CpioDecoder, FileType};
|
||||||
|
use lending_iterator::LendingIterator;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_decoder() {
|
fn test_decoder() {
|
||||||
@ -24,48 +25,55 @@ fn test_decoder() {
|
|||||||
output.stdout
|
output.stdout
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(CpioDecoder::new(buffer.as_slice()).decode_entries().count() > 3);
|
|
||||||
let mut decoder = CpioDecoder::new(buffer.as_slice());
|
let mut decoder = CpioDecoder::new(buffer.as_slice());
|
||||||
for (idx, entry_result) in decoder.decode_entries().enumerate() {
|
// 1st entry
|
||||||
let entry = entry_result.unwrap();
|
let entry = {
|
||||||
if idx == 0 {
|
let entry_result = decoder.next().unwrap();
|
||||||
assert!(entry.name() == ".");
|
entry_result.unwrap()
|
||||||
assert!(entry.metadata().file_type() == FileType::Dir);
|
};
|
||||||
assert!(entry.metadata().ino() > 0);
|
assert!(entry.name() == ".");
|
||||||
}
|
assert!(entry.metadata().file_type() == FileType::Dir);
|
||||||
if idx == 1 {
|
assert!(entry.metadata().ino() > 0);
|
||||||
assert!(entry.name() == "src");
|
// 2nd entry
|
||||||
assert!(entry.metadata().file_type() == FileType::Dir);
|
let entry = {
|
||||||
assert!(entry.metadata().ino() > 0);
|
let entry_result = decoder.next().unwrap();
|
||||||
}
|
entry_result.unwrap()
|
||||||
if idx == 2 {
|
};
|
||||||
assert!(
|
assert!(entry.name() == "src");
|
||||||
entry.name() == "src/lib.rs"
|
assert!(entry.metadata().file_type() == FileType::Dir);
|
||||||
|| entry.name() == "src/test.rs"
|
assert!(entry.metadata().ino() > 0);
|
||||||
|| entry.name() == "src/error.rs"
|
|
||||||
);
|
// 3rd entry
|
||||||
assert!(entry.metadata().file_type() == FileType::File);
|
let mut entry = {
|
||||||
assert!(entry.metadata().ino() > 0);
|
let entry_result = decoder.next().unwrap();
|
||||||
}
|
entry_result.unwrap()
|
||||||
}
|
};
|
||||||
|
assert!(
|
||||||
|
entry.name() == "src/lib.rs"
|
||||||
|
|| entry.name() == "src/test.rs"
|
||||||
|
|| entry.name() == "src/error.rs"
|
||||||
|
);
|
||||||
|
assert!(entry.metadata().file_type() == FileType::File);
|
||||||
|
assert!(entry.metadata().ino() > 0);
|
||||||
|
assert!(entry.metadata().size() > 0);
|
||||||
|
let mut buffer: Vec<u8> = Vec::new();
|
||||||
|
assert!(entry.read_all(&mut buffer).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_short_buffer() {
|
fn test_short_buffer() {
|
||||||
let short_buffer: Vec<u8> = Vec::new();
|
let short_buffer: Vec<u8> = Vec::new();
|
||||||
let mut decoder = CpioDecoder::new(short_buffer.as_slice());
|
let mut decoder = CpioDecoder::new(short_buffer.as_slice());
|
||||||
for entry_result in decoder.decode_entries() {
|
let entry_result = decoder.next().unwrap();
|
||||||
assert!(entry_result.is_err());
|
assert!(entry_result.is_err());
|
||||||
assert!(entry_result.err() == Some(Error::BufferShortError));
|
assert!(entry_result.err() == Some(Error::BufferShortError));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_invalid_buffer() {
|
fn test_invalid_buffer() {
|
||||||
let buffer: &[u8] = b"invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic";
|
let buffer: &[u8] = b"invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic.invalidmagic";
|
||||||
let mut decoder = CpioDecoder::new(buffer);
|
let mut decoder = CpioDecoder::new(buffer);
|
||||||
for entry_result in decoder.decode_entries() {
|
let entry_result = decoder.next().unwrap();
|
||||||
assert!(entry_result.is_err());
|
assert!(entry_result.is_err());
|
||||||
assert!(entry_result.err() == Some(Error::MagicError));
|
assert!(entry_result.err() == Some(Error::MagicError));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,8 @@ ringbuf = { version = "0.3.2", default-features = false, features = ["alloc"] }
|
|||||||
keyable-arc = { path = "../keyable-arc" }
|
keyable-arc = { path = "../keyable-arc" }
|
||||||
# unzip initramfs
|
# unzip initramfs
|
||||||
libflate = { git = "https://github.com/jinzhao-dev/libflate", rev = "b781da6", features = ["no_std"] }
|
libflate = { git = "https://github.com/jinzhao-dev/libflate", rev = "b781da6", features = ["no_std"] }
|
||||||
|
core2 = { version = "0.4", default_features = false, features = ["alloc"] }
|
||||||
|
lending-iterator = "0.1.7"
|
||||||
spin = "0.9.4"
|
spin = "0.9.4"
|
||||||
vte = "0.10"
|
vte = "0.10"
|
||||||
lru = "0.9.0"
|
lru = "0.9.0"
|
||||||
|
@ -232,6 +232,9 @@ impl From<cpio_decoder::error::Error> for Error {
|
|||||||
cpio_decoder::error::Error::BufferShortError => {
|
cpio_decoder::error::Error::BufferShortError => {
|
||||||
Error::with_message(Errno::EINVAL, "CPIO buffer is too short")
|
Error::with_message(Errno::EINVAL, "CPIO buffer is too short")
|
||||||
}
|
}
|
||||||
|
cpio_decoder::error::Error::IoError => {
|
||||||
|
Error::with_message(Errno::EIO, "CPIO buffer I/O error")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ use super::utils::{InodeMode, InodeType};
|
|||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use cpio_decoder::{CpioDecoder, FileType};
|
use cpio_decoder::{CpioDecoder, FileType};
|
||||||
|
use lending_iterator::LendingIterator;
|
||||||
use libflate::gzip::Decoder as GZipDecoder;
|
use libflate::gzip::Decoder as GZipDecoder;
|
||||||
|
|
||||||
/// Unpack and prepare the fs from the ramdisk CPIO buffer.
|
/// Unpack and prepare the fs from the ramdisk CPIO buffer.
|
||||||
@ -13,8 +14,13 @@ pub fn init(gzip_ramdisk_buf: &[u8]) -> Result<()> {
|
|||||||
GZipDecoder::new(gzip_ramdisk_buf)
|
GZipDecoder::new(gzip_ramdisk_buf)
|
||||||
.map_err(|_| Error::with_message(Errno::EINVAL, "invalid gzip buffer"))?,
|
.map_err(|_| Error::with_message(Errno::EINVAL, "invalid gzip buffer"))?,
|
||||||
);
|
);
|
||||||
for entry_result in decoder.decode_entries() {
|
|
||||||
let entry = entry_result?;
|
loop {
|
||||||
|
let Some(entry_result) = decoder.next() else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut entry = entry_result?;
|
||||||
|
|
||||||
// Make sure the name is a relative path, and is not end with "/".
|
// Make sure the name is a relative path, and is not end with "/".
|
||||||
let entry_name = entry.name().trim_start_matches('/').trim_end_matches('/');
|
let entry_name = entry.name().trim_start_matches('/').trim_end_matches('/');
|
||||||
@ -40,18 +46,22 @@ pub fn init(gzip_ramdisk_buf: &[u8]) -> Result<()> {
|
|||||||
match metadata.file_type() {
|
match metadata.file_type() {
|
||||||
FileType::File => {
|
FileType::File => {
|
||||||
let dentry = parent.create(name, InodeType::File, mode)?;
|
let dentry = parent.create(name, InodeType::File, mode)?;
|
||||||
dentry.vnode().write_at(0, entry.data())?;
|
entry.read_all(dentry.vnode().writer(0))?;
|
||||||
}
|
}
|
||||||
FileType::Dir => {
|
FileType::Dir => {
|
||||||
let _ = parent.create(name, InodeType::Dir, mode)?;
|
let _ = parent.create(name, InodeType::Dir, mode)?;
|
||||||
}
|
}
|
||||||
FileType::Link => {
|
FileType::Link => {
|
||||||
let dentry = parent.create(name, InodeType::SymLink, mode)?;
|
let dentry = parent.create(name, InodeType::SymLink, mode)?;
|
||||||
let link_content = core::str::from_utf8(entry.data())?;
|
let link_content = {
|
||||||
dentry.vnode().write_link(link_content)?;
|
let mut link_data: Vec<u8> = Vec::new();
|
||||||
|
entry.read_all(&mut link_data)?;
|
||||||
|
core::str::from_utf8(&link_data)?.to_string()
|
||||||
|
};
|
||||||
|
dentry.vnode().write_link(&link_content)?;
|
||||||
}
|
}
|
||||||
type_ => {
|
type_ => {
|
||||||
warn!("unsupported file type = {:?} in initramfs", type_);
|
panic!("unsupported file type = {:?} in initramfs", type_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ pub use ioctl::IoctlCmd;
|
|||||||
pub use page_cache::PageCache;
|
pub use page_cache::PageCache;
|
||||||
pub use poll::{Pollee, Poller};
|
pub use poll::{Pollee, Poller};
|
||||||
pub use status_flags::StatusFlags;
|
pub use status_flags::StatusFlags;
|
||||||
pub use vnode::Vnode;
|
pub use vnode::{Vnode, VnodeWriter};
|
||||||
|
|
||||||
mod access_mode;
|
mod access_mode;
|
||||||
mod channel;
|
mod channel;
|
||||||
|
@ -8,6 +8,7 @@ use crate::vm::vmo::Vmo;
|
|||||||
|
|
||||||
use alloc::string::String;
|
use alloc::string::String;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
|
||||||
use jinux_frame::vm::VmIo;
|
use jinux_frame::vm::VmIo;
|
||||||
use jinux_rights::Full;
|
use jinux_rights::Full;
|
||||||
|
|
||||||
@ -245,4 +246,33 @@ impl Vnode {
|
|||||||
pub fn is_dentry_cacheable(&self) -> bool {
|
pub fn is_dentry_cacheable(&self) -> bool {
|
||||||
self.inner.read().inode.is_dentry_cacheable()
|
self.inner.read().inode.is_dentry_cacheable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn writer(&self, from_offset: usize) -> VnodeWriter {
|
||||||
|
VnodeWriter {
|
||||||
|
inner: &self,
|
||||||
|
offset: from_offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VnodeWriter<'a> {
|
||||||
|
inner: &'a Vnode,
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Write for VnodeWriter<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
|
||||||
|
let write_len = self
|
||||||
|
.inner
|
||||||
|
.write_at(self.offset, buf)
|
||||||
|
.map_err(|_| IoError::new(IoErrorKind::WriteZero, "failed to write buffer"))?;
|
||||||
|
self.offset += write_len;
|
||||||
|
Ok(write_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> IoResult<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ impl VmoInner {
|
|||||||
if self.should_share_frame_with_parent(write_page) {
|
if self.should_share_frame_with_parent(write_page) {
|
||||||
return Ok(inherited_frame);
|
return Ok(inherited_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame = {
|
let frame = {
|
||||||
let options = VmAllocOptions::new(1);
|
let options = VmAllocOptions::new(1);
|
||||||
VmFrameVec::allocate(&options)?.pop().unwrap()
|
VmFrameVec::allocate(&options)?.pop().unwrap()
|
||||||
|
Reference in New Issue
Block a user