Merge pull request #5083 from greatroar/errors

Some error handling patches
This commit is contained in:
Michael Eischer 2024-10-16 18:22:49 +00:00 committed by GitHub
commit 0c0d8b8cfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 46 additions and 57 deletions

View file

@ -2,7 +2,6 @@ package errors
import (
stderrors "errors"
"fmt"
"github.com/pkg/errors"
)
@ -36,35 +35,11 @@ func As(err error, tgt interface{}) bool { return stderrors.As(err, tgt) }
// Is reports whether any error in err's tree matches target.
func Is(x, y error) bool { return stderrors.Is(x, y) }
func Join(errs ...error) error { return stderrors.Join(errs...) }
// Unwrap returns the result of calling the Unwrap method on err, if err's type contains
// an Unwrap method returning error. Otherwise, Unwrap returns nil.
//
// Unwrap only calls a method of the form "Unwrap() error". In particular Unwrap does not
// unwrap errors returned by [Join].
func Unwrap(err error) error { return stderrors.Unwrap(err) }
// CombineErrors combines multiple errors into a single error after filtering out any nil values.
// If no errors are passed, it returns nil.
// If one error is passed, it simply returns that same error.
func CombineErrors(errors ...error) (err error) {
var combinedErrorMsg string
var multipleErrors bool
for _, errVal := range errors {
if errVal != nil {
if combinedErrorMsg != "" {
combinedErrorMsg += "; " // Separate error messages with a delimiter
multipleErrors = true
} else {
// Set the first error
err = errVal
}
combinedErrorMsg += errVal.Error()
}
}
if combinedErrorMsg == "" {
return nil // If no errors, return nil
} else if !multipleErrors {
return err // If only one error, return that first error
}
return fmt.Errorf("multiple errors occurred: [%s]", combinedErrorMsg)
}

View file

@ -3,8 +3,16 @@
package fs
import "golang.org/x/sys/unix"
import (
"os"
func mknod(path string, mode uint32, dev uint64) (err error) {
return unix.Mknod(path, mode, int(dev))
"golang.org/x/sys/unix"
)
func mknod(path string, mode uint32, dev uint64) error {
err := unix.Mknod(path, mode, int(dev))
if err != nil {
err = &os.PathError{Op: "mknod", Path: path, Err: err}
}
return err
}

View file

@ -103,7 +103,7 @@ func nodeFillExtra(node *restic.Node, path string, fi os.FileInfo, ignoreXattrLi
allowExtended, err := nodeFillGenericAttributes(node, path, &stat)
if allowExtended {
// Skip processing ExtendedAttributes if allowExtended is false.
err = errors.CombineErrors(err, nodeFillExtendedAttributes(node, path, ignoreXattrListError))
err = errors.Join(err, nodeFillExtendedAttributes(node, path, ignoreXattrListError))
}
return err
}
@ -163,41 +163,29 @@ func lookupGroup(gid uint32) string {
}
// NodeCreateAt creates the node at the given path but does NOT restore node meta data.
func NodeCreateAt(node *restic.Node, path string) error {
func NodeCreateAt(node *restic.Node, path string) (err error) {
debug.Log("create node %v at %v", node.Name, path)
switch node.Type {
case restic.NodeTypeDir:
if err := nodeCreateDirAt(node, path); err != nil {
return err
}
err = nodeCreateDirAt(node, path)
case restic.NodeTypeFile:
if err := nodeCreateFileAt(path); err != nil {
return err
}
err = nodeCreateFileAt(path)
case restic.NodeTypeSymlink:
if err := nodeCreateSymlinkAt(node, path); err != nil {
return err
}
err = nodeCreateSymlinkAt(node, path)
case restic.NodeTypeDev:
if err := nodeCreateDevAt(node, path); err != nil {
return err
}
err = nodeCreateDevAt(node, path)
case restic.NodeTypeCharDev:
if err := nodeCreateCharDevAt(node, path); err != nil {
return err
}
err = nodeCreateCharDevAt(node, path)
case restic.NodeTypeFifo:
if err := nodeCreateFifoAt(path); err != nil {
return err
}
err = nodeCreateFifoAt(path)
case restic.NodeTypeSocket:
return nil
err = nil
default:
return errors.Errorf("filetype %q not implemented", node.Type)
err = errors.Errorf("filetype %q not implemented", node.Type)
}
return nil
return err
}
func nodeCreateDirAt(node *restic.Node, path string) error {

View file

@ -3,12 +3,19 @@
package fs
import "syscall"
import (
"os"
"syscall"
)
func nodeRestoreSymlinkTimestamps(path string, utimes [2]syscall.Timespec) error {
return nil
}
func mknod(path string, mode uint32, dev uint64) (err error) {
return syscall.Mknod(path, mode, dev)
func mknod(path string, mode uint32, dev uint64) error {
err := syscall.Mknod(path, mode, dev)
if err != nil {
err = &os.PathError{Op: "mknod", Path: path, Err: err}
}
return err
}

View file

@ -8,9 +8,11 @@ import (
"os"
"path/filepath"
"runtime"
"strings"
"syscall"
"testing"
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
@ -134,3 +136,12 @@ func TestNodeFromFileInfo(t *testing.T) {
})
}
}
func TestMknodError(t *testing.T) {
d := t.TempDir()
// Call mkfifo, which calls mknod, as mknod may give
// "operation not permitted" on Mac.
err := mkfifo(d, 0)
rtest.Assert(t, errors.Is(err, os.ErrExist), "want ErrExist, got %q", err)
rtest.Assert(t, strings.Contains(err.Error(), d), "filename not in %q", err)
}

View file

@ -189,7 +189,7 @@ func nodeRestoreGenericAttributes(node *restic.Node, path string, warn func(msg
}
restic.HandleUnknownGenericAttributesFound(unknownAttribs, warn)
return errors.CombineErrors(errs...)
return errors.Join(errs...)
}
// genericAttributesToWindowsAttrs converts the generic attributes map to a WindowsAttributes and also returns a string of unknown attributes that it could not convert.