mirror of https://github.com/docker/cli.git
vendor: github.com/tonistiigi/fsutil 0834f99b7b85462efb69b4f571a4fa3ca7da5ac9
full diff: ae3a8d7530...0834f99b7b
- walker: fix notadir error
- improving error returns
- more typed errors
- remove extra verbosity (eg. PathError already contains action and path)
- ensure stack traces are added to errors
- various testing and linting fixes
- copy: use Clonefileat from golang.org/x/sys/unix on macOS
- go.mod: update opencontainers/go-digest v1.0.0
- github: test go1.15
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
0e96d92567
commit
74d93d1fa2
|
@ -67,7 +67,7 @@ github.com/sirupsen/logrus 6699a89a232f3db797f2e2806398
|
||||||
github.com/spf13/cobra 86f8bfd7fef868a174e1b606783bd7f5c82ddf8f # v1.1.1
|
github.com/spf13/cobra 86f8bfd7fef868a174e1b606783bd7f5c82ddf8f # v1.1.1
|
||||||
github.com/spf13/pflag 2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab # v1.0.5
|
github.com/spf13/pflag 2e9d26c8c37aae03e3f9d4e90b7116f5accb7cab # v1.0.5
|
||||||
github.com/theupdateframework/notary d6e1431feb32348e0650bf7551ac5cffd01d857b # v0.6.1
|
github.com/theupdateframework/notary d6e1431feb32348e0650bf7551ac5cffd01d857b # v0.6.1
|
||||||
github.com/tonistiigi/fsutil ae3a8d753069d0f76fbee396457e8b6cfd7cb8c3
|
github.com/tonistiigi/fsutil 0834f99b7b85462efb69b4f571a4fa3ca7da5ac9
|
||||||
github.com/tonistiigi/go-rosetta f79598599c5d34ea253b56a1d7c89bc6a96de7db
|
github.com/tonistiigi/go-rosetta f79598599c5d34ea253b56a1d7c89bc6a96de7db
|
||||||
github.com/tonistiigi/units 6950e57a87eaf136bbe44ef2ec8e75b9e3569de2
|
github.com/tonistiigi/units 6950e57a87eaf136bbe44ef2ec8e75b9e3569de2
|
||||||
github.com/xeipuuv/gojsonpointer 02993c407bfbf5f6dae44c4f4b1cf6a39b5fc5bb
|
github.com/xeipuuv/gojsonpointer 02993c407bfbf5f6dae44c4f4b1cf6a39b5fc5bb
|
||||||
|
|
17
vendor/github.com/docker/docker/builder/dockerignore/deprecated.go
generated
vendored
Normal file
17
vendor/github.com/docker/docker/builder/dockerignore/deprecated.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Package dockerignore is deprecated. Use github.com/moby/buildkit/frontend/dockerfile/dockerignore instead.
|
||||||
|
package dockerignore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/moby/buildkit/frontend/dockerfile/dockerignore"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReadAll reads a .dockerignore file and returns the list of file patterns
|
||||||
|
// to ignore. Note this will trim whitespace from each line as well
|
||||||
|
// as use GO's "clean" func to get the shortest/cleanest path for each.
|
||||||
|
//
|
||||||
|
// Deprecated: use github.com/moby/buildkit/frontend/dockerfile/dockerignore.ReadAll instead.
|
||||||
|
func ReadAll(reader io.Reader) ([]string, error) {
|
||||||
|
return dockerignore.ReadAll(reader)
|
||||||
|
}
|
|
@ -5,16 +5,18 @@ package fsutil
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func chtimes(path string, un int64) error {
|
func chtimes(path string, un int64) error {
|
||||||
mtime := time.Unix(0, un)
|
mtime := time.Unix(0, un)
|
||||||
fi, err := os.Lstat(path)
|
fi, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
if fi.Mode()&os.ModeSymlink != 0 {
|
if fi.Mode()&os.ModeSymlink != 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return os.Chtimes(path, mtime, mtime)
|
return errors.WithStack(os.Chtimes(path, mtime, mtime))
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ type HandleChangeFn func(ChangeKind, string, os.FileInfo, error) error
|
||||||
|
|
||||||
type ContentHasher func(*types.Stat) (hash.Hash, error)
|
type ContentHasher func(*types.Stat) (hash.Hash, error)
|
||||||
|
|
||||||
func GetWalkerFn(root string) walkerFn {
|
func getWalkerFn(root string) walkerFn {
|
||||||
return func(ctx context.Context, pathC chan<- *currentPath) error {
|
return func(ctx context.Context, pathC chan<- *currentPath) error {
|
||||||
return Walk(ctx, root, nil, func(path string, f os.FileInfo, err error) error {
|
return errors.Wrap(Walk(ctx, root, nil, func(path string, f os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ func GetWalkerFn(root string) walkerFn {
|
||||||
case pathC <- p:
|
case pathC <- p:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
})
|
}), "failed to walk")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
package fsutil
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/containerd/continuity/sysx"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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 != syscall.ENODATA {
|
|
||||||
return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
|
|
||||||
}
|
|
||||||
c2, err := sysx.LGetxattr(p2, "security.capability")
|
|
||||||
if err != nil && err != syscall.ENODATA {
|
|
||||||
return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
|
|
||||||
}
|
|
||||||
return bytes.Equal(c1, c2), nil
|
|
||||||
}
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/opencontainers/go-digest"
|
"github.com/opencontainers/go-digest"
|
||||||
|
@ -32,7 +33,6 @@ type DiskWriter struct {
|
||||||
opt DiskWriterOpt
|
opt DiskWriterOpt
|
||||||
dest string
|
dest string
|
||||||
|
|
||||||
wg sync.WaitGroup
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel func()
|
cancel func()
|
||||||
eg *errgroup.Group
|
eg *errgroup.Group
|
||||||
|
@ -104,7 +104,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er
|
||||||
|
|
||||||
stat, ok := fi.Sys().(*types.Stat)
|
stat, ok := fi.Sys().(*types.Stat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Errorf("%s invalid change without stat information", p)
|
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EBADMSG, Op: "change without stat info"})
|
||||||
}
|
}
|
||||||
|
|
||||||
statCopy := *stat
|
statCopy := *stat
|
||||||
|
@ -118,13 +118,13 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er
|
||||||
rename := true
|
rename := true
|
||||||
oldFi, err := os.Lstat(destPath)
|
oldFi, err := os.Lstat(destPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
if kind != ChangeKindAdd {
|
if kind != ChangeKindAdd {
|
||||||
return errors.Wrapf(err, "invalid addition: %s", destPath)
|
return errors.Wrap(err, "modify/rm")
|
||||||
}
|
}
|
||||||
rename = false
|
rename = false
|
||||||
} else {
|
} else {
|
||||||
return errors.Wrapf(err, "failed to stat %s", destPath)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,6 @@ func (hw *hashedWriter) Digest() digest.Digest {
|
||||||
|
|
||||||
type lazyFileWriter struct {
|
type lazyFileWriter struct {
|
||||||
dest string
|
dest string
|
||||||
ctx context.Context
|
|
||||||
f *os.File
|
f *os.File
|
||||||
fileMode *os.FileMode
|
fileMode *os.FileMode
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,17 +17,17 @@ func rewriteMetadata(p string, stat *types.Stat) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Lchown(p, int(stat.Uid), int(stat.Gid)); err != nil {
|
if err := os.Lchown(p, int(stat.Uid), int(stat.Gid)); err != nil {
|
||||||
return errors.Wrapf(err, "failed to lchown %s", p)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if os.FileMode(stat.Mode)&os.ModeSymlink == 0 {
|
if os.FileMode(stat.Mode)&os.ModeSymlink == 0 {
|
||||||
if err := os.Chmod(p, os.FileMode(stat.Mode)); err != nil {
|
if err := os.Chmod(p, os.FileMode(stat.Mode)); err != nil {
|
||||||
return errors.Wrapf(err, "failed to chown %s", p)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := chtimes(p, stat.ModTime); err != nil {
|
if err := chtimes(p, stat.ModTime); err != nil {
|
||||||
return errors.Wrapf(err, "failed to chtimes %s", p)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -46,7 +46,7 @@ func handleTarTypeBlockCharFifo(path string, stat *types.Stat) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syscall.Mknod(path, mode, int(mkdev(stat.Devmajor, stat.Devminor))); err != nil {
|
if err := syscall.Mknod(path, mode, int(mkdev(stat.Devmajor, stat.Devminor))); err != nil {
|
||||||
return err
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,10 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e
|
||||||
if allowWildcard && containsWildcards(base) {
|
if allowWildcard && containsWildcards(base) {
|
||||||
fis, err := ioutil.ReadDir(filepath.Dir(realPath))
|
fis, err := ioutil.ReadDir(filepath.Dir(realPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, errors.Wrapf(err, "failed to read dir %s", filepath.Dir(realPath))
|
return nil, errors.Wrap(err, "readdir")
|
||||||
}
|
}
|
||||||
var out []string
|
var out []string
|
||||||
for _, f := range fis {
|
for _, f := range fis {
|
||||||
|
@ -97,17 +97,17 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e
|
||||||
|
|
||||||
fi, err := os.Lstat(realPath)
|
fi, err := os.Lstat(realPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, errors.Wrapf(err, "failed to lstat %s", realPath)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
if fi.Mode()&os.ModeSymlink == 0 {
|
if fi.Mode()&os.ModeSymlink == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
link, err := os.Readlink(realPath)
|
link, err := os.Readlink(realPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to readlink %s", realPath)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
link = filepath.Clean(link)
|
link = filepath.Clean(link)
|
||||||
if filepath.IsAbs(link) {
|
if filepath.IsAbs(link) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/tonistiigi/fsutil/types"
|
"github.com/tonistiigi/fsutil/types"
|
||||||
|
@ -36,7 +37,8 @@ func (fs *fs) Walk(ctx context.Context, fn filepath.WalkFunc) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *fs) Open(p string) (io.ReadCloser, error) {
|
func (fs *fs) Open(p string) (io.ReadCloser, error) {
|
||||||
return os.Open(filepath.Join(fs.root, p))
|
rc, err := os.Open(filepath.Join(fs.root, p))
|
||||||
|
return rc, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Dir struct {
|
type Dir struct {
|
||||||
|
@ -51,10 +53,10 @@ func SubDirFS(dirs []Dir) (FS, error) {
|
||||||
m := map[string]Dir{}
|
m := map[string]Dir{}
|
||||||
for _, d := range dirs {
|
for _, d := range dirs {
|
||||||
if path.Base(d.Stat.Path) != d.Stat.Path {
|
if path.Base(d.Stat.Path) != d.Stat.Path {
|
||||||
return nil, errors.Errorf("subdir %s must be single file", d.Stat.Path)
|
return nil, errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.EISDIR, Op: "invalid path"})
|
||||||
}
|
}
|
||||||
if _, ok := m[d.Stat.Path]; ok {
|
if _, ok := m[d.Stat.Path]; ok {
|
||||||
return nil, errors.Errorf("invalid path %s", d.Stat.Path)
|
return nil, errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.EEXIST, Op: "duplicate path"})
|
||||||
}
|
}
|
||||||
m[d.Stat.Path] = d
|
m[d.Stat.Path] = d
|
||||||
}
|
}
|
||||||
|
@ -70,7 +72,7 @@ func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error {
|
||||||
for _, d := range fs.dirs {
|
for _, d := range fs.dirs {
|
||||||
fi := &StatInfo{Stat: &d.Stat}
|
fi := &StatInfo{Stat: &d.Stat}
|
||||||
if !fi.IsDir() {
|
if !fi.IsDir() {
|
||||||
return errors.Errorf("fs subdir %s not mode directory", d.Stat.Path)
|
return errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.ENOTDIR, Op: "walk subdir"})
|
||||||
}
|
}
|
||||||
if err := fn(d.Stat.Path, fi, nil); err != nil {
|
if err := fn(d.Stat.Path, fi, nil); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -78,7 +80,7 @@ func (fs *subDirFS) Walk(ctx context.Context, fn filepath.WalkFunc) error {
|
||||||
if err := d.FS.Walk(ctx, func(p string, fi os.FileInfo, err error) error {
|
if err := d.FS.Walk(ctx, func(p string, fi os.FileInfo, err error) error {
|
||||||
stat, ok := fi.Sys().(*types.Stat)
|
stat, ok := fi.Sys().(*types.Stat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Wrapf(err, "invalid fileinfo without stat info: %s", p)
|
return errors.WithStack(&os.PathError{Path: d.Stat.Path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"})
|
||||||
}
|
}
|
||||||
stat.Path = path.Join(d.Stat.Path, stat.Path)
|
stat.Path = path.Join(d.Stat.Path, stat.Path)
|
||||||
if stat.Linkname != "" {
|
if stat.Linkname != "" {
|
||||||
|
@ -105,7 +107,7 @@ func (fs *subDirFS) Open(p string) (io.ReadCloser, error) {
|
||||||
}
|
}
|
||||||
d, ok := fs.m[parts[0]]
|
d, ok := fs.m[parts[0]]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, os.ErrNotExist
|
return nil, errors.WithStack(&os.PathError{Path: parts[0], Err: syscall.ENOENT, Op: "open"})
|
||||||
}
|
}
|
||||||
return d.FS.Open(parts[1])
|
return d.FS.Open(parts[1])
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,21 +5,16 @@ go 1.13
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/hcsshim v0.8.9 // indirect
|
github.com/Microsoft/hcsshim v0.8.9 // indirect
|
||||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc
|
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
|
||||||
github.com/docker/docker v0.0.0-20200511152416-a93e9eb0e95c
|
github.com/docker/docker v0.0.0-20200511152416-a93e9eb0e95c
|
||||||
github.com/gogo/protobuf v1.3.1
|
github.com/gogo/protobuf v1.3.1
|
||||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
|
|
||||||
github.com/moby/sys/mount v0.1.0 // indirect
|
github.com/moby/sys/mount v0.1.0 // indirect
|
||||||
github.com/moby/sys/mountinfo v0.1.3 // indirect
|
github.com/moby/sys/mountinfo v0.1.3 // indirect
|
||||||
github.com/onsi/ginkgo v1.7.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0
|
||||||
github.com/onsi/gomega v1.4.3 // indirect
|
|
||||||
github.com/opencontainers/go-digest v1.0.0-rc1
|
|
||||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||||
github.com/opencontainers/runc v1.0.0-rc10 // indirect
|
github.com/opencontainers/runc v1.0.0-rc10 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.5.1
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
|
golang.org/x/sys v0.0.0-20200917073148-efd3b9a0ff20
|
||||||
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
|
gotest.tools/v3 v3.0.2 // indirect
|
||||||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,7 @@ package fsutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/tonistiigi/fsutil/types"
|
"github.com/tonistiigi/fsutil/types"
|
||||||
|
@ -28,7 +29,7 @@ func (v *Hardlinks) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
|
||||||
|
|
||||||
stat, ok := fi.Sys().(*types.Stat)
|
stat, ok := fi.Sys().(*types.Stat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Errorf("invalid change without stat info: %s", p)
|
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EBADMSG, Op: "change without stat info"})
|
||||||
}
|
}
|
||||||
|
|
||||||
if fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 {
|
if fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 {
|
||||||
|
|
|
@ -20,7 +20,7 @@ type ReceiveOpt struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Receive(ctx context.Context, conn Stream, dest string, opt ReceiveOpt) error {
|
func Receive(ctx context.Context, conn Stream, dest string, opt ReceiveOpt) error {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
r := &receiver{
|
r := &receiver{
|
||||||
|
@ -105,7 +105,6 @@ func (w *dynamicWalker) fill(ctx context.Context, pathC chan<- *currentPath) err
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *receiver) run(ctx context.Context) error {
|
func (r *receiver) run(ctx context.Context) error {
|
||||||
|
@ -131,7 +130,7 @@ func (r *receiver) run(ctx context.Context) error {
|
||||||
}()
|
}()
|
||||||
destWalker := emptyWalker
|
destWalker := emptyWalker
|
||||||
if !r.merge {
|
if !r.merge {
|
||||||
destWalker = GetWalkerFn(r.dest)
|
destWalker = getWalkerFn(r.dest)
|
||||||
}
|
}
|
||||||
err := doubleWalkDiff(ctx, dw.HandleChange, destWalker, w.fill, r.filter)
|
err := doubleWalkDiff(ctx, dw.HandleChange, destWalker, w.fill, r.filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/tonistiigi/fsutil/types"
|
"github.com/tonistiigi/fsutil/types"
|
||||||
|
@ -13,7 +14,8 @@ import (
|
||||||
|
|
||||||
var bufPool = sync.Pool{
|
var bufPool = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
return make([]byte, 32*1<<10)
|
buf := make([]byte, 32*1<<10)
|
||||||
|
return &buf
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,9 +133,9 @@ func (s *sender) sendFile(h *sendHandle) error {
|
||||||
f, err := s.fs.Open(h.path)
|
f, err := s.fs.Open(h.path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
buf := bufPool.Get().([]byte)
|
buf := bufPool.Get().(*[]byte)
|
||||||
defer bufPool.Put(buf)
|
defer bufPool.Put(buf)
|
||||||
if _, err := io.CopyBuffer(&fileSender{sender: s, id: h.id}, f, buf); err != nil {
|
if _, err := io.CopyBuffer(&fileSender{sender: s, id: h.id}, f, *buf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +150,7 @@ func (s *sender) walk(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
stat, ok := fi.Sys().(*types.Stat)
|
stat, ok := fi.Sys().(*types.Stat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Wrapf(err, "invalid fileinfo without stat info: %s", path)
|
return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"})
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &types.Packet{
|
p := &types.Packet{
|
||||||
|
|
|
@ -31,13 +31,13 @@ func mkstat(path, relpath string, fi os.FileInfo, inodemap map[uint64]string) (*
|
||||||
if fi.Mode()&os.ModeSymlink != 0 {
|
if fi.Mode()&os.ModeSymlink != 0 {
|
||||||
link, err := os.Readlink(path)
|
link, err := os.Readlink(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to readlink %s", path)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
stat.Linkname = link
|
stat.Linkname = link
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := loadXattr(path, stat); err != nil {
|
if err := loadXattr(path, stat); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to xattr %s", relpath)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
|
@ -58,7 +58,7 @@ func mkstat(path, relpath string, fi os.FileInfo, inodemap map[uint64]string) (*
|
||||||
func Stat(path string) (*types.Stat, error) {
|
func Stat(path string) (*types.Stat, error) {
|
||||||
fi, err := os.Lstat(path)
|
fi, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "os stat")
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
return mkstat(path, filepath.Base(path), fi, nil)
|
return mkstat(path, filepath.Base(path), fi, nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/tonistiigi/fsutil/types"
|
"github.com/tonistiigi/fsutil/types"
|
||||||
|
@ -15,9 +16,12 @@ import (
|
||||||
func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
|
func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
|
||||||
tw := tar.NewWriter(w)
|
tw := tar.NewWriter(w)
|
||||||
err := fs.Walk(ctx, func(path string, fi os.FileInfo, err error) error {
|
err := fs.Walk(ctx, func(path string, fi os.FileInfo, err error) error {
|
||||||
|
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
stat, ok := fi.Sys().(*types.Stat)
|
stat, ok := fi.Sys().(*types.Stat)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Wrapf(err, "invalid fileinfo without stat info: %s", path)
|
return errors.WithStack(&os.PathError{Path: path, Err: syscall.EBADMSG, Op: "fileinfo without stat info"})
|
||||||
}
|
}
|
||||||
hdr, err := tar.FileInfoHeader(fi, stat.Linkname)
|
hdr, err := tar.FileInfoHeader(fi, stat.Linkname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -37,7 +41,7 @@ func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
|
||||||
hdr.Linkname = stat.Linkname
|
hdr.Linkname = stat.Linkname
|
||||||
if hdr.Linkname != "" {
|
if hdr.Linkname != "" {
|
||||||
hdr.Size = 0
|
hdr.Size = 0
|
||||||
if fi.Mode() & os.ModeSymlink != 0 {
|
if fi.Mode()&os.ModeSymlink != 0 {
|
||||||
hdr.Typeflag = tar.TypeSymlink
|
hdr.Typeflag = tar.TypeSymlink
|
||||||
} else {
|
} else {
|
||||||
hdr.Typeflag = tar.TypeLink
|
hdr.Typeflag = tar.TypeLink
|
||||||
|
@ -52,7 +56,7 @@ func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
return errors.Wrap(err, "failed to write file header")
|
return errors.Wrapf(err, "failed to write file header %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 && hdr.Linkname == "" {
|
if hdr.Typeflag == tar.TypeReg && hdr.Size > 0 && hdr.Linkname == "" {
|
||||||
|
@ -61,10 +65,10 @@ func WriteTar(ctx context.Context, fs FS, w io.Writer) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(tw, rc); err != nil {
|
if _, err := io.Copy(tw, rc); err != nil {
|
||||||
return err
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
if err := rc.Close(); err != nil {
|
if err := rc.Close(); err != nil {
|
||||||
return err
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -31,10 +32,10 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
|
||||||
p = strings.Replace(p, "\\", "", -1)
|
p = strings.Replace(p, "\\", "", -1)
|
||||||
}
|
}
|
||||||
if p != path.Clean(p) {
|
if p != path.Clean(p) {
|
||||||
return errors.Errorf("invalid unclean path %s", p)
|
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "unclean path"})
|
||||||
}
|
}
|
||||||
if path.IsAbs(p) {
|
if path.IsAbs(p) {
|
||||||
return errors.Errorf("abolute path %s not allowed", p)
|
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "absolute path"})
|
||||||
}
|
}
|
||||||
dir := path.Dir(p)
|
dir := path.Dir(p)
|
||||||
base := path.Base(p)
|
base := path.Base(p)
|
||||||
|
@ -42,7 +43,7 @@ func (v *Validator) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err
|
||||||
dir = ""
|
dir = ""
|
||||||
}
|
}
|
||||||
if dir == ".." || strings.HasPrefix(p, "../") {
|
if dir == ".." || strings.HasPrefix(p, "../") {
|
||||||
return errors.Errorf("invalid path: %s", p)
|
return errors.WithStack(&os.PathError{Path: p, Err: syscall.EINVAL, Op: "escape check"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// find a parent dir from saved records
|
// find a parent dir from saved records
|
||||||
|
|
|
@ -25,21 +25,21 @@ type WalkOpt struct {
|
||||||
func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) error {
|
func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) error {
|
||||||
root, err := filepath.EvalSymlinks(p)
|
root, err := filepath.EvalSymlinks(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to resolve %s", root)
|
return errors.WithStack(&os.PathError{Op: "resolve", Path: root, Err: err})
|
||||||
}
|
}
|
||||||
fi, err := os.Stat(root)
|
fi, err := os.Stat(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "failed to stat: %s", root)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
if !fi.IsDir() {
|
if !fi.IsDir() {
|
||||||
return errors.Errorf("%s is not a directory", root)
|
return errors.WithStack(&os.PathError{Op: "walk", Path: root, Err: syscall.ENOTDIR})
|
||||||
}
|
}
|
||||||
|
|
||||||
var pm *fileutils.PatternMatcher
|
var pm *fileutils.PatternMatcher
|
||||||
if opt != nil && opt.ExcludePatterns != nil {
|
if opt != nil && opt.ExcludePatterns != nil {
|
||||||
pm, err = fileutils.NewPatternMatcher(opt.ExcludePatterns)
|
pm, err = fileutils.NewPatternMatcher(opt.ExcludePatterns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "invalid excludepaths %s", opt.ExcludePatterns)
|
return errors.Wrapf(err, "invalid excludepatterns: %s", opt.ExcludePatterns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,17 +65,15 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err
|
||||||
|
|
||||||
seenFiles := make(map[uint64]string)
|
seenFiles := make(map[uint64]string)
|
||||||
return filepath.Walk(root, func(path string, fi os.FileInfo, err error) (retErr error) {
|
return filepath.Walk(root, func(path string, fi os.FileInfo, err error) (retErr error) {
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if retErr != nil && isNotExist(retErr) {
|
if retErr != nil && isNotExist(retErr) {
|
||||||
retErr = filepath.SkipDir
|
retErr = filepath.SkipDir
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
origpath := path
|
origpath := path
|
||||||
path, err = filepath.Rel(root, path)
|
path, err = filepath.Rel(root, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue