Update continuity vendor
Pulls in copy and fstest changes Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
parent
81386df917
commit
5a0ff41c81
@ -50,25 +50,25 @@ func testLookup(t *testing.T, fsType string) {
|
||||
}
|
||||
defer os.RemoveAll(mnt)
|
||||
|
||||
deviceName, cleanupDevice, err := loopback.New(100 << 20) // 100 MB
|
||||
loop, err := loopback.New(100 << 20) // 100 MB
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if out, err := exec.Command("mkfs", "-t", fsType, deviceName).CombinedOutput(); err != nil {
|
||||
if out, err := exec.Command("mkfs", "-t", fsType, loop.Device).CombinedOutput(); err != nil {
|
||||
// not fatal
|
||||
cleanupDevice()
|
||||
t.Skipf("could not mkfs (%s) %s: %v (out: %q)", fsType, deviceName, err, string(out))
|
||||
loop.Close()
|
||||
t.Skipf("could not mkfs (%s) %s: %v (out: %q)", fsType, loop.Device, err, string(out))
|
||||
}
|
||||
if out, err := exec.Command("mount", deviceName, mnt).CombinedOutput(); err != nil {
|
||||
if out, err := exec.Command("mount", loop.Device, mnt).CombinedOutput(); err != nil {
|
||||
// not fatal
|
||||
cleanupDevice()
|
||||
t.Skipf("could not mount %s: %v (out: %q)", deviceName, err, string(out))
|
||||
loop.Close()
|
||||
t.Skipf("could not mount %s: %v (out: %q)", loop.Device, err, string(out))
|
||||
}
|
||||
defer func() {
|
||||
testutil.Unmount(t, mnt)
|
||||
cleanupDevice()
|
||||
loop.Close()
|
||||
}()
|
||||
assert.Check(t, strings.HasPrefix(deviceName, "/dev/loop"))
|
||||
assert.Check(t, strings.HasPrefix(loop.Device, "/dev/loop"))
|
||||
checkLookup(t, fsType, mnt, mnt)
|
||||
|
||||
newMnt, err := ioutil.TempDir("", "containerd-mountinfo-test-newMnt")
|
||||
|
@ -52,24 +52,24 @@ func boltSnapshotter(t *testing.T) func(context.Context, string) (snapshots.Snap
|
||||
if os.Getpagesize() > 4096 {
|
||||
loopbackSize = int64(650 << 20) // 650 MB
|
||||
}
|
||||
deviceName, cleanupDevice, err := loopback.New(loopbackSize)
|
||||
loop, err := loopback.New(loopbackSize)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if out, err := exec.Command(mkbtrfs, deviceName).CombinedOutput(); err != nil {
|
||||
cleanupDevice()
|
||||
if out, err := exec.Command(mkbtrfs, loop.Device).CombinedOutput(); err != nil {
|
||||
loop.Close()
|
||||
return nil, nil, errors.Wrapf(err, "failed to make btrfs filesystem (out: %q)", out)
|
||||
}
|
||||
if out, err := exec.Command("mount", deviceName, root).CombinedOutput(); err != nil {
|
||||
cleanupDevice()
|
||||
return nil, nil, errors.Wrapf(err, "failed to mount device %s (out: %q)", deviceName, out)
|
||||
if out, err := exec.Command("mount", loop.Device, root).CombinedOutput(); err != nil {
|
||||
loop.Close()
|
||||
return nil, nil, errors.Wrapf(err, "failed to mount device %s (out: %q)", loop.Device, out)
|
||||
}
|
||||
|
||||
snapshotter, err := NewSnapshotter(root)
|
||||
if err != nil {
|
||||
cleanupDevice()
|
||||
loop.Close()
|
||||
return nil, nil, errors.Wrap(err, "failed to create new snapshotter")
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ func boltSnapshotter(t *testing.T) func(context.Context, string) (snapshots.Snap
|
||||
return err
|
||||
}
|
||||
err := mount.UnmountAll(root, unix.MNT_DETACH)
|
||||
if cerr := cleanupDevice(); cerr != nil {
|
||||
if cerr := loop.Close(); cerr != nil {
|
||||
err = errors.Wrap(cerr, "device cleanup failed")
|
||||
}
|
||||
return err
|
||||
|
@ -36,23 +36,23 @@ func testOverlaySupported(t testing.TB, expected bool, mkfs ...string) {
|
||||
}
|
||||
defer os.RemoveAll(mnt)
|
||||
|
||||
deviceName, cleanupDevice, err := loopback.New(100 << 20) // 100 MB
|
||||
loop, err := loopback.New(100 << 20) // 100 MB
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if out, err := exec.Command(mkfs[0], append(mkfs[1:], deviceName)...).CombinedOutput(); err != nil {
|
||||
if out, err := exec.Command(mkfs[0], append(mkfs[1:], loop.Device)...).CombinedOutput(); err != nil {
|
||||
// not fatal
|
||||
cleanupDevice()
|
||||
t.Skipf("could not mkfs (%v) %s: %v (out: %q)", mkfs, deviceName, err, string(out))
|
||||
loop.Close()
|
||||
t.Skipf("could not mkfs (%v) %s: %v (out: %q)", mkfs, loop.Device, err, string(out))
|
||||
}
|
||||
if out, err := exec.Command("mount", deviceName, mnt).CombinedOutput(); err != nil {
|
||||
if out, err := exec.Command("mount", loop.Device, mnt).CombinedOutput(); err != nil {
|
||||
// not fatal
|
||||
cleanupDevice()
|
||||
t.Skipf("could not mount %s: %v (out: %q)", deviceName, err, string(out))
|
||||
loop.Close()
|
||||
t.Skipf("could not mount %s: %v (out: %q)", loop.Device, err, string(out))
|
||||
}
|
||||
defer func() {
|
||||
testutil.Unmount(t, mnt)
|
||||
cleanupDevice()
|
||||
loop.Close()
|
||||
}()
|
||||
workload := func() {
|
||||
err = Supported(mnt)
|
||||
|
@ -4,7 +4,7 @@ github.com/containerd/cgroups c4b9ac5c7601384c965b9646fc515884e091ebb9
|
||||
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
||||
github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
|
||||
github.com/containerd/btrfs af5082808c833de0e79c1e72eea9fea239364877
|
||||
github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
|
||||
github.com/containerd/continuity f2a389ac0a02ce21c09edd7344677a601970f41c
|
||||
github.com/coreos/go-systemd 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
||||
github.com/docker/go-metrics 4ea375f7759c82740c893fc030bc37088d2ec098
|
||||
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||
|
19
vendor/github.com/containerd/continuity/LICENSE
generated
vendored
19
vendor/github.com/containerd/continuity/LICENSE
generated
vendored
@ -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.
|
||||
|
||||
|
10
vendor/github.com/containerd/continuity/README.md
generated
vendored
10
vendor/github.com/containerd/continuity/README.md
generated
vendored
@ -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.
|
||||
|
51
vendor/github.com/containerd/continuity/fs/copy.go
generated
vendored
51
vendor/github.com/containerd/continuity/fs/copy.go
generated
vendored
@ -32,14 +32,49 @@ var bufferPool = &sync.Pool{
|
||||
},
|
||||
}
|
||||
|
||||
// CopyDir copies the directory from src to dst.
|
||||
// Most efficient copy of files is attempted.
|
||||
func CopyDir(dst, src string) error {
|
||||
inodes := map[uint64]string{}
|
||||
return copyDirectory(dst, src, inodes)
|
||||
// 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
|
||||
}
|
||||
|
||||
func copyDirectory(dst, src string, inodes map[uint64]string) error {
|
||||
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, 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, &o)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
37
vendor/github.com/containerd/continuity/fs/copy_linux.go
generated
vendored
37
vendor/github.com/containerd/continuity/fs/copy_linux.go
generated
vendored
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
24
vendor/github.com/containerd/continuity/fs/copy_unix.go
generated
vendored
24
vendor/github.com/containerd/continuity/fs/copy_unix.go
generated
vendored
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/containerd/continuity/fs/copy_windows.go
generated
vendored
2
vendor/github.com/containerd/continuity/fs/copy_windows.go
generated
vendored
@ -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
|
||||
}
|
||||
|
||||
|
10
vendor/github.com/containerd/continuity/fs/fstest/compare.go
generated
vendored
10
vendor/github.com/containerd/continuity/fs/fstest/compare.go
generated
vendored
@ -49,15 +49,7 @@ func CheckDirectoryEqual(d1, d2 string) error {
|
||||
|
||||
diff := diffResourceList(m1.Resources, m2.Resources)
|
||||
if diff.HasDiff() {
|
||||
if len(diff.Deletions) != 0 {
|
||||
return errors.Errorf("directory diff between %s and %s\n%s", d1, d2, diff.String())
|
||||
}
|
||||
// TODO: Also skip Recycle Bin contents in Windows layers which is used to store deleted files in some cases
|
||||
for _, add := range diff.Additions {
|
||||
if ok, _ := metadataFiles[add.Path()]; !ok {
|
||||
return errors.Errorf("directory diff between %s and %s\n%s", d1, d2, diff.String())
|
||||
}
|
||||
}
|
||||
return errors.Errorf("directory diff between %s and %s\n%s", d1, d2, diff.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
1
vendor/github.com/containerd/continuity/fs/fstest/compare_windows.go
generated
vendored
1
vendor/github.com/containerd/continuity/fs/fstest/compare_windows.go
generated
vendored
@ -17,6 +17,7 @@
|
||||
package fstest
|
||||
|
||||
// TODO: Any more metadata files generated by Windows layers?
|
||||
// TODO: Also skip Recycle Bin contents in Windows layers which is used to store deleted files in some cases
|
||||
var metadataFiles = map[string]bool{
|
||||
"\\System Volume Information": true,
|
||||
"\\WcSandboxState": true,
|
||||
|
12
vendor/github.com/containerd/continuity/fs/fstest/continuity_util.go
generated
vendored
12
vendor/github.com/containerd/continuity/fs/fstest/continuity_util.go
generated
vendored
@ -42,7 +42,17 @@ type resourceListDifference struct {
|
||||
}
|
||||
|
||||
func (l resourceListDifference) HasDiff() bool {
|
||||
return len(l.Additions) > 0 || len(l.Deletions) > 0 || len(l.Updates) > 0
|
||||
if len(l.Deletions) > 0 || len(l.Updates) > 0 || (len(metadataFiles) == 0 && len(l.Additions) > 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, add := range l.Additions {
|
||||
if ok, _ := metadataFiles[add.Path()]; !ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (l resourceListDifference) String() string {
|
||||
|
33
vendor/github.com/containerd/continuity/fs/path.go
generated
vendored
33
vendor/github.com/containerd/continuity/fs/path.go
generated
vendored
@ -22,7 +22,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -47,9 +46,8 @@ func pathChange(lower, upper *currentPath) (ChangeKind, string) {
|
||||
if upper == nil {
|
||||
return ChangeKindDelete, lower.path
|
||||
}
|
||||
// TODO: compare by directory
|
||||
|
||||
switch i := strings.Compare(lower.path, upper.path); {
|
||||
switch i := directoryCompare(lower.path, upper.path); {
|
||||
case i < 0:
|
||||
// File in lower that is not in upper
|
||||
return ChangeKindDelete, lower.path
|
||||
@ -61,6 +59,35 @@ func pathChange(lower, upper *currentPath) (ChangeKind, string) {
|
||||
}
|
||||
}
|
||||
|
||||
func directoryCompare(a, b string) int {
|
||||
l := len(a)
|
||||
if len(b) < l {
|
||||
l = len(b)
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
c1, c2 := a[i], b[i]
|
||||
if c1 == filepath.Separator {
|
||||
c1 = byte(0)
|
||||
}
|
||||
if c2 == filepath.Separator {
|
||||
c2 = byte(0)
|
||||
}
|
||||
if c1 < c2 {
|
||||
return -1
|
||||
}
|
||||
if c1 > c2 {
|
||||
return +1
|
||||
}
|
||||
}
|
||||
if len(a) < len(b) {
|
||||
return -1
|
||||
}
|
||||
if len(a) > len(b) {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func sameFile(f1, f2 *currentPath) (bool, error) {
|
||||
if os.SameFile(f1.f, f2.f) {
|
||||
return true, nil
|
||||
|
55
vendor/github.com/containerd/continuity/testutil/loopback/loopback_linux.go
generated
vendored
55
vendor/github.com/containerd/continuity/testutil/loopback/loopback_linux.go
generated
vendored
@ -22,24 +22,25 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// New creates a loopback device, and returns its device name (/dev/loopX), and its clean-up function.
|
||||
func New(size int64) (string, func() error, error) {
|
||||
// New creates a loopback device
|
||||
func New(size int64) (*Loopback, error) {
|
||||
// create temporary file for the disk image
|
||||
file, err := ioutil.TempFile("", "containerd-test-loopback")
|
||||
if err != nil {
|
||||
return "", nil, errors.Wrap(err, "could not create temporary file for loopback")
|
||||
return nil, errors.Wrap(err, "could not create temporary file for loopback")
|
||||
}
|
||||
|
||||
if err := file.Truncate(size); err != nil {
|
||||
file.Close()
|
||||
os.Remove(file.Name())
|
||||
return "", nil, errors.Wrap(err, "failed to resize temp file")
|
||||
return nil, errors.Wrap(err, "failed to resize temp file")
|
||||
}
|
||||
file.Close()
|
||||
|
||||
@ -48,7 +49,7 @@ func New(size int64) (string, func() error, error) {
|
||||
p, err := losetup.Output()
|
||||
if err != nil {
|
||||
os.Remove(file.Name())
|
||||
return "", nil, errors.Wrap(err, "loopback setup failed")
|
||||
return nil, errors.Wrap(err, "loopback setup failed")
|
||||
}
|
||||
|
||||
deviceName := strings.TrimSpace(string(p))
|
||||
@ -68,5 +69,47 @@ func New(size int64) (string, func() error, error) {
|
||||
return os.Remove(file.Name())
|
||||
}
|
||||
|
||||
return deviceName, cleanup, nil
|
||||
l := Loopback{
|
||||
File: file.Name(),
|
||||
Device: deviceName,
|
||||
close: cleanup,
|
||||
}
|
||||
return &l, nil
|
||||
}
|
||||
|
||||
// Loopback device
|
||||
type Loopback struct {
|
||||
// File is the underlying sparse file
|
||||
File string
|
||||
// Device is /dev/loopX
|
||||
Device string
|
||||
close func() error
|
||||
}
|
||||
|
||||
// SoftSize returns st_size
|
||||
func (l *Loopback) SoftSize() (int64, error) {
|
||||
st, err := os.Stat(l.File)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return st.Size(), nil
|
||||
}
|
||||
|
||||
// HardSize returns st_blocks * 512; see stat(2)
|
||||
func (l *Loopback) HardSize() (int64, error) {
|
||||
st, err := os.Stat(l.File)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
st2, ok := st.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return 0, errors.New("st.Sys() is not a *syscall.Stat_t")
|
||||
}
|
||||
// NOTE: st_blocks has nothing to do with st_blksize; see stat(2)
|
||||
return st2.Blocks * 512, nil
|
||||
}
|
||||
|
||||
// Close detaches the device and removes the underlying file
|
||||
func (l *Loopback) Close() error {
|
||||
return l.close()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user