Fix atime problem

This commit is contained in:
Dennis Schwerdel 2017-03-29 23:24:26 +02:00 committed by Dennis Schwerdel
parent bbafe64f85
commit 545523e5ce
7 changed files with 115 additions and 13 deletions

View File

@ -76,6 +76,14 @@ pub enum Arguments {
repo_path: String, repo_path: String,
path: String path: String
}, },
Diff {
repo_path_old: String,
backup_name_old: String,
inode_old: Option<String>,
repo_path_new: String,
backup_name_new: String,
inode_new: Option<String>
},
Analyze { Analyze {
repo_path: String repo_path: String
}, },
@ -313,6 +321,11 @@ pub fn parse() -> Arguments {
(@arg REPO: +required "repository path") (@arg REPO: +required "repository path")
(@arg PATH: +required "the file path") (@arg PATH: +required "the file path")
) )
(@subcommand diff =>
(about: "display difference between two backup versions")
(@arg OLD: +required "old repository::backup[::subpath] path")
(@arg NEW: +required "new repository::backup[::subpath] path")
)
(@subcommand config => (@subcommand config =>
(about: "changes the configuration") (about: "changes the configuration")
(@arg REPO: +required "path of the repository") (@arg REPO: +required "path of the repository")
@ -460,6 +473,18 @@ pub fn parse() -> Arguments {
path: args.value_of("PATH").unwrap().to_string() path: args.value_of("PATH").unwrap().to_string()
} }
} }
if let Some(args) = args.subcommand_matches("diff") {
let (repository_old, backup_old, inode_old) = parse_repo_path(args.value_of("OLD").unwrap(), Some(true), None);
let (repository_new, backup_new, inode_new) = parse_repo_path(args.value_of("NEW").unwrap(), Some(true), None);
return Arguments::Diff {
repo_path_old: repository_old.to_string(),
backup_name_old: backup_old.unwrap().to_string(),
inode_old: inode_old.map(|v| v.to_string()),
repo_path_new: repository_new.to_string(),
backup_name_new: backup_new.unwrap().to_string(),
inode_new: inode_new.map(|v| v.to_string()),
}
}
if let Some(args) = args.subcommand_matches("analyze") { if let Some(args) = args.subcommand_matches("analyze") {
let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false)); let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), Some(false), Some(false));
return Arguments::Analyze { return Arguments::Analyze {

View File

@ -95,7 +95,6 @@ fn print_inode(inode: &Inode) {
println!("Permissions: {:3o}", inode.mode); println!("Permissions: {:3o}", inode.mode);
println!("User: {}", inode.user); println!("User: {}", inode.user);
println!("Group: {}", inode.group); println!("Group: {}", inode.group);
println!("Access time: {}", Local.timestamp(inode.access_time, 0).to_rfc2822());
println!("Modification time: {}", Local.timestamp(inode.modify_time, 0).to_rfc2822()); println!("Modification time: {}", Local.timestamp(inode.modify_time, 0).to_rfc2822());
if let Some(ref target) = inode.symlink_target { if let Some(ref target) = inode.symlink_target {
println!("Symlink target: {}", target); println!("Symlink target: {}", target);
@ -425,6 +424,25 @@ pub fn run() {
println!("{}", format_inode_one_line(&inode)); println!("{}", format_inode_one_line(&inode));
} }
}, },
Arguments::Diff{repo_path_old, backup_name_old, inode_old, repo_path_new, backup_name_new, inode_new} => {
if repo_path_old != repo_path_new {
error!("Can only run diff on same repository");
exit(2)
}
let mut repo = open_repository(&repo_path_old);
let backup_old = get_backup(&repo, &backup_name_old);
let backup_new = get_backup(&repo, &backup_name_new);
let inode1 = checked(repo.get_backup_inode(&backup_old, inode_old.unwrap_or_else(|| "/".to_string())), "load subpath inode");
let inode2 = checked(repo.get_backup_inode(&backup_new, inode_new.unwrap_or_else(|| "/".to_string())), "load subpath inode");
let diffs = checked(repo.find_differences(&inode1, &inode2), "find differences");
for diff in diffs {
println!("{} {:?}", match diff.0 {
DiffType::Add => "add",
DiffType::Mod => "mod",
DiffType::Del => "del"
}, diff.1);
}
},
Arguments::Config{repo_path, bundle_size, chunker, compression, encryption, hash} => { Arguments::Config{repo_path, bundle_size, chunker, compression, encryption, hash} => {
let mut repo = open_repository(&repo_path); let mut repo = open_repository(&repo_path);
if let Some(bundle_size) = bundle_size { if let Some(bundle_size) = bundle_size {

View File

@ -87,7 +87,7 @@ impl FuseInode {
ino: self.num, ino: self.num,
size: self.inode.size, size: self.inode.size,
blocks: self.inode.size / 512, blocks: self.inode.size / 512,
atime: Timespec::new(self.inode.access_time, 0), atime: Timespec::new(self.inode.modify_time, 0),
mtime: Timespec::new(self.inode.modify_time, 0), mtime: Timespec::new(self.inode.modify_time, 0),
ctime: Timespec::new(0, 0), ctime: Timespec::new(0, 0),
crtime: Timespec::new(0, 0), crtime: Timespec::new(0, 0),

View File

@ -1,7 +1,7 @@
pub use ::util::*; pub use ::util::*;
pub use ::bundledb::{BundleReader, BundleMode, BundleWriter, BundleInfo, BundleId, BundleDbError, BundleDb, BundleWriterError}; pub use ::bundledb::{BundleReader, BundleMode, BundleWriter, BundleInfo, BundleId, BundleDbError, BundleDb, BundleWriterError};
pub use ::chunker::{ChunkerType, Chunker, ChunkerStatus, IChunker, ChunkerError}; pub use ::chunker::{ChunkerType, Chunker, ChunkerStatus, IChunker, ChunkerError};
pub use ::repository::{Repository, Backup, Config, RepositoryError, RepositoryInfo, Inode, FileType, RepositoryIntegrityError, BackupFileError, BackupError, BackupOptions, BundleAnalysis, FileContents}; pub use ::repository::{Repository, Backup, Config, RepositoryError, RepositoryInfo, Inode, FileType, RepositoryIntegrityError, BackupFileError, BackupError, BackupOptions, BundleAnalysis, FileContents, DiffType};
pub use ::index::{Index, Location, IndexError}; pub use ::index::{Index, Location, IndexError};
pub use ::mount::FuseFilesystem; pub use ::mount::FuseFilesystem;

View File

@ -31,6 +31,11 @@ pub struct BackupOptions {
} }
pub enum DiffType {
Add, Mod, Del
}
impl Repository { impl Repository {
pub fn get_backups(&self) -> Result<HashMap<String, Backup>, RepositoryError> { pub fn get_backups(&self) -> Result<HashMap<String, Backup>, RepositoryError> {
Ok(try!(Backup::get_all_from(&self.crypto.lock().unwrap(), &self.backups_path))) Ok(try!(Backup::get_all_from(&self.crypto.lock().unwrap(), &self.backups_path)))
@ -159,7 +164,7 @@ impl Repository {
let meta_size = 1000; // add 1000 for encoded metadata let meta_size = 1000; // add 1000 for encoded metadata
backup.total_data_size += inode.size + meta_size; backup.total_data_size += inode.size + meta_size;
if let Some(ref_inode) = reference { if let Some(ref_inode) = reference {
if !ref_inode.is_unchanged(&inode) { if !ref_inode.is_same_meta_quick(&inode) {
backup.changed_data_size += inode.size + meta_size; backup.changed_data_size += inode.size + meta_size;
} }
} else { } else {
@ -295,4 +300,52 @@ impl Repository {
versions.sort_by_key(|v| v.1.modify_time); versions.sort_by_key(|v| v.1.modify_time);
Ok(versions) Ok(versions)
} }
#[inline]
fn find_differences_recurse(&mut self, inode1: &Inode, inode2: &Inode, path: PathBuf, diffs: &mut Vec<(DiffType, PathBuf)>) -> Result<(), RepositoryError> {
if !inode1.is_same_meta(inode2) || inode1.contents != inode2.contents {
diffs.push((DiffType::Mod, path.clone()));
}
if let Some(ref children1) = inode1.children {
if let Some(ref children2) = inode2.children {
for name in children1.keys() {
if !children2.contains_key(name) {
diffs.push((DiffType::Del, path.join(name)));
}
}
} else {
for name in children1.keys() {
diffs.push((DiffType::Del, path.join(name)));
}
}
}
if let Some(ref children2) = inode2.children {
if let Some(ref children1) = inode1.children {
for (name, chunks2) in children2 {
if let Some(chunks1) = children1.get(name) {
if chunks1 != chunks2 {
let inode1 = try!(self.get_inode(chunks1));
let inode2 = try!(self.get_inode(chunks2));
try!(self.find_differences_recurse(&inode1, &inode2, path.join(name), diffs));
}
} else {
diffs.push((DiffType::Add, path.join(name)));
}
}
} else {
for name in children2.keys() {
diffs.push((DiffType::Add, path.join(name)));
}
}
}
Ok(())
}
#[inline]
pub fn find_differences(&mut self, inode1: &Inode, inode2: &Inode) -> Result<Vec<(DiffType, PathBuf)>, RepositoryError> {
let mut diffs = vec![];
let path = PathBuf::from("/");
try!(self.find_differences_recurse(inode1, inode2, path, &mut diffs));
Ok(diffs)
}
} }

View File

@ -111,9 +111,9 @@ pub struct Inode {
pub mode: u32, pub mode: u32,
pub user: u32, pub user: u32,
pub group: u32, pub group: u32,
pub access_time: i64, pub __old_access_time: i64,
pub modify_time: i64, pub modify_time: i64,
pub create_time: i64, pub __old_create_time: i64,
pub symlink_target: Option<String>, pub symlink_target: Option<String>,
pub contents: Option<FileContents>, pub contents: Option<FileContents>,
pub children: Option<BTreeMap<String, ChunkList>> pub children: Option<BTreeMap<String, ChunkList>>
@ -127,9 +127,9 @@ impl Default for Inode {
mode: 0o644, mode: 0o644,
user: 1000, user: 1000,
group: 1000, group: 1000,
access_time: 0, __old_access_time: 0,
modify_time: 0, modify_time: 0,
create_time: 0, __old_create_time: 0,
symlink_target: None, symlink_target: None,
contents: None, contents: None,
children: None children: None
@ -143,9 +143,9 @@ serde_impl!(Inode(u8) {
mode: u32 => 3, mode: u32 => 3,
user: u32 => 4, user: u32 => 4,
group: u32 => 5, group: u32 => 5,
access_time: i64 => 6, __old_access_time: i64 => 6,
modify_time: i64 => 7, modify_time: i64 => 7,
create_time: i64 => 8, __old_create_time: i64 => 8,
symlink_target: Option<String> => 9, symlink_target: Option<String> => 9,
contents: Option<FileContents> => 10, contents: Option<FileContents> => 10,
children: BTreeMap<String, ChunkList> => 11 children: BTreeMap<String, ChunkList> => 11
@ -213,7 +213,13 @@ impl Inode {
Ok(file) Ok(file)
} }
pub fn is_unchanged(&self, other: &Inode) -> bool { pub fn is_same_meta(&self, other: &Inode) -> bool {
self.file_type == other.file_type && self.size == other.size && self.mode == other.mode
&& self.user == other.user && self.group == other.group && self.name == other.name
&& self.modify_time == other.modify_time && self.symlink_target == other.symlink_target
}
pub fn is_same_meta_quick(&self, other: &Inode) -> bool {
self.modify_time == other.modify_time self.modify_time == other.modify_time
&& self.file_type == other.file_type && self.file_type == other.file_type
&& self.size == other.size && self.size == other.size
@ -236,7 +242,7 @@ impl Repository {
let mut inode = try!(Inode::get_from(path.as_ref())); let mut inode = try!(Inode::get_from(path.as_ref()));
if inode.file_type == FileType::File && inode.size > 0 { if inode.file_type == FileType::File && inode.size > 0 {
if let Some(reference) = reference { if let Some(reference) = reference {
if reference.is_unchanged(&inode) { if reference.is_same_meta_quick(&inode) {
inode.contents = reference.contents.clone(); inode.contents = reference.contents.clone();
return Ok(inode) return Ok(inode)
} }

View File

@ -22,7 +22,7 @@ use std::io::Write;
pub use self::error::RepositoryError; pub use self::error::RepositoryError;
pub use self::config::Config; pub use self::config::Config;
pub use self::metadata::{Inode, FileType, FileContents}; pub use self::metadata::{Inode, FileType, FileContents};
pub use self::backup::{BackupError, BackupOptions}; pub use self::backup::{BackupError, BackupOptions, DiffType};
pub use self::backup_file::{Backup, BackupFileError}; pub use self::backup_file::{Backup, BackupFileError};
pub use self::integrity::RepositoryIntegrityError; pub use self::integrity::RepositoryIntegrityError;
pub use self::info::{RepositoryInfo, BundleAnalysis}; pub use self::info::{RepositoryInfo, BundleAnalysis};