mirror of
				https://github.com/Dummi26/rembackup.git
				synced 2025-10-31 11:26:16 +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
 | ||||||
|         changes.push(IndexChange::AddDir(rel_path.to_path_buf())); |     let index_rel_path = index_files.join(rel_path); | ||||||
|     } |     let mut index_entries = match fs::read_dir(&index_rel_path) { | ||||||
|     for entry in fs::read_dir(source.join(rel_path))? { |         Err(_) => { | ||||||
|  |             changes.push(IndexChange::AddDir(rel_path.to_path_buf())); | ||||||
|  |             HashMap::new() | ||||||
|  |         } | ||||||
|  |         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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Mark
						Mark