From 0f82812b9a514dd2e23ea7ec509f40a9988577f4 Mon Sep 17 00:00:00 2001 From: Ivan Shapovalov Date: Thu, 5 Dec 2024 18:12:33 +0400 Subject: [PATCH] WIP: remember and log last non-fatal clone error --- internal/fs/file.go | 10 +++++++--- internal/restorer/restorer.go | 7 ++++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/internal/fs/file.go b/internal/fs/file.go index 78db7c696..26b33fb95 100644 --- a/internal/fs/file.go +++ b/internal/fs/file.go @@ -151,16 +151,20 @@ func doClone(srcName, destName string, method cloneMethod) (cloned bool, err err // Clone performs a local possibly accelerated copy of srcName to destName. // The cloned flag reports whether an accelerated copy (reflink) was performed. -func Clone(srcName, destName string) (cloned bool, err error) { +// The cloneErr value specifies the last non-fatal error during attempted +// accelerated copy. +func Clone(srcName, destName string) (cloned bool, err error, cloneErr error) { for _, fn := range cloneMethods { cloned, err = doClone(srcName, destName, fn) // if a particular method is not supported, or we hit the cross-device limitation, // "eat" the error and go to the next method or the fallback if errors.Is(err, unix.EXDEV) || errors.Is(err, unix.ENOTSUP) { + cloneErr = err continue } - return cloned, err + return cloned, err, cloneErr } - return doClone(srcName, destName, doCloneCopy) + cloned, err = doClone(srcName, destName, doCloneCopy) + return cloned, err, cloneErr } diff --git a/internal/restorer/restorer.go b/internal/restorer/restorer.go index 56ec29c21..0312a64dc 100644 --- a/internal/restorer/restorer.go +++ b/internal/restorer/restorer.go @@ -318,18 +318,23 @@ func (res *Restorer) restoreHardlinkAt(node *restic.Node, target, path, location func (res *Restorer) restoreReflink(node *restic.Node, target, path, location string) error { cloned := true + var cloneErr error if !res.opts.DryRun { var err error if err = fs.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) { return errors.Wrap(err, "RemoveNode") } - cloned, err = fs.Clone(target, path) + cloned, err, cloneErr = fs.Clone(target, path) if err != nil { return errors.WithStack(err) } } res.opts.Progress.AddClonedFile(location, node.Size, cloned) + if !cloned { + fmt.Fprintf(os.Stderr, "warning: could not reflink %v to %v: %v\n", target, path, cloneErr) + } + // reflinked files *do* have separate metadata return res.restoreNodeMetadataTo(node, path, location) }