Skip to content

feat: count unreadable source files during backup - #561

Open
BradKollmyer wants to merge 2 commits into
rustic-rs:mainfrom
BradKollmyer:fix/backup-unreadable-source-errors
Open

feat: count unreadable source files during backup#561
BradKollmyer wants to merge 2 commits into
rustic-rs:mainfrom
BradKollmyer:fix/backup-unreadable-source-errors

Conversation

@BradKollmyer

@BradKollmyer BradKollmyer commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • count source scan and archival errors instead of only logging them
  • report those errors through Progress::error (scan / archival)
  • attach the source path on local walk/open failures
  • expose a SnapshotSummary.error_count for the just-completed backup

Why

restic returns exit code 3 when some source files cannot be read, and still creates a snapshot of the remaining files. rustic currently ignores those errors and exits 0, so automation cannot detect incomplete backups.

Validation

  • cargo test --test integration test_backup_unreadable_file_sets_error_count (unix; chmod 000 file)
  • cargo fmt --all
  • clippy on the changed files

A companion rustic CLI PR will use error_count to exit 3 and emit restic-compatible JSON error / exit_error messages.

Track scan and archival errors instead of silently ignoring them, and
expose the count on SnapshotSummary so callers can return restic exit
code 3 for incomplete snapshots.
@BradKollmyer

Copy link
Copy Markdown
Contributor Author

Companion CLI PR: rustic-rs/rustic#1908

Comment thread crates/core/src/archiver.rs Outdated
/// Report a source-file error, count it, and continue the backup.
fn report_source_error(p: &Progress, errors: &AtomicU64, during: &'static str, err: &RusticError) {
_ = errors.fetch_add(1, Ordering::Relaxed);
let item = err.context_value("path").unwrap_or("");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of the unwrap and later checking for an empty string, please work with an Option

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — Progress::error now takes Option<&str>, and report_source_error passes err.context_value("path") through without converting a missing path to an empty string.

Comment thread crates/core/src/progress.rs Outdated
/// * `during` - What was being attempted, e.g. `"scan"` or `"archival"`
/// * `message` - Error message
fn error(&self, item: &str, during: &str, message: &str) {
if item.is_empty() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same change here: the trait method now takes Option<&str> and the default logger matches on Some/None instead of checking for an empty string.

Comment thread crates/core/tests/integration/backup.rs Outdated
#[cfg(unix)]
struct RestorePerms<'a>(&'a Path);

#[cfg(unix)]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to restore permissions for a file which is anyway located just in a temp dir?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, it was unnecessary. unlink only needs write permission on the parent directory, so the RestorePerms drop guard is gone.

Comment on lines +252 to +254
///
/// This is not persisted in the snapshot file; it is only set on a snapshot
/// returned from a just-completed backup.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I suggest to also persist this information in case the error count > 0. This is then a quite important information...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now serialized when non-zero (skip_serializing_if zero, default on deserialize) so existing snapshots stay unchanged and incomplete backups keep the count. The integration test reloads the snapshot from the repo to check it round-trips.

Pass source paths as Option through Progress::error instead of empty
strings. Persist SnapshotSummary.error_count when it is non-zero. Drop
the chmod restore in the tempdir test; unlink only needs directory
permissions.
@aawsome aawsome changed the title fix: count unreadable source files during backup feat: count unreadable source files during backup Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants