Fix dependencies
This commit is contained in:
		
							
								
								
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var bufferPool = &sync.Pool{
 | 
			
		||||
	New: func() interface{} {
 | 
			
		||||
		buffer := make([]byte, 32*1024)
 | 
			
		||||
		return &buffer
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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, 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)
 | 
			
		||||
	}
 | 
			
		||||
	if !stat.IsDir() {
 | 
			
		||||
		return errors.Errorf("source is not directory")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if st, err := os.Stat(dst); err != nil {
 | 
			
		||||
		if err := os.Mkdir(dst, stat.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to mkdir %s", dst)
 | 
			
		||||
		}
 | 
			
		||||
	} else if !st.IsDir() {
 | 
			
		||||
		return errors.Errorf("cannot copy to non-directory: %s", dst)
 | 
			
		||||
	} else {
 | 
			
		||||
		if err := os.Chmod(dst, stat.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod on %s", dst)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fis, err := ioutil.ReadDir(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to read %s", src)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := copyFileInfo(stat, dst); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to copy file info for %s", dst)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, fi := range fis {
 | 
			
		||||
		source := filepath.Join(src, fi.Name())
 | 
			
		||||
		target := filepath.Join(dst, fi.Name())
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case fi.IsDir():
 | 
			
		||||
			if err := copyDirectory(target, source, inodes, o); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		case (fi.Mode() & os.ModeType) == 0:
 | 
			
		||||
			link, err := getLinkSource(target, fi, inodes)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrap(err, "failed to get hardlink")
 | 
			
		||||
			}
 | 
			
		||||
			if link != "" {
 | 
			
		||||
				if err := os.Link(link, target); err != nil {
 | 
			
		||||
					return errors.Wrap(err, "failed to create hard link")
 | 
			
		||||
				}
 | 
			
		||||
			} else if err := CopyFile(target, source); err != nil {
 | 
			
		||||
				return errors.Wrap(err, "failed to copy files")
 | 
			
		||||
			}
 | 
			
		||||
		case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink:
 | 
			
		||||
			link, err := os.Readlink(source)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to read link: %s", source)
 | 
			
		||||
			}
 | 
			
		||||
			if err := os.Symlink(link, target); err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to create symlink: %s", target)
 | 
			
		||||
			}
 | 
			
		||||
		case (fi.Mode() & os.ModeDevice) == os.ModeDevice:
 | 
			
		||||
			if err := copyDevice(target, fi); err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to create device")
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			// TODO: Support pipes and sockets
 | 
			
		||||
			return errors.Wrapf(err, "unsupported mode %s", fi.Mode())
 | 
			
		||||
		}
 | 
			
		||||
		if err := copyFileInfo(fi, target); err != nil {
 | 
			
		||||
			return errors.Wrap(err, "failed to copy file info")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := copyXAttrs(target, source, o.xeh); err != nil {
 | 
			
		||||
			return errors.Wrap(err, "failed to copy xattrs")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CopyFile copies the source file to the target.
 | 
			
		||||
// The most efficient means of copying is used for the platform.
 | 
			
		||||
func CopyFile(target, source string) error {
 | 
			
		||||
	src, err := os.Open(source)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to open source %s", source)
 | 
			
		||||
	}
 | 
			
		||||
	defer src.Close()
 | 
			
		||||
	tgt, err := os.Create(target)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to open target %s", target)
 | 
			
		||||
	}
 | 
			
		||||
	defer tgt.Close()
 | 
			
		||||
 | 
			
		||||
	return copyFileContent(tgt, src)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	st := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
 | 
			
		||||
		if os.IsPermission(err) {
 | 
			
		||||
			// Normally if uid/gid are the same this would be a no-op, but some
 | 
			
		||||
			// filesystems may still return EPERM... for instance NFS does this.
 | 
			
		||||
			// In such a case, this is not an error.
 | 
			
		||||
			if dstStat, err2 := os.Lstat(name); err2 == nil {
 | 
			
		||||
				st2 := dstStat.Sys().(*syscall.Stat_t)
 | 
			
		||||
				if st.Uid == st2.Uid && st.Gid == st2.Gid {
 | 
			
		||||
					err = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chown %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
 | 
			
		||||
		if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timespec := []unix.Timespec{unix.Timespec(StatAtime(st)), unix.Timespec(StatMtime(st))}
 | 
			
		||||
	if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to utime %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const maxSSizeT = int64(^uint(0) >> 1)
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	st, err := src.Stat()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrap(err, "unable to stat source")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size := st.Size()
 | 
			
		||||
	first := true
 | 
			
		||||
	srcFd := int(src.Fd())
 | 
			
		||||
	dstFd := int(dst.Fd())
 | 
			
		||||
 | 
			
		||||
	for 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")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
			_, err = io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
			bufferPool.Put(buf)
 | 
			
		||||
			return errors.Wrap(err, "userspace copy failed")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		first = false
 | 
			
		||||
		size -= int64(n)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	xattrKeys, err := sysx.LListxattr(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		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 {
 | 
			
		||||
			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 {
 | 
			
		||||
			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
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	st, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("unsupported stat type")
 | 
			
		||||
	}
 | 
			
		||||
	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,112 @@
 | 
			
		||||
// +build solaris darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	st := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
 | 
			
		||||
		if os.IsPermission(err) {
 | 
			
		||||
			// Normally if uid/gid are the same this would be a no-op, but some
 | 
			
		||||
			// filesystems may still return EPERM... for instance NFS does this.
 | 
			
		||||
			// In such a case, this is not an error.
 | 
			
		||||
			if dstStat, err2 := os.Lstat(name); err2 == nil {
 | 
			
		||||
				st2 := dstStat.Sys().(*syscall.Stat_t)
 | 
			
		||||
				if st.Uid == st2.Uid && st.Gid == st2.Gid {
 | 
			
		||||
					err = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chown %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
 | 
			
		||||
		if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timespec := []syscall.Timespec{StatAtime(st), StatMtime(st)}
 | 
			
		||||
	if err := syscall.UtimesNano(name, timespec); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to utime %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
	_, err := io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	bufferPool.Put(buf)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	xattrKeys, err := sysx.LListxattr(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		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 {
 | 
			
		||||
			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 {
 | 
			
		||||
			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
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	st, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("unsupported stat type")
 | 
			
		||||
	}
 | 
			
		||||
	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,49 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: copy windows specific metadata
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
	_, err := io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	bufferPool.Put(buf)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	return errors.New("device copy not supported")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,326 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sync/errgroup"
 | 
			
		||||
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ChangeKind is the type of modification that
 | 
			
		||||
// a change is making.
 | 
			
		||||
type ChangeKind int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// ChangeKindUnmodified represents an unmodified
 | 
			
		||||
	// file
 | 
			
		||||
	ChangeKindUnmodified = iota
 | 
			
		||||
 | 
			
		||||
	// ChangeKindAdd represents an addition of
 | 
			
		||||
	// a file
 | 
			
		||||
	ChangeKindAdd
 | 
			
		||||
 | 
			
		||||
	// ChangeKindModify represents a change to
 | 
			
		||||
	// an existing file
 | 
			
		||||
	ChangeKindModify
 | 
			
		||||
 | 
			
		||||
	// ChangeKindDelete represents a delete of
 | 
			
		||||
	// a file
 | 
			
		||||
	ChangeKindDelete
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (k ChangeKind) String() string {
 | 
			
		||||
	switch k {
 | 
			
		||||
	case ChangeKindUnmodified:
 | 
			
		||||
		return "unmodified"
 | 
			
		||||
	case ChangeKindAdd:
 | 
			
		||||
		return "add"
 | 
			
		||||
	case ChangeKindModify:
 | 
			
		||||
		return "modify"
 | 
			
		||||
	case ChangeKindDelete:
 | 
			
		||||
		return "delete"
 | 
			
		||||
	default:
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Change represents single change between a diff and its parent.
 | 
			
		||||
type Change struct {
 | 
			
		||||
	Kind ChangeKind
 | 
			
		||||
	Path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChangeFunc is the type of function called for each change
 | 
			
		||||
// computed during a directory changes calculation.
 | 
			
		||||
type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error
 | 
			
		||||
 | 
			
		||||
// Changes computes changes between two directories calling the
 | 
			
		||||
// given change function for each computed change. The first
 | 
			
		||||
// directory is intended to the base directory and second
 | 
			
		||||
// directory the changed directory.
 | 
			
		||||
//
 | 
			
		||||
// The change callback is called by the order of path names and
 | 
			
		||||
// should be appliable in that order.
 | 
			
		||||
//  Due to this apply ordering, the following is true
 | 
			
		||||
//  - Removed directory trees only create a single change for the root
 | 
			
		||||
//    directory removed. Remaining changes are implied.
 | 
			
		||||
//  - A directory which is modified to become a file will not have
 | 
			
		||||
//    delete entries for sub-path items, their removal is implied
 | 
			
		||||
//    by the removal of the parent directory.
 | 
			
		||||
//
 | 
			
		||||
// Opaque directories will not be treated specially and each file
 | 
			
		||||
// removed from the base directory will show up as a removal.
 | 
			
		||||
//
 | 
			
		||||
// File content comparisons will be done on files which have timestamps
 | 
			
		||||
// which may have been truncated. If either of the files being compared
 | 
			
		||||
// has a zero value nanosecond value, each byte will be compared for
 | 
			
		||||
// differences. If 2 files have the same seconds value but different
 | 
			
		||||
// nanosecond values where one of those values is zero, the files will
 | 
			
		||||
// be considered unchanged if the content is the same. This behavior
 | 
			
		||||
// is to account for timestamp truncation during archiving.
 | 
			
		||||
func Changes(ctx context.Context, a, b string, changeFn ChangeFunc) error {
 | 
			
		||||
	if a == "" {
 | 
			
		||||
		logrus.Debugf("Using single walk diff for %s", b)
 | 
			
		||||
		return addDirChanges(ctx, changeFn, b)
 | 
			
		||||
	} else if diffOptions := detectDirDiff(b, a); diffOptions != nil {
 | 
			
		||||
		logrus.Debugf("Using single walk diff for %s from %s", diffOptions.diffDir, a)
 | 
			
		||||
		return diffDirChanges(ctx, changeFn, a, diffOptions)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("Using double walk diff for %s from %s", b, a)
 | 
			
		||||
	return doubleWalkDiff(ctx, changeFn, a, b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addDirChanges(ctx context.Context, changeFn ChangeFunc, root string) error {
 | 
			
		||||
	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(root, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return changeFn(ChangeKindAdd, path, f, nil)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// diffDirOptions is used when the diff can be directly calculated from
 | 
			
		||||
// a diff directory to its base, without walking both trees.
 | 
			
		||||
type diffDirOptions struct {
 | 
			
		||||
	diffDir      string
 | 
			
		||||
	skipChange   func(string) (bool, error)
 | 
			
		||||
	deleteChange func(string, string, os.FileInfo) (string, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// diffDirChanges walks the diff directory and compares changes against the base.
 | 
			
		||||
func diffDirChanges(ctx context.Context, changeFn ChangeFunc, base string, o *diffDirOptions) error {
 | 
			
		||||
	changedDirs := make(map[string]struct{})
 | 
			
		||||
	return filepath.Walk(o.diffDir, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(o.diffDir, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: handle opaqueness, start new double walker at this
 | 
			
		||||
		// location to get deletes, and skip tree in single walker
 | 
			
		||||
 | 
			
		||||
		if o.skipChange != nil {
 | 
			
		||||
			if skip, err := o.skipChange(path); skip {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var kind ChangeKind
 | 
			
		||||
 | 
			
		||||
		deletedFile, err := o.deleteChange(o.diffDir, path, f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Find out what kind of modification happened
 | 
			
		||||
		if deletedFile != "" {
 | 
			
		||||
			path = deletedFile
 | 
			
		||||
			kind = ChangeKindDelete
 | 
			
		||||
			f = nil
 | 
			
		||||
		} else {
 | 
			
		||||
			// Otherwise, the file was added
 | 
			
		||||
			kind = ChangeKindAdd
 | 
			
		||||
 | 
			
		||||
			// ...Unless it already existed in a base, in which case, it's a modification
 | 
			
		||||
			stat, err := os.Stat(filepath.Join(base, path))
 | 
			
		||||
			if err != nil && !os.IsNotExist(err) {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				// The file existed in the base, so that's a modification
 | 
			
		||||
 | 
			
		||||
				// However, if it's a directory, maybe it wasn't actually modified.
 | 
			
		||||
				// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
 | 
			
		||||
				if stat.IsDir() && f.IsDir() {
 | 
			
		||||
					if f.Size() == stat.Size() && f.Mode() == stat.Mode() && sameFsTime(f.ModTime(), stat.ModTime()) {
 | 
			
		||||
						// Both directories are the same, don't record the change
 | 
			
		||||
						return nil
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				kind = ChangeKindModify
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If /foo/bar/file.txt is modified, then /foo/bar must be part of the changed files.
 | 
			
		||||
		// This block is here to ensure the change is recorded even if the
 | 
			
		||||
		// modify time, mode and size of the parent directory in the rw and ro layers are all equal.
 | 
			
		||||
		// Check https://github.com/docker/docker/pull/13590 for details.
 | 
			
		||||
		if f.IsDir() {
 | 
			
		||||
			changedDirs[path] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindDelete {
 | 
			
		||||
			parent := filepath.Dir(path)
 | 
			
		||||
			if _, ok := changedDirs[parent]; !ok && parent != "/" {
 | 
			
		||||
				pi, err := os.Stat(filepath.Join(o.diffDir, parent))
 | 
			
		||||
				if err := changeFn(ChangeKindModify, parent, pi, err); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				changedDirs[parent] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return changeFn(kind, path, f, nil)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// doubleWalkDiff walks both directories to create a diff
 | 
			
		||||
func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err error) {
 | 
			
		||||
	g, ctx := errgroup.WithContext(ctx)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		c1 = make(chan *currentPath)
 | 
			
		||||
		c2 = make(chan *currentPath)
 | 
			
		||||
 | 
			
		||||
		f1, f2 *currentPath
 | 
			
		||||
		rmdir  string
 | 
			
		||||
	)
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		defer close(c1)
 | 
			
		||||
		return pathWalk(ctx, a, c1)
 | 
			
		||||
	})
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		defer close(c2)
 | 
			
		||||
		return pathWalk(ctx, b, c2)
 | 
			
		||||
	})
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		for c1 != nil || c2 != nil {
 | 
			
		||||
			if f1 == nil && c1 != nil {
 | 
			
		||||
				f1, err = nextPath(ctx, c1)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f1 == nil {
 | 
			
		||||
					c1 = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if f2 == nil && c2 != nil {
 | 
			
		||||
				f2, err = nextPath(ctx, c2)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f2 == nil {
 | 
			
		||||
					c2 = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if f1 == nil && f2 == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var f os.FileInfo
 | 
			
		||||
			k, p := pathChange(f1, f2)
 | 
			
		||||
			switch k {
 | 
			
		||||
			case ChangeKindAdd:
 | 
			
		||||
				if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f = f2.f
 | 
			
		||||
				f2 = nil
 | 
			
		||||
			case ChangeKindDelete:
 | 
			
		||||
				// Check if this file is already removed by being
 | 
			
		||||
				// under of a removed directory
 | 
			
		||||
				if rmdir != "" && strings.HasPrefix(f1.path, rmdir) {
 | 
			
		||||
					f1 = nil
 | 
			
		||||
					continue
 | 
			
		||||
				} else if f1.f.IsDir() {
 | 
			
		||||
					rmdir = f1.path + string(os.PathSeparator)
 | 
			
		||||
				} else if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f1 = nil
 | 
			
		||||
			case ChangeKindModify:
 | 
			
		||||
				same, err := sameFile(f1, f2)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f1.f.IsDir() && !f2.f.IsDir() {
 | 
			
		||||
					rmdir = f1.path + string(os.PathSeparator)
 | 
			
		||||
				} else if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f = f2.f
 | 
			
		||||
				f1 = nil
 | 
			
		||||
				f2 = nil
 | 
			
		||||
				if same {
 | 
			
		||||
					if !isLinked(f) {
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
					k = ChangeKindUnmodified
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if err := changeFn(k, p, f, nil); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return g.Wait()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
// +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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// detectDirDiff returns diff dir options if a directory could
 | 
			
		||||
// be found in the mount info for upper which is the direct
 | 
			
		||||
// diff with the provided lower directory
 | 
			
		||||
func detectDirDiff(upper, lower string) *diffDirOptions {
 | 
			
		||||
	// TODO: get mount options for upper
 | 
			
		||||
	// TODO: detect AUFS
 | 
			
		||||
	// TODO: detect overlay
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// compareSysStat returns whether the stats are equivalent,
 | 
			
		||||
// whether the files are considered the same file, and
 | 
			
		||||
// an error
 | 
			
		||||
func compareSysStat(s1, s2 interface{}) (bool, error) {
 | 
			
		||||
	ls1, ok := s1.(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	ls2, ok := s2.(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareCapabilities(p1, p2 string) (bool, error) {
 | 
			
		||||
	c1, err := sysx.LGetxattr(p1, "security.capability")
 | 
			
		||||
	if err != nil && err != sysx.ENODATA {
 | 
			
		||||
		return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
 | 
			
		||||
	}
 | 
			
		||||
	c2, err := sysx.LGetxattr(p2, "security.capability")
 | 
			
		||||
	if err != nil && err != sysx.ENODATA {
 | 
			
		||||
		return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.Equal(c1, c2), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isLinked(f os.FileInfo) bool {
 | 
			
		||||
	s, ok := f.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return !f.IsDir() && s.Nlink > 1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func detectDirDiff(upper, lower string) *diffDirOptions {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareSysStat(s1, s2 interface{}) (bool, error) {
 | 
			
		||||
	f1, ok := s1.(windows.Win32FileAttributeData)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	f2, ok := s2.(windows.Win32FileAttributeData)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	return f1.FileAttributes == f2.FileAttributes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareCapabilities(p1, p2 string) (bool, error) {
 | 
			
		||||
	// TODO: Use windows equivalent
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isLinked(os.FileInfo) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
// +build linux
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func locateDummyIfEmpty(path string) (string, error) {
 | 
			
		||||
	children, err := ioutil.ReadDir(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	if len(children) != 0 {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	dummyFile, err := ioutil.TempFile(path, "fsutils-dummy")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	name := dummyFile.Name()
 | 
			
		||||
	err = dummyFile.Close()
 | 
			
		||||
	return name, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SupportsDType returns whether the filesystem mounted on path supports d_type
 | 
			
		||||
func SupportsDType(path string) (bool, error) {
 | 
			
		||||
	// locate dummy so that we have at least one dirent
 | 
			
		||||
	dummy, err := locateDummyIfEmpty(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	if dummy != "" {
 | 
			
		||||
		defer os.Remove(dummy)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	visited := 0
 | 
			
		||||
	supportsDType := true
 | 
			
		||||
	fn := func(ent *syscall.Dirent) bool {
 | 
			
		||||
		visited++
 | 
			
		||||
		if ent.Type == syscall.DT_UNKNOWN {
 | 
			
		||||
			supportsDType = false
 | 
			
		||||
			// stop iteration
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		// continue iteration
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if err = iterateReadDir(path, fn); err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	if visited == 0 {
 | 
			
		||||
		return false, fmt.Errorf("did not hit any dirent during iteration %s", path)
 | 
			
		||||
	}
 | 
			
		||||
	return supportsDType, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error {
 | 
			
		||||
	d, err := os.Open(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer d.Close()
 | 
			
		||||
	fd := int(d.Fd())
 | 
			
		||||
	buf := make([]byte, 4096)
 | 
			
		||||
	for {
 | 
			
		||||
		nbytes, err := syscall.ReadDirent(fd, buf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if nbytes == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		for off := 0; off < nbytes; {
 | 
			
		||||
			ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off]))
 | 
			
		||||
			if stop := fn(ent); stop {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			off += int(ent.Reclen)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "context"
 | 
			
		||||
 | 
			
		||||
// Usage of disk information
 | 
			
		||||
type Usage struct {
 | 
			
		||||
	Inodes int64
 | 
			
		||||
	Size   int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiskUsage counts the number of inodes and disk usage for the resources under
 | 
			
		||||
// path.
 | 
			
		||||
func DiskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
	return diskUsage(ctx, roots...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiffUsage counts the numbers of inodes and disk usage in the
 | 
			
		||||
// diff between the 2 directories. The first path is intended
 | 
			
		||||
// as the base directory and the second as the changed directory.
 | 
			
		||||
func DiffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	return diffUsage(ctx, a, b)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
// +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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type inode struct {
 | 
			
		||||
	// TODO(stevvooe): Can probably reduce memory usage by not tracking
 | 
			
		||||
	// device, but we can leave this right for now.
 | 
			
		||||
	dev, ino uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newInode(stat *syscall.Stat_t) inode {
 | 
			
		||||
	return inode{
 | 
			
		||||
		// Dev is uint32 on darwin/bsd, uint64 on linux/solaris
 | 
			
		||||
		dev: uint64(stat.Dev), // nolint: unconvert
 | 
			
		||||
		// Ino is uint32 on bsd, uint64 on darwin/linux/solaris
 | 
			
		||||
		ino: uint64(stat.Ino), // nolint: unconvert
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		size   int64
 | 
			
		||||
		inodes = map[inode]struct{}{} // expensive!
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for _, root := range roots {
 | 
			
		||||
		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				return ctx.Err()
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			inoKey := newInode(fi.Sys().(*syscall.Stat_t))
 | 
			
		||||
			if _, ok := inodes[inoKey]; !ok {
 | 
			
		||||
				inodes[inoKey] = struct{}{}
 | 
			
		||||
				size += fi.Size()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return Usage{}, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Inodes: int64(len(inodes)),
 | 
			
		||||
		Size:   size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size   int64
 | 
			
		||||
		inodes = map[inode]struct{}{} // expensive!
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindModify {
 | 
			
		||||
			inoKey := newInode(fi.Sys().(*syscall.Stat_t))
 | 
			
		||||
			if _, ok := inodes[inoKey]; !ok {
 | 
			
		||||
				inodes[inoKey] = struct{}{}
 | 
			
		||||
				size += fi.Size()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return Usage{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Inodes: int64(len(inodes)),
 | 
			
		||||
		Size:   size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
// +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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size int64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// TODO(stevvooe): Support inodes (or equivalent) for windows.
 | 
			
		||||
 | 
			
		||||
	for _, root := range roots {
 | 
			
		||||
		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				return ctx.Err()
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			size += fi.Size()
 | 
			
		||||
			return nil
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return Usage{}, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Size: size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size int64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindModify {
 | 
			
		||||
			size += fi.Size()
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return Usage{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Size: size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
// GetLinkInfo returns an identifier representing the node a hardlink is pointing
 | 
			
		||||
// to. If the file is not hard linked then 0 will be returned.
 | 
			
		||||
func GetLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	return getLinkInfo(fi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getLinkSource returns a path for the given name and
 | 
			
		||||
// file info to its link source in the provided inode
 | 
			
		||||
// map. If the given file name is not in the map and
 | 
			
		||||
// has other links, it is added to the inode map
 | 
			
		||||
// to be a source for other link locations.
 | 
			
		||||
func getLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
 | 
			
		||||
	inode, isHardlink := getLinkInfo(fi)
 | 
			
		||||
	if !isHardlink {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path, ok := inodes[inode]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		inodes[inode] = name
 | 
			
		||||
	}
 | 
			
		||||
	return path, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
// +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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	s, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ino is uint32 on bsd, uint64 on darwin/linux/solaris
 | 
			
		||||
	return uint64(s.Ino), !fi.IsDir() && s.Nlink > 1 // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	return 0, false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										313
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										313
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,313 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errTooManyLinks = errors.New("too many links")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type currentPath struct {
 | 
			
		||||
	path     string
 | 
			
		||||
	f        os.FileInfo
 | 
			
		||||
	fullPath string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pathChange(lower, upper *currentPath) (ChangeKind, string) {
 | 
			
		||||
	if lower == nil {
 | 
			
		||||
		if upper == nil {
 | 
			
		||||
			panic("cannot compare nil paths")
 | 
			
		||||
		}
 | 
			
		||||
		return ChangeKindAdd, upper.path
 | 
			
		||||
	}
 | 
			
		||||
	if upper == nil {
 | 
			
		||||
		return ChangeKindDelete, lower.path
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch i := directoryCompare(lower.path, upper.path); {
 | 
			
		||||
	case i < 0:
 | 
			
		||||
		// File in lower that is not in upper
 | 
			
		||||
		return ChangeKindDelete, lower.path
 | 
			
		||||
	case i > 0:
 | 
			
		||||
		// File in upper that is not in lower
 | 
			
		||||
		return ChangeKindAdd, upper.path
 | 
			
		||||
	default:
 | 
			
		||||
		return ChangeKindModify, upper.path
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	equalStat, err := compareSysStat(f1.f.Sys(), f2.f.Sys())
 | 
			
		||||
	if err != nil || !equalStat {
 | 
			
		||||
		return equalStat, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if eq, err := compareCapabilities(f1.fullPath, f2.fullPath); err != nil || !eq {
 | 
			
		||||
		return eq, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If not a directory also check size, modtime, and content
 | 
			
		||||
	if !f1.f.IsDir() {
 | 
			
		||||
		if f1.f.Size() != f2.f.Size() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		t1 := f1.f.ModTime()
 | 
			
		||||
		t2 := f2.f.ModTime()
 | 
			
		||||
 | 
			
		||||
		if t1.Unix() != t2.Unix() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 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)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil || !eq {
 | 
			
		||||
				return eq, err
 | 
			
		||||
			}
 | 
			
		||||
		} else if t1.Nanosecond() != t2.Nanosecond() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareSymlinkTarget(p1, p2 string) (bool, error) {
 | 
			
		||||
	t1, err := os.Readlink(p1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	t2, err := os.Readlink(p2)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	return t1 == t2, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const compareChuckSize = 32 * 1024
 | 
			
		||||
 | 
			
		||||
// compareFileContent compares the content of 2 same sized files
 | 
			
		||||
// by comparing each byte.
 | 
			
		||||
func compareFileContent(p1, p2 string) (bool, error) {
 | 
			
		||||
	f1, err := os.Open(p1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f1.Close()
 | 
			
		||||
	f2, err := os.Open(p2)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f2.Close()
 | 
			
		||||
 | 
			
		||||
	b1 := make([]byte, compareChuckSize)
 | 
			
		||||
	b2 := make([]byte, compareChuckSize)
 | 
			
		||||
	for {
 | 
			
		||||
		n1, err1 := f1.Read(b1)
 | 
			
		||||
		if err1 != nil && err1 != io.EOF {
 | 
			
		||||
			return false, err1
 | 
			
		||||
		}
 | 
			
		||||
		n2, err2 := f2.Read(b2)
 | 
			
		||||
		if err2 != nil && err2 != io.EOF {
 | 
			
		||||
			return false, err2
 | 
			
		||||
		}
 | 
			
		||||
		if n1 != n2 || !bytes.Equal(b1[:n1], b2[:n2]) {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		if err1 == io.EOF && err2 == io.EOF {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pathWalk(ctx context.Context, root string, pathC chan<- *currentPath) error {
 | 
			
		||||
	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(root, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p := ¤tPath{
 | 
			
		||||
			path:     path,
 | 
			
		||||
			f:        f,
 | 
			
		||||
			fullPath: filepath.Join(root, path),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return ctx.Err()
 | 
			
		||||
		case pathC <- p:
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func nextPath(ctx context.Context, pathC <-chan *currentPath) (*currentPath, error) {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		return nil, ctx.Err()
 | 
			
		||||
	case p := <-pathC:
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootPath joins a path with a root, evaluating and bounding any
 | 
			
		||||
// symlink to the root directory.
 | 
			
		||||
func RootPath(root, path string) (string, error) {
 | 
			
		||||
	if path == "" {
 | 
			
		||||
		return root, nil
 | 
			
		||||
	}
 | 
			
		||||
	var linksWalked int // to protect against cycles
 | 
			
		||||
	for {
 | 
			
		||||
		i := linksWalked
 | 
			
		||||
		newpath, err := walkLinks(root, path, &linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		path = newpath
 | 
			
		||||
		if i == linksWalked {
 | 
			
		||||
			newpath = filepath.Join("/", newpath)
 | 
			
		||||
			if path == newpath {
 | 
			
		||||
				return filepath.Join(root, newpath), nil
 | 
			
		||||
			}
 | 
			
		||||
			path = newpath
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func walkLink(root, path string, linksWalked *int) (newpath string, islink bool, err error) {
 | 
			
		||||
	if *linksWalked > 255 {
 | 
			
		||||
		return "", false, errTooManyLinks
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path = filepath.Join("/", path)
 | 
			
		||||
	if path == "/" {
 | 
			
		||||
		return path, false, nil
 | 
			
		||||
	}
 | 
			
		||||
	realPath := filepath.Join(root, path)
 | 
			
		||||
 | 
			
		||||
	fi, err := os.Lstat(realPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// If path does not yet exist, treat as non-symlink
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			return path, false, nil
 | 
			
		||||
		}
 | 
			
		||||
		return "", false, err
 | 
			
		||||
	}
 | 
			
		||||
	if fi.Mode()&os.ModeSymlink == 0 {
 | 
			
		||||
		return path, false, nil
 | 
			
		||||
	}
 | 
			
		||||
	newpath, err = os.Readlink(realPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", false, err
 | 
			
		||||
	}
 | 
			
		||||
	*linksWalked++
 | 
			
		||||
	return newpath, true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func walkLinks(root, path string, linksWalked *int) (string, error) {
 | 
			
		||||
	switch dir, file := filepath.Split(path); {
 | 
			
		||||
	case dir == "":
 | 
			
		||||
		newpath, _, err := walkLink(root, file, linksWalked)
 | 
			
		||||
		return newpath, err
 | 
			
		||||
	case file == "":
 | 
			
		||||
		if os.IsPathSeparator(dir[len(dir)-1]) {
 | 
			
		||||
			if dir == "/" {
 | 
			
		||||
				return dir, nil
 | 
			
		||||
			}
 | 
			
		||||
			return walkLinks(root, dir[:len(dir)-1], linksWalked)
 | 
			
		||||
		}
 | 
			
		||||
		newpath, _, err := walkLink(root, dir, linksWalked)
 | 
			
		||||
		return newpath, err
 | 
			
		||||
	default:
 | 
			
		||||
		newdir, err := walkLinks(root, dir, linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		if !islink {
 | 
			
		||||
			return newpath, nil
 | 
			
		||||
		}
 | 
			
		||||
		if filepath.IsAbs(newpath) {
 | 
			
		||||
			return newpath, nil
 | 
			
		||||
		}
 | 
			
		||||
		return filepath.Join(newdir, newpath), nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
// +build darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StatAtime returns the access time from a stat struct
 | 
			
		||||
func StatAtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Atimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatCtime returns the created time from a stat struct
 | 
			
		||||
func StatCtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Ctimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatMtime returns the modified time from a stat struct
 | 
			
		||||
func StatMtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Mtimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatATimeAsTime returns the access time as a time.Time
 | 
			
		||||
func StatATimeAsTime(st *syscall.Stat_t) time.Time {
 | 
			
		||||
	return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StatAtime returns the Atim
 | 
			
		||||
func StatAtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Atim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatCtime returns the Ctim
 | 
			
		||||
func StatCtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Ctim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatMtime returns the Mtim
 | 
			
		||||
func StatMtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Mtim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatATimeAsTime returns st.Atim as a time.Time
 | 
			
		||||
func StatATimeAsTime(st *syscall.Stat_t) time.Time {
 | 
			
		||||
	// The int64 conversions ensure the line compiles for 32-bit systems as well.
 | 
			
		||||
	return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
/*
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// Gnu tar and the go tar writer don't have sub-second mtime
 | 
			
		||||
// precision, which is problematic when we apply changes via tar
 | 
			
		||||
// files, we handle this by comparing for exact times, *or* same
 | 
			
		||||
// second count and either a or b having exactly 0 nanoseconds
 | 
			
		||||
func sameFsTime(a, b time.Time) bool {
 | 
			
		||||
	return a == b ||
 | 
			
		||||
		(a.Unix() == b.Unix() &&
 | 
			
		||||
			(a.Nanosecond() == 0 || b.Nanosecond() == 0))
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user