From 9a463ed516f5acc18872e85f0946a18c1ee16d34 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Mon, 16 Oct 2017 20:36:18 -0700 Subject: WIP on SLEEP read/write --- src/bin/geniza-sleep.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 49 ++++++++++++++++++++++++------ src/sleep.rs | 3 -- 3 files changed, 120 insertions(+), 12 deletions(-) create mode 100644 src/bin/geniza-sleep.rs delete mode 100644 src/sleep.rs (limited to 'src') diff --git a/src/bin/geniza-sleep.rs b/src/bin/geniza-sleep.rs new file mode 100644 index 0000000..168f803 --- /dev/null +++ b/src/bin/geniza-sleep.rs @@ -0,0 +1,80 @@ + +#[macro_use] +extern crate clap; + +extern crate geniza; + +// TODO: more careful import +use geniza::*; +use std::path::Path; + +use clap::{App, SubCommand}; + +fn run() -> Result<()> { + + let matches = App::new("geniza-sleep") + .version(env!("CARGO_PKG_VERSION")) + .subcommand(SubCommand::with_name("info") + .about("Reads a SLEEP file and shows some basic metadata") + .arg_from_usage(" 'SLEEP file to read'")) + .subcommand(SubCommand::with_name("create") + .about("Creates an empty SLEEP file (with header)") + .arg_from_usage(" 'SLEEP file to write (can't exist)'") + .arg_from_usage(" 'Magic word to use (eg, 0x5025700)'") + .arg_from_usage(" 'Size of each entry (bytes)'") + .arg_from_usage(" 'Name of algorithm (empty string for none)'")) + .get_matches(); + + + match matches.subcommand() { + ("info", Some(subm)) => { + let path = Path::new(subm.value_of("FILE").unwrap()); + let sf = SleepFile::open(path, false)?; + //debug!(println!("{:?}", sf)); + println!("Magic: 0x{:X}", sf.get_magic()); + println!("Algorithm: '{}'", sf.get_algorithm().or(Some("".to_string())).unwrap()); + println!("Entry Size (bytes): {}", sf.get_entry_size()); + println!("Entry count: {}", sf.length()?); + }, + ("create", Some(subm)) => { + let path = Path::new(subm.value_of("FILE").unwrap()); + let algo_name = subm.value_of("algo_name").unwrap(); + let algo_name = if algo_name.len() == 0 { + None + } else { + Some(algo_name.to_string()) + }; + SleepFile::create( + path, + value_t_or_exit!(subm, "magic", u32), + value_t_or_exit!(subm, "entry_size", u16), + algo_name)?; + println!("Done!"); + }, + _ => { + println!("Missing or unimplemented command!"); + println!("{}", matches.usage()); + ::std::process::exit(-1); + }, + } + Ok(()) +} + +// TODO: is there a shorter error_chain 'main()' to use here? +fn main() { + if let Err(ref e) = run() { + println!("error: {}", e); + + for e in e.iter().skip(1) { + println!("caused by: {}", e); + } + + // The backtrace is not always generated. Try to run this example + // with `RUST_BACKTRACE=1`. + if let Some(backtrace) = e.backtrace() { + println!("backtrace: {:?}", backtrace); + } + + ::std::process::exit(1); + } +} diff --git a/src/lib.rs b/src/lib.rs index 63fd9bf..18dffbc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ use std::io::prelude::*; use std::path::Path; use std::fs::File; use integer_encoding::FixedInt; +use std::fs::OpenOptions; mod errors { // Create the Error, ErrorKind, ResultExt, and Result types @@ -33,6 +34,7 @@ pub struct SleepFile { file: File, magic: u32, entry_size: u16, + // Option isn't necessary here... idiomatic? algorithm_name: Option, } @@ -42,15 +44,18 @@ impl SleepFile { pub fn open(path: &Path, writable: bool) -> Result { - // TODO: use writable here - let mut f = File::open(path)?; + let mut f = OpenOptions::new() + .read(true) + .write(writable) + .create(false) + .open(path)?; let mut header = [0; 32]; f.read_exact(&mut header)?; let version: u8 = header[4]; if version != 0 { return Err("Invalid SLEEP header: version must be 0".into()); } - let algo_len: u8 = header[8]; + let algo_len: u8 = header[7]; if algo_len > 24 { return Err("Invalid SLEEP header: can't have algo_len > 24".into()); } @@ -60,18 +65,44 @@ impl SleepFile { // TODO: endian-ness of u16 entry_size Ok(SleepFile { file: f, - magic: FixedInt::decode_fixed(&header[0..4]), - entry_size: FixedInt::decode_fixed(&header[6..8]), + magic: u32::from_be(FixedInt::decode_fixed(&header[0..4])), + entry_size: u16::from_be(FixedInt::decode_fixed(&header[5..7])), algorithm_name: algorithm_name, }) } -/* - pub fn create(path: Path, magic: u32, entry_size: u16, algo: &str) -> Result { - let mut sf = SleepFile { + pub fn create(path: &Path, magic: u32, entry_size: u16, algo: Option) -> Result { + // This function will *not* allow overwriting an existing file. + + let mut header = [0; 32]; + u32::to_be(magic).encode_fixed(&mut header[0..4]); + header[4] = 0; // version + u16::to_be(entry_size).encode_fixed(&mut header[5..7]); + if let Some(name) = algo.clone() { + let name = name.as_bytes(); + let algo_len = name.len(); + if algo_len > 24 { + return Err("Algorithm name must be 24 bytes at most".into()); + } + header[7] = algo_len as u8; + header[8..(8+algo_len)].clone_from_slice(name); + } else { + header[7] = 0; }; + + let mut f = OpenOptions::new() + .read(true) + .write(true) + .create_new(true) + .open(path)?; + f.write(&header)?; + Ok(SleepFile { + file: f, + magic: magic, + entry_size: entry_size, + algorithm_name: algo, + }) } -*/ } impl SleepStorage for SleepFile { diff --git a/src/sleep.rs b/src/sleep.rs deleted file mode 100644 index b28b04f..0000000 --- a/src/sleep.rs +++ /dev/null @@ -1,3 +0,0 @@ - - - -- cgit v1.2.3