fix(transfer): enqueue full destination path instead of directory

Queued transfers stored only the destination directory as the target
path. Downstream upload logic treats the queued destination as the full
file path and passes it straight to create_file, so transfers failed
with a Failure error when the remote target resolved to a directory.

Append each entry's file name to the destination directory at enqueue
time in both enqueue_file and enqueue_all, matching the single-file
transfer path which already builds the full target path.
This commit is contained in:
Christian Visintin
2026-06-08 19:48:33 +02:00
parent 352eec4762
commit 70bd7d7330
2 changed files with 37 additions and 3 deletions
+31 -2
View File
@@ -159,11 +159,18 @@ impl FileExplorer {
.insert(PathBuf::from(src), PathBuf::from(dst));
}
/// Enqueue all files for transfer
/// Enqueue all files for transfer.
///
/// `dst` is the destination *directory*; each entry is enqueued with its own
/// file name appended, so the stored destination is the full target path.
pub fn enqueue_all(&mut self, dst: &Path) {
let files: Vec<_> = self.iter_files().map(|f| f.path.clone()).collect();
for file in files {
self.enqueue(&file, dst);
let dest = match file.file_name() {
Some(name) => dst.join(name),
None => dst.to_path_buf(),
};
self.enqueue(&file, &dest);
}
}
@@ -659,6 +666,28 @@ mod tests {
assert_eq!(explorer.enqueued().len(), 0);
}
#[test]
fn test_should_enqueue_all_with_dest_file_name() {
let mut explorer: FileExplorer = FileExplorer::default();
explorer.set_files(vec![
make_fs_entry("a.txt", false),
make_fs_entry("b.txt", false),
]);
// Enqueue all into a remote destination directory
explorer.enqueue_all(Path::new("/remote/dir"));
let queue = explorer.enqueued();
assert_eq!(queue.len(), 2);
// Destination must be the directory joined with the file name, not the directory alone
assert_eq!(
queue.get(Path::new("a.txt")).unwrap(),
Path::new("/remote/dir/a.txt")
);
assert_eq!(
queue.get(Path::new("b.txt")).unwrap(),
Path::new("/remote/dir/b.txt")
);
}
fn make_fs_entry(name: &str, is_dir: bool) -> File {
let t: SystemTime = SystemTime::now();
let metadata = Metadata {
+6 -1
View File
@@ -355,7 +355,12 @@ impl FileTransferActivity {
self.browser.explorer_mut().dequeue(&src);
} else {
debug!("Marking file {}", src.display());
let dest = self.browser.other_explorer_no_found().wrkdir.clone();
// Destination is the other pane's working directory joined with the file
// name, so the queued entry holds the full target path (not just the dir).
let mut dest = self.browser.other_explorer_no_found().wrkdir.clone();
if let Some(name) = src.file_name() {
dest.push(name);
}
self.browser.explorer_mut().enqueue(&src, &dest);
}
self.reload_browser_file_list();