diff --git a/go.mod b/go.mod index 74bad2a99e9b..2f4a64c1c219 100644 --- a/go.mod +++ b/go.mod @@ -60,7 +60,7 @@ require ( github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.0 - github.com/tonistiigi/fsutil v0.0.0-20220930225714-4638ad635be5 + github.com/tonistiigi/fsutil v0.0.0-20221114235510-0127568185cf github.com/tonistiigi/go-actions-cache v0.0.0-20220404170428-0bdeb6e1eac7 github.com/tonistiigi/go-archvariant v1.0.0 github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea diff --git a/go.sum b/go.sum index 5bbf08454b33..4f6730467b4e 100644 --- a/go.sum +++ b/go.sum @@ -1366,8 +1366,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-20220930225714-4638ad635be5 h1:NJ1nZs4j4XcBJKIY5sAwTGp9w5b78Zxr3+r0zXRuKnA= -github.com/tonistiigi/fsutil v0.0.0-20220930225714-4638ad635be5/go.mod h1:F83XRhNblQsKQH9hcKEE45GAOkL9590mtw9KsD0Q4fE= +github.com/tonistiigi/fsutil v0.0.0-20221114235510-0127568185cf h1:2n2v98sRhXEG0Kh7+EvctaNIyOim36Ekp4pGDzbuvO8= +github.com/tonistiigi/fsutil v0.0.0-20221114235510-0127568185cf/go.mod h1:AvLEd1LEIl64G2Jpgwo7aVV5lGH0ePcKl0ygGIHNYl8= 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/copy/copy.go b/vendor/github.com/tonistiigi/fsutil/copy/copy.go index 75586bcb88e5..558c553f7c5a 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy.go @@ -153,6 +153,7 @@ func (c *copier) prepareTargetDir(srcFollowed, src, destPath string, copyDirCont type User struct { UID, GID int + SID string } type Chowner func(*User) (*User, error) @@ -294,6 +295,10 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov if err != nil { return errors.Wrapf(err, "failed to stat %s", src) } + targetFi, err := os.Lstat(target) + if err != nil && !os.IsNotExist(err) { + return errors.Wrapf(err, "failed to stat %s", src) + } include := true var ( @@ -335,6 +340,7 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov } copyFileInfo := include + restoreFileTimestamp := false notify := true switch { @@ -346,8 +352,10 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov return err } else if !overwriteTargetMetadata { // if we aren't supposed to overwrite existing target metadata, - // then we only need to copy file info if we newly created it + // then we only need to copy the new file info if we newly created + // it, or restore the previous file timestamp if not copyFileInfo = created + restoreFileTimestamp = !created } notify = false case (fi.Mode() & os.ModeType) == 0: @@ -379,13 +387,17 @@ func (c *copier) copy(ctx context.Context, src, srcComponents, target string, ov } if copyFileInfo { - if err := c.copyFileInfo(fi, target); err != nil { + if err := c.copyFileInfo(fi, src, target); err != nil { return errors.Wrap(err, "failed to copy file info") } if err := copyXAttrs(target, src, c.xattrErrorHandler); err != nil { return errors.Wrap(err, "failed to copy xattrs") } + } else if restoreFileTimestamp && targetFi != nil { + if err := c.copyFileTimestamp(fi, target); err != nil { + return errors.Wrap(err, "failed to restore file timestamp") + } } if notify { if err := c.notifyChange(target, fi); err != nil { @@ -449,7 +461,7 @@ func (c *copier) createParentDirs(src, srcComponents, target string, overwriteTa return err } if created { - if err := c.copyFileInfo(fi, parentDir.dstPath); err != nil { + if err := c.copyFileInfo(fi, parentDir.srcPath, parentDir.dstPath); err != nil { return errors.Wrap(err, "failed to copy file info") } diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go index 2ac813eea994..971cb5c5d49c 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_linux.go @@ -15,9 +15,7 @@ func getUIDGID(fi os.FileInfo) (uid, gid int) { return int(st.Uid), int(st.Gid) } -func (c *copier) copyFileInfo(fi os.FileInfo, name string) error { - st := fi.Sys().(*syscall.Stat_t) - +func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { chown := c.chown uid, gid := getUIDGID(fi) old := &User{UID: uid, GID: gid} @@ -40,17 +38,23 @@ func (c *copier) copyFileInfo(fi os.FileInfo, name string) error { } } + if err := c.copyFileTimestamp(fi, name); err != nil { + return err + } + + return nil +} + +func (c *copier) copyFileTimestamp(fi os.FileInfo, name string) error { if c.utime != nil { - if err := Utimes(name, c.utime); err != nil { - return err - } - } else { - 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 Utimes(name, c.utime) } + st := fi.Sys().(*syscall.Stat_t) + 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 } diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go index 22281ba5dde4..945e96c5f23d 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_unix.go @@ -16,8 +16,7 @@ func getUIDGID(fi os.FileInfo) (uid, gid int) { return int(st.Uid), int(st.Gid) } -func (c *copier) copyFileInfo(fi os.FileInfo, name string) error { - st := fi.Sys().(*syscall.Stat_t) +func (c *copier) copyFileInfo(fi os.FileInfo, src, name string) error { chown := c.chown uid, gid := getUIDGID(fi) old := &User{UID: uid, GID: gid} @@ -40,15 +39,21 @@ func (c *copier) copyFileInfo(fi os.FileInfo, name string) error { } } + if err := c.copyFileTimestamp(fi, name); err != nil { + return err + } + return nil +} + +func (c *copier) copyFileTimestamp(fi os.FileInfo, name string) error { if c.utime != nil { - if err := Utimes(name, c.utime); err != nil { - return err - } - } else { - 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 Utimes(name, c.utime) + } + + st := fi.Sys().(*syscall.Stat_t) + 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 } diff --git a/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go b/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go index 330c0e3f2c35..19a44a752f09 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/copy_windows.go @@ -4,14 +4,60 @@ import ( "io" "os" + "github.com/Microsoft/go-winio" "github.com/pkg/errors" + "golang.org/x/sys/windows" ) -func (c *copier) copyFileInfo(fi os.FileInfo, name string) error { +const ( + seTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" +) + +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) + + if err != nil { + return err + } + + dacl, _, err := secInfo.DACL() + if 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 { + + return err + } + return nil +} + +func (c *copier) copyFileTimestamp(fi os.FileInfo, name string) error { // TODO: copy windows specific metadata return nil diff --git a/vendor/github.com/tonistiigi/fsutil/copy/mkdir.go b/vendor/github.com/tonistiigi/fsutil/copy/mkdir.go index 98547544759b..9553c08be307 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/mkdir.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/mkdir.go @@ -4,26 +4,8 @@ import ( "os" "syscall" "time" - - "github.com/pkg/errors" ) -func Chown(p string, old *User, fn Chowner) error { - if fn == nil { - return nil - } - user, err := fn(old) - if err != nil { - return errors.WithStack(err) - } - if user != nil { - if err := os.Lchown(p, user.UID, user.GID); err != nil { - return err - } - } - return nil -} - // MkdirAll is forked os.MkdirAll func MkdirAll(path string, perm os.FileMode, user Chowner, tm *time.Time) error { // Fast path: if we can tell whether path is a directory or file, stop with success or error. diff --git a/vendor/github.com/tonistiigi/fsutil/copy/mkdir_unix.go b/vendor/github.com/tonistiigi/fsutil/copy/mkdir_unix.go index f6d196b784d3..8bc5711bf086 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/mkdir_unix.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/mkdir_unix.go @@ -4,6 +4,7 @@ package fs import ( + "os" "time" "github.com/pkg/errors" @@ -31,3 +32,19 @@ func Utimes(p string, tm *time.Time) error { return nil } + +func Chown(p string, old *User, fn Chowner) error { + if fn == nil { + return nil + } + user, err := fn(old) + if err != nil { + return errors.WithStack(err) + } + if user != nil { + if err := os.Lchown(p, user.UID, user.GID); err != nil { + return err + } + } + 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 6bd17e813358..6edb1f5f7f6c 100644 --- a/vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go +++ b/vendor/github.com/tonistiigi/fsutil/copy/mkdir_windows.go @@ -1,10 +1,21 @@ +//go:build windows // +build windows package fs import ( + "fmt" "os" + "syscall" "time" + + "github.com/Microsoft/go-winio" + "github.com/pkg/errors" + "golang.org/x/sys/windows" +) + +const ( + containerAdministratorSidString = "S-1-5-93-2-1" ) func fixRootDirectory(p string) string { @@ -19,3 +30,64 @@ func fixRootDirectory(p string) string { func Utimes(p string, tm *time.Time) error { return nil } + +func Chown(p string, old *User, fn Chowner) error { + if fn == nil { + return nil + } + user, err := fn(old) + if err != nil { + return errors.WithStack(err) + } + + 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 { + return errors.Wrap(err, "converting to utf16 ptr") + } + var userSID *windows.SID + if err := windows.ConvertStringSidToSid(sidPtr, &userSID); err != nil { + return errors.Wrap(err, "converting to windows SID") + } + var dacl *windows.ACL + newEntries := []windows.EXPLICIT_ACCESS{ + { + AccessPermissions: windows.GENERIC_ALL, + AccessMode: windows.GRANT_ACCESS, + Inheritance: windows.SUB_CONTAINERS_AND_OBJECTS_INHERIT, + Trustee: windows.TRUSTEE{ + TrusteeForm: windows.TRUSTEE_IS_SID, + TrusteeValue: windows.TrusteeValueFromSID(userSID), + }, + }, + } + newAcl, err := windows.ACLFromEntries(newEntries, dacl) + if err != nil { + 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 { + + return err + } + + return nil +} diff --git a/vendor/github.com/tonistiigi/fsutil/diskwriter.go b/vendor/github.com/tonistiigi/fsutil/diskwriter.go index 8f2574b5078d..b822644ddc9c 100644 --- a/vendor/github.com/tonistiigi/fsutil/diskwriter.go +++ b/vendor/github.com/tonistiigi/fsutil/diskwriter.go @@ -4,6 +4,7 @@ import ( "context" "hash" "io" + gofs "io/fs" "os" "path/filepath" "strconv" @@ -33,10 +34,11 @@ type DiskWriter struct { opt DiskWriterOpt dest string - ctx context.Context - cancel func() - eg *errgroup.Group - filter FilterFunc + ctx context.Context + cancel func() + eg *errgroup.Group + filter FilterFunc + dirModTimes map[string]int64 } func NewDiskWriter(ctx context.Context, dest string, opt DiskWriterOpt) (*DiskWriter, error) { @@ -51,17 +53,32 @@ func NewDiskWriter(ctx context.Context, dest string, opt DiskWriterOpt) (*DiskWr eg, ctx := errgroup.WithContext(ctx) return &DiskWriter{ - opt: opt, - dest: dest, - eg: eg, - ctx: ctx, - cancel: cancel, - filter: opt.Filter, + opt: opt, + dest: dest, + eg: eg, + ctx: ctx, + cancel: cancel, + filter: opt.Filter, + dirModTimes: map[string]int64{}, }, nil } func (dw *DiskWriter) Wait(ctx context.Context) error { - return dw.eg.Wait() + if err := dw.eg.Wait(); err != nil { + return err + } + return filepath.WalkDir(dw.dest, func(path string, d gofs.DirEntry, prevErr error) error { + if prevErr != nil { + return prevErr + } + if !d.IsDir() { + return nil + } + if mtime, ok := dw.dirModTimes[path]; ok { + return chtimes(path, mtime) + } + return nil + }) } func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, err error) (retErr error) { @@ -147,6 +164,7 @@ func (dw *DiskWriter) HandleChange(kind ChangeKind, p string, fi os.FileInfo, er if err := os.Mkdir(newPath, fi.Mode()); err != nil { return errors.Wrapf(err, "failed to create dir %s", newPath) } + dw.dirModTimes[destPath] = statCopy.ModTime case fi.Mode()&os.ModeDevice != 0 || fi.Mode()&os.ModeNamedPipe != 0: if err := handleTarTypeBlockCharFifo(newPath, &statCopy); err != nil { return errors.Wrapf(err, "failed to create device %s", newPath) diff --git a/vendor/modules.txt b/vendor/modules.txt index b96f60c4061b..81939c8c63f0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -643,7 +643,7 @@ github.com/sirupsen/logrus ## explicit; go 1.13 github.com/stretchr/testify/assert github.com/stretchr/testify/require -# github.com/tonistiigi/fsutil v0.0.0-20220930225714-4638ad635be5 +# github.com/tonistiigi/fsutil v0.0.0-20221114235510-0127568185cf ## explicit; go 1.18 github.com/tonistiigi/fsutil github.com/tonistiigi/fsutil/copy