Merge pull request #53247 from thaJeztah/vendor_go_archive

vendor: github.com/moby/go-archive v0.3.0
This commit is contained in:
Sebastiaan van Stijn
2026-07-30 20:57:21 +02:00
committed by GitHub
8 changed files with 134 additions and 39 deletions

2
go.mod
View File

@@ -64,7 +64,7 @@ require (
github.com/mitchellh/copystructure v1.2.0
github.com/moby/buildkit v0.32.0
github.com/moby/docker-image-spec v1.3.1
github.com/moby/go-archive v0.2.2-0.20260729101603-a11565d1683c
github.com/moby/go-archive v0.3.0
github.com/moby/ipvs v1.1.0
github.com/moby/locker v1.0.1
github.com/moby/moby/api v1.55.0

4
go.sum
View File

@@ -547,8 +547,8 @@ github.com/moby/buildkit v0.32.0 h1:slXarYQoMo4cp2d9x30M9t0L4R+c0CVMov+5P1hhiHY=
github.com/moby/buildkit v0.32.0/go.mod h1:Y10FBWvqxl/Wmhdzjee1Y2wQfjifTiwxENIUdaVNdME=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.2.2-0.20260729101603-a11565d1683c h1:FHEkke3COBYyr7/aIk1782G/4oVN/6L/ISEMD5dPIDk=
github.com/moby/go-archive v0.2.2-0.20260729101603-a11565d1683c/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
github.com/moby/go-archive v0.3.0 h1:nos4BtzzUIqB406BgQnWGMI4qib9BZ8XUHU+ucv/n1c=
github.com/moby/go-archive v0.3.0/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
github.com/moby/ipvs v1.1.0 h1:ONN4pGaZQgAx+1Scz5RvWV4Q7Gb+mvfRh3NsPS+1XQQ=
github.com/moby/ipvs v1.1.0/go.mod h1:4VJMWuf098bsUMmZEiD4Tjk/O7mOn3l1PTD3s4OoYAs=
github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg=

View File

@@ -610,13 +610,13 @@ func createTarFile(root *os.Root, dstPath string, hdr *tar.Header, reader io.Rea
// Follow the hardlink only when its target is not itself a symlink.
fi, err := root.Lstat(filepath.FromSlash(path.Clean(hdr.Linkname)))
if err == nil && fi.Mode()&os.ModeSymlink == 0 {
if err := root.Chtimes(dstPath, aTime, mTime); err != nil {
if err := chtimes(root, dstPath, aTime, mTime); err != nil {
return err
}
}
default:
// All other file types follow symlinks.
if err := root.Chtimes(dstPath, aTime, mTime); err != nil {
if err := chtimes(root, dstPath, aTime, mTime); err != nil {
return err
}
}
@@ -996,7 +996,7 @@ loop:
for _, d := range dirs {
aTime := boundTime(latestTime(d.hdr.AccessTime, d.hdr.ModTime))
if err := root.Chtimes(d.name, aTime, boundTime(d.hdr.ModTime)); err != nil {
if err := chtimes(root, d.name, aTime, boundTime(d.hdr.ModTime)); err != nil {
return err
}
}

View File

@@ -316,19 +316,40 @@ func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir
}
}
// newNameRebaser returns a function that replaces oldBase with newBase at the
// beginning of POSIX-style archive entry names. It converts oldBase and newBase
// to forward-slash form and trims trailing slashes.
//
// When rebasing from the archive root, the returned function removes all
// leading slashes from names. It otherwise preserves the remainder verbatim
// and does not clean or canonicalize paths.
func newNameRebaser(oldBase, newBase string) func(string) string {
oldBase = strings.TrimRight(filepath.ToSlash(oldBase), "/")
newBase = strings.TrimRight(filepath.ToSlash(newBase), "/")
if oldBase == "" {
return func(name string) string {
name = strings.TrimLeft(name, "/")
if newBase == "" {
return name
}
return newBase + "/" + name
}
}
return func(name string) string {
suffix, ok := strings.CutPrefix(name, oldBase)
if !ok || suffix != "" && !strings.HasPrefix(suffix, "/") {
return name
}
return newBase + suffix
}
}
// RebaseArchiveEntries rewrites the given srcContent archive replacing
// an occurrence of oldBase with newBase at the beginning of entry names.
func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.ReadCloser {
oldBase = filepath.ToSlash(oldBase)
newBase = filepath.ToSlash(newBase)
if oldBase == "/" {
// If oldBase specifies the root directory, use an empty string as
// oldBase instead so that newBase doesn't replace the path separator
// that all paths will start with.
oldBase = ""
}
rebase := newNameRebaser(oldBase, newBase)
rebased, w := io.Pipe()
go func() {
@@ -356,9 +377,9 @@ func RebaseArchiveEntries(srcContent io.Reader, oldBase, newBase string) io.Read
//
// To fix, set the format to PAX here. See docker/for-linux issue #484.
hdr.Format = tar.FormatPAX
hdr.Name = strings.Replace(hdr.Name, oldBase, newBase, 1)
hdr.Name = rebase(hdr.Name)
if hdr.Typeflag == tar.TypeLink {
hdr.Linkname = strings.Replace(hdr.Linkname, oldBase, newBase, 1)
hdr.Linkname = rebase(hdr.Linkname)
}
if err = rebasedTar.WriteHeader(hdr); err != nil {

View File

@@ -213,7 +213,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
}
for _, d := range dirs {
if err := root.Chtimes(d.name, boundTime(latestTime(d.hdr.AccessTime, d.hdr.ModTime)), boundTime(d.hdr.ModTime)); err != nil {
if err := chtimes(root, d.name, boundTime(latestTime(d.hdr.AccessTime, d.hdr.ModTime)), boundTime(d.hdr.ModTime)); err != nil {
return 0, err
}
}

View File

@@ -15,12 +15,12 @@ import (
)
// chtimes changes the access and modification time of a file at the given
// path.
// path relative to root.
//
// Callers must use boundTime to ensure timestamps are within the range
// supported by os.Chtimes.
func chtimes(name string, atime time.Time, mtime time.Time) error {
return os.Chtimes(name, atime, mtime)
func chtimes(root *os.Root, name string, atime, mtime time.Time) error {
return root.Chtimes(name, atime, mtime)
}
func lchtimes(root *os.Root, name string, atime, mtime time.Time) error {

View File

@@ -1,37 +1,111 @@
package archive
import (
"errors"
"os"
"path/filepath"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
// chtimes changes the access and modification time of a file at the given
// path.
// path relative to root.
//
// Symlink entries are handled separately through lchtimes. The final path
// component is expected not to be a reparse point; if one is encountered,
// chtimes returns an error.
//
// Callers must use boundTime to ensure timestamps are within the range
// supported by os.Chtimes.
func chtimes(name string, atime time.Time, mtime time.Time) error {
if err := os.Chtimes(name, atime, mtime); err != nil {
func chtimes(root *os.Root, name string, atime, mtime time.Time) error {
parent, err := root.OpenFile(filepath.Dir(name), os.O_RDONLY, 0)
if err != nil {
return err
}
defer parent.Close()
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)
// Symlink entries are handled by lchtimes. The destination for all
// chtimes callers is therefore expected not to be a reparse point.
//
// Do not follow the final component: if it was concurrently replaced
// with a reparse point, fail instead of updating its target.
return chtimesAt(parent, filepath.Base(name), atime, mtime, true)
}
func lchtimes(root *os.Root, name string, atime time.Time, mtime time.Time) error {
return nil
}
func chtimesAt(parent *os.File, name string, atime, mtime time.Time, noFollow bool) error {
h, err := openForWriteAttributesAt(windows.Handle(parent.Fd()), name, noFollow)
if err != nil {
if noFollow && errors.Is(err, windows.STATUS_REPARSE_POINT_ENCOUNTERED) {
// Encountering a reparse point when noFollow is requested is unexpected.
// Treat it as a potential breakout to fail extraction safely.
return breakoutError(err)
}
return err
}
defer func() { _ = windows.Close(h) }()
var (
creationTime = windows.NsecToFiletime(mtime.UnixNano())
accessTime = windows.NsecToFiletime(atime.UnixNano())
modificationTime = windows.NsecToFiletime(mtime.UnixNano())
)
return windows.SetFileTime(h, &creationTime, &accessTime, &modificationTime)
}
// openForWriteAttributesAt opens name relative to parent with permission to
// modify its file attributes. If noFollow is true, it does not follow reparse
// points.
//
// This implementation is based on Go's internal Windows Openat support:
//
// https://github.com/golang/go/blob/go1.26.0/src/internal/syscall/windows/at_windows.go
//
// It is used by os.Root's Windows implementation for root-relative filesystem
// operations:
//
// https://github.com/golang/go/blob/go1.26.0/src/os/root_windows.go
//
// Keep this implementation aligned with the upstream code until an equivalent
// operation is available from golang.org/x/sys/windows.
func openForWriteAttributesAt(parent windows.Handle, name string, noFollow bool) (windows.Handle, error) {
name16, err := windows.UTF16FromString(name)
if err != nil {
return windows.InvalidHandle, err
}
attrs := uint32(windows.OBJ_CASE_INSENSITIVE)
if noFollow {
attrs |= windows.OBJ_DONT_REPARSE
}
var handle windows.Handle
err = windows.NtCreateFile(
&handle,
windows.SYNCHRONIZE|windows.FILE_WRITE_ATTRIBUTES,
&windows.OBJECT_ATTRIBUTES{
Length: uint32(unsafe.Sizeof(windows.OBJECT_ATTRIBUTES{})),
RootDirectory: parent,
ObjectName: &windows.NTUnicodeString{
Length: uint16((len(name16) - 1) * 2), // #nosec G115 -- Length is USHORT by definition. A Windows path component cannot exceed uint16 bytes.
MaximumLength: uint16(len(name16) * 2), // #nosec G115 -- MaximumLength is USHORT by definition. A Windows path component cannot exceed uint16 bytes.
Buffer: &name16[0],
},
Attributes: attrs,
},
&windows.IO_STATUS_BLOCK{},
nil,
windows.FILE_ATTRIBUTE_NORMAL,
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
windows.FILE_OPEN,
windows.FILE_OPEN_FOR_BACKUP_INTENT|windows.FILE_SYNCHRONOUS_IO_NONALERT,
0, // EA buffer
0, // EA length
)
return handle, err
}

2
vendor/modules.txt vendored
View File

@@ -1266,7 +1266,7 @@ github.com/moby/buildkit/worker/label
# github.com/moby/docker-image-spec v1.3.1
## explicit; go 1.18
github.com/moby/docker-image-spec/specs-go/v1
# github.com/moby/go-archive v0.2.2-0.20260729101603-a11565d1683c
# github.com/moby/go-archive v0.3.0
## explicit; go 1.25
github.com/moby/go-archive
github.com/moby/go-archive/chrootarchive