Browse Source

pkg/system: return even richer xattr errors

The names of extended attributes are not completely freeform. Attributes
are namespaced, and the kernel enforces (among other things) that only
attributes whose names are prefixed with a valid namespace are
permitted. The name of the attribute therefore needs to be known in
order to diagnose issues with lsetxattr. Include the name of the
extended attribute in the errors returned from the Lsetxattr and
Lgetxattr so users and us can more easily troubleshoot xattr-related
issues. Include the name in a separate rich-error field to provide code
handling the error enough information to determine whether or not the
failure can be ignored.

Signed-off-by: Cory Snider <csnider@mirantis.com>
(cherry picked from commit 43bf65c174aff8f7c30a100c2783510009345e55)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Cory Snider 1 year ago
parent
commit
c0573b133f
3 changed files with 28 additions and 9 deletions
  1. 5 2
      builder/remotecontext/archive.go
  2. 18 0
      pkg/system/xattrs.go
  3. 5 7
      pkg/system/xattrs_linux.go

+ 5 - 2
builder/remotecontext/archive.go

@@ -9,6 +9,7 @@ import (
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/longpath"
 	"github.com/docker/docker/pkg/longpath"
+	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/tarsum"
 	"github.com/docker/docker/pkg/tarsum"
 	"github.com/moby/sys/symlink"
 	"github.com/moby/sys/symlink"
 	"github.com/pkg/errors"
 	"github.com/pkg/errors"
@@ -24,9 +25,11 @@ func (c *archiveContext) Close() error {
 }
 }
 
 
 func convertPathError(err error, cleanpath string) error {
 func convertPathError(err error, cleanpath string) error {
-	if err, ok := err.(*os.PathError); ok {
+	switch err := err.(type) {
+	case *os.PathError:
+		err.Path = cleanpath
+	case *system.XattrError:
 		err.Path = cleanpath
 		err.Path = cleanpath
-		return err
 	}
 	}
 	return err
 	return err
 }
 }

+ 18 - 0
pkg/system/xattrs.go

@@ -0,0 +1,18 @@
+package system // import "github.com/docker/docker/pkg/system"
+
+type XattrError struct {
+	Op   string
+	Attr string
+	Path string
+	Err  error
+}
+
+func (e *XattrError) Error() string { return e.Op + " " + e.Attr + " " + e.Path + ": " + e.Err.Error() }
+
+func (e *XattrError) Unwrap() error { return e.Err }
+
+// Timeout reports whether this error represents a timeout.
+func (e *XattrError) Timeout() bool {
+	t, ok := e.Err.(interface{ Timeout() bool })
+	return ok && t.Timeout()
+}

+ 5 - 7
pkg/system/xattrs_linux.go

@@ -1,8 +1,6 @@
 package system // import "github.com/docker/docker/pkg/system"
 package system // import "github.com/docker/docker/pkg/system"
 
 
 import (
 import (
-	"io/fs"
-
 	"golang.org/x/sys/unix"
 	"golang.org/x/sys/unix"
 )
 )
 
 
@@ -10,8 +8,8 @@ import (
 // and associated with the given path in the file system.
 // and associated with the given path in the file system.
 // It will returns a nil slice and nil error if the xattr is not set.
 // It will returns a nil slice and nil error if the xattr is not set.
 func Lgetxattr(path string, attr string) ([]byte, error) {
 func Lgetxattr(path string, attr string) ([]byte, error) {
-	pathErr := func(err error) ([]byte, error) {
-		return nil, &fs.PathError{Op: "lgetxattr", Path: path, Err: err}
+	sysErr := func(err error) ([]byte, error) {
+		return nil, &XattrError{Op: "lgetxattr", Attr: attr, Path: path, Err: err}
 	}
 	}
 
 
 	// Start with a 128 length byte array
 	// Start with a 128 length byte array
@@ -22,7 +20,7 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
 		// Buffer too small, use zero-sized buffer to get the actual size
 		// Buffer too small, use zero-sized buffer to get the actual size
 		sz, errno = unix.Lgetxattr(path, attr, []byte{})
 		sz, errno = unix.Lgetxattr(path, attr, []byte{})
 		if errno != nil {
 		if errno != nil {
-			return pathErr(errno)
+			return sysErr(errno)
 		}
 		}
 		dest = make([]byte, sz)
 		dest = make([]byte, sz)
 		sz, errno = unix.Lgetxattr(path, attr, dest)
 		sz, errno = unix.Lgetxattr(path, attr, dest)
@@ -32,7 +30,7 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
 	case errno == unix.ENODATA:
 	case errno == unix.ENODATA:
 		return nil, nil
 		return nil, nil
 	case errno != nil:
 	case errno != nil:
-		return pathErr(errno)
+		return sysErr(errno)
 	}
 	}
 
 
 	return dest[:sz], nil
 	return dest[:sz], nil
@@ -43,7 +41,7 @@ func Lgetxattr(path string, attr string) ([]byte, error) {
 func Lsetxattr(path string, attr string, data []byte, flags int) error {
 func Lsetxattr(path string, attr string, data []byte, flags int) error {
 	err := unix.Lsetxattr(path, attr, data, flags)
 	err := unix.Lsetxattr(path, attr, data, flags)
 	if err != nil {
 	if err != nil {
-		return &fs.PathError{Op: "lsetxattr", Path: path, Err: err}
+		return &XattrError{Op: "lsetxattr", Attr: attr, Path: path, Err: err}
 	}
 	}
 	return nil
 	return nil
 }
 }