forked from TrueCloudLab/restic
backup: Only return a warning for duplicate directory entries
The backup command failed if a directory contains duplicate entries. Downgrade the severity of this problem from fatal error to a warning. This allows users to still create a backup.
This commit is contained in:
parent
d7d7b4ab27
commit
403b01b788
4 changed files with 25 additions and 1 deletions
12
changelog/unreleased/issue-1866
Normal file
12
changelog/unreleased/issue-1866
Normal file
|
@ -0,0 +1,12 @@
|
|||
Enhancement: Improve handling of directories with duplicate entries
|
||||
|
||||
If for some reason a directory contains a duplicate entry, this caused the
|
||||
backup command to fail with a `node "path/to/file" already present` or `nodes
|
||||
are not ordered got "path/to/file", last "path/to/file"` error.
|
||||
|
||||
The error handling has been changed to only report a warning in this case. Make
|
||||
sure to check that the filesystem in question is not damaged!
|
||||
|
||||
https://github.com/restic/restic/issues/1866
|
||||
https://github.com/restic/restic/issues/3937
|
||||
https://github.com/restic/restic/pull/3880
|
|
@ -2,6 +2,7 @@ package archiver
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/restic/restic/internal/debug"
|
||||
"github.com/restic/restic/internal/restic"
|
||||
|
@ -79,6 +80,7 @@ func (s *TreeSaver) save(ctx context.Context, job *saveTreeJob) (*restic.Node, I
|
|||
job.nodes = nil
|
||||
|
||||
builder := restic.NewTreeJSONBuilder()
|
||||
var lastNode *restic.Node
|
||||
|
||||
for i, fn := range nodes {
|
||||
// fn is a copy, so clear the original value explicitly
|
||||
|
@ -105,9 +107,15 @@ func (s *TreeSaver) save(ctx context.Context, job *saveTreeJob) (*restic.Node, I
|
|||
|
||||
debug.Log("insert %v", fnr.node.Name)
|
||||
err := builder.AddNode(fnr.node)
|
||||
if err != nil && errors.Is(err, restic.ErrTreeNotOrdered) && lastNode != nil && fnr.node.Equals(*lastNode) {
|
||||
// ignore error if an _identical_ node already exists, but nevertheless issue a warning
|
||||
_ = s.errFn(fnr.target, err)
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, stats, err
|
||||
}
|
||||
lastNode = fnr.node
|
||||
}
|
||||
|
||||
buf, err := builder.Finalize()
|
||||
|
|
|
@ -145,6 +145,8 @@ func SaveTree(ctx context.Context, r BlobSaver, t *Tree) (ID, error) {
|
|||
return id, err
|
||||
}
|
||||
|
||||
var ErrTreeNotOrdered = errors.Errorf("nodes are not ordered or duplicate")
|
||||
|
||||
type TreeJSONBuilder struct {
|
||||
buf bytes.Buffer
|
||||
lastName string
|
||||
|
@ -158,7 +160,7 @@ func NewTreeJSONBuilder() *TreeJSONBuilder {
|
|||
|
||||
func (builder *TreeJSONBuilder) AddNode(node *Node) error {
|
||||
if node.Name <= builder.lastName {
|
||||
return errors.Errorf("nodes are not ordered got %q, last %q", node.Name, builder.lastName)
|
||||
return fmt.Errorf("node %q, last%q: %w", node.Name, builder.lastName, ErrTreeNotOrdered)
|
||||
}
|
||||
if builder.lastName != "" {
|
||||
_ = builder.buf.WriteByte(',')
|
||||
|
|
|
@ -3,6 +3,7 @@ package restic_test
|
|||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -136,6 +137,7 @@ func TestTreeEqualSerialization(t *testing.T) {
|
|||
|
||||
rtest.Assert(t, tree.Insert(node) != nil, "no error on duplicate node")
|
||||
rtest.Assert(t, builder.AddNode(node) != nil, "no error on duplicate node")
|
||||
rtest.Assert(t, errors.Is(builder.AddNode(node), restic.ErrTreeNotOrdered), "wrong error returned")
|
||||
}
|
||||
|
||||
treeBytes, err := json.Marshal(tree)
|
||||
|
|
Loading…
Reference in a new issue