From 9326890987f9845f704ac738ea463005f54e31de Mon Sep 17 00:00:00 2001 From: Eric Harding Date: Tue, 25 Aug 2026 17:13:58 -0400 Subject: [PATCH] Treat empty remote dest path as home directory scp's "host:" (no path after the colon) means the remote home directory, reusing the source's basename. resolve_dest_paths only recognized a directory target via a trailing '/', so an empty path fell through and was used literally as the filename, producing an empty --dest-final and hanging the remote --server --recv. --- src/naming.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/naming.rs b/src/naming.rs index 089f286..cd129b9 100644 --- a/src/naming.rs +++ b/src/naming.rs @@ -81,10 +81,11 @@ pub fn resolve_dest_paths( effective_compress: bool, partial_ext: &str, ) -> DestPaths { - // DEST may name a directory (trailing '/') -- in that case reuse the + // DEST may name a directory (trailing '/', or empty as in scp's + // "host:" meaning the remote home directory) -- in that case reuse the // source's logical basename underneath it. Otherwise DEST names the file // directly. - let dest_logical = if dest_path.ends_with('/') { + let dest_logical = if dest_path.is_empty() || dest_path.ends_with('/') { let base = Path::new(&source_stripped.logical) .file_name() .map(|n| n.to_string_lossy().to_string()) @@ -240,6 +241,16 @@ mod tests { assert_eq!(d.final_path, "/out/cap.pcap"); } + #[test] + fn dest_paths_empty_target_is_home_dir() { + // scp-style "host:" (empty remote path) means the remote home + // directory -- reuse the source's basename, don't leave it empty. + let src = strip_name("cap.pcap.partial", "partial"); + let d = resolve_dest_paths("", &src, false, "partial"); + assert_eq!(d.final_path, "cap.pcap"); + assert_eq!(d.temp_path, "cap.pcap.partial"); + } + #[test] fn size_parsing() { assert_eq!(parse_size("256k").unwrap(), 256 * 1024);