From 23055aaadfa2a89f4bc3db3a1e8368002a1213f5 Mon Sep 17 00:00:00 2001 From: David Potter Date: Tue, 7 Jan 2020 10:33:58 -0800 Subject: [PATCH 1/2] Correct #2537 (cmd_stats file counting issue) --- changelog/unreleased/issue-2537 | 5 +++++ cmd/restic/cmd_stats.go | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 changelog/unreleased/issue-2537 diff --git a/changelog/unreleased/issue-2537 b/changelog/unreleased/issue-2537 new file mode 100644 index 000000000..6e639d552 --- /dev/null +++ b/changelog/unreleased/issue-2537 @@ -0,0 +1,5 @@ +Bugfix: Fix incorrect file counts in `stats --mode restore-size` + +The restore-size mode of stats was failing to count empty directories and some files with hard links. + +https://github.com/restic/restic/issues/2537 diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index a202fd029..5306082bf 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -247,8 +247,13 @@ func statsWalkTree(repo restic.Repository, stats *statsContainer) walker.WalkFun // as this is a file in the snapshot, we can simply count its // size without worrying about uniqueness, since duplicate files // will still be restored - stats.TotalSize += node.Size stats.TotalFileCount++ + + // TODO - Issue #2531 Handle hard links by identifying duplicate inodes. + // (Duplicates should appear in the file count, but not the size count) + stats.TotalSize += node.Size + + return false, nil } return true, nil From 71900248ab70ad91fa440ed0a55387e938288985 Mon Sep 17 00:00:00 2001 From: David Potter Date: Tue, 7 Jan 2020 17:05:16 -0800 Subject: [PATCH 2/2] Correct #2531 (`stats` restore-size calculates hard links incorrectly) --- changelog/unreleased/issue-2531 | 5 +++++ cmd/restic/cmd_stats.go | 22 +++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 changelog/unreleased/issue-2531 diff --git a/changelog/unreleased/issue-2531 b/changelog/unreleased/issue-2531 new file mode 100644 index 000000000..92910c007 --- /dev/null +++ b/changelog/unreleased/issue-2531 @@ -0,0 +1,5 @@ +Bugfix: Fix incorrect size calculation in `stats --mode restore-size` + +The restore-size mode of stats was counting hard-linked files as if they were independent. + +https://github.com/restic/restic/issues/2531 diff --git a/cmd/restic/cmd_stats.go b/cmd/restic/cmd_stats.go index 5306082bf..4ebb68dbf 100644 --- a/cmd/restic/cmd_stats.go +++ b/cmd/restic/cmd_stats.go @@ -89,10 +89,11 @@ func runStats(gopts GlobalOptions, args []string) error { // create a container for the stats (and other needed state) stats := &statsContainer{ - uniqueFiles: make(map[fileID]struct{}), - fileBlobs: make(map[string]restic.IDSet), - blobs: restic.NewBlobSet(), - blobsSeen: restic.NewBlobSet(), + uniqueFiles: make(map[fileID]struct{}), + uniqueInodes: make(map[uint64]struct{}), + fileBlobs: make(map[string]restic.IDSet), + blobs: restic.NewBlobSet(), + blobsSeen: restic.NewBlobSet(), } if snapshotIDString != "" { @@ -249,9 +250,12 @@ func statsWalkTree(repo restic.Repository, stats *statsContainer) walker.WalkFun // will still be restored stats.TotalFileCount++ - // TODO - Issue #2531 Handle hard links by identifying duplicate inodes. - // (Duplicates should appear in the file count, but not the size count) - stats.TotalSize += node.Size + // if inodes are present, only count each inode once + // (hard links do not increase restore size) + if _, ok := stats.uniqueInodes[node.Inode]; !ok || node.Inode == 0 { + stats.uniqueInodes[node.Inode] = struct{}{} + stats.TotalSize += node.Size + } return false, nil } @@ -306,6 +310,10 @@ type statsContainer struct { // contents (hashed sequence of content blob IDs) uniqueFiles map[fileID]struct{} + // uniqueInodes marks visited files according to their + // inode # (hashed sequence of inode numbers) + uniqueInodes map[uint64]struct{} + // fileBlobs maps a file name (path) to the set of // blobs that have been seen as a part of the file fileBlobs map[string]restic.IDSet