From 000ac6f383c4afdf7f7c5fac2904b2dbf71e9205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Mon, 27 Mar 2023 20:33:18 +0200 Subject: [PATCH 01/11] Add and handle `follow` option in `CopyOptions` --- src/dir.rs | 4 +++ src/file.rs | 70 ++++++++++++++++++++++++++++++++++++++++----------- src/lib.rs | 3 +++ tests/file.rs | 6 ++--- 4 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index a5d1112..8ab7da4 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -619,6 +619,7 @@ where overwrite: options.overwrite, skip_exist: options.skip_exist, buffer_size: options.buffer_size, + follow: false, }; let mut result_copy: Result; let mut work = true; @@ -931,6 +932,7 @@ where overwrite: options.overwrite, skip_exist: options.skip_exist, buffer_size: options.buffer_size, + follow: false, }; if let Some(file_name) = file_name.to_str() { @@ -1126,6 +1128,7 @@ where overwrite: options.overwrite, skip_exist: options.skip_exist, buffer_size: options.buffer_size, + follow: false, }; let mut result_copy: Result; @@ -1268,6 +1271,7 @@ where overwrite: options.overwrite, skip_exist: options.skip_exist, buffer_size: options.buffer_size, + follow: false, }; if let Some(file_name) = file_name.to_str() { diff --git a/src/file.rs b/src/file.rs index 2b62576..070cccc 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,7 +1,9 @@ use crate::error::{Error, ErrorKind, Result}; use std; -use std::fs::{remove_file, File}; +use std::fs::{read_link, remove_file, File}; use std::io::{Read, Write}; +#[cfg(unix)] +use std::os::unix::fs::symlink; use std::path::Path; // Options and flags which can be used to configure how a file will be copied or moved. @@ -12,6 +14,8 @@ pub struct CopyOptions { pub skip_exist: bool, /// Sets buffer size for copy/move work only with receipt information about process work. pub buffer_size: usize, + /// Follows the last symbolic link in the path + pub follow: bool, } impl CopyOptions { @@ -30,6 +34,7 @@ impl CopyOptions { overwrite: false, skip_exist: false, buffer_size: 64000, //64kb + follow: true, } } @@ -94,26 +99,54 @@ where Q: AsRef, { let from = from.as_ref(); - if !from.exists() { - if let Some(msg) = from.to_str() { - let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); - err!(&msg, ErrorKind::NotFound); + match from.try_exists() { + Ok(false) => { + if options.follow { + err!( + &if let Some(msg) = from.to_str() { + format!("Path \"{}\" is a broken symlink or doesn't exist!", msg) + } else { + String::from("Path is a broken symlink or doesn't exist!") + }, + if from.is_symlink() { + ErrorKind::InvalidFile + } else { + ErrorKind::NotFound + } + ) + } } - err!( - "Path does not exist or you don't have access!", - ErrorKind::NotFound - ); + Err(_) => { + if let Some(msg) = from.to_str() { + let msg = format!("You don't have access to \"{}\" path!", msg); + err!(&msg, ErrorKind::PermissionDenied); + } + err!("You don't have access!", ErrorKind::PermissionDenied); + } + _ => {} } if !from.is_file() { - if let Some(msg) = from.to_str() { - let msg = format!("Path \"{}\" is not a file!", msg); - err!(&msg, ErrorKind::InvalidFile); + if options.follow { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } else if !from.is_symlink() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a file or symlink!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file or symlink!", ErrorKind::InvalidFile); } - err!("Path is not a file!", ErrorKind::InvalidFile); } - if !options.overwrite && to.as_ref().exists() { + if !options.overwrite + && (to.as_ref().exists() || + // If the target is a broken symlink, it should not be overwritten + to.as_ref().is_symlink()) + { if options.skip_exist { return Ok(0); } @@ -122,9 +155,16 @@ where let msg = format!("Path \"{}\" exists", msg); err!(&msg, ErrorKind::AlreadyExists); } + err!("Path exists!", ErrorKind::AlreadyExists); } - Ok(std::fs::copy(from, to)?) + if options.follow || from.is_file() { + Ok(std::fs::copy(from, to)?) + } else { + #[cfg(unix)] + symlink(read_link(from)?, &to)?; + Ok(to.as_ref().as_os_str().len() as u64) + } } /// Copies the contents of one file to another file with information about progress. diff --git a/src/lib.rs b/src/lib.rs index 118643a..76468e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -354,6 +354,7 @@ where overwrite: options.overwrite, skip_exist: options.skip_exist, buffer_size: options.buffer_size, + follow: false, }; if let Some(file_name) = item.file_name() { @@ -541,6 +542,7 @@ where overwrite: options.overwrite, skip_exist: options.skip_exist, buffer_size: options.buffer_size, + follow: false, }; if let Some(file_name) = item.file_name() { @@ -666,6 +668,7 @@ where overwrite: options.overwrite, skip_exist: options.skip_exist, buffer_size: options.buffer_size, + follow: false, }; if let Some(file_name) = item.file_name() { diff --git a/tests/file.rs b/tests/file.rs index 67840a5..a6094d0 100644 --- a/tests/file.rs +++ b/tests/file.rs @@ -168,8 +168,7 @@ fn it_copy_source_not_exist() { Err(err) => match err.kind { ErrorKind::NotFound => { let wrong_path = format!( - "Path \"{}\" does not exist or you don't have \ - access!", + "Path \"{}\" is a broken symlink or doesn't exist!", test_file.to_str().unwrap() ); assert_eq!(wrong_path, err.to_string()); @@ -643,8 +642,7 @@ fn it_move_source_not_exist() { Err(err) => match err.kind { ErrorKind::NotFound => { let wrong_path = format!( - "Path \"{}\" does not exist or you don't have \ - access!", + "Path \"{}\" is a broken symlink or doesn't exist!", test_file.to_str().unwrap() ); From 8c00ea19f6dbd5a177cc7fe26728254d028729e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Mon, 27 Mar 2023 22:22:54 +0200 Subject: [PATCH 02/11] Add simple tests for `file` module --- tests/file.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/file.rs b/tests/file.rs index a6094d0..80f60e9 100644 --- a/tests/file.rs +++ b/tests/file.rs @@ -9,6 +9,22 @@ use fs_extra::file::*; const TEST_FOLDER: &'static str = "./tests/temp/file"; +#[cfg(unix)] +fn create_file_symlink, Q: AsRef>( + original: P, + link: Q, +) -> std::io::Result<()> { + std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) +} + +#[cfg(windows)] +fn create_file_symlink, Q: AsRef>( + original: P, + link: Q, +) -> std::io::Result<()> { + std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()) +} + fn files_eq(file1: P, file2: Q) -> Result where P: AsRef, @@ -1032,3 +1048,63 @@ fn it_move_with_progress_exist_overwrite_and_skip_exist() { Err(err) => panic!(err.to_string()), } } + +#[test] +#[cfg(unix)] +fn it_copy_not_overwrite_broken_symlink() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_not_overwrite_broken_symlink"); + let mut test_link = test_file.clone(); + let mut test_target = test_file.clone(); + + test_file.push("file"); + test_link.push("link"); + test_target.push("nothing"); + + fs_extra::dir::create_all(&test_link.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test").unwrap(); + create_file_symlink(test_target, &test_link).unwrap(); + + let options = CopyOptions::new(); + + match copy(&test_file, &test_link, &options) { + Ok(_) => panic!("should be error"), + Err(err) => match err.kind { + ErrorKind::AlreadyExists => {} + _ => panic!("wrong error: {:?}", err.kind), + }, + } +} + +#[test] +fn it_copy_symlink_not_follow() { + let mut test_file = PathBuf::from(TEST_FOLDER); + test_file.push("it_copy_symlink_not_follow"); + let mut test_link = test_file.clone(); + let mut test_link_to = test_file.clone(); + + test_file.push("file"); + test_link.push("link"); + test_link_to.push("link_copy"); + + fs_extra::dir::create_all(&test_link.parent().unwrap(), true).unwrap(); + fs_extra::dir::create_all(&test_file.parent().unwrap(), true).unwrap(); + + write_all(&test_file, "test").unwrap(); + create_file_symlink(&test_file, &test_link).unwrap(); + + let options = CopyOptions { + follow: false, + ..CopyOptions::new() + }; + + match copy(&test_link, &test_link_to, &options) { + Ok(_) => { + assert!(test_link_to.is_symlink()); + assert_eq!(std::fs::read_link(test_link_to).unwrap(), test_file); + } + Err(_) => panic!("Should not be error"), + } +} From 957eaa0d9714dadb9c93c36c06826b14b624921e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Tue, 28 Mar 2023 20:31:05 +0200 Subject: [PATCH 03/11] Improve flow control --- src/dir.rs | 1 + src/file.rs | 84 ++++++++++++++++----------------------------------- tests/file.rs | 10 ++---- 3 files changed, 29 insertions(+), 66 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index 8ab7da4..2d3f854 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -1149,6 +1149,7 @@ where } } } + if is_remove { remove(from)?; } diff --git a/src/file.rs b/src/file.rs index 070cccc..0a39202 100644 --- a/src/file.rs +++ b/src/file.rs @@ -99,72 +99,40 @@ where Q: AsRef, { let from = from.as_ref(); - match from.try_exists() { - Ok(false) => { - if options.follow { - err!( - &if let Some(msg) = from.to_str() { - format!("Path \"{}\" is a broken symlink or doesn't exist!", msg) - } else { - String::from("Path is a broken symlink or doesn't exist!") - }, - if from.is_symlink() { - ErrorKind::InvalidFile - } else { - ErrorKind::NotFound - } - ) - } - } - Err(_) => { - if let Some(msg) = from.to_str() { - let msg = format!("You don't have access to \"{}\" path!", msg); - err!(&msg, ErrorKind::PermissionDenied); - } - err!("You don't have access!", ErrorKind::PermissionDenied); - } - _ => {} - } + let to = to.as_ref(); - if !from.is_file() { - if options.follow { - if let Some(msg) = from.to_str() { - let msg = format!("Path \"{}\" is not a file!", msg); - err!(&msg, ErrorKind::InvalidFile); - } - err!("Path is not a file!", ErrorKind::InvalidFile); - } else if !from.is_symlink() { - if let Some(msg) = from.to_str() { - let msg = format!("Path \"{}\" is not a file or symlink!", msg); - err!(&msg, ErrorKind::InvalidFile); - } - err!("Path is not a file or symlink!", ErrorKind::InvalidFile); - } - } - - if !options.overwrite - && (to.as_ref().exists() || - // If the target is a broken symlink, it should not be overwritten - to.as_ref().is_symlink()) - { - if options.skip_exist { + if !options.overwrite && to.symlink_metadata().is_ok() { + if !options.skip_exist { + err!( + &format!("Path \"{}\" exists", to.display()), + ErrorKind::AlreadyExists + ); + } else { return Ok(0); } - - if let Some(msg) = to.as_ref().to_str() { - let msg = format!("Path \"{}\" exists", msg); - err!(&msg, ErrorKind::AlreadyExists); - } - err!("Path exists!", ErrorKind::AlreadyExists); } - if options.follow || from.is_file() { - Ok(std::fs::copy(from, to)?) - } else { + if !options.follow && from.is_symlink() { #[cfg(unix)] symlink(read_link(from)?, &to)?; - Ok(to.as_ref().as_os_str().len() as u64) + return Ok(to.as_os_str().len() as u64); + } + + if !from.try_exists()? { + err!( + &format!("Path \"{}\" doesn't exist!", from.display()), + ErrorKind::NotFound + ); } + + if !from.is_file() { + err!( + &format!("Path \"{}\" is not a file!", from.display()), + ErrorKind::InvalidFile + ); + } + + Ok(std::fs::copy(from, to)?) } /// Copies the contents of one file to another file with information about progress. diff --git a/tests/file.rs b/tests/file.rs index 80f60e9..aa76b4e 100644 --- a/tests/file.rs +++ b/tests/file.rs @@ -183,10 +183,7 @@ fn it_copy_source_not_exist() { Ok(_) => panic!("should be error"), Err(err) => match err.kind { ErrorKind::NotFound => { - let wrong_path = format!( - "Path \"{}\" is a broken symlink or doesn't exist!", - test_file.to_str().unwrap() - ); + let wrong_path = format!("Path \"{}\" doesn't exist!", test_file.to_str().unwrap()); assert_eq!(wrong_path, err.to_string()); () } @@ -657,10 +654,7 @@ fn it_move_source_not_exist() { Ok(_) => panic!("should be error"), Err(err) => match err.kind { ErrorKind::NotFound => { - let wrong_path = format!( - "Path \"{}\" is a broken symlink or doesn't exist!", - test_file.to_str().unwrap() - ); + let wrong_path = format!("Path \"{}\" doesn't exist!", test_file.to_str().unwrap()); assert_eq!(wrong_path, err.to_string()); () From b2147ffaf5a89ca2ad293f74bf26855a9d7fd327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Tue, 28 Mar 2023 21:23:53 +0200 Subject: [PATCH 04/11] Use `symlink_metadata` function to get file size --- src/dir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dir.rs b/src/dir.rs index 2d3f854..7a75c06 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -750,7 +750,7 @@ where } } } else { - dir_size = path.as_ref().metadata()?.len(); + dir_size = path.as_ref().symlink_metadata()?.len(); files.push(item); } Ok(DirContent { From cd0a7be96b3ceea0f82489387f8153382518f1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Tue, 28 Mar 2023 21:42:54 +0200 Subject: [PATCH 05/11] Support wasi and redox --- src/file.rs | 6 ++++-- src/lib.rs | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/file.rs b/src/file.rs index 0a39202..4af9701 100644 --- a/src/file.rs +++ b/src/file.rs @@ -2,8 +2,10 @@ use crate::error::{Error, ErrorKind, Result}; use std; use std::fs::{read_link, remove_file, File}; use std::io::{Read, Write}; -#[cfg(unix)] +#[cfg(any(unix, target_os = "redox"))] use std::os::unix::fs::symlink; +#[cfg(target_os = "wasi")] +use std::os::wasi::fs::symlink_path as symlink; use std::path::Path; // Options and flags which can be used to configure how a file will be copied or moved. @@ -113,7 +115,7 @@ where } if !options.follow && from.is_symlink() { - #[cfg(unix)] + #[cfg(any(unix, target_os = "wasi", target_os = "redox"))] symlink(read_link(from)?, &to)?; return Ok(to.as_os_str().len() as u64); } diff --git a/src/lib.rs b/src/lib.rs index 76468e8..63a418e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] + macro_rules! err { ($text:expr, $kind:expr) => { return Err(Error::new($kind, $text)) From 060e33eef4ecc1df25130183d9960b8374d264c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Tue, 28 Mar 2023 21:48:11 +0200 Subject: [PATCH 06/11] Support windows --- src/file.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/file.rs b/src/file.rs index 4af9701..c202e6f 100644 --- a/src/file.rs +++ b/src/file.rs @@ -6,6 +6,8 @@ use std::io::{Read, Write}; use std::os::unix::fs::symlink; #[cfg(target_os = "wasi")] use std::os::wasi::fs::symlink_path as symlink; +#[cfg(windows)] +use std::os::windows::fs::{symlink_dir, symlink_file, FileTypeExt}; use std::path::Path; // Options and flags which can be used to configure how a file will be copied or moved. @@ -116,7 +118,13 @@ where if !options.follow && from.is_symlink() { #[cfg(any(unix, target_os = "wasi", target_os = "redox"))] - symlink(read_link(from)?, &to)?; + symlink(read_link(from)?, to)?; + #[cfg(windows)] + if from.symlink_metadata()?.file_type().is_symlink_dir() { + symlink_dir(read_link(from)?, to)?; + } else { + symlink_file(read_link(from)?, to)?; + } return Ok(to.as_os_str().len() as u64); } From 02ce6bd6d67cb42462b1e2beab0a308ad3d3582a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Wed, 29 Mar 2023 11:47:18 +0200 Subject: [PATCH 07/11] Apply fixes to progress functions --- src/dir.rs | 5 +++-- src/file.rs | 50 ++++++++++++++++++++++++++++++-------------------- tests/file.rs | 6 ++---- 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index 7a75c06..685913d 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -727,7 +727,8 @@ where } let item = item.unwrap().to_string(); - if path.as_ref().is_dir() { + let meta = path.as_ref().symlink_metadata()?; + if meta.is_dir() { dir_size = path.as_ref().metadata()?.len(); directories.push(item); if depth == 0 || depth > 1 { @@ -750,7 +751,7 @@ where } } } else { - dir_size = path.as_ref().symlink_metadata()?.len(); + dir_size = meta.len(); files.push(item); } Ok(DirContent { diff --git a/src/file.rs b/src/file.rs index c202e6f..f21eee0 100644 --- a/src/file.rs +++ b/src/file.rs @@ -182,35 +182,45 @@ where F: FnMut(TransitProcess), { let from = from.as_ref(); - if !from.exists() { - if let Some(msg) = from.to_str() { - let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); - err!(&msg, ErrorKind::NotFound); + let to = to.as_ref(); + + if !options.overwrite && (to.try_exists()? || to.symlink_metadata().is_ok()) { + if !options.skip_exist { + err!( + &format!("Path \"{}\" exists", to.display()), + ErrorKind::AlreadyExists + ); + } else { + return Ok(0); + } + } + + if !options.follow && from.is_symlink() { + #[cfg(any(unix, target_os = "wasi", target_os = "redox"))] + symlink(read_link(from)?, to)?; + #[cfg(windows)] + if from.symlink_metadata()?.file_type().is_symlink_dir() { + symlink_dir(read_link(from)?, to)?; + } else { + symlink_file(read_link(from)?, to)?; } + return Ok(to.as_os_str().len() as u64); + } + + if !from.try_exists()? { err!( - "Path does not exist or you don't have access!", + &format!("Path \"{}\" doesn't exist!", from.display()), ErrorKind::NotFound ); } if !from.is_file() { - if let Some(msg) = from.to_str() { - let msg = format!("Path \"{}\" is not a file!", msg); - err!(&msg, ErrorKind::InvalidFile); - } - err!("Path is not a file!", ErrorKind::InvalidFile); + err!( + &format!("Path \"{}\" is not a file!", from.display()), + ErrorKind::InvalidFile + ); } - if !options.overwrite && to.as_ref().exists() { - if options.skip_exist { - return Ok(0); - } - - if let Some(msg) = to.as_ref().to_str() { - let msg = format!("Path \"{}\" exists", msg); - err!(&msg, ErrorKind::AlreadyExists); - } - } let mut file_from = File::open(from)?; let mut buf = vec![0; options.buffer_size]; let file_size = file_from.metadata()?.len(); diff --git a/tests/file.rs b/tests/file.rs index aa76b4e..f411466 100644 --- a/tests/file.rs +++ b/tests/file.rs @@ -442,8 +442,7 @@ fn it_copy_with_progress_source_not_exist() { Err(err) => match err.kind { ErrorKind::NotFound => { let wrong_path = format!( - "Path \"{}\" does not exist or you don't have \ - access!", + "Path \"{}\" doesn't exist!", test_file.to_str().unwrap() ); @@ -905,8 +904,7 @@ fn it_move_with_progress_source_not_exist() { Err(err) => match err.kind { ErrorKind::NotFound => { let wrong_path = format!( - "Path \"{}\" does not exist or you don't have \ - access!", + "Path \"{}\" doesn't exist!", test_file.to_str().unwrap() ); From a27690918e4c8cf51b5de07fbebbc315df33a78c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Wed, 29 Mar 2023 14:23:47 +0200 Subject: [PATCH 08/11] Add directory test from pr example --- tests/dir.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/tests/dir.rs b/tests/dir.rs index 2647066..b5845ec 100644 --- a/tests/dir.rs +++ b/tests/dir.rs @@ -18,6 +18,16 @@ where content1 == content2 } +fn symlinks_eq(symlink1: P, symlink2: Q) -> bool +where + P: AsRef, + Q: AsRef, +{ + let target1 = fs::read_link(symlink1).unwrap(); + let target2 = fs::read_link(symlink2).unwrap(); + target1 == target2 +} + fn compare_dir(path_from: P, path_to: Q) -> bool where P: AsRef, @@ -28,7 +38,7 @@ where None => panic!("Invalid folder from"), Some(dir_name) => { path_to.push(dir_name.as_os_str()); - if !path_to.exists() { + if !path_to.exists() && !path_to.is_symlink() { return false; } } @@ -47,10 +57,16 @@ where None => panic!("No file name"), Some(file_name) => { path_to.push(file_name); - if !path_to.exists() { - return false; - } else if !files_eq(&path, path_to.clone()) { - return false; + if path_to.is_symlink() { + if !symlinks_eq(&path, &path_to) { + return false; + } + } else if path_to.is_file() { + if !path_to.exists() { + return false; + } else if !files_eq(&path, path_to.clone()) { + return false; + } } } } @@ -70,7 +86,7 @@ fn get_dir_size() -> u64 { .len() } -#[cfg(unix)] +#[cfg(any(unix, target_os = "wasi", target_os = "redox"))] fn create_file_symlink, Q: AsRef>( original: P, link: Q, @@ -4822,3 +4838,33 @@ fn it_move_with_progress_content_only_option() { _ => {} } } + +#[test] +fn it_move_with_symlinks() { + let copy_options = &CopyOptions { + copy_inside: true, + ..CopyOptions::new() + }; + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_symlinks"); + let path_from = test_dir.clone().join("dir"); + let path_to1 = test_dir.clone().join("dir_cpy1"); + let path_to2 = test_dir.clone().join("dir_cpy2"); + + let test_file = Path::new("file"); + let test_link = Path::new("link"); + let test_dir1 = Path::new("dir_in"); + let test_link1 = test_dir1.clone().join("link1"); + + let _ = remove(test_dir); + create_all(&path_from.join(&test_dir1), true).unwrap(); + fs_extra::file::write_all(&path_from.join(&test_file), "test").unwrap(); + + create_file_symlink(&test_file, &path_from.join(&test_link)).unwrap(); + create_file_symlink(&Path::new("..").join(test_file), &path_from.join(&test_link1)).unwrap(); + + copy(&path_from, &path_to1.join("dir"), ©_options).unwrap(); + assert!(compare_dir(&path_from, &path_to1)); + + move_dir(&path_to1.join("dir"), &path_to2.join("dir"), ©_options).unwrap(); + assert!(compare_dir(&path_from, &path_to2)); +} From aa4468a4b1048ed80bd6faec1d939e3c660e6b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Wed, 29 Mar 2023 15:38:35 +0200 Subject: [PATCH 09/11] Add `move_dir_with_progress` tests --- tests/dir.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++++- tests/file.rs | 10 ++-------- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/tests/dir.rs b/tests/dir.rs index b5845ec..6b05837 100644 --- a/tests/dir.rs +++ b/tests/dir.rs @@ -4860,7 +4860,11 @@ fn it_move_with_symlinks() { fs_extra::file::write_all(&path_from.join(&test_file), "test").unwrap(); create_file_symlink(&test_file, &path_from.join(&test_link)).unwrap(); - create_file_symlink(&Path::new("..").join(test_file), &path_from.join(&test_link1)).unwrap(); + create_file_symlink( + &Path::new("..").join(test_file), + &path_from.join(&test_link1), + ) + .unwrap(); copy(&path_from, &path_to1.join("dir"), ©_options).unwrap(); assert!(compare_dir(&path_from, &path_to1)); @@ -4868,3 +4872,45 @@ fn it_move_with_symlinks() { move_dir(&path_to1.join("dir"), &path_to2.join("dir"), ©_options).unwrap(); assert!(compare_dir(&path_from, &path_to2)); } + +#[test] +fn it_move_with_symlinks_progress() { + let copy_options = &CopyOptions { + copy_inside: true, + ..CopyOptions::new() + }; + let test_dir = Path::new(TEST_FOLDER).join("it_move_with_symlinks_progress"); + let path_from = test_dir.clone().join("dir"); + let path_to1 = test_dir.clone().join("dir_cpy1"); + let path_to2 = test_dir.clone().join("dir_cpy2"); + + let test_file = Path::new("file"); + let test_link = Path::new("link"); + let test_dir1 = Path::new("dir_in"); + let test_link1 = test_dir1.clone().join("link1"); + + let func_test = |_process_info: TransitProcess| TransitProcessResult::ContinueOrAbort; + + let _ = remove(test_dir); + create_all(&path_from.join(&test_dir1), true).unwrap(); + fs_extra::file::write_all(&path_from.join(&test_file), "test").unwrap(); + + create_file_symlink(&test_file, &path_from.join(&test_link)).unwrap(); + create_file_symlink( + &Path::new("..").join(test_file), + &path_from.join(&test_link1), + ) + .unwrap(); + + copy_with_progress(&path_from, &path_to1.join("dir"), ©_options, &func_test).unwrap(); + assert!(compare_dir(&path_from, &path_to1)); + + move_dir_with_progress( + &path_to1.join("dir"), + &path_to2.join("dir"), + ©_options, + &func_test, + ) + .unwrap(); + assert!(compare_dir(&path_from, &path_to2)); +} diff --git a/tests/file.rs b/tests/file.rs index f411466..5f847be 100644 --- a/tests/file.rs +++ b/tests/file.rs @@ -441,10 +441,7 @@ fn it_copy_with_progress_source_not_exist() { Ok(_) => panic!("should be error"), Err(err) => match err.kind { ErrorKind::NotFound => { - let wrong_path = format!( - "Path \"{}\" doesn't exist!", - test_file.to_str().unwrap() - ); + let wrong_path = format!("Path \"{}\" doesn't exist!", test_file.to_str().unwrap()); assert_eq!(wrong_path, err.to_string()); () @@ -903,10 +900,7 @@ fn it_move_with_progress_source_not_exist() { Ok(_) => panic!("should be error"), Err(err) => match err.kind { ErrorKind::NotFound => { - let wrong_path = format!( - "Path \"{}\" doesn't exist!", - test_file.to_str().unwrap() - ); + let wrong_path = format!("Path \"{}\" doesn't exist!", test_file.to_str().unwrap()); assert_eq!(wrong_path, err.to_string()); () From d9b45a1414be10819ff7566ef913c56922fc1bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Wed, 29 Mar 2023 15:38:46 +0200 Subject: [PATCH 10/11] Fix progress functions --- src/dir.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dir.rs b/src/dir.rs index 685913d..7badb67 100644 --- a/src/dir.rs +++ b/src/dir.rs @@ -943,7 +943,7 @@ where } info_process.file_bytes_copied = 0; - info_process.file_total_bytes = Path::new(&file).metadata()?.len(); + info_process.file_total_bytes = Path::new(&file).symlink_metadata()?.len(); let mut result_copy: Result; let mut work = true; @@ -1283,7 +1283,7 @@ where } info_process.file_bytes_copied = 0; - info_process.file_total_bytes = Path::new(&file).metadata()?.len(); + info_process.file_total_bytes = Path::new(&file).symlink_metadata()?.len(); let mut result_copy: Result; let mut work = true; From fd78b4ea7f449753f046c8d3faa3fab7a89519c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Grzegorz=20P=C5=82aczek?= Date: Wed, 29 Mar 2023 23:03:56 +0200 Subject: [PATCH 11/11] Fix cfg --- tests/file.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/file.rs b/tests/file.rs index 5f847be..cac47f1 100644 --- a/tests/file.rs +++ b/tests/file.rs @@ -1036,7 +1036,7 @@ fn it_move_with_progress_exist_overwrite_and_skip_exist() { } #[test] -#[cfg(unix)] +#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))] fn it_copy_not_overwrite_broken_symlink() { let mut test_file = PathBuf::from(TEST_FOLDER); test_file.push("it_copy_not_overwrite_broken_symlink"); @@ -1065,6 +1065,7 @@ fn it_copy_not_overwrite_broken_symlink() { } #[test] +#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))] fn it_copy_symlink_not_follow() { let mut test_file = PathBuf::from(TEST_FOLDER); test_file.push("it_copy_symlink_not_follow");