From 26aa65e0d40baa2f8344597d0119d6cf9f6dba0d Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Fri, 12 Jul 2024 23:14:03 +0200 Subject: [PATCH] restore: add regression test for corrupt in-place restore of large file --- internal/restorer/restorer_test.go | 49 ++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/internal/restorer/restorer_test.go b/internal/restorer/restorer_test.go index 2f28265cc..cd2e954e5 100644 --- a/internal/restorer/restorer_test.go +++ b/internal/restorer/restorer_test.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "fmt" "io" "math" "os" @@ -32,6 +33,7 @@ type Snapshot struct { type File struct { Data string + DataParts []string Links uint64 Inode uint64 Mode os.FileMode @@ -59,11 +61,11 @@ type FileAttributes struct { Encrypted bool } -func saveFile(t testing.TB, repo restic.BlobSaver, node File) restic.ID { +func saveFile(t testing.TB, repo restic.BlobSaver, data string) restic.ID { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - id, _, _, err := repo.SaveBlob(ctx, restic.DataBlob, []byte(node.Data), restic.ID{}, false) + id, _, _, err := repo.SaveBlob(ctx, restic.DataBlob, []byte(data), restic.ID{}, false) if err != nil { t.Fatal(err) } @@ -80,17 +82,24 @@ func saveDir(t testing.TB, repo restic.BlobSaver, nodes map[string]Node, inode u inode++ switch node := n.(type) { case File: - fi := n.(File).Inode + fi := node.Inode if fi == 0 { fi = inode } - lc := n.(File).Links + lc := node.Links if lc == 0 { lc = 1 } fc := []restic.ID{} - if len(n.(File).Data) > 0 { - fc = append(fc, saveFile(t, repo, node)) + size := 0 + if len(node.Data) > 0 { + size = len(node.Data) + fc = append(fc, saveFile(t, repo, node.Data)) + } else if len(node.DataParts) > 0 { + for _, part := range node.DataParts { + fc = append(fc, saveFile(t, repo, part)) + size += len(part) + } } mode := node.Mode if mode == 0 { @@ -104,22 +113,21 @@ func saveDir(t testing.TB, repo restic.BlobSaver, nodes map[string]Node, inode u UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), Content: fc, - Size: uint64(len(n.(File).Data)), + Size: uint64(size), Inode: fi, Links: lc, GenericAttributes: getGenericAttributes(node.attributes, false), }) rtest.OK(t, err) case Symlink: - symlink := n.(Symlink) err := tree.Insert(&restic.Node{ Type: "symlink", Mode: os.ModeSymlink | 0o777, - ModTime: symlink.ModTime, + ModTime: node.ModTime, Name: name, UID: uint32(os.Getuid()), GID: uint32(os.Getgid()), - LinkTarget: symlink.Target, + LinkTarget: node.Target, Inode: inode, Links: 1, }) @@ -1050,6 +1058,27 @@ func TestRestorerOverwriteBehavior(t *testing.T) { } } +func TestRestorerOverwriteLarge(t *testing.T) { + parts := make([]string, 100) + for i := 0; i < len(parts); i++ { + parts[i] = fmt.Sprint(i) + } + + baseTime := time.Now() + baseSnapshot := Snapshot{ + Nodes: map[string]Node{ + "foo": File{DataParts: parts[0:5], ModTime: baseTime}, + }, + } + overwriteSnapshot := Snapshot{ + Nodes: map[string]Node{ + "foo": File{DataParts: parts, ModTime: baseTime}, + }, + } + + saveSnapshotsAndOverwrite(t, baseSnapshot, overwriteSnapshot, Options{Overwrite: OverwriteAlways}) +} + func TestRestorerOverwriteSpecial(t *testing.T) { baseTime := time.Now() baseSnapshot := Snapshot{