#![forbid(unsafe_code)]
use std::path::PathBuf;
use crate::store::{Store, StoreConfig};
#[derive(Debug, Clone, clap::Args)]
pub struct MkfsArgs {
#[arg(value_name = "STORE")]
pub store: PathBuf,
#[arg(long, default_value_t = 128 * 1024 * 1024)]
pub segment_size: u64,
#[arg(long)]
pub uuid: Option<String>,
}
pub fn run(args: &MkfsArgs) -> Result<(), String> {
let uuid = match &args.uuid {
Some(s) => {
let bytes = hex_decode(s)?;
if bytes.len() != 16 {
return Err("uuid must be exactly 16 bytes (32 hex digits)".into());
}
let mut u = [0u8; 16];
u.copy_from_slice(&bytes);
u
}
None => {
let mut u = [0u8; 16];
getrandom_fill(&mut u);
u
}
};
let config = StoreConfig {
segment_size: args.segment_size,
..Default::default()
};
Store::create(&args.store, &config, uuid).map_err(|e| e.to_string())?;
println!(
"created entropyfs store at {} (uuid {})",
args.store.display(),
hex_encode(&uuid)
);
Ok(())
}
pub fn hex_decode(s: &str) -> Result<Vec<u8>, String> {
let s = s.strip_prefix("0x").unwrap_or(s);
if !s.len().is_multiple_of(2) {
return Err("hex string must have even length".into());
}
let mut out = Vec::with_capacity(s.len() / 2);
let bytes = s.as_bytes();
for i in (0..bytes.len()).step_by(2) {
let hi =
hex_val(bytes[i]).ok_or_else(|| format!("invalid hex digit {}", bytes[i] as char))?;
let lo = hex_val(bytes[i + 1])
.ok_or_else(|| format!("invalid hex digit {}", bytes[i + 1] as char))?;
out.push((hi << 4) | lo);
}
Ok(out)
}
fn hex_val(b: u8) -> Option<u8> {
match b {
b'0'..=b'9' => Some(b - b'0'),
b'a'..=b'f' => Some(b - b'a' + 10),
b'A'..=b'F' => Some(b - b'A' + 10),
_ => None,
}
}
pub fn hex_encode(bytes: &[u8]) -> String {
let mut s = String::with_capacity(bytes.len() * 2);
for b in bytes {
s.push_str(&format!("{b:02x}"));
}
s
}
fn getrandom_fill(buf: &mut [u8]) {
use std::io::Read;
let mut f = std::fs::File::open("/dev/urandom").expect("urandom");
f.read_exact(buf).expect("urandom read");
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hex_roundtrip() {
let s = "0x00112233445566778899aabbccddeeff";
let bytes = hex_decode(s).unwrap();
assert_eq!(bytes.len(), 16);
assert_eq!(hex_encode(&bytes), "00112233445566778899aabbccddeeff");
assert!(hex_decode("xyz").is_err());
assert!(hex_decode("abc").is_err());
}
}