This commit is contained in:
Dennis Schwerdel 2018-08-16 11:32:49 +02:00
parent 46e94bc7a6
commit 381bdf654d
4 changed files with 133 additions and 137 deletions

View File

@ -4,10 +4,17 @@ use super::*;
use std::path::{Path, PathBuf};
pub use ::repository::ModuleIntegrityReport;
quick_error!{
#[derive(Debug)]
pub enum InodeIntegrityError {
BackupRead(path: PathBuf, err: Box<RepositoryError>) {
cause(err)
description(tr!("Backup unreadable"))
display("{}", tr_format!("Backup unreadable: {:?}\n\tcaused by: {}", path, err))
}
BrokenInode(path: PathBuf, err: Box<RepositoryError>) {
cause(err)
description(tr!("Broken inode"))
@ -27,32 +34,32 @@ pub trait RepositoryIntegrityIO {
) -> Result<(), RepositoryError>;
fn check_subtree(&mut self, path: PathBuf, chunks: &[Chunk], checked: &mut Bitmap,
lock: &OnlineMode
) -> Result<(), RepositoryError>;
errors: &mut Vec<InodeIntegrityError>, lock: &OnlineMode
);
fn check_backup_inode(&mut self, inode: &Inode, path: &Path, lock: &OnlineMode
) -> ModuleIntegrityReport<InodeIntegrityError>;
fn check_backup(&mut self, name: &str, backup: &mut BackupFile, lock: &OnlineMode
) -> ModuleIntegrityReport<InodeIntegrityError>;
fn check_backups(&mut self, lock: &OnlineMode) -> ModuleIntegrityReport<InodeIntegrityError>;
fn check_and_repair_subtree(&mut self, path: PathBuf, chunks: &[Chunk], checked: &mut Bitmap,
lock: &BackupMode
errors: &mut Vec<InodeIntegrityError>, lock: &BackupMode
) -> Result<Option<ChunkList>, RepositoryError>;
fn evacuate_broken_backup(&self, name: &str, lock: &BackupMode) -> Result<(), RepositoryError>;
fn check_backup_inode(&mut self, name: &str, backup: &mut BackupFile, path: &Path,
lock: &OnlineMode
) -> Result<(), RepositoryError>;
fn check_and_repair_backup_inode(&mut self, name: &str, backup: &mut BackupFile, path: &Path,
lock: &BackupMode,
) -> Result<(), RepositoryError>;
fn check_backup(&mut self, name: &str, backup: &mut BackupFile, lock: &OnlineMode
) -> Result<(), RepositoryError>;
) -> Result<ModuleIntegrityReport<InodeIntegrityError>, RepositoryError>;
fn check_and_repair_backup(&mut self, name: &str, backup: &mut BackupFile, lock: &BackupMode
) -> Result<(), RepositoryError>;
) -> Result<ModuleIntegrityReport<InodeIntegrityError>, RepositoryError>;
fn check_backups(&mut self, lock: &OnlineMode) -> Result<(), RepositoryError>;
fn check_and_repair_backups(&mut self, lock: &BackupMode) -> Result<(), RepositoryError>;
fn check_and_repair_backups(&mut self, lock: &BackupMode
) -> Result<ModuleIntegrityReport<InodeIntegrityError>, RepositoryError>;
}
@ -78,31 +85,92 @@ impl RepositoryIntegrityIO for Repository {
}
fn check_subtree(&mut self, path: PathBuf, chunks: &[Chunk], checked: &mut Bitmap,
lock: &OnlineMode,
) -> Result<(), RepositoryError> {
errors: &mut Vec<InodeIntegrityError>, lock: &OnlineMode
) {
let mut modified = false;
match self.mark_chunks(checked, chunks, false) {
Ok(false) => return Ok(()),
Ok(false) => return,
Ok(true) => (),
Err(err) => return Err(InodeIntegrityError::BrokenInode(path, Box::new(err)).into()),
Err(err) => {
errors.push(InodeIntegrityError::BrokenInode(path, Box::new(err)));
return
},
}
let mut inode = try!(self.get_inode(chunks, lock));
let mut inode = match self.get_inode(chunks, lock) {
Ok(inode) => inode,
Err(err) => {
errors.push(InodeIntegrityError::BrokenInode(path, Box::new(err)));
return
}
};
// Mark the content chunks as used
if let Err(err) = self.check_inode_contents(&inode, checked, lock) {
return Err(InodeIntegrityError::MissingInodeData(path, Box::new(err)).into());
errors.push(InodeIntegrityError::MissingInodeData(path, Box::new(err)));
return
}
// Put children in to do
if let Some(ref mut children) = inode.children {
for (name, chunks) in children.iter_mut() {
try!(self.check_subtree(path.join(name), chunks, checked, lock));
self.check_subtree(path.join(name), chunks, checked, errors, lock);
}
}
try!(self.mark_chunks(checked, chunks, true));
Ok(())
self.mark_chunks(checked, chunks, true).unwrap();
}
fn check_backup_inode(&mut self, inode: &Inode, path: &Path, lock: &OnlineMode
) -> ModuleIntegrityReport<InodeIntegrityError> {
tr_info!("Checking inode...");
let mut report = ModuleIntegrityReport { errors_unfixed: vec![], errors_fixed: vec![] };
let mut checked = self.get_chunk_marker();
if let Err(err) = self.check_inode_contents(inode, &mut checked, lock) {
report.errors_unfixed.push(InodeIntegrityError::MissingInodeData(path.to_path_buf(), Box::new(err)));
}
if let Some(ref children) = inode.children {
for (name, chunks) in children.iter() {
self.check_subtree(path.join(name), chunks, &mut checked, &mut report.errors_unfixed, lock);
}
}
report
}
#[inline]
fn check_backup(&mut self, name: &str, backup: &mut BackupFile, lock: &OnlineMode,
) -> ModuleIntegrityReport<InodeIntegrityError> {
tr_info!("Checking backup...");
let mut checked = self.get_chunk_marker();
let mut report = ModuleIntegrityReport { errors_unfixed: vec![], errors_fixed: vec![] };
self.check_subtree(Path::new("").to_path_buf(), &backup.root, &mut checked, &mut report.errors_unfixed, lock);
report
}
fn check_backups(&mut self, lock: &OnlineMode) -> ModuleIntegrityReport<InodeIntegrityError> {
tr_info!("Checking backups...");
let mut checked = self.get_chunk_marker();
let mut report = ModuleIntegrityReport { errors_unfixed: vec![], errors_fixed: vec![] };
let backup_map = match self.get_all_backups() {
Ok(backup_map) => backup_map,
Err(RepositoryError::BackupFile(BackupFileError::PartialBackupsList(backup_map,
failed))) => {
tr_warn!("Some backups could not be read, ignoring them");
for path in &failed {
report.errors_unfixed.push(InodeIntegrityError::BackupRead(path.to_path_buf(),
Box::new(RepositoryError::BackupFile(BackupFileError::PartialBackupsList(backup_map.clone(), failed.clone())))
))
}
backup_map
},
_ => return report
};
for (name, mut backup) in ProgressIter::new(tr!("checking backups"), backup_map.len(), backup_map.into_iter()) {
let path = format!("{}::", name);
self.check_subtree(Path::new(&path).to_path_buf(), &backup.root,
&mut checked, &mut report.errors_unfixed, lock);
}
report
}
fn check_and_repair_subtree(&mut self, path: PathBuf, chunks: &[Chunk], checked: &mut Bitmap,
lock: &BackupMode,
errors: &mut Vec<InodeIntegrityError>, lock: &BackupMode,
) -> Result<Option<ChunkList>, RepositoryError> {
let mut modified = false;
match self.mark_chunks(checked, chunks, false) {
@ -113,12 +181,7 @@ impl RepositoryIntegrityIO for Repository {
let mut inode = try!(self.get_inode(chunks, lock.as_online()));
// Mark the content chunks as used
if let Err(err) = self.check_inode_contents(&inode, checked, lock.as_online()) {
tr_warn!(
"Problem detected: data of {:?} is corrupt\n\tcaused by: {}",
path,
err
);
tr_info!("Removing inode data");
errors.push(InodeIntegrityError::MissingInodeData(path.clone(), Box::new(err)));
inode.data = Some(FileData::Inline(vec![].into()));
inode.size = 0;
modified = true;
@ -127,19 +190,14 @@ impl RepositoryIntegrityIO for Repository {
if let Some(ref mut children) = inode.children {
let mut removed = vec![];
for (name, chunks) in children.iter_mut() {
match self.check_and_repair_subtree(path.join(name), chunks, checked, lock) {
match self.check_and_repair_subtree(path.join(name), chunks, checked, errors, lock) {
Ok(None) => (),
Ok(Some(c)) => {
*chunks = c;
modified = true;
}
Err(err) => {
tr_warn!(
"Problem detected: inode {:?} is corrupt\n\tcaused by: {}",
path.join(name),
err
);
tr_info!("Removing broken inode from backup");
errors.push(InodeIntegrityError::BrokenInode(path.join(name), Box::new(err)));
removed.push(name.to_string());
modified = true;
}
@ -178,42 +236,17 @@ impl RepositoryIntegrityIO for Repository {
Ok(())
}
fn check_backup_inode(&mut self, name: &str, backup: &mut BackupFile, path: &Path,
lock: &OnlineMode
) -> Result<(), RepositoryError> {
tr_info!("Checking inode...");
let mut checked = self.get_chunk_marker();
let mut inodes = try!(self.get_backup_path(backup, path, lock));
let mut inode = inodes.pop().unwrap();
let mut modified = false;
if let Err(err) = self.check_inode_contents(&inode, &mut checked, lock) {
return Err(
InodeIntegrityError::MissingInodeData(path.to_path_buf(), Box::new(err)).into()
);
}
if let Some(ref mut children) = inode.children {
for (name, chunks) in children.iter_mut() {
try!(self.check_subtree(path.join(name), chunks, &mut checked, lock));
}
}
Ok(())
}
fn check_and_repair_backup_inode(&mut self, name: &str, backup: &mut BackupFile, path: &Path,
lock: &BackupMode
) -> Result<(), RepositoryError> {
) -> Result<ModuleIntegrityReport<InodeIntegrityError>, RepositoryError> {
tr_info!("Checking inode...");
let mut checked = self.get_chunk_marker();
let mut inodes = try!(self.get_backup_path(backup, path, lock.as_online()));
let mut inode = inodes.pop().unwrap();
let mut modified = false;
let mut errors = vec![];
if let Err(err) = self.check_inode_contents(&inode, &mut checked, lock.as_online()) {
tr_warn!(
"Problem detected: data of {:?} is corrupt\n\tcaused by: {}",
path,
err
);
tr_info!("Removing inode data");
errors.push(InodeIntegrityError::MissingInodeData(path.to_path_buf(), Box::new(err)));
inode.data = Some(FileData::Inline(vec![].into()));
inode.size = 0;
modified = true;
@ -221,19 +254,14 @@ impl RepositoryIntegrityIO for Repository {
if let Some(ref mut children) = inode.children {
let mut removed = vec![];
for (name, chunks) in children.iter_mut() {
match self.check_and_repair_subtree(path.join(name), chunks, &mut checked, lock) {
match self.check_and_repair_subtree(path.join(name), chunks, &mut checked, &mut errors, lock) {
Ok(None) => (),
Ok(Some(c)) => {
*chunks = c;
modified = true;
}
Err(err) => {
tr_warn!(
"Problem detected: inode {:?} is corrupt\n\tcaused by: {}",
path.join(name),
err
);
tr_info!("Removing broken inode from backup");
errors.push(InodeIntegrityError::BrokenInode(path.join(name), Box::new(err)));
removed.push(name.to_string());
modified = true;
}
@ -256,25 +284,17 @@ impl RepositoryIntegrityIO for Repository {
try!(self.evacuate_broken_backup(name, lock));
try!(self.save_backup(backup, name, lock));
}
Ok(())
}
#[inline]
fn check_backup(&mut self, name: &str, backup: &mut BackupFile, lock: &OnlineMode,
) -> Result<(), RepositoryError> {
tr_info!("Checking backup...");
let mut checked = self.get_chunk_marker();
try!(self.check_subtree(Path::new("").to_path_buf(), &backup.root, &mut checked, lock));
Ok(())
Ok(ModuleIntegrityReport{errors_unfixed: vec![], errors_fixed: errors})
}
#[inline]
fn check_and_repair_backup(&mut self, name: &str, backup: &mut BackupFile, lock: &BackupMode,
) -> Result<(), RepositoryError> {
) -> Result<ModuleIntegrityReport<InodeIntegrityError>, RepositoryError> {
tr_info!("Checking backup...");
let mut checked = self.get_chunk_marker();
let mut errors = vec![];
match self.check_and_repair_subtree(Path::new("").to_path_buf(),
&backup.root, &mut checked, lock
&backup.root, &mut checked, &mut errors, lock
) {
Ok(None) => (),
Ok(Some(chunks)) => {
@ -285,43 +305,18 @@ impl RepositoryIntegrityIO for Repository {
try!(self.save_backup(backup, name, lock));
}
Err(err) => {
tr_warn!(
"The root of the backup {} has been corrupted\n\tcaused by: {}",
name,
err
);
errors.push(InodeIntegrityError::BrokenInode(PathBuf::from("/"), Box::new(err)));
try!(self.evacuate_broken_backup(name, lock));
}
}
Ok(())
Ok(ModuleIntegrityReport{errors_unfixed: vec![], errors_fixed: errors})
}
fn check_backups(&mut self, lock: &OnlineMode) -> Result<(), RepositoryError> {
tr_info!("Checking backups...");
let mut checked = self.get_chunk_marker();
let backup_map = match self.get_all_backups() {
Ok(backup_map) => backup_map,
Err(RepositoryError::BackupFile(BackupFileError::PartialBackupsList(backup_map,
_failed))) => {
tr_warn!("Some backups could not be read, ignoring them");
backup_map
}
Err(err) => return Err(err),
};
for (name, mut backup) in
ProgressIter::new(tr!("checking backups"), backup_map.len(), backup_map.into_iter())
{
let path = format!("{}::", name);
try!(self.check_subtree(Path::new(&path).to_path_buf(), &backup.root,
&mut checked, lock));
}
Ok(())
}
fn check_and_repair_backups(&mut self, lock: &BackupMode) -> Result<(), RepositoryError> {
fn check_and_repair_backups(&mut self, lock: &BackupMode
) -> Result<ModuleIntegrityReport<InodeIntegrityError>, RepositoryError> {
tr_info!("Checking backups...");
let mut checked = self.get_chunk_marker();
let mut errors = vec![];
let backup_map = match self.get_all_backups() {
Ok(backup_map) => backup_map,
Err(RepositoryError::BackupFile(BackupFileError::PartialBackupsList(backup_map,
@ -339,6 +334,7 @@ impl RepositoryIntegrityIO for Repository {
Path::new(&path).to_path_buf(),
&backup.root,
&mut checked,
&mut errors,
lock
) {
Ok(None) => (),
@ -350,15 +346,11 @@ impl RepositoryIntegrityIO for Repository {
try!(self.save_backup(&backup, &name, lock));
}
Err(err) => {
tr_warn!(
"The root of the backup {} has been corrupted\n\tcaused by: {}",
name,
err
);
errors.push(InodeIntegrityError::BrokenInode(PathBuf::from(format!("{}::/", name)), Box::new(err)));
try!(self.evacuate_broken_backup(&name, lock));
}
}
}
Ok(())
Ok(ModuleIntegrityReport{errors_unfixed: vec![], errors_fixed: errors})
}
}

View File

@ -321,7 +321,11 @@ impl BackupRepository {
})
}
pub fn check(&mut self, options: CheckOptions) -> Result<(), RepositoryError> {
pub fn check(&mut self, options: &CheckOptions) -> Result<(), RepositoryError> {
self.0.online_mode(|r, l| {
r.check(options.index, options.bundles, options.bundle_data, l);
Ok(())
});
unimplemented!()
//TODO: implement
}

View File

@ -827,7 +827,7 @@ pub fn run() -> Result<(), ErrorCode> {
options.all_backups();
}
checked!(
repo.check(options),
repo.check(&options),
"check repository",
ErrorCode::CheckRun
);

View File

@ -46,15 +46,15 @@ quick_error!{
}
pub struct ModuleIntegrityReport {
pub errors_fixed: Vec<IntegrityError>,
pub errors_unfixed: Vec<IntegrityError>
pub struct ModuleIntegrityReport<T> {
pub errors_fixed: Vec<T>,
pub errors_unfixed: Vec<T>
}
pub struct IntegrityReport {
pub bundle_map: Option<ModuleIntegrityReport>,
pub index: Option<ModuleIntegrityReport>,
pub bundles: Option<ModuleIntegrityReport>
pub bundle_map: Option<ModuleIntegrityReport<IntegrityError>>,
pub index: Option<ModuleIntegrityReport<IntegrityError>>,
pub bundles: Option<ModuleIntegrityReport<IntegrityError>>
}
@ -83,7 +83,7 @@ impl Repository {
Ok(new)
}
pub fn check_bundle_map(&mut self) -> ModuleIntegrityReport {
pub fn check_bundle_map(&mut self) -> ModuleIntegrityReport<IntegrityError> {
tr_info!("Checking bundle map...");
let mut errors = vec![];
for (_id, bundle_id) in self.bundle_map.bundles() {
@ -120,7 +120,7 @@ impl Repository {
self.save_bundle_map(lock.as_localwrite())
}
pub fn check_and_repair_bundle_map(&mut self, lock: &OnlineMode) -> Result<ModuleIntegrityReport, RepositoryError> {
pub fn check_and_repair_bundle_map(&mut self, lock: &OnlineMode) -> Result<ModuleIntegrityReport<IntegrityError>, RepositoryError> {
let mut report = self.check_bundle_map();
if !report.errors_unfixed.is_empty() {
try!(self.rebuild_bundle_map(lock));
@ -183,7 +183,7 @@ impl Repository {
}
#[inline]
pub fn check_index(&mut self, lock: &ReadonlyMode) -> ModuleIntegrityReport {
pub fn check_index(&mut self, lock: &ReadonlyMode) -> ModuleIntegrityReport<IntegrityError> {
tr_info!("Checking index integrity...");
let mut errors: Vec<IntegrityError> = self.index.check().into_iter().map(IntegrityError::Index).collect();
tr_info!("Checking index entries...");
@ -191,7 +191,7 @@ impl Repository {
ModuleIntegrityReport { errors_fixed: vec![], errors_unfixed: errors }
}
pub fn check_and_repair_index(&mut self, lock: &OnlineMode) -> Result<ModuleIntegrityReport, RepositoryError> {
pub fn check_and_repair_index(&mut self, lock: &OnlineMode) -> Result<ModuleIntegrityReport<IntegrityError>, RepositoryError> {
let mut report = self.check_index(lock.as_readonly());
if !report.errors_unfixed.is_empty() {
try!(self.rebuild_index(lock));
@ -201,7 +201,7 @@ impl Repository {
}
#[inline]
fn check_bundles_internal(&mut self, full: bool, lock: &OnlineMode) -> (ModuleIntegrityReport, Vec<BundleId>) {
fn check_bundles_internal(&mut self, full: bool, lock: &OnlineMode) -> (ModuleIntegrityReport<IntegrityError>, Vec<BundleId>) {
tr_info!("Checking bundle integrity...");
let mut errors = vec![];
let mut bundles = vec![];
@ -213,11 +213,11 @@ impl Repository {
}
#[inline]
pub fn check_bundles(&mut self, full: bool, lock: &OnlineMode) -> ModuleIntegrityReport {
pub fn check_bundles(&mut self, full: bool, lock: &OnlineMode) -> ModuleIntegrityReport<IntegrityError> {
self.check_bundles_internal(full, lock).0
}
pub fn check_and_repair_bundles(&mut self, full: bool, lock: &VacuumMode) -> Result<ModuleIntegrityReport, RepositoryError> {
pub fn check_and_repair_bundles(&mut self, full: bool, lock: &VacuumMode) -> Result<ModuleIntegrityReport<IntegrityError>, RepositoryError> {
let (mut report, bundles) = self.check_bundles_internal(full, lock.as_online());
if !report.errors_unfixed.is_empty() {
try!(self.bundles.repair(lock, &bundles));