vendor: github.com/tonistiigi/fsutil v0.0.0-20230629203738-36ef4d8c0dbb
- Fix copy on windows plus tests
- Fix follow symlinkResolver on Windows
- Implement proper renameFile on Windows
- Fix potential nil pointer dereference
- Use RunWithPrivileges
- Fix leaking file handle
- handle mkdir race for diskwriter
- walk: avoid stat()'ing files unnecessarily
- ci: fix freebsd workflow
- update to Go 1.20
full diff: fb433841cb...36ef4d8c0d
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
531dbd7af5
commit
010c3718e3
14 changed files with 247 additions and 68 deletions
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
2
vendor/github.com/tonistiigi/fsutil/Dockerfile
generated
vendored
2
vendor/github.com/tonistiigi/fsutil/Dockerfile
generated
vendored
|
@ -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
|
||||
|
||||
|
|
90
vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go
generated
vendored
90
vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go
generated
vendored
|
@ -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
|
||||
}
|
||||
|
||||
|
|
48
vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go
generated
vendored
48
vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go
generated
vendored
|
@ -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
|
||||
}
|
||||
|
|
8
vendor/github.com/tonistiigi/fsutil/diskwriter.go
generated
vendored
8
vendor/github.com/tonistiigi/fsutil/diskwriter.go
generated
vendored
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
7
vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go
generated
vendored
7
vendor/github.com/tonistiigi/fsutil/diskwriter_unix.go
generated
vendored
|
@ -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
|
||||
}
|
||||
|
|
79
vendor/github.com/tonistiigi/fsutil/diskwriter_windows.go
generated
vendored
79
vendor/github.com/tonistiigi/fsutil/diskwriter_windows.go
generated
vendored
|
@ -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
|
||||
}
|
||||
|
|
2
vendor/github.com/tonistiigi/fsutil/docker-bake.hcl
generated
vendored
2
vendor/github.com/tonistiigi/fsutil/docker-bake.hcl
generated
vendored
|
@ -1,5 +1,5 @@
|
|||
variable "GO_VERSION" {
|
||||
default = "1.18"
|
||||
default = "1.20"
|
||||
}
|
||||
|
||||
group "default" {
|
||||
|
|
15
vendor/github.com/tonistiigi/fsutil/followlinks.go
generated
vendored
15
vendor/github.com/tonistiigi/fsutil/followlinks.go
generated
vendored
|
@ -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)
|
||||
|
|
14
vendor/github.com/tonistiigi/fsutil/followlinks_unix.go
generated
vendored
Normal file
14
vendor/github.com/tonistiigi/fsutil/followlinks_unix.go
generated
vendored
Normal file
|
@ -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)
|
||||
}
|
15
vendor/github.com/tonistiigi/fsutil/followlinks_windows.go
generated
vendored
Normal file
15
vendor/github.com/tonistiigi/fsutil/followlinks_windows.go
generated
vendored
Normal file
|
@ -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
|
||||
}
|
25
vendor/github.com/tonistiigi/fsutil/walker.go
generated
vendored
25
vendor/github.com/tonistiigi/fsutil/walker.go
generated
vendored
|
@ -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
|
||||
|
|
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue