mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
Update archive to use time operations directly
Update archive time logic to mirror containerd's Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
@@ -822,26 +822,22 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
|
||||
return err
|
||||
}
|
||||
|
||||
aTime := hdr.AccessTime
|
||||
if aTime.Before(hdr.ModTime) {
|
||||
// Last access time should never be before last modified time.
|
||||
aTime = hdr.ModTime
|
||||
}
|
||||
aTime := boundTime(latestTime(hdr.AccessTime, hdr.ModTime))
|
||||
mTime := boundTime(hdr.ModTime)
|
||||
|
||||
// system.Chtimes doesn't support a NOFOLLOW flag atm
|
||||
// chtimes doesn't support a NOFOLLOW flag atm
|
||||
if hdr.Typeflag == tar.TypeLink {
|
||||
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
|
||||
if err := system.Chtimes(path, aTime, hdr.ModTime); err != nil {
|
||||
if err := chtimes(path, aTime, mTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else if hdr.Typeflag != tar.TypeSymlink {
|
||||
if err := system.Chtimes(path, aTime, hdr.ModTime); err != nil {
|
||||
if err := chtimes(path, aTime, mTime); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ts := []syscall.Timespec{timeToTimespec(aTime), timeToTimespec(hdr.ModTime)}
|
||||
if err := system.LUtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
|
||||
if err := lchtimes(path, aTime, mTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -1201,7 +1197,7 @@ loop:
|
||||
// #nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
|
||||
path := filepath.Join(dest, hdr.Name)
|
||||
|
||||
if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
||||
if err := chtimes(path, boundTime(latestTime(hdr.AccessTime, hdr.ModTime)), boundTime(hdr.ModTime)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"gotest.tools/v3/assert"
|
||||
"gotest.tools/v3/skip"
|
||||
)
|
||||
@@ -107,7 +106,7 @@ func provisionSampleDir(t *testing.T, root string, files []FileData) {
|
||||
|
||||
if info.filetype != Symlink {
|
||||
// Set a consistent ctime, atime for all files and dirs
|
||||
err := system.Chtimes(p, now, now)
|
||||
err := chtimes(p, now, now)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
@@ -292,7 +291,7 @@ func mutateSampleDir(t *testing.T, root string) {
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Touch file
|
||||
err = system.Chtimes(path.Join(root, "file4"), time.Now().Add(time.Second), time.Now().Add(time.Second))
|
||||
err = chtimes(path.Join(root, "file4"), time.Now().Add(time.Second), time.Now().Add(time.Second))
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Replace file with dir
|
||||
@@ -327,7 +326,7 @@ func mutateSampleDir(t *testing.T, root string) {
|
||||
assert.NilError(t, err)
|
||||
|
||||
// Touch dir
|
||||
err = system.Chtimes(path.Join(root, "dir3"), time.Now().Add(time.Second), time.Now().Add(time.Second))
|
||||
err = chtimes(path.Join(root, "dir3"), time.Now().Add(time.Second), time.Now().Add(time.Second))
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// Errors used or returned by this file.
|
||||
@@ -203,7 +202,7 @@ func CopyInfoDestinationPath(path string) (info CopyInfo, err error) {
|
||||
return CopyInfo{}, err
|
||||
}
|
||||
|
||||
if !system.IsAbs(linkTarget) {
|
||||
if !filepath.IsAbs(linkTarget) {
|
||||
// Join with the parent directory.
|
||||
dstParent, _ := SplitPathDirEntry(path)
|
||||
linkTarget = filepath.Join(dstParent, linkTarget)
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/pkg/pools"
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// UnpackLayer unpack `layer` to a `dest`. The stream `layer` can be
|
||||
@@ -200,7 +199,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||
for _, hdr := range dirs {
|
||||
// #nosec G305 -- The header was checked for path traversal before it was appended to the dirs slice.
|
||||
path := filepath.Join(dest, hdr.Name)
|
||||
if err := system.Chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
||||
if err := chtimes(path, hdr.AccessTime, hdr.ModTime); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
38
pkg/archive/time.go
Normal file
38
pkg/archive/time.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package archive // import "github.com/docker/docker/pkg/archive"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
minTime = time.Unix(0, 0)
|
||||
maxTime time.Time
|
||||
)
|
||||
|
||||
func init() {
|
||||
if unsafe.Sizeof(syscall.Timespec{}.Nsec) == 8 {
|
||||
// This is a 64 bit timespec
|
||||
// os.Chtimes limits time to the following
|
||||
maxTime = time.Unix(0, 1<<63-1)
|
||||
} else {
|
||||
// This is a 32 bit timespec
|
||||
maxTime = time.Unix(1<<31-1, 0)
|
||||
}
|
||||
}
|
||||
|
||||
func boundTime(t time.Time) time.Time {
|
||||
if t.Before(minTime) || t.After(maxTime) {
|
||||
return minTime
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func latestTime(t1, t2 time.Time) time.Time {
|
||||
if t1.Before(t2) {
|
||||
return t2
|
||||
}
|
||||
return t1
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package archive // import "github.com/docker/docker/pkg/archive"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func timeToTimespec(time time.Time) (ts syscall.Timespec) {
|
||||
if time.IsZero() {
|
||||
// Return UTIME_OMIT special value
|
||||
ts.Sec = 0
|
||||
ts.Nsec = (1 << 30) - 2
|
||||
return
|
||||
}
|
||||
return syscall.NsecToTimespec(time.UnixNano())
|
||||
}
|
||||
40
pkg/archive/time_nonwindows.go
Normal file
40
pkg/archive/time_nonwindows.go
Normal file
@@ -0,0 +1,40 @@
|
||||
//go:build !windows
|
||||
|
||||
package archive // import "github.com/docker/docker/pkg/archive"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// chtimes changes the access time and modified time of a file at the given path.
|
||||
// If the modified time is prior to the Unix Epoch (unixMinTime), or after the
|
||||
// end of Unix Time (unixEpochTime), os.Chtimes has undefined behavior. In this
|
||||
// case, Chtimes defaults to Unix Epoch, just in case.
|
||||
func chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||
return os.Chtimes(name, atime, mtime)
|
||||
}
|
||||
|
||||
func timeToTimespec(time time.Time) (ts unix.Timespec) {
|
||||
if time.IsZero() {
|
||||
// Return UTIME_OMIT special value
|
||||
ts.Sec = 0
|
||||
ts.Nsec = (1 << 30) - 2
|
||||
return
|
||||
}
|
||||
return unix.NsecToTimespec(time.UnixNano())
|
||||
}
|
||||
|
||||
func lchtimes(name string, atime time.Time, mtime time.Time) error {
|
||||
utimes := [2]unix.Timespec{
|
||||
timeToTimespec(atime),
|
||||
timeToTimespec(mtime),
|
||||
}
|
||||
err := unix.UtimesNanoAt(unix.AT_FDCWD, name, utimes[0:], unix.AT_SYMLINK_NOFOLLOW)
|
||||
if err != nil && err != unix.ENOSYS {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
//go:build !linux
|
||||
|
||||
package archive // import "github.com/docker/docker/pkg/archive"
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
func timeToTimespec(time time.Time) (ts syscall.Timespec) {
|
||||
nsec := int64(0)
|
||||
if !time.IsZero() {
|
||||
nsec = time.UnixNano()
|
||||
}
|
||||
return syscall.NsecToTimespec(nsec)
|
||||
}
|
||||
32
pkg/archive/time_windows.go
Normal file
32
pkg/archive/time_windows.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package archive // import "github.com/docker/docker/pkg/archive"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||
if err := os.Chtimes(name, atime, mtime); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pathp, err := windows.UTF16PtrFromString(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h, err := windows.CreateFile(pathp,
|
||||
windows.FILE_WRITE_ATTRIBUTES, windows.FILE_SHARE_WRITE, nil,
|
||||
windows.OPEN_EXISTING, windows.FILE_FLAG_BACKUP_SEMANTICS, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer windows.Close(h)
|
||||
c := windows.NsecToFiletime(mtime.UnixNano())
|
||||
return windows.SetFileTime(h, &c, nil, nil)
|
||||
}
|
||||
|
||||
func lchtimes(name string, atime time.Time, mtime time.Time) error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user