Browse code

vendor: update containerd/continuity efbc4488d8fe1bdc16bde3b2d2990d9b3a899165

full diff: https://github.com/containerd/continuity/compare/26c1120b8d4107d2471b93ad78ef7ce1fc84c4c4...efbc4488d8fe1bdc16bde3b2d2990d9b3a899165

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>

Sebastiaan van Stijn authored on 2020/07/28 23:33:16
Showing 12 changed files
... ...
@@ -124,7 +124,7 @@ google.golang.org/genproto                          3f1135a288c9a07e340ae8ba4cc6
124 124
 # containerd
125 125
 github.com/containerd/containerd                    c80284d4b5291a351bb471bcdabb5c1d95e7a583 # master / v1.4.0-dev
126 126
 github.com/containerd/fifo                          ff969a566b00877c63489baf6e8c35d60af6142c
127
-github.com/containerd/continuity                    26c1120b8d4107d2471b93ad78ef7ce1fc84c4c4
127
+github.com/containerd/continuity                    efbc4488d8fe1bdc16bde3b2d2990d9b3a899165
128 128
 github.com/containerd/cgroups                       44306b6a1d46985d916b48b4199f93a378af314f
129 129
 github.com/containerd/console                       8375c3424e4d7b114e8a90a4a40c8e1b40d1d4e6 # v1.0.0
130 130
 github.com/containerd/go-runc                       7016d3ce2328dd2cb1192b2076ebd565c4e8df0c
... ...
@@ -32,6 +32,7 @@ func DeviceInfo(fi os.FileInfo) (uint64, uint64, error) {
32 32
 		return 0, 0, fmt.Errorf("cannot extract device from os.FileInfo")
33 33
 	}
34 34
 
35
+	//nolint:unconvert
35 36
 	dev := uint64(sys.Rdev)
36 37
 	return uint64(unix.Major(dev)), uint64(unix.Minor(dev)), nil
37 38
 }
... ...
@@ -138,6 +138,10 @@ func (d *driver) Lstat(p string) (os.FileInfo, error) {
138 138
 	return os.Lstat(p)
139 139
 }
140 140
 
141
+func (d *driver) Readlink(p string) (string, error) {
142
+	return os.Readlink(p)
143
+}
144
+
141 145
 func (d *driver) Mkdir(p string, mode os.FileMode) error {
142 146
 	return os.Mkdir(p, mode)
143 147
 }
... ...
@@ -131,8 +131,3 @@ func (d *driver) LSetxattr(path string, attrMap map[string][]byte) error {
131 131
 func (d *driver) DeviceInfo(fi os.FileInfo) (maj uint64, min uint64, err error) {
132 132
 	return devices.DeviceInfo(fi)
133 133
 }
134
-
135
-// Readlink was forked on Windows to fix a Golang bug, use the "os" package here
136
-func (d *driver) Readlink(p string) (string, error) {
137
-	return os.Readlink(p)
138
-}
... ...
@@ -1,3 +1,5 @@
1
+// +build go1.13
2
+
1 3
 /*
2 4
    Copyright The containerd Authors.
3 5
 
... ...
@@ -14,12 +16,14 @@
14 14
    limitations under the License.
15 15
 */
16 16
 
17
+// Go 1.13 is the minimally supported version for Windows.
18
+// Earlier golang releases have bug in os.Readlink
19
+// (see https://github.com/golang/go/issues/30463).
20
+
17 21
 package driver
18 22
 
19 23
 import (
20 24
 	"os"
21
-
22
-	"github.com/containerd/continuity/sysx"
23 25
 )
24 26
 
25 27
 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) {
35 35
 	// TODO: Use Window's equivalent
36 36
 	return os.Chmod(path, mode)
37 37
 }
38
-
39
-// Readlink is forked in order to support Volume paths which are used
40
-// in container layers.
41
-func (d *driver) Readlink(p string) (string, error) {
42
-	return sysx.Readlink(p)
43
-}
... ...
@@ -117,15 +117,13 @@ func sameFile(f1, f2 *currentPath) (bool, error) {
117 117
 		// If the timestamp may have been truncated in both of the
118 118
 		// files, check content of file to determine difference
119 119
 		if t1.Nanosecond() == 0 && t2.Nanosecond() == 0 {
120
-			var eq bool
121 120
 			if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink {
122
-				eq, err = compareSymlinkTarget(f1.fullPath, f2.fullPath)
123
-			} else if f1.f.Size() > 0 {
124
-				eq, err = compareFileContent(f1.fullPath, f2.fullPath)
121
+				return compareSymlinkTarget(f1.fullPath, f2.fullPath)
125 122
 			}
126
-			if err != nil || !eq {
127
-				return eq, err
123
+			if f1.f.Size() == 0 { // if file sizes are zero length, the files are the same by definition
124
+				return true, nil
128 125
 			}
126
+			return compareFileContent(f1.fullPath, f2.fullPath)
129 127
 		} else if t1.Nanosecond() != t2.Nanosecond() {
130 128
 			return false, nil
131 129
 		}
... ...
@@ -1,6 +1,6 @@
1 1
 module github.com/containerd/continuity
2 2
 
3
-go 1.11
3
+go 1.13
4 4
 
5 5
 require (
6 6
 	bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898
7 7
deleted file mode 100644
... ...
@@ -1,26 +0,0 @@
1
-// +build !windows
2
-
3
-/*
4
-   Copyright The containerd Authors.
5
-
6
-   Licensed under the Apache License, Version 2.0 (the "License");
7
-   you may not use this file except in compliance with the License.
8
-   You may obtain a copy of the License at
9
-
10
-       http://www.apache.org/licenses/LICENSE-2.0
11
-
12
-   Unless required by applicable law or agreed to in writing, software
13
-   distributed under the License is distributed on an "AS IS" BASIS,
14
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
-   See the License for the specific language governing permissions and
16
-   limitations under the License.
17
-*/
18
-
19
-package syscallx
20
-
21
-import "syscall"
22
-
23
-// Readlink returns the destination of the named symbolic link.
24
-func Readlink(path string, buf []byte) (n int, err error) {
25
-	return syscall.Readlink(path, buf)
26
-}
27 1
deleted file mode 100644
... ...
@@ -1,112 +0,0 @@
1
-/*
2
-   Copyright The containerd Authors.
3
-
4
-   Licensed under the Apache License, Version 2.0 (the "License");
5
-   you may not use this file except in compliance with the License.
6
-   You may obtain a copy of the License at
7
-
8
-       http://www.apache.org/licenses/LICENSE-2.0
9
-
10
-   Unless required by applicable law or agreed to in writing, software
11
-   distributed under the License is distributed on an "AS IS" BASIS,
12
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
-   See the License for the specific language governing permissions and
14
-   limitations under the License.
15
-*/
16
-
17
-package syscallx
18
-
19
-import (
20
-	"syscall"
21
-	"unsafe"
22
-)
23
-
24
-type reparseDataBuffer struct {
25
-	ReparseTag        uint32
26
-	ReparseDataLength uint16
27
-	Reserved          uint16
28
-
29
-	// GenericReparseBuffer
30
-	reparseBuffer byte
31
-}
32
-
33
-type mountPointReparseBuffer struct {
34
-	SubstituteNameOffset uint16
35
-	SubstituteNameLength uint16
36
-	PrintNameOffset      uint16
37
-	PrintNameLength      uint16
38
-	PathBuffer           [1]uint16
39
-}
40
-
41
-type symbolicLinkReparseBuffer struct {
42
-	SubstituteNameOffset uint16
43
-	SubstituteNameLength uint16
44
-	PrintNameOffset      uint16
45
-	PrintNameLength      uint16
46
-	Flags                uint32
47
-	PathBuffer           [1]uint16
48
-}
49
-
50
-const (
51
-	_IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
52
-	_SYMLINK_FLAG_RELATIVE      = 1
53
-)
54
-
55
-// Readlink returns the destination of the named symbolic link.
56
-func Readlink(path string, buf []byte) (n int, err error) {
57
-	fd, err := syscall.CreateFile(syscall.StringToUTF16Ptr(path), syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING,
58
-		syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
59
-	if err != nil {
60
-		return -1, err
61
-	}
62
-	defer syscall.CloseHandle(fd)
63
-
64
-	rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
65
-	var bytesReturned uint32
66
-	err = syscall.DeviceIoControl(fd, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
67
-	if err != nil {
68
-		return -1, err
69
-	}
70
-
71
-	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
72
-	var s string
73
-	switch rdb.ReparseTag {
74
-	case syscall.IO_REPARSE_TAG_SYMLINK:
75
-		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
76
-		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
77
-		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
78
-		if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 {
79
-			if len(s) >= 4 && s[:4] == `\??\` {
80
-				s = s[4:]
81
-				switch {
82
-				case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar
83
-					// do nothing
84
-				case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar
85
-					s = `\\` + s[4:]
86
-				default:
87
-					// unexpected; do nothing
88
-				}
89
-			} else {
90
-				// unexpected; do nothing
91
-			}
92
-		}
93
-	case _IO_REPARSE_TAG_MOUNT_POINT:
94
-		data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
95
-		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
96
-		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
97
-		if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar
98
-			if len(s) < 48 || s[:11] != `\??\Volume{` {
99
-				s = s[4:]
100
-			}
101
-		} else {
102
-			// unexpected; do nothing
103
-		}
104
-	default:
105
-		// the path is not a symlink or junction but another type of reparse
106
-		// point
107
-		return -1, syscall.ENOENT
108
-	}
109
-	n = copy(buf, []byte(s))
110
-
111
-	return n, nil
112
-}
113 1
deleted file mode 100644
... ...
@@ -1,128 +0,0 @@
1
-/*
2
-   Copyright The containerd Authors.
3
-
4
-   Licensed under the Apache License, Version 2.0 (the "License");
5
-   you may not use this file except in compliance with the License.
6
-   You may obtain a copy of the License at
7
-
8
-       http://www.apache.org/licenses/LICENSE-2.0
9
-
10
-   Unless required by applicable law or agreed to in writing, software
11
-   distributed under the License is distributed on an "AS IS" BASIS,
12
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
-   See the License for the specific language governing permissions and
14
-   limitations under the License.
15
-*/
16
-
17
-package sysx
18
-
19
-import (
20
-	"os"
21
-	"path/filepath"
22
-
23
-	"github.com/containerd/continuity/syscallx"
24
-)
25
-
26
-// Readlink returns the destination of the named symbolic link.
27
-// If there is an error, it will be of type *PathError.
28
-func Readlink(name string) (string, error) {
29
-	for len := 128; ; len *= 2 {
30
-		b := make([]byte, len)
31
-		n, e := fixCount(syscallx.Readlink(fixLongPath(name), b))
32
-		if e != nil {
33
-			return "", &os.PathError{Op: "readlink", Path: name, Err: e}
34
-		}
35
-		if n < len {
36
-			return string(b[0:n]), nil
37
-		}
38
-	}
39
-}
40
-
41
-// Many functions in package syscall return a count of -1 instead of 0.
42
-// Using fixCount(call()) instead of call() corrects the count.
43
-func fixCount(n int, err error) (int, error) {
44
-	if n < 0 {
45
-		n = 0
46
-	}
47
-	return n, err
48
-}
49
-
50
-// fixLongPath returns the extended-length (\\?\-prefixed) form of
51
-// path when needed, in order to avoid the default 260 character file
52
-// path limit imposed by Windows. If path is not easily converted to
53
-// the extended-length form (for example, if path is a relative path
54
-// or contains .. elements), or is short enough, fixLongPath returns
55
-// path unmodified.
56
-//
57
-// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
58
-func fixLongPath(path string) string {
59
-	// Do nothing (and don't allocate) if the path is "short".
60
-	// Empirically (at least on the Windows Server 2013 builder),
61
-	// the kernel is arbitrarily okay with < 248 bytes. That
62
-	// matches what the docs above say:
63
-	// "When using an API to create a directory, the specified
64
-	// path cannot be so long that you cannot append an 8.3 file
65
-	// name (that is, the directory name cannot exceed MAX_PATH
66
-	// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
67
-	//
68
-	// The MSDN docs appear to say that a normal path that is 248 bytes long
69
-	// will work; empirically the path must be less then 248 bytes long.
70
-	if len(path) < 248 {
71
-		// Don't fix. (This is how Go 1.7 and earlier worked,
72
-		// not automatically generating the \\?\ form)
73
-		return path
74
-	}
75
-
76
-	// The extended form begins with \\?\, as in
77
-	// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
78
-	// The extended form disables evaluation of . and .. path
79
-	// elements and disables the interpretation of / as equivalent
80
-	// to \. The conversion here rewrites / to \ and elides
81
-	// . elements as well as trailing or duplicate separators. For
82
-	// simplicity it avoids the conversion entirely for relative
83
-	// paths or paths containing .. elements. For now,
84
-	// \\server\share paths are not converted to
85
-	// \\?\UNC\server\share paths because the rules for doing so
86
-	// are less well-specified.
87
-	if len(path) >= 2 && path[:2] == `\\` {
88
-		// Don't canonicalize UNC paths.
89
-		return path
90
-	}
91
-	if !filepath.IsAbs(path) {
92
-		// Relative path
93
-		return path
94
-	}
95
-
96
-	const prefix = `\\?`
97
-
98
-	pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
99
-	copy(pathbuf, prefix)
100
-	n := len(path)
101
-	r, w := 0, len(prefix)
102
-	for r < n {
103
-		switch {
104
-		case os.IsPathSeparator(path[r]):
105
-			// empty block
106
-			r++
107
-		case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
108
-			// /./
109
-			r++
110
-		case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
111
-			// /../ is currently unhandled
112
-			return path
113
-		default:
114
-			pathbuf[w] = '\\'
115
-			w++
116
-			for ; r < n && !os.IsPathSeparator(path[r]); r++ {
117
-				pathbuf[w] = path[r]
118
-				w++
119
-			}
120
-		}
121
-	}
122
-	// A drive's root directory needs a trailing \
123
-	if w == len(`\\?\c:`) {
124
-		pathbuf[w] = '\\'
125
-		w++
126
-	}
127
-	return string(pathbuf[:w])
128
-}
... ...
@@ -20,7 +20,6 @@ package sysx
20 20
 
21 21
 import (
22 22
 	"bytes"
23
-	"syscall"
24 23
 
25 24
 	"golang.org/x/sys/unix"
26 25
 )
... ...
@@ -66,60 +65,53 @@ func LGetxattr(path, attr string) ([]byte, error) {
66 66
 	return getxattrAll(path, attr, unix.Lgetxattr)
67 67
 }
68 68
 
69
-const defaultXattrBufferSize = 5
69
+const defaultXattrBufferSize = 128
70 70
 
71 71
 type listxattrFunc func(path string, dest []byte) (int, error)
72 72
 
73 73
 func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) {
74
-	var p []byte // nil on first execution
75
-
76
-	for {
77
-		n, err := listFunc(path, p) // first call gets buffer size.
74
+	buf := make([]byte, defaultXattrBufferSize)
75
+	n, err := listFunc(path, buf)
76
+	for err == unix.ERANGE {
77
+		// Buffer too small, use zero-sized buffer to get the actual size
78
+		n, err = listFunc(path, []byte{})
78 79
 		if err != nil {
79 80
 			return nil, err
80 81
 		}
82
+		buf = make([]byte, n)
83
+		n, err = listFunc(path, buf)
84
+	}
85
+	if err != nil {
86
+		return nil, err
87
+	}
81 88
 
82
-		if n > len(p) {
83
-			p = make([]byte, n)
84
-			continue
85
-		}
86
-
87
-		p = p[:n]
88
-
89
-		ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0})
90
-		var entries []string
91
-		for _, p := range ps {
92
-			s := string(p)
93
-			if s != "" {
94
-				entries = append(entries, s)
95
-			}
89
+	ps := bytes.Split(bytes.TrimSuffix(buf[:n], []byte{0}), []byte{0})
90
+	var entries []string
91
+	for _, p := range ps {
92
+		if len(p) > 0 {
93
+			entries = append(entries, string(p))
96 94
 		}
97
-
98
-		return entries, nil
99 95
 	}
96
+
97
+	return entries, nil
100 98
 }
101 99
 
102 100
 type getxattrFunc func(string, string, []byte) (int, error)
103 101
 
104 102
 func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) {
105
-	p := make([]byte, defaultXattrBufferSize)
106
-	for {
107
-		n, err := getFunc(path, attr, p)
103
+	buf := make([]byte, defaultXattrBufferSize)
104
+	n, err := getFunc(path, attr, buf)
105
+	for err == unix.ERANGE {
106
+		// Buffer too small, use zero-sized buffer to get the actual size
107
+		n, err = getFunc(path, attr, []byte{})
108 108
 		if err != nil {
109
-			if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE {
110
-				p = make([]byte, len(p)*2) // this can't be ideal.
111
-				continue                   // try again!
112
-			}
113
-
114 109
 			return nil, err
115 110
 		}
116
-
117
-		// realloc to correct size and repeat
118
-		if n > len(p) {
119
-			p = make([]byte, n)
120
-			continue
121
-		}
122
-
123
-		return p[:n], nil
111
+		buf = make([]byte, n)
112
+		n, err = getFunc(path, attr, buf)
113
+	}
114
+	if err != nil {
115
+		return nil, err
124 116
 	}
117
+	return buf[:n], nil
125 118
 }
... ...
@@ -23,7 +23,7 @@ import (
23 23
 	"runtime"
24 24
 )
25 25
 
26
-var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
26
+var errUnsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
27 27
 
28 28
 // Listxattr calls syscall listxattr and reads all content
29 29
 // and returns a string array
... ...
@@ -33,17 +33,17 @@ func Listxattr(path string) ([]string, error) {
33 33
 
34 34
 // Removexattr calls syscall removexattr
35 35
 func Removexattr(path string, attr string) (err error) {
36
-	return unsupported
36
+	return errUnsupported
37 37
 }
38 38
 
39 39
 // Setxattr calls syscall setxattr
40 40
 func Setxattr(path string, attr string, data []byte, flags int) (err error) {
41
-	return unsupported
41
+	return errUnsupported
42 42
 }
43 43
 
44 44
 // Getxattr calls syscall getxattr
45 45
 func Getxattr(path, attr string) ([]byte, error) {
46
-	return []byte{}, unsupported
46
+	return []byte{}, errUnsupported
47 47
 }
48 48
 
49 49
 // LListxattr lists xattrs, not following symlinks
... ...
@@ -53,12 +53,12 @@ func LListxattr(path string) ([]string, error) {
53 53
 
54 54
 // LRemovexattr removes an xattr, not following symlinks
55 55
 func LRemovexattr(path string, attr string) (err error) {
56
-	return unsupported
56
+	return errUnsupported
57 57
 }
58 58
 
59 59
 // LSetxattr sets an xattr, not following symlinks
60 60
 func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
61
-	return unsupported
61
+	return errUnsupported
62 62
 }
63 63
 
64 64
 // LGetxattr gets an xattr, not following symlinks