diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bin/geniza-drive.rs | 70 | ||||
-rw-r--r-- | src/drive.rs | 106 |
2 files changed, 145 insertions, 31 deletions
diff --git a/src/bin/geniza-drive.rs b/src/bin/geniza-drive.rs new file mode 100644 index 0000000..05c7fb7 --- /dev/null +++ b/src/bin/geniza-drive.rs @@ -0,0 +1,70 @@ +// Free Software under GPL-3.0, see LICENSE +// Copyright 2017 Bryan Newbold + +#[macro_use] +extern crate clap; +extern crate env_logger; +#[macro_use] +extern crate error_chain; +extern crate geniza; + +// TODO: more careful import +use geniza::*; +use std::path::Path; +use clap::{App, Arg, SubCommand}; + +fn run() -> Result<()> { + env_logger::init().unwrap(); + + let matches = App::new("geniza-drive") + .version(env!("CARGO_PKG_VERSION")) + // TODO: dat-dir for all commands up here, and have a default vaule ('./dat') + .arg(Arg::with_name("dat-dir") + .short("d") + .long("dat-dir") + .value_name("PATH") + .help("dat drive directory") + .default_value(".dat") // TODO: needs to be default_value_os? + .takes_value(true)) + .subcommand( + SubCommand::with_name("ls") + .about("Lists current files in this dat") + ) + .subcommand( + SubCommand::with_name("log") + .about("History of additions/deletions from this dat") + ) + .get_matches(); + +/* + mode: ::std::option::Option<u32>, + uid: ::std::option::Option<u32>, + gid: ::std::option::Option<u32>, + size: ::std::option::Option<u64>, + blocks: ::std::option::Option<u64>, + offset: ::std::option::Option<u64>, + byteOffset: ::std::option::Option<u64>, + mtime: ::std::option::Option<u64>, + ctime: ::std::option::Option<u64>, +*/ + + let dir = Path::new(matches.value_of("dat-dir").unwrap()); + match matches.subcommand() { + ("ls", Some(_subm)) => { + } + ("log", Some(_subm)) => { + let mut drive = DatDrive::open(dir, false)?; + for entry in drive.history(1) { + println!("{:?}", entry?); + } + } + _ => { + println!("Missing or unimplemented command!"); + println!("{}", matches.usage()); + ::std::process::exit(-1); + } + } + Ok(()) +} + +quick_main!(run); diff --git a/src/drive.rs b/src/drive.rs index 179bebb..7369fb2 100644 --- a/src/drive.rs +++ b/src/drive.rs @@ -1,12 +1,12 @@ -use std::io::{Read, Write}; +use std::io::Read; use std::path::Path; -use protobuf::Message; +//XXX: use protobuf::Message; use protobuf::parse_from_bytes; use errors::*; use sleep_register::*; -use metadata_msgs::{Index, Stat, Node}; +use metadata_msgs::{Stat, Node}; /// "Sort of" follows rust std::fs API for file system access. pub struct DatDrive { @@ -19,53 +19,76 @@ impl DatDrive { /// Instantiates a drive in the given directory. Path should be the complete path (eg, ending /// in '/.dat/'), not an enclosing directory containing files. pub fn create<P: AsRef<Path>>(path: P) -> Result<DatDrive> { + // Calculate content discovery key and write as Index entry in metadata register unimplemented!() } /// Path should be the complete path (eg, ending in '/.dat/'), not an enclosing directory /// containing files. - pub fn open<P: AsRef<Path>>(path: P) -> Result<DatDrive> { - unimplemented!() + pub fn open<P: AsRef<Path>>(path: P, writable: bool) -> Result<DatDrive> { + let mdrive = SleepDirRegister::open(path.as_ref(), "metadata", writable)?; + if mdrive.len()? == 0 { + bail!("Expected at least one entry (Index) in metadata register"); + } + let cdrive = SleepDirRegister::open(path.as_ref(), "content", writable)?; + Ok(DatDrive { + metadata: mdrive, + content: cdrive, + }) } } impl<'a> DatDrive { - pub fn history(start: u64) -> DriveHistory<'a> { + fn find_path(path: &Path) -> Result<u64> { unimplemented!() } - pub fn read_dir_recursive<P: AsRef<Path>>(path: P) -> ReadDriveDir<'a> { + pub fn history<'b>(&'b mut self, start: u64) -> DriveHistory<'b> { + // Start must be at least 1; index 0 is the Index item + let start = if start == 0 { 1 } else { start }; + DriveHistory { + drive: self, + current: start, + } + } + + pub fn read_dir_recursive<P: AsRef<Path>>(&mut self, path: P) -> ReadDriveDir<'a> { unimplemented!() } - pub fn read_dir<P: AsRef<Path>>(path: P) -> ReadDriveDir<'a> { + pub fn read_dir<P: AsRef<Path>>(&mut self, path: P) -> ReadDriveDir<'a> { unimplemented!() } - pub fn file_metadata<P: AsRef<Path>>(path: P) -> Result<Stat> { + pub fn file_metadata<P: AsRef<Path>>(&mut self, path: P) -> Result<Stat> { unimplemented!() } - pub fn create_file_bytes<P: AsRef<Path>>(path: P, stat: &Stat, data: &[u8]) -> Result<()> { + pub fn create_file_bytes<P: AsRef<Path>>(&mut self, path: P, stat: &Stat, data: &[u8]) -> Result<()> { unimplemented!() } - pub fn create_file<P: AsRef<Path>, R: Read>(path: P, stat: &Stat, source: R) -> Result<()> { + pub fn create_file<P: AsRef<Path>, R: Read>(&mut self, path: P, stat: &Stat, source: R) -> Result<()> { unimplemented!() } /// Copies Stat metadata and all content from a file in the "real" filesystem into the /// DatDrive. - pub fn import_file<P: AsRef<Path>, Q: AsRef<Path>>(source: P, dest: Q) -> Result<()> { + pub fn import_file<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, source: P, dest: Q) -> Result<()> { + unimplemented!() + } + + /// Copies a file from the drive to the "real" filesystem, preserving Stat metadata. + pub fn export_file<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, source: P, dest: Q) -> Result<()> { unimplemented!() } /* Possible future helper functions to be even more like std::fs - pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> - pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<()> - pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> - pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> Result<()> + pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, from: P, to: Q) -> Result<()> + pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, from: P, to: Q) -> Result<()> + pub fn remove_file<P: AsRef<Path>>(&mut self, path: P) -> Result<()> + pub fn remove_dir_all<P: AsRef<Path>>(&mut self, path: P) -> Result<()> */ } @@ -74,12 +97,12 @@ impl<'a> DatDrive { fn test_dd_open() { let mut dd = - DatDrive::open(Path::new("test-data/dat/simple/.dat/")).unwrap(); + DatDrive::open(Path::new("test-data/dat/simple/.dat/"), false).unwrap(); // verified from dat log - assert_eq!(dd.history().collect().len(), 2); - assert_eq!(dd.read_dir().collect().len(), 1); - assert_eq!(dd.read_dir_recurisve().collect().len(), 1); + assert_eq!(dd.history(1).count(), 2); + assert_eq!(dd.read_dir("/").count(), 1); + assert_eq!(dd.read_dir_recursive("/").count(), 1); } #[test] @@ -88,21 +111,49 @@ fn test_dd_create() { let tmp_dir = TempDir::new("geniza-test").unwrap(); let mut dd = DatDrive::create(tmp_dir.path()).unwrap(); - assert_eq!(dd.history().collect().len(), 0); - assert_eq!(dd.read_dir().collect().len(), 0); - assert_eq!(dd.read_dir_recurisve().collect().len(), 0); + assert_eq!(dd.history(1).count(), 0); + assert_eq!(dd.read_dir("/").count(), 0); + assert_eq!(dd.read_dir_recursive("/").count(), 0); } +// TODO: unpack Node into a pub struct +#[derive(Debug)] pub struct DriveEntry { node: Node, index: u64, } +/// Iterator over full drive history (file additions/deletions). pub struct DriveHistory<'a> { drive: &'a mut DatDrive, + current: u64, } -/// Iterator +impl<'a> Iterator for DriveHistory<'a> { + type Item = Result<DriveEntry>; + fn next(&mut self) -> Option<Result<DriveEntry>> { + if self.current >= self.drive.metadata.len().unwrap() { + return None; + } + // TODO: handle Err, not unwrap + let data = match self.drive.metadata.get_data_entry(self.current) { + Err(e) => { return Some(Err(e)) }, + Ok(v) => v, + }; + let node = match parse_from_bytes::<Node>(&data) { + Err(e) => { return Some(Err(e.into())) }, + Ok(v) => v, + }; + let de = Ok(DriveEntry { + node, + index: self.current, + }); + self.current += 1; + return Some(de); + } +} + +/// Iterator over drive file entries. pub struct ReadDriveDir<'a> { drive: &'a mut DatDrive, recursive: bool, @@ -124,13 +175,6 @@ impl<'a> ReadDriveDir<'a> { } } -impl<'a> Iterator for DriveHistory<'a> { - type Item = DriveEntry; - fn next(&mut self) -> Option<DriveEntry> { - unimplemented!(); - } -} - impl<'a> Iterator for ReadDriveDir<'a> { type Item = DriveEntry; fn next(&mut self) -> Option<DriveEntry> { |