From 929486d078811faae4b052e00a98987817a903ed Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 25 Apr 2026 22:21:51 +0200 Subject: [PATCH 1/4] initfs: Replace metadata field on Entry with executable field on EntryKind::File --- initfs/tools/src/lib.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/initfs/tools/src/lib.rs b/initfs/tools/src/lib.rs index 8d01587783..29e3679635 100644 --- a/initfs/tools/src/lib.rs +++ b/initfs/tools/src/lib.rs @@ -1,5 +1,5 @@ use std::convert::{TryFrom, TryInto}; -use std::fs::{DirEntry, File, Metadata, OpenOptions}; +use std::fs::{DirEntry, File, OpenOptions}; use std::io::{prelude::*, SeekFrom}; use std::path::{Path, PathBuf}; @@ -23,7 +23,7 @@ pub const DEFAULT_MAX_SIZE: u64 = 64 * MEBIBYTE; const PAGE_SIZE: u16 = 4096; enum EntryKind { - File(File), + File { file: File, executable: bool }, Dir(Dir), Link(PathBuf), } @@ -31,7 +31,6 @@ enum EntryKind { struct Entry { name: Vec, kind: EntryKind, - metadata: Metadata, } struct Dir { entries: Vec, @@ -101,9 +100,13 @@ fn read_directory(path: &Path, root_path: &Path) -> Result { } else if file_type.is_char_device() { return unsupported_type("character device", &entry); } else if file_type.is_file() { - EntryKind::File(File::open(entry.path()).with_context(|| { - anyhow!("failed to open file `{}`", entry.path().to_string_lossy(),) - })?) + let executable = metadata.permissions().mode() & 0o100 != 0; + EntryKind::File { + file: File::open(entry.path()).with_context(|| { + anyhow!("failed to open file `{}`", entry.path().to_string_lossy(),) + })?, + executable, + } } else if file_type.is_dir() { EntryKind::Dir(read_directory(&entry.path(), root_path)?) } else if file_type.is_symlink() { @@ -139,7 +142,6 @@ fn read_directory(path: &Path, root_path: &Path) -> Result { Ok(Entry { kind: entry_kind, - metadata, name, }) }) @@ -256,11 +258,14 @@ fn allocate_and_write_dir(state: &mut State, dir: &Dir) -> Result { (write_result, initfs::InodeType::Dir) } - EntryKind::File(ref file) => { + EntryKind::File { + ref file, + executable, + } => { let write_result = allocate_and_write_file(state, file) .context("failed to copy file into image")?; - let type_ = if entry.metadata.permissions().mode() & 0o100 != 0 { + let type_ = if executable { initfs::InodeType::ExecutableFile } else { initfs::InodeType::RegularFile From 34471854e23a24f8545be6e7a22ed5b1fd3eedf0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 25 Apr 2026 22:24:47 +0200 Subject: [PATCH 2/4] initfs: Remove Dir wrapper --- initfs/tools/src/lib.rs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/initfs/tools/src/lib.rs b/initfs/tools/src/lib.rs index 29e3679635..657a8962e7 100644 --- a/initfs/tools/src/lib.rs +++ b/initfs/tools/src/lib.rs @@ -24,7 +24,7 @@ const PAGE_SIZE: u16 = 4096; enum EntryKind { File { file: File, executable: bool }, - Dir(Dir), + Dir(Vec), Link(PathBuf), } @@ -32,9 +32,6 @@ struct Entry { name: Vec, kind: EntryKind, } -struct Dir { - entries: Vec, -} struct State<'path> { file: OutputImageGuard<'path>, @@ -55,7 +52,7 @@ fn write_all_at(file: &File, buf: &[u8], offset: u64, r#where: &str) -> Result<( Ok(()) } -fn read_directory(path: &Path, root_path: &Path) -> Result { +fn read_directory(path: &Path, root_path: &Path) -> Result> { let read_dir = path .read_dir() .with_context(|| anyhow!("failed to read directory `{}`", path.to_string_lossy(),))?; @@ -147,7 +144,7 @@ fn read_directory(path: &Path, root_path: &Path) -> Result { }) .collect::>>()?; - Ok(Dir { entries }) + Ok(entries) } fn bump_alloc(state: &mut State, size: u64, why: &str) -> Result { @@ -230,10 +227,10 @@ fn allocate_and_write_link(state: &mut State, link: &Path) -> Result Result { +fn allocate_and_write_dir(state: &mut State, dir: &[Entry]) -> Result { let entry_size = u16::try_from(std::mem::size_of::()).context("entry size too large")?; - let entry_count = u16::try_from(dir.entries.len()).context("too many subdirectories")?; + let entry_count = u16::try_from(dir.len()).context("too many subdirectories")?; let entry_table_length = u32::from(entry_count) .checked_mul(u32::from(entry_size)) @@ -245,7 +242,7 @@ fn allocate_and_write_dir(state: &mut State, dir: &Dir) -> Result { .try_into() .context("directory entries offset too high")?; - for (index, entry) in dir.entries.iter().enumerate() { + for (index, entry) in dir.iter().enumerate() { let (write_result, ty) = match entry.kind { EntryKind::Dir(ref subdir) => { let write_result = allocate_and_write_dir(state, subdir).with_context(|| { @@ -334,7 +331,7 @@ fn allocate_and_write_dir(state: &mut State, dir: &Dir) -> Result { offset: entry_table_offset, }) } -fn allocate_contents(state: &mut State, dir: &Dir) -> Result { +fn allocate_contents(state: &mut State, dir: &[Entry]) -> Result { let write_result = allocate_and_write_dir(state, dir) .context("failed to allocate and write all directories and files")?; From b0c675634bfc5f7b29e55c84cf67072d6500cf54 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 25 Apr 2026 22:25:16 +0200 Subject: [PATCH 3/4] initfs: Minor cleanups --- initfs/tools/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/initfs/tools/src/lib.rs b/initfs/tools/src/lib.rs index 657a8962e7..3ac389bd15 100644 --- a/initfs/tools/src/lib.rs +++ b/initfs/tools/src/lib.rs @@ -8,10 +8,10 @@ use std::os::unix::fs::{FileExt, FileTypeExt, PermissionsExt}; use anyhow::{anyhow, bail, Context, Result}; -use redox_initfs::types::{self as initfs, Offset}; +use redox_initfs::types as initfs; -pub const KIBIBYTE: u64 = 1024; -pub const MEBIBYTE: u64 = KIBIBYTE * 1024; +const KIBIBYTE: u64 = 1024; +const MEBIBYTE: u64 = KIBIBYTE * 1024; #[cfg(debug_assertions)] pub const DEFAULT_MAX_SIZE: u64 = 256 * MEBIBYTE; @@ -369,7 +369,7 @@ impl InodeTable { } } -fn write_inode_table(state: &mut State) -> Result { +fn write_inode_table(state: &mut State) -> Result { log::debug!("there are {} inodes", state.inode_table.count()); let inode_size: u32 = std::mem::size_of::() From e0cffb0a36c06ac32667039e5aad8a65990d3db3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 25 Apr 2026 22:27:24 +0200 Subject: [PATCH 4/4] initfs: Allow building an initfs without assembling it on disk first --- initfs/tools/src/lib.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/initfs/tools/src/lib.rs b/initfs/tools/src/lib.rs index 3ac389bd15..64d64e39de 100644 --- a/initfs/tools/src/lib.rs +++ b/initfs/tools/src/lib.rs @@ -22,15 +22,15 @@ pub const DEFAULT_MAX_SIZE: u64 = 64 * MEBIBYTE; // FIXME make this configurable to handle systems with 16k and 64k pages. const PAGE_SIZE: u16 = 4096; -enum EntryKind { +pub enum EntryKind { File { file: File, executable: bool }, Dir(Vec), Link(PathBuf), } -struct Entry { - name: Vec, - kind: EntryKind, +pub struct Entry { + pub name: Vec, + pub kind: EntryKind, } struct State<'path> { @@ -458,6 +458,15 @@ pub fn archive( let root_path = source; let root = read_directory(root_path, root_path).context("failed to read root")?; + build_initfs(destination_path, max_size, bootstrap_code, root) +} + +pub fn build_initfs( + destination_path: &Path, + max_size: u64, + bootstrap_code: &Path, + root: Vec, +) -> std::result::Result<(), anyhow::Error> { let previous_extension = destination_path.extension().map_or("", |ext| { ext.to_str() .expect("expected destination path to be valid UTF-8")