aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bin/geniza-drive.rs17
-rw-r--r--src/drive.rs34
2 files changed, 44 insertions, 7 deletions
diff --git a/src/bin/geniza-drive.rs b/src/bin/geniza-drive.rs
index 7f945b0..79ba480 100644
--- a/src/bin/geniza-drive.rs
+++ b/src/bin/geniza-drive.rs
@@ -45,6 +45,12 @@ fn run() -> Result<()> {
.arg_from_usage("--target <path> 'path to import the file to (if not top level)'")
)
.subcommand(
+ SubCommand::with_name("export-file")
+ .about("Copies a file from dat archive to local disk")
+ .arg_from_usage("<FILE> 'file to export'")
+ .arg_from_usage("--target <path> 'path to save the file to (if not same name)'")
+ )
+ .subcommand(
SubCommand::with_name("log")
.about("History of additions/deletions from this dat")
)
@@ -61,7 +67,7 @@ fn run() -> Result<()> {
let dir = Path::new(matches.value_of("dat-dir").unwrap());
match matches.subcommand() {
("init", Some(_subm)) => {
- let drive = DatDrive::create(dir)?;
+ let _drive = DatDrive::create(dir)?;
// TODO: print public key in hex
println!("Done!");
}
@@ -82,6 +88,15 @@ fn run() -> Result<()> {
drive.import_file(&path, &fpath)?;
}
+ ("export-file", Some(subm)) => {
+ let path = Path::new(subm.value_of("FILE").unwrap());
+ let mut drive = DatDrive::open(dir, true)?;
+ let fpath = match subm.value_of("target") {
+ None => Path::new("/").join(path.file_name().unwrap()),
+ Some(p) => Path::new("/").join(p)
+ };
+ drive.export_file(&path, &fpath)?;
+ }
("cat", Some(subm)) => {
let path = Path::new(subm.value_of("FILE").unwrap());
let mut drive = DatDrive::open(dir, true)?;
diff --git a/src/drive.rs b/src/drive.rs
index 9aa6ea2..740e949 100644
--- a/src/drive.rs
+++ b/src/drive.rs
@@ -1,8 +1,8 @@
-use std::io::Read;
+use std::io::{Read, Write};
use std::path::{Path, PathBuf};
-use std::os::unix::fs::MetadataExt;
-use std::fs::File;
+use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
+use std::fs::{File, OpenOptions};
use std::cmp::min;
use std::ffi::OsStr;
use protobuf::Message;
@@ -403,6 +403,7 @@ impl<'a> DatDrive {
Ok(children)
}
+ // XXX: needs test
/// 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>>(&mut self, source: P, dest: Q) -> Result<()> {
@@ -418,15 +419,36 @@ impl<'a> DatDrive {
self.add_file(dest, &mut stat, in_file)
}
+ // XXX: needs test
/// 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!()
+ pub fn export_file<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, source: P, dest: Q) -> Result<()> {
+
+ let source = source.as_ref();
+ let de = self.get_file_entry(source)?;
+ if let Some(entry) = de {
+ let stat = entry.stat.unwrap();
+ let mut out_file = OpenOptions::new()
+ .create_new(true)
+ .write(true)
+ .mode(stat.get_mode())
+ .open(dest)?;
+ let offset = stat.get_offset();
+ let blocks = stat.get_blocks();
+ for i in offset..(offset+blocks) {
+ let chunk = self.content.get_data_entry(i)?;
+ out_file.write_all(&chunk)?;
+ }
+ // TODO: more outfile metadata (uid, guid, etc)
+ } else {
+ bail!("Couldn't find path: {}", source.display());
+ }
+
+ Ok(())
}
pub fn read_file_bytes<P: AsRef<Path>>(&mut self, path: P) -> Result<Vec<u8>> {
let de = self.get_file_entry(path.as_ref())?;
if let Some(entry) = de {
- // XXX: read and concatonate chunks
let stat = entry.stat.unwrap();
let mut buf = vec![];
let offset = stat.get_offset();