Refactor into a separate library and tools crate.
This commit is contained in:
+1
-1
@@ -27,5 +27,5 @@ anyhow = "1"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"redox-initfs-ar",
|
||||
"tools",
|
||||
]
|
||||
|
||||
@@ -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
@@ -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>())
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
Reference in New Issue
Block a user