use std::{ collections::HashSet, fs, io, os::unix::prelude::PermissionsExt, path::{Path, PathBuf}, time::Duration, }; use crate::{BackgroundTask, Share}; pub(crate) fn task_copy( src: Vec<(PathBuf, Vec<(PathBuf, bool)>)>, target: PathBuf, share: &mut Share, ) { share.tasks.push(BackgroundTask::new( "cp".to_string(), move |status| { let mut total: usize = src.iter().map(|v| v.1.len()).sum(); for (parent, rel_paths) in src { let mut created: HashSet = HashSet::new(); for (rel_path, copy_recursive) in rel_paths { total = total.saturating_sub(1); { let s = format!("cp {total}"); *status.lock().unwrap() = s; } let file_from = parent.join(&rel_path); let file_to = target.join(&rel_path); let is_dir = file_from.is_dir(); let parent_created = if let Some(parent) = rel_path.parent() { parent.as_os_str().is_empty() || created.contains(parent) } else { true }; if parent_created { if is_dir { copy_dir(file_from, file_to, copy_recursive); created.insert(rel_path); } else { fs::copy(&file_from, &file_to); } } else { let rel_path = rel_path.file_name().unwrap(); let file_to = target.join(&rel_path); if is_dir { copy_dir(file_from, file_to, copy_recursive); created.insert(rel_path.into()); } else { fs::copy(&file_from, &file_to); } } } } Ok(()) }, true, )); } fn copy_dir( file_from: impl AsRef, file_to: impl AsRef, recursive: bool, ) -> io::Result<()> { fs::create_dir(&file_to)?; if recursive { if let Ok(e) = fs::read_dir(file_from) { for e in e { if let Ok(e) = e { let p = e.path(); let t = file_to.as_ref().join(e.file_name()); if p.is_dir() { copy_dir(p, t, recursive); } else { fs::copy(&p, &t); } } } } } Ok(()) } pub(crate) fn task_del(paths: Vec, share: &mut Share) { let mut total: usize = paths.len(); share.tasks.push(BackgroundTask::new( format!("rm {total}"), move |status| { for path in paths { { total -= 1; let s = format!("rm {total}"); *status.lock().unwrap() = s; } if path.is_dir() { fs::remove_dir(path); } else { fs::remove_file(path); } } Ok(()) }, true, )); } pub(crate) fn task_chmod(paths: Vec, mode: u32, share: &mut Share) { let mut total = paths.len(); share.tasks.push(BackgroundTask::new( format!("chmod {total}"), move |status| { for path in paths { { total -= 1; let s = format!("chmod {total}"); *status.lock().unwrap() = s; } fs::set_permissions(path, fs::Permissions::from_mode(mode)); } Ok(()) }, true, )); }