From c51d247f030051abb4b97770d49bac30343e45c8 Mon Sep 17 00:00:00 2001 From: Dimitris Mandalidis Date: Tue, 4 Dec 2018 08:07:06 +0200 Subject: [PATCH] Ignore xattr ENOTSUP errors on copy (fixes #38155) Signed-off-by: Dimitris Mandalidis (cherry picked from commit d0192ae154e6244edd4bf1bb298ea24146378058) Signed-off-by: Sebastiaan van Stijn --- container/container_unix.go | 15 ++++++- vendor.conf | 2 +- .../github.com/containerd/continuity/LICENSE | 19 ++------ .../containerd/continuity/README.md | 10 +++++ .../containerd/continuity/fs/copy.go | 45 ++++++++++++++++--- .../containerd/continuity/fs/copy_linux.go | 37 ++++++++++++--- .../containerd/continuity/fs/copy_unix.go | 24 ++++++++-- .../containerd/continuity/fs/copy_windows.go | 2 +- 8 files changed, 122 insertions(+), 32 deletions(-) diff --git a/container/container_unix.go b/container/container_unix.go index ed664f3eecc59..1a184555ee5b1 100644 --- a/container/container_unix.go +++ b/container/container_unix.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "path/filepath" + "syscall" "github.com/containerd/continuity/fs" "github.com/docker/docker/api/types" @@ -388,6 +389,18 @@ func (container *Container) DetachAndUnmount(volumeEventLog func(name, action st return container.UnmountVolumes(volumeEventLog) } +// ignoreUnsupportedXAttrs ignores errors when extended attributes +// are not supported +func ignoreUnsupportedXAttrs() fs.CopyDirOpt { + xeh := func(dst, src, xattrKey string, err error) error { + if errors.Cause(err) != syscall.ENOTSUP { + return err + } + return nil + } + return fs.WithXAttrErrorHandler(xeh) +} + // copyExistingContents copies from the source to the destination and // ensures the ownership is appropriately set. func copyExistingContents(source, destination string) error { @@ -399,7 +412,7 @@ func copyExistingContents(source, destination string) error { // destination is not empty, do not copy return nil } - return fs.CopyDir(destination, source) + return fs.CopyDir(destination, source, ignoreUnsupportedXAttrs()) } // TmpfsMounts returns the list of tmpfs mounts diff --git a/vendor.conf b/vendor.conf index 432daeb4f98f7..d86fe274edbf2 100644 --- a/vendor.conf +++ b/vendor.conf @@ -120,7 +120,7 @@ google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9 # containerd github.com/containerd/containerd 9754871865f7fe2f4e74d43e2fc7ccd237edcbce # v1.2.2 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c -github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4 +github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2 github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23 github.com/containerd/cri 0d5cabd006cb5319dc965046067b8432d9fa5ef8 # release/1.2 branch diff --git a/vendor/github.com/containerd/continuity/LICENSE b/vendor/github.com/containerd/continuity/LICENSE index 8f71f43fee3f7..584149b6ee28c 100644 --- a/vendor/github.com/containerd/continuity/LICENSE +++ b/vendor/github.com/containerd/continuity/LICENSE @@ -1,6 +1,7 @@ + Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -175,28 +176,16 @@ END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} + Copyright The containerd Authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - diff --git a/vendor/github.com/containerd/continuity/README.md b/vendor/github.com/containerd/continuity/README.md index 0e91ce07b58aa..f9f9ef0f96375 100644 --- a/vendor/github.com/containerd/continuity/README.md +++ b/vendor/github.com/containerd/continuity/README.md @@ -72,3 +72,13 @@ If you change the proto file you will need to rebuild the generated Go with `go ```console $ go generate ./proto ``` + +## Project details + +continuity is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE). +As a containerd sub-project, you will find the: + * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md), + * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS), + * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md) + +information in our [`containerd/project`](https://github.com/containerd/project) repository. diff --git a/vendor/github.com/containerd/continuity/fs/copy.go b/vendor/github.com/containerd/continuity/fs/copy.go index 42df6a9a541e1..ad61022ad5610 100644 --- a/vendor/github.com/containerd/continuity/fs/copy.go +++ b/vendor/github.com/containerd/continuity/fs/copy.go @@ -32,14 +32,49 @@ var bufferPool = &sync.Pool{ }, } +// XAttrErrorHandlers transform a non-nil xattr error. +// Return nil to ignore an error. +// xattrKey can be empty for listxattr operation. +type XAttrErrorHandler func(dst, src, xattrKey string, err error) error + +type copyDirOpts struct { + xeh XAttrErrorHandler +} + +type CopyDirOpt func(*copyDirOpts) error + +// WithXAttrErrorHandler allows specifying XAttrErrorHandler +// If nil XAttrErrorHandler is specified (default), CopyDir stops +// on a non-nil xattr error. +func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt { + return func(o *copyDirOpts) error { + o.xeh = xeh + return nil + } +} + +// WithAllowXAttrErrors allows ignoring xattr errors. +func WithAllowXAttrErrors() CopyDirOpt { + xeh := func(dst, src, xattrKey string, err error) error { + return nil + } + return WithXAttrErrorHandler(xeh) +} + // CopyDir copies the directory from src to dst. // Most efficient copy of files is attempted. -func CopyDir(dst, src string) error { +func CopyDir(dst, src string, opts ...CopyDirOpt) error { + var o copyDirOpts + for _, opt := range opts { + if err := opt(&o); err != nil { + return err + } + } inodes := map[uint64]string{} - return copyDirectory(dst, src, inodes) + return copyDirectory(dst, src, inodes, &o) } -func copyDirectory(dst, src string, inodes map[uint64]string) error { +func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error { stat, err := os.Stat(src) if err != nil { return errors.Wrapf(err, "failed to stat %s", src) @@ -75,7 +110,7 @@ func copyDirectory(dst, src string, inodes map[uint64]string) error { switch { case fi.IsDir(): - if err := copyDirectory(target, source, inodes); err != nil { + if err := copyDirectory(target, source, inodes, o); err != nil { return err } continue @@ -111,7 +146,7 @@ func copyDirectory(dst, src string, inodes map[uint64]string) error { return errors.Wrap(err, "failed to copy file info") } - if err := copyXAttrs(target, source); err != nil { + if err := copyXAttrs(target, source, o.xeh); err != nil { return errors.Wrap(err, "failed to copy xattrs") } } diff --git a/vendor/github.com/containerd/continuity/fs/copy_linux.go b/vendor/github.com/containerd/continuity/fs/copy_linux.go index e041b5661f032..81c71522aa17b 100644 --- a/vendor/github.com/containerd/continuity/fs/copy_linux.go +++ b/vendor/github.com/containerd/continuity/fs/copy_linux.go @@ -59,6 +59,8 @@ func copyFileInfo(fi os.FileInfo, name string) error { return nil } +const maxSSizeT = int64(^uint(0) >> 1) + func copyFileContent(dst, src *os.File) error { st, err := src.Stat() if err != nil { @@ -71,7 +73,16 @@ func copyFileContent(dst, src *os.File) error { dstFd := int(dst.Fd()) for size > 0 { - n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, int(size), 0) + // Ensure that we are never trying to copy more than SSIZE_MAX at a + // time and at the same time avoids overflows when the file is larger + // than 4GB on 32-bit systems. + var copySize int + if size > maxSSizeT { + copySize = int(maxSSizeT) + } else { + copySize = int(size) + } + n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, copySize, 0) if err != nil { if (err != unix.ENOSYS && err != unix.EXDEV) || !first { return errors.Wrap(err, "copy file range failed") @@ -90,18 +101,34 @@ func copyFileContent(dst, src *os.File) error { return nil } -func copyXAttrs(dst, src string) error { +func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error { xattrKeys, err := sysx.LListxattr(src) if err != nil { - return errors.Wrapf(err, "failed to list xattrs on %s", src) + e := errors.Wrapf(err, "failed to list xattrs on %s", src) + if xeh != nil { + e = xeh(dst, src, "", e) + } + return e } for _, xattr := range xattrKeys { data, err := sysx.LGetxattr(src, xattr) if err != nil { - return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + if xeh != nil { + if e = xeh(dst, src, xattr, e); e == nil { + continue + } + } + return e } if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil { - return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + if xeh != nil { + if e = xeh(dst, src, xattr, e); e == nil { + continue + } + } + return e } } diff --git a/vendor/github.com/containerd/continuity/fs/copy_unix.go b/vendor/github.com/containerd/continuity/fs/copy_unix.go index 1a8ae5ebd1934..73c01a46ddd78 100644 --- a/vendor/github.com/containerd/continuity/fs/copy_unix.go +++ b/vendor/github.com/containerd/continuity/fs/copy_unix.go @@ -69,18 +69,34 @@ func copyFileContent(dst, src *os.File) error { return err } -func copyXAttrs(dst, src string) error { +func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error { xattrKeys, err := sysx.LListxattr(src) if err != nil { - return errors.Wrapf(err, "failed to list xattrs on %s", src) + e := errors.Wrapf(err, "failed to list xattrs on %s", src) + if xeh != nil { + e = xeh(dst, src, "", e) + } + return e } for _, xattr := range xattrKeys { data, err := sysx.LGetxattr(src, xattr) if err != nil { - return errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src) + if xeh != nil { + if e = xeh(dst, src, xattr, e); e == nil { + continue + } + } + return e } if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil { - return errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst) + if xeh != nil { + if e = xeh(dst, src, xattr, e); e == nil { + continue + } + } + return e } } diff --git a/vendor/github.com/containerd/continuity/fs/copy_windows.go b/vendor/github.com/containerd/continuity/fs/copy_windows.go index be8e6489bf961..27c7d7dbb9f36 100644 --- a/vendor/github.com/containerd/continuity/fs/copy_windows.go +++ b/vendor/github.com/containerd/continuity/fs/copy_windows.go @@ -40,7 +40,7 @@ func copyFileContent(dst, src *os.File) error { return err } -func copyXAttrs(dst, src string) error { +func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error { return nil }