From b50d3ba805cdad20e9352398a3d2054219ebcddd Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Tue, 7 Mar 2017 11:12:34 +0100 Subject: [PATCH 1/2] Refuse to create empty snapshots Closes #862 --- src/restic/archiver/archiver.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/restic/archiver/archiver.go b/src/restic/archiver/archiver.go index 6a5b84a31..e90cfd8f8 100644 --- a/src/restic/archiver/archiver.go +++ b/src/restic/archiver/archiver.go @@ -734,6 +734,21 @@ func (arch *Archiver) Snapshot(p *restic.Progress, paths, tags []string, hostnam return nil, restic.ID{}, err } + // receive the top-level tree + root := (<-resCh).(*restic.Node) + debug.Log("root node received: %v", root.Subtree.Str()) + sn.Tree = root.Subtree + + // load top-level tree again to see if it is empty + toptree, err := arch.repo.LoadTree(*root.Subtree) + if err != nil { + return nil, restic.ID{}, err + } + + if len(toptree.Nodes) == 0 { + return nil, restic.ID{}, errors.Fatal("no files/dirs saved, refusing to create empty snapshot") + } + // save index err = arch.repo.SaveIndex() if err != nil { @@ -743,11 +758,6 @@ func (arch *Archiver) Snapshot(p *restic.Progress, paths, tags []string, hostnam debug.Log("saved indexes") - // receive the top-level tree - root := (<-resCh).(*restic.Node) - debug.Log("root node received: %v", root.Subtree.Str()) - sn.Tree = root.Subtree - // save snapshot id, err := arch.repo.SaveJSONUnpacked(restic.SnapshotFile, sn) if err != nil { From bb144436c7280bef06af65abbc11187e8375111f Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Tue, 7 Mar 2017 11:17:15 +0100 Subject: [PATCH 2/2] Add test for empty snapshot --- src/restic/archiver/archiver_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/restic/archiver/archiver_test.go b/src/restic/archiver/archiver_test.go index 3cb8ba183..72e3b3a96 100644 --- a/src/restic/archiver/archiver_test.go +++ b/src/restic/archiver/archiver_test.go @@ -294,3 +294,23 @@ func assertNoUnreferencedPacks(t *testing.T, chkr *checker.Checker) { OK(t, err) } } + +func TestArchiveEmptySnapshot(t *testing.T) { + repo, cleanup := repository.TestRepository(t) + defer cleanup() + + arch := archiver.New(repo) + + sn, id, err := arch.Snapshot(nil, []string{"file-does-not-exist-123123213123", "file2-does-not-exist-too-123123123"}, nil, "localhost", nil) + if err == nil { + t.Errorf("expected error for empty snapshot, got nil") + } + + if !id.IsNull() { + t.Errorf("expected null ID for empty snapshot, got %v", id.Str()) + } + + if sn != nil { + t.Errorf("expected null snapshot for empty snapshot, got %v", sn) + } +}