diff --git a/vendor.mod b/vendor.mod index 184e45c8ec..1f0630396f 100644 --- a/vendor.mod +++ b/vendor.mod @@ -173,7 +173,7 @@ require ( github.com/spdx/tools-golang v0.3.1-0.20230104082527-d6f58551be3f // indirect github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/tinylib/msgp v1.1.8 // indirect - github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa // indirect + github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb // indirect github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 // indirect github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect diff --git a/vendor.sum b/vendor.sum index 9ee62c88d6..464f8695b7 100644 --- a/vendor.sum +++ b/vendor.sum @@ -1397,8 +1397,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1 github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tonistiigi/fsutil v0.0.0-20201103201449-0834f99b7b85/go.mod h1:a7cilN64dG941IOXfhJhlH0qB92hxJ9A1ewrdUmJ6xo= -github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa h1:XOFp/3aBXlqmOFAg3r6e0qQjPnK5I970LilqX+Is1W8= -github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa/go.mod h1:AvLEd1LEIl64G2Jpgwo7aVV5lGH0ePcKl0ygGIHNYl8= +github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb h1:uUe8rNyVXM8moActoBol6Xf6xX2GMr7SosR2EywMvGg= +github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb/go.mod h1:SxX/oNQ/ag6Vaoli547ipFK9J7BZn5JqJG0JE8lf8bA= github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 h1:8eY6m1mjgyB8XySUR7WvebTM8D/Vs86jLJzD/Tw7zkc= github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7/go.mod h1:qqvyZqkfwkoJuPU/bw61bItaoO0SJ8YSW0vSVRRvsRg= github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0= diff --git a/vendor/github.com/tonistiigi/fsutil/Dockerfile b/vendor/github.com/tonistiigi/fsutil/Dockerfile index 252b497638..9584648d05 100644 --- a/vendor/github.com/tonistiigi/fsutil/Dockerfile +++ b/vendor/github.com/tonistiigi/fsutil/Dockerfile @@ -1,5 +1,5 @@ #syntax=docker/dockerfile:1 -ARG GO_VERSION=1.18 +ARG GO_VERSION=1.20 FROM --platform=$BUILDPLATFORM tonistiigi/xx:1.1.0 AS xx diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go index 19a44a752f..58f822d0cf 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go @@ -13,53 +13,83 @@ const ( seTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" ) +func getUIDGID(fi os.FileInfo) (uid, gid int) { + return 0, 0 +} + +func getFileSecurityInfo(name string) (*windows.SID, *windows.ACL, error) { + secInfo, err := windows.GetNamedSecurityInfo( + name, windows.SE_FILE_OBJECT, + windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION) + + if err != nil { + return nil, nil, errors.Wrap(err, "fetching security info") + } + sid, _, err := secInfo.Owner() + if err != nil { + return nil, nil, errors.Wrap(err, "fetching owner SID") + } + dacl, _, err := secInfo.DACL() + if err != nil { + return nil, nil, errors.Wrap(err, "fetching dacl") + } + return sid, dacl, nil +} + func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { if err := os.Chmod(name, fi.Mode()); err != nil { return errors.Wrapf(err, "failed to chmod %s", name) } - // Copy file ownership and ACL - // We need SeRestorePrivilege and SeTakeOwnershipPrivilege in order - // to restore security info on a file, especially if we're trying to - // apply security info which includes SIDs not necessarily present on - // the host. - privileges := []string{winio.SeRestorePrivilege, seTakeOwnershipPrivilege} - if err := winio.EnableProcessPrivileges(privileges); err != nil { - return err - } - defer winio.DisableProcessPrivileges(privileges) - - secInfo, err := windows.GetNamedSecurityInfo( - src, windows.SE_FILE_OBJECT, - windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION) - + sid, dacl, err := getFileSecurityInfo(src) if err != nil { - return err + return errors.Wrap(err, "getting file info") } - dacl, _, err := secInfo.DACL() - if err != nil { - return err + if c.chown != nil { + // Use the defined chowner. + usr := &User{SID: sid.String()} + if err := Chown(name, usr, c.chown); err != nil { + return errors.Wrapf(err, "failed to chown %s", name) + } + return nil + } else { + // Copy file ownership and ACL from the source file. + // We need SeRestorePrivilege and SeTakeOwnershipPrivilege in order + // to restore security info on a file, especially if we're trying to + // apply security info which includes SIDs not necessarily present on + // the host. + privileges := []string{winio.SeRestorePrivilege, seTakeOwnershipPrivilege} + if err := winio.EnableProcessPrivileges(privileges); err != nil { + return err + } + defer winio.DisableProcessPrivileges(privileges) + + if err := windows.SetNamedSecurityInfo( + name, windows.SE_FILE_OBJECT, + windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION, + sid, nil, dacl, nil); err != nil { + + return err + } } - sid, _, err := secInfo.Owner() - if err != nil { - return err - } - - if err := windows.SetNamedSecurityInfo( - name, windows.SE_FILE_OBJECT, - windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION, - sid, nil, dacl, nil); err != nil { - + if err := c.copyFileTimestamp(fi, name); err != nil { return err } return nil } func (c *copier) copyFileTimestamp(fi os.FileInfo, name string) error { - // TODO: copy windows specific metadata + if c.utime != nil { + return Utimes(name, c.utime) + } + if fi.Mode()&os.ModeSymlink == 0 { + if err := os.Chtimes(name, fi.ModTime(), fi.ModTime()); err != nil { + return errors.Wrap(err, "changing mtime") + } + } return nil } diff --git a/vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go b/vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go index 6edb1f5f7f..d8dddae935 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go @@ -28,6 +28,15 @@ func fixRootDirectory(p string) string { } func Utimes(p string, tm *time.Time) error { + info, err := os.Lstat(p) + if err != nil { + return errors.Wrap(err, "fetching file info") + } + if tm != nil && info.Mode()&os.ModeSymlink == 0 { + if err := os.Chtimes(p, *tm, *tm); err != nil { + return errors.Wrap(err, "changing times") + } + } return nil } @@ -39,22 +48,14 @@ func Chown(p string, old *User, fn Chowner) error { if err != nil { return errors.WithStack(err) } - - userSIDstring := user.SID + var userSIDstring string + if user != nil && user.SID != "" { + userSIDstring = user.SID + } if userSIDstring == "" { userSIDstring = containerAdministratorSidString } - // Copy file ownership and ACL - // We need SeRestorePrivilege and SeTakeOwnershipPrivilege in order - // to restore security info on a file, especially if we're trying to - // apply security info which includes SIDs not necessarily present on - // the host. - privileges := []string{winio.SeRestorePrivilege, seTakeOwnershipPrivilege} - if err := winio.EnableProcessPrivileges(privileges); err != nil { - return err - } - defer winio.DisableProcessPrivileges(privileges) sidPtr, err := syscall.UTF16PtrFromString(userSIDstring) if err != nil { @@ -81,13 +82,22 @@ func Chown(p string, old *User, fn Chowner) error { return fmt.Errorf("adding acls: %w", err) } - if err := windows.SetNamedSecurityInfo( - p, windows.SE_FILE_OBJECT, - windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION, - userSID, nil, newAcl, nil); err != nil { + // Copy file ownership and ACL + // We need SeRestorePrivilege and SeTakeOwnershipPrivilege in order + // to restore security info on a file, especially if we're trying to + // apply security info which includes SIDs not necessarily present on + // the host. + privileges := []string{winio.SeRestorePrivilege, seTakeOwnershipPrivilege} + err = winio.RunWithPrivileges(privileges, func() error { + if err := windows.SetNamedSecurityInfo( + p, windows.SE_FILE_OBJECT, + windows.OWNER_SECURITY_INFORMATION|windows.DACL_SECURITY_INFORMATION, + userSID, nil, newAcl, nil); err != nil { - return err - } + return err + } + return nil + }) - return nil + return err } diff --git a/vendor/github.com/tonistiigi/fsutil/diskwriter.go b/vendor/github.com/tonistiigi/fsutil/diskwriter.go index b822644ddc..10b6085138 100644 --- a/vendor/github.com/tonistiigi/fsutil/diskwriter.go +++ b/vendor/github.com/tonistiigi/fsutil/diskwriter.go @@ -162,6 +162,10 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er switch { case fi.IsDir(): if err := os.Mkdir(newPath, fi.Mode()); err != nil { + if errors.Is(err, syscall.EEXIST) { + // we saw a race to create this directory, so try again + return dw.HandleChange(kind, p, fi, nil) + } return errors.Wrapf(err, "failed to create dir %s", newPath) } dw.dirModTimes[destPath] = statCopy.ModTime @@ -188,7 +192,6 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er file.Close() return err } - break } if err := file.Close(); err != nil { return errors.Wrapf(err, "failed to close %s", newPath) @@ -205,7 +208,8 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er return errors.Wrapf(err, "failed to remove %s", destPath) } } - if err := os.Rename(newPath, destPath); err != nil { + + if err := renameFile(newPath, destPath); err != nil { return errors.Wrapf(err, "failed to rename %s to %s", newPath, destPath) } } diff --git a/vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go b/vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go index 1d97d6f9d7..ccd554ab87 100644 --- a/vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go +++ b/vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go @@ -51,3 +51,10 @@ func handleTarTypeBlockCharFifo(path string, stat *types.Stat) error { } return nil } + +func renameFile(src, dst string) error { + if err := os.Rename(src, dst); err != nil { + return errors.Wrapf(err, "failed to rename %s to %s", src, dst) + } + return nil +} diff --git a/vendor/github.com/tonistiigi/fsutil/diskwriter_windows.go b/vendor/github.com/tonistiigi/fsutil/diskwriter_windows.go index 036544f0b6..2dd3f7d05f 100644 --- a/vendor/github.com/tonistiigi/fsutil/diskwriter_windows.go +++ b/vendor/github.com/tonistiigi/fsutil/diskwriter_windows.go @@ -1,8 +1,15 @@ +//go:build windows // +build windows package fsutil import ( + "fmt" + iofs "io/fs" + "os" + "syscall" + + "github.com/Microsoft/go-winio" "github.com/pkg/errors" "github.com/tonistiigi/fsutil/types" ) @@ -16,3 +23,75 @@ func rewriteMetadata(p string, stat *types.Stat) error { func handleTarTypeBlockCharFifo(path string, stat *types.Stat) error { return errors.New("Not implemented on windows") } + +func getFileHandle(path string, info iofs.FileInfo) (syscall.Handle, error) { + p, err := syscall.UTF16PtrFromString(path) + if err != nil { + return 0, errors.Wrap(err, "converting string to UTF-16") + } + attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS) + if info.Mode()&os.ModeSymlink != 0 { + // Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink. + // See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted + attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT + } + h, err := syscall.CreateFile(p, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0) + if err != nil { + return 0, errors.Wrap(err, "getting file handle") + } + return h, nil +} + +func readlink(path string, info iofs.FileInfo) ([]byte, error) { + h, err := getFileHandle(path, info) + if err != nil { + return nil, errors.Wrap(err, "getting file handle") + } + defer syscall.CloseHandle(h) + + rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE) + var bytesReturned uint32 + err = syscall.DeviceIoControl(h, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil) + if err != nil { + return nil, errors.Wrap(err, "sending I/O control command") + } + return rdbbuf[:bytesReturned], nil +} + +func getReparsePoint(path string, info iofs.FileInfo) (*winio.ReparsePoint, error) { + target, err := readlink(path, info) + if err != nil { + return nil, errors.Wrap(err, "fetching link") + } + rp, err := winio.DecodeReparsePoint(target) + if err != nil { + return nil, errors.Wrap(err, "decoding reparse point") + } + return rp, nil +} + +func renameFile(src, dst string) error { + info, err := os.Lstat(dst) + if err != nil { + if !os.IsNotExist(err) { + return errors.Wrap(err, "getting file info") + } + } + + if info != nil && info.Mode()&os.ModeSymlink != 0 { + dstInfoRp, err := getReparsePoint(dst, info) + if err != nil { + return errors.Wrap(err, "getting reparse point") + } + if dstInfoRp.IsMountPoint { + return fmt.Errorf("%s is a mount point", dst) + } + if err := os.Remove(dst); err != nil { + return errors.Wrapf(err, "removing %s", dst) + } + } + if err := os.Rename(src, dst); err != nil { + return errors.Wrapf(err, "failed to rename %s to %s", src, dst) + } + return nil +} diff --git a/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl b/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl index 3d7d182c3c..6ba3c86724 100644 --- a/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl +++ b/vendor/github.com/tonistiigi/fsutil/docker-bake.hcl @@ -1,5 +1,5 @@ variable "GO_VERSION" { - default = "1.18" + default = "1.20" } group "default" { diff --git a/vendor/github.com/tonistiigi/fsutil/followlinks.go b/vendor/github.com/tonistiigi/fsutil/followlinks.go index 136a908211..f03a9cf350 100644 --- a/vendor/github.com/tonistiigi/fsutil/followlinks.go +++ b/vendor/github.com/tonistiigi/fsutil/followlinks.go @@ -19,7 +19,7 @@ func FollowLinks(root string, paths []string) ([]string, error) { } res := make([]string, 0, len(r.resolved)) for r := range r.resolved { - res = append(res, r) + res = append(res, filepath.ToSlash(r)) } sort.Strings(res) return dedupePaths(res), nil @@ -31,6 +31,12 @@ type symlinkResolver struct { } func (r *symlinkResolver) append(p string) error { + if runtime.GOOS == "windows" && filepath.IsAbs(filepath.FromSlash(p)) { + absParts := strings.SplitN(p, ":", 2) + if len(absParts) == 2 { + p = absParts[1] + } + } p = filepath.Join(".", p) current := "." for { @@ -41,7 +47,6 @@ func (r *symlinkResolver) append(p string) error { if err != nil { return err } - p = "" if len(parts) == 2 { p = parts[1] @@ -76,7 +81,7 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e if allowWildcard && containsWildcards(base) { fis, err := os.ReadDir(filepath.Dir(realPath)) if err != nil { - if errors.Is(err, os.ErrNotExist) { + if isNotFound(err) { return nil, nil } return nil, errors.Wrap(err, "readdir") @@ -96,7 +101,7 @@ func (r *symlinkResolver) readSymlink(p string, allowWildcard bool) ([]string, e fi, err := os.Lstat(realPath) if err != nil { - if errors.Is(err, os.ErrNotExist) { + if isNotFound(err) { return nil, nil } return nil, errors.WithStack(err) @@ -139,7 +144,7 @@ func dedupePaths(in []string) []string { if s == "." { return nil } - if strings.HasPrefix(s, last+string(filepath.Separator)) { + if strings.HasPrefix(s, last+"/") { continue } out = append(out, s) diff --git a/vendor/github.com/tonistiigi/fsutil/followlinks_unix.go b/vendor/github.com/tonistiigi/fsutil/followlinks_unix.go new file mode 100644 index 0000000000..41ae5e42a4 --- /dev/null +++ b/vendor/github.com/tonistiigi/fsutil/followlinks_unix.go @@ -0,0 +1,14 @@ +//go:build !windows +// +build !windows + +package fsutil + +import ( + "os" + + "github.com/pkg/errors" +) + +func isNotFound(err error) bool { + return errors.Is(err, os.ErrNotExist) +} diff --git a/vendor/github.com/tonistiigi/fsutil/followlinks_windows.go b/vendor/github.com/tonistiigi/fsutil/followlinks_windows.go new file mode 100644 index 0000000000..443ebd7ff8 --- /dev/null +++ b/vendor/github.com/tonistiigi/fsutil/followlinks_windows.go @@ -0,0 +1,15 @@ +package fsutil + +import ( + "os" + + "github.com/pkg/errors" + "golang.org/x/sys/windows" +) + +func isNotFound(err error) bool { + if errors.Is(err, os.ErrNotExist) || errors.Is(err, windows.ERROR_INVALID_NAME) { + return true + } + return false +} diff --git a/vendor/github.com/tonistiigi/fsutil/walker.go b/vendor/github.com/tonistiigi/fsutil/walker.go index f95101f319..545f5e905f 100644 --- a/vendor/github.com/tonistiigi/fsutil/walker.go +++ b/vendor/github.com/tonistiigi/fsutil/walker.go @@ -2,6 +2,7 @@ package fsutil import ( "context" + gofs "io/fs" "os" "path/filepath" "strings" @@ -47,11 +48,11 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err if err != nil { return errors.WithStack(&os.PathError{Op: "resolve", Path: root, Err: err}) } - fi, err := os.Stat(root) + rootFI, err := os.Stat(root) if err != nil { return errors.WithStack(err) } - if !fi.IsDir() { + if !rootFI.IsDir() { return errors.WithStack(&os.PathError{Op: "walk", Path: root, Err: syscall.ENOTDIR}) } @@ -126,7 +127,7 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err var parentDirs []visitedDir seenFiles := make(map[uint64]string) - return filepath.Walk(root, func(path string, fi os.FileInfo, walkErr error) (retErr error) { + return filepath.WalkDir(root, func(path string, dirEntry gofs.DirEntry, walkErr error) (retErr error) { defer func() { if retErr != nil && isNotExist(retErr) { retErr = filepath.SkipDir @@ -146,9 +147,10 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err var ( dir visitedDir isDir bool + fi gofs.FileInfo ) - if fi != nil { - isDir = fi.IsDir() + if dirEntry != nil { + isDir = dirEntry.IsDir() } if includeMatcher != nil || excludeMatcher != nil { @@ -161,6 +163,11 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err } if isDir { + fi, err = dirEntry.Info() + if err != nil { + return err + } + dir = visitedDir{ fi: fi, path: path, @@ -268,6 +275,14 @@ func Walk(ctx context.Context, p string, opt *WalkOpt, fn filepath.WalkFunc) err dir.calledFn = true + // The FileInfo might have already been read further up. + if fi == nil { + fi, err = dirEntry.Info() + if err != nil { + return err + } + } + stat, err := mkstat(origpath, path, fi, seenFiles) if err != nil { return err diff --git a/vendor/modules.txt b/vendor/modules.txt index ba72ef1999..1d92d530cb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -969,8 +969,8 @@ github.com/syndtr/gocapability/capability # github.com/tinylib/msgp v1.1.8 ## explicit; go 1.15 github.com/tinylib/msgp/msgp -# github.com/tonistiigi/fsutil v0.0.0-20230105215944-fb433841cbfa -## explicit; go 1.18 +# github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb +## explicit; go 1.19 github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil/copy github.com/tonistiigi/fsutil/types