mirror of
https://github.com/Dummi26/rembackup.git
synced 2025-03-10 05:13:54 +01:00
detect file/directory removal and replacing a file with a directory or a directory with a file
also change changes/actions print style for brevity
This commit is contained in:
parent
90f0a8ded4
commit
f4cd0851dd
@ -49,7 +49,3 @@ Note 2: `~/index` and `/mnt/backup` don't need to exist yet - they will be creat
|
|||||||
If this is the first backup, you can try to maximize the speed of `/mnt/backup`.
|
If this is the first backup, you can try to maximize the speed of `/mnt/backup`.
|
||||||
If you want remote backups, you should probably connect the server's disk directly to your computer.
|
If you want remote backups, you should probably connect the server's disk directly to your computer.
|
||||||
The backups after the initial one will be a lot faster, so you can switch to remote backups after this.
|
The backups after the initial one will be a lot faster, so you can switch to remote backups after this.
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
detect files that have been removed
|
|
||||||
|
@ -53,6 +53,24 @@ pub fn apply_indexchanges_int(
|
|||||||
}
|
}
|
||||||
fs::write(&index.join(file), index_file.save())?;
|
fs::write(&index.join(file), index_file.save())?;
|
||||||
}
|
}
|
||||||
|
IndexChange::RemoveFile(file) => {
|
||||||
|
let i = index.join(file);
|
||||||
|
let t = target.join(file);
|
||||||
|
if let Err(e) = fs::remove_file(&t) {
|
||||||
|
eprintln!("\n[warn] couldn't remove file {t:?}, keeping index file {i:?}: {e:?}\n If this error keeps appearing, check if the file was deleted on the target system but still exists in the index. if yes, consider manually deleting it.");
|
||||||
|
} else {
|
||||||
|
fs::remove_file(i)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IndexChange::RemoveDir(dir) => {
|
||||||
|
let i = index.join(dir);
|
||||||
|
let t = target.join(dir);
|
||||||
|
if let Err(e) = fs::remove_dir_all(&t) {
|
||||||
|
eprintln!("\n[warn] couldn't remove directory {t:?}, keeping index files under {i:?}: {e:?}\n If this error keeps appearing, check if the directory was deleted on the target system but still exists in the index. if yes, consider manually deleting it.");
|
||||||
|
} else {
|
||||||
|
fs::remove_dir_all(i)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let i = i + 1;
|
let i = i + 1;
|
||||||
|
@ -8,4 +8,8 @@ pub enum IndexChange {
|
|||||||
AddDir(PathBuf),
|
AddDir(PathBuf),
|
||||||
/// Add or update a file
|
/// Add or update a file
|
||||||
AddFile(PathBuf, IndexFile),
|
AddFile(PathBuf, IndexFile),
|
||||||
|
/// Remove a file
|
||||||
|
RemoveFile(PathBuf),
|
||||||
|
/// Remove a directory (recursively)
|
||||||
|
RemoveDir(PathBuf),
|
||||||
}
|
}
|
||||||
|
21
src/main.rs
21
src/main.rs
@ -29,25 +29,28 @@ fn main() {
|
|||||||
if changes.is_empty() {
|
if changes.is_empty() {
|
||||||
eprintln!("done! found no changes.");
|
eprintln!("done! found no changes.");
|
||||||
} else {
|
} else {
|
||||||
eprintln!("done! found {} changes.", changes.len());
|
eprintln!("done! found {} changes:", changes.len());
|
||||||
// display the changes
|
// display the changes
|
||||||
eprintln!(" - - - - -");
|
|
||||||
for change in &changes {
|
for change in &changes {
|
||||||
match change {
|
match change {
|
||||||
IndexChange::AddDir(v) => eprintln!(" - Add the directory {v:?}"),
|
IndexChange::AddDir(v) => eprintln!(" >> {}", v.display()),
|
||||||
IndexChange::AddFile(v, _) => eprintln!(" - Add the file {v:?}"),
|
IndexChange::AddFile(v, _) => eprintln!(" + {}", v.display()),
|
||||||
|
IndexChange::RemoveFile(v) => eprintln!(" - {}", v.display()),
|
||||||
|
IndexChange::RemoveDir(v) => eprintln!(" [-] {}", v.display()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eprintln!(
|
eprintln!(" - - - - -");
|
||||||
"Press Enter to add these {} changes to the backup.",
|
eprintln!(" >> add directory");
|
||||||
changes.len()
|
eprintln!(" + add/update file");
|
||||||
);
|
eprintln!(" - remove file");
|
||||||
|
eprintln!(" [-] remove directory (and all contents!)");
|
||||||
|
eprintln!("Press Enter to to apply these actions.");
|
||||||
// apply changes
|
// apply changes
|
||||||
if std::io::stdin().read_line(&mut String::new()).is_ok() {
|
if std::io::stdin().read_line(&mut String::new()).is_ok() {
|
||||||
match apply_indexchanges(&args.source, &args.index, &args.target, &changes) {
|
match apply_indexchanges(&args.source, &args.index, &args.target, &changes) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to apply index changes: {e}");
|
eprintln!("Failed to apply: {e}");
|
||||||
exit(30);
|
exit(30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{fs, io, path::Path};
|
use std::{collections::HashMap, fs, io, path::Path};
|
||||||
|
|
||||||
use crate::{indexchanges::IndexChange, indexfile::IndexFile};
|
use crate::{indexchanges::IndexChange, indexfile::IndexFile};
|
||||||
|
|
||||||
@ -14,10 +14,15 @@ pub fn perform_index_diff(source: &Path, index: &Path) -> io::Result<Vec<IndexCh
|
|||||||
Ok(changes)
|
Ok(changes)
|
||||||
}
|
}
|
||||||
fn rec(
|
fn rec(
|
||||||
|
// location of source files
|
||||||
source: &Path,
|
source: &Path,
|
||||||
|
// relative path used on this iteration
|
||||||
rel_path: &Path,
|
rel_path: &Path,
|
||||||
|
// location of the index
|
||||||
index_files: &Path,
|
index_files: &Path,
|
||||||
|
// list of changes to be made
|
||||||
changes: &mut Vec<IndexChange>,
|
changes: &mut Vec<IndexChange>,
|
||||||
|
// if the index is part of `source`, where exactly is it?
|
||||||
inner_index: Option<&Path>,
|
inner_index: Option<&Path>,
|
||||||
) -> Result<(), io::Error> {
|
) -> Result<(), io::Error> {
|
||||||
if let Some(ii) = &inner_index {
|
if let Some(ii) = &inner_index {
|
||||||
@ -27,13 +32,31 @@ fn rec(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !index_files.join(rel_path).try_exists()? {
|
// used to find removals
|
||||||
|
let index_rel_path = index_files.join(rel_path);
|
||||||
|
let mut index_entries = match fs::read_dir(&index_rel_path) {
|
||||||
|
Err(_) => {
|
||||||
changes.push(IndexChange::AddDir(rel_path.to_path_buf()));
|
changes.push(IndexChange::AddDir(rel_path.to_path_buf()));
|
||||||
|
HashMap::new()
|
||||||
}
|
}
|
||||||
for entry in fs::read_dir(source.join(rel_path))? {
|
Ok(e) => e
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|v| v.ok())
|
||||||
|
.map(|v| Ok((v.file_name(), v.file_type()?.is_dir())))
|
||||||
|
.collect::<Result<_, io::Error>>()?,
|
||||||
|
};
|
||||||
|
// compare source files with index
|
||||||
|
let source_files = fs::read_dir(source.join(rel_path))?.collect::<Vec<_>>();
|
||||||
|
// find changes/adds
|
||||||
|
for entry in source_files {
|
||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
let metadata = entry.metadata()?;
|
let metadata = entry.metadata()?;
|
||||||
|
let in_index_and_is_dir = index_entries.remove(&entry.file_name());
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
|
if let Some(false) = in_index_and_is_dir {
|
||||||
|
// is dir, but was file -> remove file
|
||||||
|
changes.push(IndexChange::RemoveFile(rel_path.join(entry.file_name())));
|
||||||
|
}
|
||||||
rec(
|
rec(
|
||||||
source,
|
source,
|
||||||
&rel_path.join(entry.file_name()),
|
&rel_path.join(entry.file_name()),
|
||||||
@ -42,6 +65,10 @@ fn rec(
|
|||||||
inner_index,
|
inner_index,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
|
if let Some(true) = in_index_and_is_dir {
|
||||||
|
// is file, but was dir -> remove dir
|
||||||
|
changes.push(IndexChange::RemoveDir(rel_path.join(entry.file_name())));
|
||||||
|
}
|
||||||
let newif = IndexFile::new_from_metadata(&metadata);
|
let newif = IndexFile::new_from_metadata(&metadata);
|
||||||
let oldif = IndexFile::from_path(&index_files.join(rel_path).join(entry.file_name()));
|
let oldif = IndexFile::from_path(&index_files.join(rel_path).join(entry.file_name()));
|
||||||
match oldif {
|
match oldif {
|
||||||
@ -53,5 +80,13 @@ fn rec(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// removals
|
||||||
|
for (removed_file, is_dir) in index_entries {
|
||||||
|
changes.push(if is_dir {
|
||||||
|
IndexChange::RemoveDir(rel_path.join(removed_file))
|
||||||
|
} else {
|
||||||
|
IndexChange::RemoveFile(rel_path.join(removed_file))
|
||||||
|
});
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user