aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2017-10-16 20:36:18 -0700
committerBryan Newbold <bnewbold@robocracy.org>2017-10-16 20:36:18 -0700
commit9a463ed516f5acc18872e85f0946a18c1ee16d34 (patch)
tree3aff012155cd26f03d59ea48e59f2e127d93efaa
parentbde2282d17474783d83a1e538beaaaff296115b7 (diff)
downloadgeniza-9a463ed516f5acc18872e85f0946a18c1ee16d34.tar.gz
geniza-9a463ed516f5acc18872e85f0946a18c1ee16d34.zip
WIP on SLEEP read/write
-rw-r--r--src/bin/geniza-sleep.rs80
-rw-r--r--src/lib.rs49
-rw-r--r--src/sleep.rs3
3 files changed, 120 insertions, 12 deletions
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("<FILE> 'SLEEP file to read'"))
+ .subcommand(SubCommand::with_name("create")
+ .about("Creates an empty SLEEP file (with header)")
+ .arg_from_usage("<FILE> 'SLEEP file to write (can't exist)'")
+ .arg_from_usage("<magic> 'Magic word to use (eg, 0x5025700)'")
+ .arg_from_usage("<entry_size> 'Size of each entry (bytes)'")
+ .arg_from_usage("<algo_name> '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<String>,
}
@@ -42,15 +44,18 @@ impl SleepFile {
pub fn open(path: &Path, writable: bool) -> Result<SleepFile> {
- // 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<SleepFile> {
- let mut sf = SleepFile {
+ pub fn create(path: &Path, magic: u32, entry_size: u16, algo: Option<String>) -> Result<SleepFile> {
+ // 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 @@
-
-
-