use std::{ env::args, fs::File, io::{self, Write}, path::Path, }; const BLOCK_SIZE: u32 = 512; const MAX_NAME_LEN: u32 = BLOCK_SIZE - 4 - 4 - 2 - 1; fn main() { let mut archive = File::create("initrd").expect("Could not open initrd"); for file_path in args().skip(1) { let file_path = Path::new(&file_path); let file_name = file_path.file_name().unwrap(); let file_name_len = u32::try_from(file_name.len()).unwrap(); assert!( file_name_len <= MAX_NAME_LEN, "File {:?} has name longer than {} bytes", file_name, MAX_NAME_LEN ); let mut file = File::open(file_path).expect("File did not exist"); let length = u32::try_from(file.metadata().expect("Could not get file metadata").len()) .expect("File size greater than 4 GiB"); let file_num_blocks = (length / BLOCK_SIZE) + if length % BLOCK_SIZE == 0 { 0 } else { 1 }; let mut header_block = Vec::new(); header_block.extend_from_slice(&length.to_be_bytes()); header_block.extend_from_slice(&file_num_blocks.to_be_bytes()); header_block.extend_from_slice(&file_name_len.to_be_bytes()); header_block.extend_from_slice(file_name.to_str().unwrap().as_bytes()); header_block.push(0); header_block.resize(BLOCK_SIZE as usize, 0); archive .write_all(&header_block) .expect("Could not write to initrd"); #[allow(clippy::cast_possible_truncation)] let bytes_written = io::copy(&mut file, &mut archive) .expect("Could not read from file/write to initrd") as u32; if (bytes_written % BLOCK_SIZE) != 0 { let bytes_padding = (BLOCK_SIZE) - (bytes_written % BLOCK_SIZE); archive .write_all(&vec![0; bytes_padding as usize]) .expect("Could not write to initrd"); } } archive .write_all(&[0; BLOCK_SIZE as usize]) .expect("Could not write to initrd"); }