From af553d1fed978489ace9338d9953d49053b2c55c Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Tue, 31 May 2022 09:39:25 +0100 Subject: [PATCH] Only scan one filesystem by default (can configure 'cross_filesystems' if needed) --- datman/src/bin/datman.rs | 6 +++--- datman/src/commands/backup.rs | 4 +++- datman/src/commands/ibrowse.rs | 10 +++++++--- datman/src/commands/ilabel.rs | 15 ++++++++++----- datman/src/descriptor.rs | 2 ++ datman/src/remote/backup_source_requester.rs | 12 ++++++++++-- datman/src/remote/backup_source_responder.rs | 3 ++- datman/src/tree.rs | 19 +++++++++++++++---- 8 files changed, 52 insertions(+), 19 deletions(-) diff --git a/datman/src/bin/datman.rs b/datman/src/bin/datman.rs index f3dd5ac..19f890f 100644 --- a/datman/src/bin/datman.rs +++ b/datman/src/bin/datman.rs @@ -195,10 +195,10 @@ fn main() -> anyhow::Result<()> { unimplemented!(); } DatmanCommand::InteractiveLabelling { source_name } => { - interactive_labelling_session(Path::new("."), source_name).unwrap(); + interactive_labelling_session(Path::new("."), source_name)?; } DatmanCommand::InteractiveBrowsing { source_name } => { - datman::commands::ibrowse::session(Path::new("."), source_name).unwrap(); + datman::commands::ibrowse::session(Path::new("."), source_name)?; } DatmanCommand::BackupOne { source_name, @@ -317,7 +317,7 @@ fn main() -> anyhow::Result<()> { let descriptor = load_descriptor(Path::new(".")).unwrap(); let destination = &descriptor.piles[&pile_name]; let report = datman::commands::report::generate_report(destination, &descriptor)?; - + datman::commands::report::print_report(&report)?; datman::commands::report::print_filesystem_space(&destination.path)?; } diff --git a/datman/src/commands/backup.rs b/datman/src/commands/backup.rs index 7cc07c8..0e77852 100644 --- a/datman/src/commands/backup.rs +++ b/datman/src/commands/backup.rs @@ -147,10 +147,12 @@ pub fn backup_source_to_destination( SourceDescriptor::DirectorySource { hostname: _, directory, + cross_filesystems, } => { info!("Looking to backup {} to {}", source_name, dest_name); info!("Scanning."); - let tree = scan(directory)?.ok_or_else(|| anyhow!("Source does not exist."))?; + let tree = scan(directory, !*cross_filesystems)? + .ok_or_else(|| anyhow!("Source does not exist."))?; let absolute_source_path = desc_path.join(directory); let absolute_dest_path = desc_path.join(&dest.path); diff --git a/datman/src/commands/ibrowse.rs b/datman/src/commands/ibrowse.rs index 7a73d38..37c0b92 100644 --- a/datman/src/commands/ibrowse.rs +++ b/datman/src/commands/ibrowse.rs @@ -68,15 +68,19 @@ pub fn session(path: &Path, source_name: String) -> anyhow::Result<()> { .get(&source_name) .ok_or_else(|| anyhow!("Could not find source {:?}!", source_name))?; - let directory = match source_descriptor { - SourceDescriptor::DirectorySource { directory, .. } => directory, + let (directory, one_filesystem) = match source_descriptor { + SourceDescriptor::DirectorySource { + directory, + cross_filesystems, + .. + } => (directory, !*cross_filesystems), SourceDescriptor::VirtualSource { .. } => { bail!("Cannot browse virtual source."); } }; println!("Scanning source; this might take a little while..."); - let mut dir_scan: FileTree1> = scan(directory)? + let mut dir_scan: FileTree1> = scan(directory, one_filesystem)? .ok_or_else(|| anyhow!("Empty source."))? .replace_meta(&None); diff --git a/datman/src/commands/ilabel.rs b/datman/src/commands/ilabel.rs index 08d68ba..0d9ef41 100644 --- a/datman/src/commands/ilabel.rs +++ b/datman/src/commands/ilabel.rs @@ -186,12 +186,13 @@ pub fn interactive_labelling_session(path: &Path, source_name: String) -> anyhow if let SourceDescriptor::DirectorySource { hostname, directory, + cross_filesystems, } = source { let my_hostname = get_hostname(); let mut dir_scan = if &my_hostname == hostname { info!("Scanning source; this might take a little while..."); - scan(directory)? + scan(directory, !*cross_filesystems)? .ok_or_else(|| anyhow!("Empty source."))? .replace_meta(&None) } else { @@ -206,10 +207,14 @@ pub fn interactive_labelling_session(path: &Path, source_name: String) -> anyhow // then request to scan info!("Requesting scan from remote source... (this may take some time)"); - let scan = - backup_source_requester::scanning(&mut read, &mut write, directory.as_ref())? - .ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))? - .replace_meta(&None); + let scan = backup_source_requester::scanning( + &mut read, + &mut write, + directory.as_ref(), + !*cross_filesystems, + )? + .ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))? + .replace_meta(&None); backup_source_requester::quit(&mut read, &mut write)?; diff --git a/datman/src/descriptor.rs b/datman/src/descriptor.rs index 370db5d..03d8dc3 100644 --- a/datman/src/descriptor.rs +++ b/datman/src/descriptor.rs @@ -52,6 +52,8 @@ pub enum SourceDescriptor { DirectorySource { hostname: String, directory: PathBuf, + #[serde(default)] + cross_filesystems: bool, }, VirtualSource { /// The name of the helper program that will be used to do this backup. diff --git a/datman/src/remote/backup_source_requester.rs b/datman/src/remote/backup_source_requester.rs index 3ba0200..51ff529 100644 --- a/datman/src/remote/backup_source_requester.rs +++ b/datman/src/remote/backup_source_requester.rs @@ -47,10 +47,12 @@ pub fn scanning( read: &mut R, write: &mut W, path: &Path, + one_filesystem: bool, ) -> anyhow::Result>> { info!("Scanning."); write_message(write, &"scan")?; write_message(write, &path)?; + write_message(write, &one_filesystem)?; write.flush()?; let scan_result: Option> = read_message(read)?; @@ -177,6 +179,7 @@ pub fn backup_remote_source_to_destination SourceDescriptor::DirectorySource { hostname, directory, + cross_filesystems, } => { let remote_host_descriptor = descriptor .remote_hosts @@ -198,8 +201,13 @@ pub fn backup_remote_source_to_destination // then request to scan info!("Requesting scan... (this may take some time)"); - let scan_result = scanning(&mut read, &mut write, directory.as_ref())? - .ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?; + let scan_result = scanning( + &mut read, + &mut write, + directory.as_ref(), + !*cross_filesystems, + )? + .ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?; let mut root = label_filter_and_convert(scan_result, descriptor, desc_path, source_name, dest)? diff --git a/datman/src/remote/backup_source_responder.rs b/datman/src/remote/backup_source_responder.rs index cc01573..8efac4d 100644 --- a/datman/src/remote/backup_source_responder.rs +++ b/datman/src/remote/backup_source_responder.rs @@ -42,7 +42,8 @@ pub fn introduction(read: &mut R, write: &mut W) -> anyhow::R pub fn scanning(read: &mut R, write: &mut W) -> anyhow::Result<()> { let path: PathBuf = read_message(read)?; - let scan_result = scan(&path)?; + let one_filesystem: bool = read_message(read)?; + let scan_result = scan(&path, one_filesystem)?; write_message(write, &scan_result)?; write.flush()?; Ok(()) diff --git a/datman/src/tree.rs b/datman/src/tree.rs index 3873562..48645c0 100644 --- a/datman/src/tree.rs +++ b/datman/src/tree.rs @@ -24,7 +24,7 @@ use std::path::Path; use anyhow::anyhow; use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; -use log::warn; +use log::{info, warn}; use serde::{Deserialize, Serialize}; pub use yama::definitions::FilesystemOwnership; @@ -216,12 +216,14 @@ pub fn mtime_msec(metadata: &Metadata) -> u64 { } /// Scan the filesystem to produce a Tree, using a default progress bar. -pub fn scan(path: &Path) -> anyhow::Result>> { +pub fn scan(path: &Path, one_filesystem: bool) -> anyhow::Result>> { let pbar = ProgressBar::with_draw_target(0, ProgressDrawTarget::stdout_with_hz(2)); pbar.set_style(ProgressStyle::default_spinner().template("{spinner} {pos:7} {msg}")); pbar.set_message("dir scan"); - let result = scan_with_progress_bar(path, &pbar); + let one_filesystem = if one_filesystem { Some(None) } else { None }; + + let result = scan_with_progress_bar(path, &pbar, one_filesystem); pbar.finish_at_current_pos(); result } @@ -230,6 +232,7 @@ pub fn scan(path: &Path) -> anyhow::Result>> { pub fn scan_with_progress_bar( path: &Path, progress_bar: &ProgressBar, + mut one_filesystem: Option>, ) -> anyhow::Result>> { let metadata_res = symlink_metadata(path); progress_bar.inc(1); @@ -249,6 +252,14 @@ pub fn scan_with_progress_bar( let metadata = metadata_res?; let filetype = metadata.file_type(); + if let Some(one_filesystem) = one_filesystem.as_mut() { + let this_fs = metadata.dev(); + if *one_filesystem.get_or_insert(this_fs) != this_fs { + info!("Stopping at filesystem boundary: {:?}", path); + return Ok(None); + } + } + /*let name = path .file_name() .ok_or(anyhow!("No filename, wat"))? @@ -294,7 +305,7 @@ pub fn scan_with_progress_bar( for entry in dir_read? { let entry: DirEntry = entry?; - let scanned = scan_with_progress_bar(&entry.path(), progress_bar)?; + let scanned = scan_with_progress_bar(&entry.path(), progress_bar, one_filesystem)?; if let Some(scanned) = scanned { children.insert( entry