backup: store but warn if extended metadata for item is incomplete

Files were not included in the backup if the extended metadata for the
file could not be read. This is rather drastic. Instead settle on
returning a warning but still including the file in the backup.
This commit is contained in:
Michael Eischer 2024-08-03 19:10:11 +02:00
parent d407abb50f
commit 73c9780321
3 changed files with 43 additions and 1 deletions

View file

@ -0,0 +1,15 @@
Change: let `backup` store files with incomplete metadata
If restic failed to read the extended metadata for a file or folder while
creating a backup, then the file or folder was not included in the resulting
snapshot. Instead, only a warning message was printed along with exiting
with exit code 3.
Now, restic also includes items for which the extended metadata could not
be read in a snapshot. The warning message has been changed to read
```
incomplete metadata for /path/to/file: details on error
```
https://github.com/restic/restic/issues/4953
https://github.com/restic/restic/pull/4977

View file

@ -263,7 +263,8 @@ func (arch *Archiver) nodeFromFileInfo(snPath, filename string, fi os.FileInfo,
// overwrite name to match that within the snapshot
node.Name = path.Base(snPath)
if err != nil {
return node, fmt.Errorf("nodeFromFileInfo %v: %w", filename, err)
err = fmt.Errorf("incomplete metadata for %v: %w", filename, err)
return node, arch.error(filename, err)
}
return node, err
}

View file

@ -3,6 +3,7 @@ package archiver
import (
"bytes"
"context"
"fmt"
"io"
"os"
"path/filepath"
@ -2338,3 +2339,28 @@ func TestRacyFileSwap(t *testing.T) {
t.Errorf("Save() excluded the node, that's unexpected")
}
}
func TestMetadataBackupErrorFiltering(t *testing.T) {
tempdir := t.TempDir()
repo := repository.TestRepository(t)
filename := filepath.Join(tempdir, "file")
rtest.OK(t, os.WriteFile(filename, []byte("example"), 0o600))
fi, err := os.Stat(filename)
rtest.OK(t, err)
arch := New(repo, fs.Local{}, Options{})
var filteredErr error
replacementErr := fmt.Errorf("replacement")
arch.Error = func(item string, err error) error {
filteredErr = err
return replacementErr
}
// check that errors from reading extended metadata are properly filtered
node, err := arch.nodeFromFileInfo("file", filename+"invalid", fi, false)
rtest.Assert(t, node != nil, "node is missing")
rtest.Assert(t, err == replacementErr, "expected %v got %v", replacementErr, err)
rtest.Assert(t, filteredErr != nil, "missing inner error")
}