Refactor into a separate library and tools crate.

This commit is contained in:
4lDO2
2022-03-26 18:15:49 +01:00
parent 08d18160ee
commit 89b8fb8984
8 changed files with 148 additions and 42 deletions
+1 -1
View File
@@ -27,5 +27,5 @@ anyhow = "1"
[workspace]
members = [
"redox-initfs-ar",
"tools",
]
+7
View File
@@ -204,6 +204,9 @@ impl<'initfs> InitFs<'initfs> {
plain::from_bytes::<Header>(&self.base[..core::mem::size_of::<Header>()])
.expect("expected header type to require no alignment, and size to be sufficient")
}
pub fn header(&self) -> &Header {
self.get_header_assume_valid()
}
fn header_len_8() -> u8 {
core::mem::size_of::<Header>()
.try_into()
@@ -248,6 +251,10 @@ impl<'initfs> InitFs<'initfs> {
}
pub const ROOT_INODE: Inode = Inode(0);
pub fn all_inodes(&self) -> impl Iterator<Item = Inode> {
(0..self.inode_count()).map(Inode)
}
pub fn inode_count(&self) -> u16 {
self.get_header_assume_valid().inode_count.get()
}
+6 -1
View File
@@ -4,7 +4,7 @@ pub const MAGIC: [u8; 8] = *b"RedoxFtw";
macro_rules! primitive(
($wrapper:ident, $bits:expr, $primitive:ident) => {
#[repr(transparent)]
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Default)]
pub struct $wrapper([u8; $bits / 8]);
impl $wrapper {
@@ -31,6 +31,11 @@ macro_rules! primitive(
wrapper.get()
}
}
impl core::fmt::Debug for $wrapper {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:#0width$x}", self.get(), width = 2 * core::mem::size_of::<$primitive>())
}
}
}
);
+1 -1
View File
@@ -4,7 +4,7 @@ use std::path::Path;
use anyhow::{anyhow, bail, Context, Result};
#[path = "../redox-initfs-ar/src/archive.rs"]
#[path = "../tools/src/archive_common.rs"]
mod archive;
#[test]
@@ -8,11 +8,20 @@ license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
path = "src/bin/archive.rs"
name = "redox-initfs-ar"
[[bin]]
path = "src/bin/dump.rs"
name = "redox-initfs-dump"
[dependencies]
anyhow = "1"
clap = "2.33"
env_logger = "0.8"
log = "0.4"
plain = "0.2"
twox-hash = "1.6"
redox-initfs = { path = ".." }
@@ -34,11 +34,12 @@ struct State<'path> {
max_size: u64,
inode_count: u16,
buffer: Box<[u8]>,
inode_table_offset: u32,
}
fn write_all_at(file: &File, buf: &[u8], offset: u64, r#where: &str) -> Result<()> {
file.write_all_at(buf, offset)?;
log::debug!("Wrote {}..{} within {}", offset, offset + buf.len() as u64, r#where);
log::trace!("Wrote {}..{} within {}", offset, offset + buf.len() as u64, r#where);
Ok(())
}
@@ -176,8 +177,7 @@ fn write_inode(
ty: initfs::InodeType,
metadata: &Metadata,
write_result: WriteResult,
inode_table_offset: u32,
index: u16,
inode: u16,
) -> Result<()> {
let inode_size: u32 = std::mem::size_of::<initfs::InodeHeader>()
.try_into()
@@ -188,23 +188,23 @@ fn write_inode(
// TODO: Use main buffer and write in bulk.
let mut inode_buf = [0_u8; std::mem::size_of::<initfs::InodeHeader>()];
let inode = plain::from_mut_bytes::<initfs::InodeHeader>(&mut inode_buf)
let inode_hdr = plain::from_mut_bytes::<initfs::InodeHeader>(&mut inode_buf)
.expect("expected inode struct to have alignment 1, and buffer size to match");
*inode = initfs::InodeHeader {
*inode_hdr = initfs::InodeHeader {
type_and_mode: type_and_mode.into(),
length: write_result.size.into(),
offset: initfs::Offset(write_result.offset.into()),
gid: metadata.gid().into(),
uid: metadata.uid().into(),
gid: 0.into(),//metadata.gid().into(),
uid: 0.into(),//metadata.uid().into(),
};
log::debug!("Writing inode index {} from offset {}", index, inode_table_offset);
log::debug!("Writing inode index {} from offset {}", inode, state.inode_table_offset);
write_all_at(
&*state.file,
&inode_buf,
u64::from(inode_table_offset + u32::from(index) * inode_size),
u64::from(state.inode_table_offset + u32::from(inode) * inode_size),
"write_inode",
)
.context("failed to write inode struct to disk image")
@@ -212,8 +212,7 @@ fn write_inode(
fn allocate_and_write_dir(
state: &mut State,
dir: &Dir,
inode_table_offset: u32,
start_inode: &mut u16,
current_inode: &mut u16,
) -> Result<WriteResult> {
let entry_size =
u16::try_from(std::mem::size_of::<initfs::DirEntry>()).context("entry size too large")?;
@@ -228,22 +227,11 @@ fn allocate_and_write_dir(
.try_into()
.context("directory entries offset too high")?;
let this_start_inode = *start_inode;
let inode_size: u32 = std::mem::size_of::<initfs::InodeHeader>()
.try_into()
.expect("inode header length cannot fit within u32");
*start_inode += entry_count;
let inode_table_offset =
inode_table_offset + u32::from(this_start_inode) * u32::from(inode_size);
for (index, entry) in dir.entries.iter().enumerate() {
let (write_result, ty) = match entry.kind {
EntryKind::Dir(ref subdir) => {
let write_result =
allocate_and_write_dir(state, subdir, inode_table_offset, start_inode)
allocate_and_write_dir(state, subdir, current_inode)
.with_context(|| {
anyhow!(
"failed to copy directory entries from `{}` into image",
@@ -266,13 +254,13 @@ fn allocate_and_write_dir(
.try_into()
.expect("expected dir entry count not to exceed u32");
*current_inode += 1;
write_inode(
state,
ty,
&entry.metadata,
write_result,
inode_table_offset,
index,
*current_inode,
)?;
let (name_offset, name_len) = {
@@ -293,10 +281,10 @@ fn allocate_and_write_dir(
let direntry = plain::from_mut_bytes::<initfs::DirEntry>(&mut direntry_buf)
.expect("expected dir entry struct to have alignment 1, and buffer size to match");
let inode = this_start_inode + index;
log::debug!("Linking inode {} into dir entry index {}, file name `{}`", current_inode, index, String::from_utf8_lossy(&entry.name));
*direntry = initfs::DirEntry {
inode: inode.into(),
inode: (*current_inode).into(),
name_len: name_len.into(),
name_offset: initfs::Offset(name_offset.into()),
};
@@ -319,13 +307,12 @@ fn allocate_and_write_dir(
fn allocate_contents_and_write_inodes(
state: &mut State,
dir: &Dir,
inode_table_offset: u32,
root_metadata: Metadata,
) -> Result<()> {
let index = 0;
let mut start_inode = 1;
let start_inode = 0;
let mut current_inode = start_inode;
let write_result = allocate_and_write_dir(state, dir, inode_table_offset, &mut start_inode)
let write_result = allocate_and_write_dir(state, dir, &mut current_inode)
.context("failed to allocate and write all directories and files")?;
write_inode(
@@ -333,8 +320,7 @@ fn allocate_contents_and_write_inodes(
initfs::InodeType::Dir,
&root_metadata,
write_result,
inode_table_offset,
index,
start_inode,
)
}
@@ -409,6 +395,7 @@ pub fn archive(&Args { destination_path, max_size, source }: &Args) -> Result<()
// Include root directory.
inode_count: 1,
buffer: vec![0_u8; BUFFER_SIZE].into_boxed_slice(),
inode_table_offset: 0,
};
let root_path = source;
@@ -449,10 +436,11 @@ pub fn archive(&Args { destination_path, max_size, source }: &Args) -> Result<()
.into(),
);
state.inode_table_offset = inode_table_offset.0.get();
allocate_contents_and_write_inodes(
&mut state,
&root,
inode_table_offset.0.get(),
root_metadata,
)?;
@@ -3,12 +3,13 @@ use std::path::Path;
use anyhow::{Context, Result};
use clap::{App, Arg};
mod archive;
use self::archive::*;
#[path = "../archive_common.rs"]
mod archive_common;
use self::archive_common::{self as archive, Args, DEFAULT_MAX_SIZE};
fn main() -> Result<()> {
let matches = App::new(clap::crate_name!())
.about(clap::crate_description!())
let matches = App::new("redox-initfs-ar")
.about("create an initfs image from a directory")
.version(clap::crate_version!())
.author(clap::crate_authors!())
.arg(
@@ -58,5 +59,5 @@ fn main() -> Result<()> {
destination_path: Path::new(destination),
max_size,
};
self::archive::archive(&args)
archive::archive(&args)
}
+96
View File
@@ -0,0 +1,96 @@
use anyhow::{Context, Result};
use clap::{App, Arg};
use redox_initfs::InitFs;
fn main() -> Result<()> {
let matches = App::new("redox-initfs-dump")
.about("dump initfs metadata")
.version(clap::crate_version!())
.author(clap::crate_authors!())
.arg(
Arg::with_name("IMAGE")
.takes_value(true)
.required(true)
.help("specify the image to dump")
)
.get_matches();
let source = matches
.value_of_os("IMAGE")
.expect("expected the required arg IMAGE to exist");
let bytes = std::fs::read(source).context("failed to read image into memory")?;
let initfs = InitFs::new(&bytes).context("failed to parse initfs header")?;
dbg!(initfs.header());
for inode in initfs.all_inodes() {
print!("{:?}: ", inode);
let inode_struct = match initfs.get_inode(inode) {
Some(s) => s,
None => {
println!("failed to obtain.");
continue;
}
};
print!("mode={:#0o}, uid={}, gid={}, kind=", inode_struct.mode(), inode_struct.uid(), inode_struct.gid());
use redox_initfs::InodeKind;
match inode_struct.kind() {
InodeKind::Unknown => println!("(unknown)"),
InodeKind::Dir(dir) => {
print!("dir{{");
let ec = match dir.entry_count().ok() {
Some(c) => c,
None => {
println!("(failed to get entry count)}}");
continue;
}
};
println!("entries=[");
for entry in 0..ec {
let entry = match dir.get_entry(entry).ok().flatten() {
Some(e) => e,
None => {
println!("\t(unknown),");
continue;
}
};
let name = match entry.name().ok() {
Some(name) => name,
None => {
println!("\t(unknown name),");
continue;
}
};
println!("\t`{}` => {:?},", String::from_utf8_lossy(name), entry.inode());
}
println!("]}}");
}
InodeKind::File(file) => {
print!("file{{");
match file.data().ok() {
Some(d) => {
use std::hash::Hasher;
let mut hasher = twox_hash::XxHash64::with_seed(0);
hasher.write(d);
print!("len={}, hash={:#0x}", d.len(), hasher.finish());
}
None => {
print!("(failed to get data)");
}
}
println!("}}");
}
}
}
Ok(())
}