Only scan one filesystem by default (can configure 'cross_filesystems' if needed)
This commit is contained in:
parent
e8fc448ace
commit
af553d1fed
|
@ -195,10 +195,10 @@ fn main() -> anyhow::Result<()> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
DatmanCommand::InteractiveLabelling { source_name } => {
|
DatmanCommand::InteractiveLabelling { source_name } => {
|
||||||
interactive_labelling_session(Path::new("."), source_name).unwrap();
|
interactive_labelling_session(Path::new("."), source_name)?;
|
||||||
}
|
}
|
||||||
DatmanCommand::InteractiveBrowsing { 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 {
|
DatmanCommand::BackupOne {
|
||||||
source_name,
|
source_name,
|
||||||
|
|
|
@ -147,10 +147,12 @@ pub fn backup_source_to_destination<PT: ProgressTracker>(
|
||||||
SourceDescriptor::DirectorySource {
|
SourceDescriptor::DirectorySource {
|
||||||
hostname: _,
|
hostname: _,
|
||||||
directory,
|
directory,
|
||||||
|
cross_filesystems,
|
||||||
} => {
|
} => {
|
||||||
info!("Looking to backup {} to {}", source_name, dest_name);
|
info!("Looking to backup {} to {}", source_name, dest_name);
|
||||||
info!("Scanning.");
|
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_source_path = desc_path.join(directory);
|
||||||
let absolute_dest_path = desc_path.join(&dest.path);
|
let absolute_dest_path = desc_path.join(&dest.path);
|
||||||
|
|
|
@ -68,15 +68,19 @@ pub fn session(path: &Path, source_name: String) -> anyhow::Result<()> {
|
||||||
.get(&source_name)
|
.get(&source_name)
|
||||||
.ok_or_else(|| anyhow!("Could not find source {:?}!", source_name))?;
|
.ok_or_else(|| anyhow!("Could not find source {:?}!", source_name))?;
|
||||||
|
|
||||||
let directory = match source_descriptor {
|
let (directory, one_filesystem) = match source_descriptor {
|
||||||
SourceDescriptor::DirectorySource { directory, .. } => directory,
|
SourceDescriptor::DirectorySource {
|
||||||
|
directory,
|
||||||
|
cross_filesystems,
|
||||||
|
..
|
||||||
|
} => (directory, !*cross_filesystems),
|
||||||
SourceDescriptor::VirtualSource { .. } => {
|
SourceDescriptor::VirtualSource { .. } => {
|
||||||
bail!("Cannot browse virtual source.");
|
bail!("Cannot browse virtual source.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Scanning source; this might take a little while...");
|
println!("Scanning source; this might take a little while...");
|
||||||
let mut dir_scan: FileTree1<Option<State>> = scan(directory)?
|
let mut dir_scan: FileTree1<Option<State>> = scan(directory, one_filesystem)?
|
||||||
.ok_or_else(|| anyhow!("Empty source."))?
|
.ok_or_else(|| anyhow!("Empty source."))?
|
||||||
.replace_meta(&None);
|
.replace_meta(&None);
|
||||||
|
|
||||||
|
|
|
@ -186,12 +186,13 @@ pub fn interactive_labelling_session(path: &Path, source_name: String) -> anyhow
|
||||||
if let SourceDescriptor::DirectorySource {
|
if let SourceDescriptor::DirectorySource {
|
||||||
hostname,
|
hostname,
|
||||||
directory,
|
directory,
|
||||||
|
cross_filesystems,
|
||||||
} = source
|
} = source
|
||||||
{
|
{
|
||||||
let my_hostname = get_hostname();
|
let my_hostname = get_hostname();
|
||||||
let mut dir_scan = if &my_hostname == hostname {
|
let mut dir_scan = if &my_hostname == hostname {
|
||||||
info!("Scanning source; this might take a little while...");
|
info!("Scanning source; this might take a little while...");
|
||||||
scan(directory)?
|
scan(directory, !*cross_filesystems)?
|
||||||
.ok_or_else(|| anyhow!("Empty source."))?
|
.ok_or_else(|| anyhow!("Empty source."))?
|
||||||
.replace_meta(&None)
|
.replace_meta(&None)
|
||||||
} else {
|
} else {
|
||||||
|
@ -206,10 +207,14 @@ pub fn interactive_labelling_session(path: &Path, source_name: String) -> anyhow
|
||||||
|
|
||||||
// then request to scan
|
// then request to scan
|
||||||
info!("Requesting scan from remote source... (this may take some time)");
|
info!("Requesting scan from remote source... (this may take some time)");
|
||||||
let scan =
|
let scan = backup_source_requester::scanning(
|
||||||
backup_source_requester::scanning(&mut read, &mut write, directory.as_ref())?
|
&mut read,
|
||||||
.ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?
|
&mut write,
|
||||||
.replace_meta(&None);
|
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)?;
|
backup_source_requester::quit(&mut read, &mut write)?;
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,8 @@ pub enum SourceDescriptor {
|
||||||
DirectorySource {
|
DirectorySource {
|
||||||
hostname: String,
|
hostname: String,
|
||||||
directory: PathBuf,
|
directory: PathBuf,
|
||||||
|
#[serde(default)]
|
||||||
|
cross_filesystems: bool,
|
||||||
},
|
},
|
||||||
VirtualSource {
|
VirtualSource {
|
||||||
/// The name of the helper program that will be used to do this backup.
|
/// The name of the helper program that will be used to do this backup.
|
||||||
|
|
|
@ -47,10 +47,12 @@ pub fn scanning<R: Read, W: Write>(
|
||||||
read: &mut R,
|
read: &mut R,
|
||||||
write: &mut W,
|
write: &mut W,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
|
one_filesystem: bool,
|
||||||
) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
|
) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
|
||||||
info!("Scanning.");
|
info!("Scanning.");
|
||||||
write_message(write, &"scan")?;
|
write_message(write, &"scan")?;
|
||||||
write_message(write, &path)?;
|
write_message(write, &path)?;
|
||||||
|
write_message(write, &one_filesystem)?;
|
||||||
write.flush()?;
|
write.flush()?;
|
||||||
let scan_result: Option<FileTree<(), (), (), ()>> = read_message(read)?;
|
let scan_result: Option<FileTree<(), (), (), ()>> = read_message(read)?;
|
||||||
|
|
||||||
|
@ -177,6 +179,7 @@ pub fn backup_remote_source_to_destination<PT: ProgressTracker + Send + 'static>
|
||||||
SourceDescriptor::DirectorySource {
|
SourceDescriptor::DirectorySource {
|
||||||
hostname,
|
hostname,
|
||||||
directory,
|
directory,
|
||||||
|
cross_filesystems,
|
||||||
} => {
|
} => {
|
||||||
let remote_host_descriptor = descriptor
|
let remote_host_descriptor = descriptor
|
||||||
.remote_hosts
|
.remote_hosts
|
||||||
|
@ -198,8 +201,13 @@ pub fn backup_remote_source_to_destination<PT: ProgressTracker + Send + 'static>
|
||||||
|
|
||||||
// then request to scan
|
// then request to scan
|
||||||
info!("Requesting scan... (this may take some time)");
|
info!("Requesting scan... (this may take some time)");
|
||||||
let scan_result = scanning(&mut read, &mut write, directory.as_ref())?
|
let scan_result = scanning(
|
||||||
.ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?;
|
&mut read,
|
||||||
|
&mut write,
|
||||||
|
directory.as_ref(),
|
||||||
|
!*cross_filesystems,
|
||||||
|
)?
|
||||||
|
.ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?;
|
||||||
|
|
||||||
let mut root =
|
let mut root =
|
||||||
label_filter_and_convert(scan_result, descriptor, desc_path, source_name, dest)?
|
label_filter_and_convert(scan_result, descriptor, desc_path, source_name, dest)?
|
||||||
|
|
|
@ -42,7 +42,8 @@ pub fn introduction<R: Read, W: Write>(read: &mut R, write: &mut W) -> anyhow::R
|
||||||
|
|
||||||
pub fn scanning<R: Read, W: Write>(read: &mut R, write: &mut W) -> anyhow::Result<()> {
|
pub fn scanning<R: Read, W: Write>(read: &mut R, write: &mut W) -> anyhow::Result<()> {
|
||||||
let path: PathBuf = read_message(read)?;
|
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_message(write, &scan_result)?;
|
||||||
write.flush()?;
|
write.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -24,7 +24,7 @@ use std::path::Path;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
|
||||||
use log::warn;
|
use log::{info, warn};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub use yama::definitions::FilesystemOwnership;
|
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.
|
/// Scan the filesystem to produce a Tree, using a default progress bar.
|
||||||
pub fn scan(path: &Path) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
|
pub fn scan(path: &Path, one_filesystem: bool) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
|
||||||
let pbar = ProgressBar::with_draw_target(0, ProgressDrawTarget::stdout_with_hz(2));
|
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_style(ProgressStyle::default_spinner().template("{spinner} {pos:7} {msg}"));
|
||||||
pbar.set_message("dir scan");
|
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();
|
pbar.finish_at_current_pos();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -230,6 +232,7 @@ pub fn scan(path: &Path) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
|
||||||
pub fn scan_with_progress_bar(
|
pub fn scan_with_progress_bar(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
progress_bar: &ProgressBar,
|
progress_bar: &ProgressBar,
|
||||||
|
mut one_filesystem: Option<Option<u64>>,
|
||||||
) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
|
) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
|
||||||
let metadata_res = symlink_metadata(path);
|
let metadata_res = symlink_metadata(path);
|
||||||
progress_bar.inc(1);
|
progress_bar.inc(1);
|
||||||
|
@ -249,6 +252,14 @@ pub fn scan_with_progress_bar(
|
||||||
let metadata = metadata_res?;
|
let metadata = metadata_res?;
|
||||||
let filetype = metadata.file_type();
|
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
|
/*let name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
.ok_or(anyhow!("No filename, wat"))?
|
.ok_or(anyhow!("No filename, wat"))?
|
||||||
|
@ -294,7 +305,7 @@ pub fn scan_with_progress_bar(
|
||||||
|
|
||||||
for entry in dir_read? {
|
for entry in dir_read? {
|
||||||
let entry: DirEntry = entry?;
|
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 {
|
if let Some(scanned) = scanned {
|
||||||
children.insert(
|
children.insert(
|
||||||
entry
|
entry
|
||||||
|
|
Loading…
Reference in New Issue