From 1b9814f5c615021f7fbcac67e49bfb56d1df95e4 Mon Sep 17 00:00:00 2001 From: Ross Andrews Date: Mon, 11 May 2026 20:23:07 -0500 Subject: [PATCH] fix --- src/main.rs | 9 ++--- src/parsing.rs | 105 +++++++++++++++++++++++++------------------------ 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/main.rs b/src/main.rs index 906a223..4f76158 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,8 +30,7 @@ mod tests { operation_type: Close, drawer_file: "blah.drawer".into(), key: Path("foo.key".into()), - target_path: "blah".into(), - target_inferred: false, + target_path: Some("blah".into()), force: false, } )) @@ -45,8 +44,7 @@ mod tests { operation_type: Open, drawer_file: "blah.drawer".into(), key: Path("foo.key".into()), - target_path: "blah".into(), - target_inferred: false, + target_path: Some("blah".into()), force: false, } )) @@ -60,8 +58,7 @@ mod tests { operation_type: Open, drawer_file: "blah.drawer".into(), key: Path("foo.key".into()), - target_path: "blah".into(), - target_inferred: true, + target_path: None, force: false, } )) diff --git a/src/parsing.rs b/src/parsing.rs index a69b732..ed4253f 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -22,9 +22,8 @@ pub struct DrawerOperation { pub operation_type: OperationType, pub drawer_file: PathBuf, pub key: KeyType, - pub target_path: PathBuf, + pub target_path: Option, pub force: bool, - pub target_inferred: bool, } #[derive(Debug, PartialEq)] @@ -74,32 +73,22 @@ where match cli.command { Command::Open { drawer_file, target_path, key, force } => { let key = resolve_key(key); - let (target, target_inferred) = match target_path { - Some(p) => (p, false), - None => (PathBuf::from(drawer_file.file_stem().unwrap_or_default()), true), - }; Ok(DrawerOperation { operation_type: OperationType::Open, drawer_file, key, - target_path: target, + target_path, force, - target_inferred, }) } Command::Close { drawer_file, target_path, key } => { let key = resolve_key(key); - let (target, target_inferred) = match target_path { - Some(p) => (p, false), - None => (PathBuf::from(drawer_file.file_stem().unwrap_or_default()), true), - }; Ok(DrawerOperation { operation_type: OperationType::Close, drawer_file, key, - target_path: target, + target_path, force: false, - target_inferred }) } Command::Key { filename } => { @@ -107,9 +96,8 @@ where operation_type: OperationType::Key, drawer_file: filename, key: KeyType::EnvVar, - target_path: PathBuf::from("."), + target_path: None, force: false, - target_inferred: false, }) } } @@ -138,6 +126,16 @@ fn single_file_entry(data: &[u8]) -> Option { } impl DrawerOperation { + // Returns the default target when no target_path is specified. + // For close and for directory drawers on open: the drawer file stem. + // For single-file drawers on open: the filename stored in the archive. + fn default_target(&self, single_file: Option<&std::path::Path>) -> PathBuf { + match single_file { + Some(p) => PathBuf::from(p.file_name().unwrap_or_default()), + None => PathBuf::from(self.drawer_file.file_stem().unwrap_or_default()), + } + } + pub fn perform(&self) -> Result<(), DrawerError> { self.validate()?; match self.operation_type { @@ -153,12 +151,26 @@ impl DrawerOperation { let decrypted = self.decrypt(encrypted)?; - if let Some(entry_name) = single_file_entry(&decrypted) { - let output = if self.target_inferred { - PathBuf::from(entry_name.file_name().unwrap_or_default()) - } else { - self.target_path.clone() - }; + let sf = single_file_entry(&decrypted); + let target = self.target_path.as_ref().cloned() + .unwrap_or_else(|| self.default_target(sf.as_deref())); + + if self.target_path.is_none() { + println!("(assuming into {})", target.display()); + } + + if !self.force && target.exists() { + if target.is_file() { + return Err(DrawerError::TargetNotEmpty(target.clone())); + } + let mut entries = std::fs::read_dir(&target) + .map_err(|_| DrawerError::TargetInvalid(target.clone()))?; + if entries.next().is_some() { + return Err(DrawerError::TargetNotEmpty(target.clone())); + } + } + + if sf.is_some() { let cursor = std::io::Cursor::new(&decrypted); let gz = GzDecoder::new(cursor); let mut archive = tar::Archive::new(gz); @@ -167,13 +179,12 @@ impl DrawerOperation { .next() .ok_or(DrawerError::UntarFailed)? .map_err(|_| DrawerError::UntarFailed)?; - entry.unpack(&output).map_err(|_| DrawerError::UntarFailed)?; + entry.unpack(&target).map_err(|_| DrawerError::UntarFailed)?; } else { let cursor = std::io::Cursor::new(decrypted); let gz = GzDecoder::new(cursor); let mut archive = tar::Archive::new(gz); - archive.unpack(&self.target_path) - .map_err(|_| DrawerError::UntarFailed)?; + archive.unpack(&target).map_err(|_| DrawerError::UntarFailed)?; } Ok(()) } @@ -202,16 +213,19 @@ impl DrawerOperation { } fn perform_close(&self) -> Result<(), DrawerError> { + let target = self.target_path.as_ref().cloned() + .unwrap_or_else(|| self.default_target(None)); + let mut buf: Vec = Vec::new(); { let gz = GzEncoder::new(&mut buf, Compression::default()); let mut archive = tar::Builder::new(gz); - if self.target_path.is_dir() { - archive.append_dir_all(".", &self.target_path) + if target.is_dir() { + archive.append_dir_all(".", &target) .map_err(|_| DrawerError::TarFailed)?; } else { - let name = self.target_path.file_name().unwrap_or_default(); - archive.append_path_with_name(&self.target_path, name) + let name = target.file_name().unwrap_or_default(); + archive.append_path_with_name(&target, name) .map_err(|_| DrawerError::TarFailed)?; } let gz = archive.into_inner() @@ -299,22 +313,9 @@ impl DrawerOperation { } fn validate_open(&self) -> Result<(), DrawerError> { - if self.target_inferred { - println!("(assuming into {})", self.target_path.display()); - } if !self.drawer_file.exists() { return Err(DrawerError::DrawerFileNotFound(self.drawer_file.clone())); } - if !self.force && self.target_path.exists() { - if self.target_path.is_file() { - return Err(DrawerError::TargetNotEmpty(self.target_path.clone())); - } - let mut entries = std::fs::read_dir(&self.target_path) - .map_err(|_| DrawerError::TargetInvalid(self.target_path.clone()))?; - if entries.next().is_some() { - return Err(DrawerError::TargetNotEmpty(self.target_path.clone())); - } - } Ok(()) } @@ -328,19 +329,21 @@ impl DrawerOperation { } fn validate_close(&self) -> Result<(), DrawerError> { - if self.target_inferred { - println!("(assuming from {})", self.target_path.display()); + let target = self.target_path.as_ref().cloned() + .unwrap_or_else(|| self.default_target(None)); + if self.target_path.is_none() { + println!("(assuming from {})", target.display()); } - let meta = std::fs::metadata(&self.target_path) - .map_err(|_| DrawerError::TargetInvalid(self.target_path.clone()))?; + let meta = std::fs::metadata(&target) + .map_err(|_| DrawerError::TargetInvalid(target.clone()))?; if !meta.is_dir() && !meta.is_file() { - return Err(DrawerError::TargetInvalid(self.target_path.clone())); + return Err(DrawerError::TargetInvalid(target.clone())); } - if meta.is_dir() && std::fs::read_dir(&self.target_path).is_err() { - return Err(DrawerError::TargetInvalid(self.target_path.clone())); + if meta.is_dir() && std::fs::read_dir(&target).is_err() { + return Err(DrawerError::TargetInvalid(target.clone())); } - let canon_target = self.target_path.canonicalize() - .unwrap_or_else(|_| self.target_path.clone()); + let canon_target = target.canonicalize() + .unwrap_or_else(|_| target.clone()); let drawer_parent = match self.drawer_file.parent() { None => Path::new("."), Some(p) if p == Path::new("") => {