vendor: update containerd/continuity efbc4488d8fe1bdc16bde3b2d2990d9b3a899165

full diff: 26c1120b8d...efbc4488d8

Relevant changes:

- sysx/xattr: fix and improve
    - fix getxattrAll: change initial buffer size to 128 to prevent unneeded
      iterations and change the logic to get the real size in case we get ERANGE
      rather than doubling the buffer)
    - improve listxattrAll; refactor for readability, prevent calling `listxattr()`
      twice. Handle condition when attributes size is changed in between the two
      calls to listxattr().
- Remove Windows' Readlink fork
    - Drops support for Go 1.12 and under
- Fix sameFile() to recognize empty files as the same
    - fixes "Empty files can diff as "modified" even when they're not"

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2020-07-28 16:33:16 +02:00
parent 0f41a77c69
commit afdf5483c9
No known key found for this signature in database
GPG key ID: 76698F39D527CE8C
12 changed files with 55 additions and 333 deletions

View file

@ -124,7 +124,7 @@ google.golang.org/genproto 3f1135a288c9a07e340ae8ba4cc6
# containerd
github.com/containerd/containerd c80284d4b5291a351bb471bcdabb5c1d95e7a583 # master / v1.4.0-dev
github.com/containerd/fifo ff969a566b00877c63489baf6e8c35d60af6142c
github.com/containerd/continuity 26c1120b8d4107d2471b93ad78ef7ce1fc84c4c4
github.com/containerd/continuity efbc4488d8fe1bdc16bde3b2d2990d9b3a899165
github.com/containerd/cgroups 44306b6a1d46985d916b48b4199f93a378af314f
github.com/containerd/console 8375c3424e4d7b114e8a90a4a40c8e1b40d1d4e6 # v1.0.0
github.com/containerd/go-runc 7016d3ce2328dd2cb1192b2076ebd565c4e8df0c

View file

@ -32,6 +32,7 @@ func DeviceInfo(fi os.FileInfo) (uint64, uint64, error) {
return 0, 0, fmt.Errorf("cannot extract device from os.FileInfo")
}
//nolint:unconvert
dev := uint64(sys.Rdev)
return uint64(unix.Major(dev)), uint64(unix.Minor(dev)), nil
}

View file

@ -138,6 +138,10 @@ func (d *driver) Lstat(p string) (os.FileInfo, error) {
return os.Lstat(p)
}
func (d *driver) Readlink(p string) (string, error) {
return os.Readlink(p)
}
func (d *driver) Mkdir(p string, mode os.FileMode) error {
return os.Mkdir(p, mode)
}

View file

@ -131,8 +131,3 @@ func (d *driver) LSetxattr(path string, attrMap map[string][]byte) error {
func (d *driver) DeviceInfo(fi os.FileInfo) (maj uint64, min uint64, err error) {
return devices.DeviceInfo(fi)
}
// Readlink was forked on Windows to fix a Golang bug, use the "os" package here
func (d *driver) Readlink(p string) (string, error) {
return os.Readlink(p)
}

View file

@ -1,3 +1,5 @@
// +build go1.13
/*
Copyright The containerd Authors.
@ -14,12 +16,14 @@
limitations under the License.
*/
// Go 1.13 is the minimally supported version for Windows.
// Earlier golang releases have bug in os.Readlink
// (see https://github.com/golang/go/issues/30463).
package driver
import (
"os"
"github.com/containerd/continuity/sysx"
)
func (d *driver) Mknod(path string, mode os.FileMode, major, minor int) error {
@ -35,9 +39,3 @@ func (d *driver) Lchmod(path string, mode os.FileMode) (err error) {
// TODO: Use Window's equivalent
return os.Chmod(path, mode)
}
// Readlink is forked in order to support Volume paths which are used
// in container layers.
func (d *driver) Readlink(p string) (string, error) {
return sysx.Readlink(p)
}

View file

@ -117,15 +117,13 @@ func sameFile(f1, f2 *currentPath) (bool, error) {
// If the timestamp may have been truncated in both of the
// files, check content of file to determine difference
if t1.Nanosecond() == 0 && t2.Nanosecond() == 0 {
var eq bool
if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink {
eq, err = compareSymlinkTarget(f1.fullPath, f2.fullPath)
} else if f1.f.Size() > 0 {
eq, err = compareFileContent(f1.fullPath, f2.fullPath)
return compareSymlinkTarget(f1.fullPath, f2.fullPath)
}
if err != nil || !eq {
return eq, err
if f1.f.Size() == 0 { // if file sizes are zero length, the files are the same by definition
return true, nil
}
return compareFileContent(f1.fullPath, f2.fullPath)
} else if t1.Nanosecond() != t2.Nanosecond() {
return false, nil
}

View file

@ -1,6 +1,6 @@
module github.com/containerd/continuity
go 1.11
go 1.13
require (
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898

View file

@ -1,26 +0,0 @@
// +build !windows
/*
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
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.
*/
package syscallx
import "syscall"
// Readlink returns the destination of the named symbolic link.
func Readlink(path string, buf []byte) (n int, err error) {
return syscall.Readlink(path, buf)
}

View file

@ -1,112 +0,0 @@
/*
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
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.
*/
package syscallx
import (
"syscall"
"unsafe"
)
type reparseDataBuffer struct {
ReparseTag uint32
ReparseDataLength uint16
Reserved uint16
// GenericReparseBuffer
reparseBuffer byte
}
type mountPointReparseBuffer struct {
SubstituteNameOffset uint16
SubstituteNameLength uint16
PrintNameOffset uint16
PrintNameLength uint16
PathBuffer [1]uint16
}
type symbolicLinkReparseBuffer struct {
SubstituteNameOffset uint16
SubstituteNameLength uint16
PrintNameOffset uint16
PrintNameLength uint16
Flags uint32
PathBuffer [1]uint16
}
const (
_IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
_SYMLINK_FLAG_RELATIVE = 1
)
// Readlink returns the destination of the named symbolic link.
func Readlink(path string, buf []byte) (n int, err error) {
fd, err := syscall.CreateFile(syscall.StringToUTF16Ptr(path), syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING,
syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
if err != nil {
return -1, err
}
defer syscall.CloseHandle(fd)
rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
var bytesReturned uint32
err = syscall.DeviceIoControl(fd, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
if err != nil {
return -1, err
}
rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
var s string
switch rdb.ReparseTag {
case syscall.IO_REPARSE_TAG_SYMLINK:
data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 {
if len(s) >= 4 && s[:4] == `\??\` {
s = s[4:]
switch {
case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar
// do nothing
case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar
s = `\\` + s[4:]
default:
// unexpected; do nothing
}
} else {
// unexpected; do nothing
}
}
case _IO_REPARSE_TAG_MOUNT_POINT:
data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar
if len(s) < 48 || s[:11] != `\??\Volume{` {
s = s[4:]
}
} else {
// unexpected; do nothing
}
default:
// the path is not a symlink or junction but another type of reparse
// point
return -1, syscall.ENOENT
}
n = copy(buf, []byte(s))
return n, nil
}

View file

@ -1,128 +0,0 @@
/*
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
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.
*/
package sysx
import (
"os"
"path/filepath"
"github.com/containerd/continuity/syscallx"
)
// Readlink returns the destination of the named symbolic link.
// If there is an error, it will be of type *PathError.
func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
n, e := fixCount(syscallx.Readlink(fixLongPath(name), b))
if e != nil {
return "", &os.PathError{Op: "readlink", Path: name, Err: e}
}
if n < len {
return string(b[0:n]), nil
}
}
}
// Many functions in package syscall return a count of -1 instead of 0.
// Using fixCount(call()) instead of call() corrects the count.
func fixCount(n int, err error) (int, error) {
if n < 0 {
n = 0
}
return n, err
}
// fixLongPath returns the extended-length (\\?\-prefixed) form of
// path when needed, in order to avoid the default 260 character file
// path limit imposed by Windows. If path is not easily converted to
// the extended-length form (for example, if path is a relative path
// or contains .. elements), or is short enough, fixLongPath returns
// path unmodified.
//
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
func fixLongPath(path string) string {
// Do nothing (and don't allocate) if the path is "short".
// Empirically (at least on the Windows Server 2013 builder),
// the kernel is arbitrarily okay with < 248 bytes. That
// matches what the docs above say:
// "When using an API to create a directory, the specified
// path cannot be so long that you cannot append an 8.3 file
// name (that is, the directory name cannot exceed MAX_PATH
// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
//
// The MSDN docs appear to say that a normal path that is 248 bytes long
// will work; empirically the path must be less then 248 bytes long.
if len(path) < 248 {
// Don't fix. (This is how Go 1.7 and earlier worked,
// not automatically generating the \\?\ form)
return path
}
// The extended form begins with \\?\, as in
// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
// The extended form disables evaluation of . and .. path
// elements and disables the interpretation of / as equivalent
// to \. The conversion here rewrites / to \ and elides
// . elements as well as trailing or duplicate separators. For
// simplicity it avoids the conversion entirely for relative
// paths or paths containing .. elements. For now,
// \\server\share paths are not converted to
// \\?\UNC\server\share paths because the rules for doing so
// are less well-specified.
if len(path) >= 2 && path[:2] == `\\` {
// Don't canonicalize UNC paths.
return path
}
if !filepath.IsAbs(path) {
// Relative path
return path
}
const prefix = `\\?`
pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
copy(pathbuf, prefix)
n := len(path)
r, w := 0, len(prefix)
for r < n {
switch {
case os.IsPathSeparator(path[r]):
// empty block
r++
case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
// /./
r++
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
// /../ is currently unhandled
return path
default:
pathbuf[w] = '\\'
w++
for ; r < n && !os.IsPathSeparator(path[r]); r++ {
pathbuf[w] = path[r]
w++
}
}
}
// A drive's root directory needs a trailing \
if w == len(`\\?\c:`) {
pathbuf[w] = '\\'
w++
}
return string(pathbuf[:w])
}

View file

@ -20,7 +20,6 @@ package sysx
import (
"bytes"
"syscall"
"golang.org/x/sys/unix"
)
@ -66,60 +65,53 @@ func LGetxattr(path, attr string) ([]byte, error) {
return getxattrAll(path, attr, unix.Lgetxattr)
}
const defaultXattrBufferSize = 5
const defaultXattrBufferSize = 128
type listxattrFunc func(path string, dest []byte) (int, error)
func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) {
var p []byte // nil on first execution
for {
n, err := listFunc(path, p) // first call gets buffer size.
buf := make([]byte, defaultXattrBufferSize)
n, err := listFunc(path, buf)
for err == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
n, err = listFunc(path, []byte{})
if err != nil {
return nil, err
}
if n > len(p) {
p = make([]byte, n)
continue
}
p = p[:n]
ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0})
var entries []string
for _, p := range ps {
s := string(p)
if s != "" {
entries = append(entries, s)
}
}
return entries, nil
buf = make([]byte, n)
n, err = listFunc(path, buf)
}
if err != nil {
return nil, err
}
ps := bytes.Split(bytes.TrimSuffix(buf[:n], []byte{0}), []byte{0})
var entries []string
for _, p := range ps {
if len(p) > 0 {
entries = append(entries, string(p))
}
}
return entries, nil
}
type getxattrFunc func(string, string, []byte) (int, error)
func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) {
p := make([]byte, defaultXattrBufferSize)
for {
n, err := getFunc(path, attr, p)
buf := make([]byte, defaultXattrBufferSize)
n, err := getFunc(path, attr, buf)
for err == unix.ERANGE {
// Buffer too small, use zero-sized buffer to get the actual size
n, err = getFunc(path, attr, []byte{})
if err != nil {
if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE {
p = make([]byte, len(p)*2) // this can't be ideal.
continue // try again!
}
return nil, err
}
// realloc to correct size and repeat
if n > len(p) {
p = make([]byte, n)
continue
}
return p[:n], nil
buf = make([]byte, n)
n, err = getFunc(path, attr, buf)
}
if err != nil {
return nil, err
}
return buf[:n], nil
}

View file

@ -23,7 +23,7 @@ import (
"runtime"
)
var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
var errUnsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
// Listxattr calls syscall listxattr and reads all content
// and returns a string array
@ -33,17 +33,17 @@ func Listxattr(path string) ([]string, error) {
// Removexattr calls syscall removexattr
func Removexattr(path string, attr string) (err error) {
return unsupported
return errUnsupported
}
// Setxattr calls syscall setxattr
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
return unsupported
return errUnsupported
}
// Getxattr calls syscall getxattr
func Getxattr(path, attr string) ([]byte, error) {
return []byte{}, unsupported
return []byte{}, errUnsupported
}
// LListxattr lists xattrs, not following symlinks
@ -53,12 +53,12 @@ func LListxattr(path string) ([]string, error) {
// LRemovexattr removes an xattr, not following symlinks
func LRemovexattr(path string, attr string) (err error) {
return unsupported
return errUnsupported
}
// LSetxattr sets an xattr, not following symlinks
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
return unsupported
return errUnsupported
}
// LGetxattr gets an xattr, not following symlinks