Skip to content

Commit

Permalink
builder/dockerfile: ADD with best-effort xattrs
Browse files Browse the repository at this point in the history
Archives being unpacked by Dockerfiles may have been created on other
OSes with different conventions and semantics for xattrs, making them
impossible to apply when extracting. Restore the old best-effort xattr
behaviour users have come to depend on in the classic builder.

Signed-off-by: Cory Snider <csnider@mirantis.com>
  • Loading branch information
corhere committed Jan 22, 2024
1 parent c87e0ad commit b647e79
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 8 deletions.
2 changes: 1 addition & 1 deletion builder/dockerfile/copy.go
Expand Up @@ -472,7 +472,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
return copyDirectory(archiver, srcPath, destPath, options.identity)
}
if options.decompress && archive.IsArchivePath(srcPath) && !source.noDecompress {
return archiver.UntarPath(srcPath, destPath)
return archiver.UntarPath(srcPath, destPath, archive.WithBestEffortXattrs(true))
}

destExistsAsDir, err := isExistingDirectory(destPath)
Expand Down
31 changes: 24 additions & 7 deletions pkg/archive/archive.go
Expand Up @@ -1275,7 +1275,7 @@ func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decomp

// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
// If either Tar or Untar fails, TarUntar aborts and returns the error.
func (archiver *Archiver) TarUntar(src, dst string) error {
func (archiver *Archiver) TarUntar(src, dst string, opts ...func(*TarOptions)) error {
archive, err := TarWithOptions(src, &TarOptions{Compression: Uncompressed})
if err != nil {
return err
Expand All @@ -1284,11 +1284,14 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
options := &TarOptions{
IDMap: archiver.IDMapping,
}
for _, o := range opts {
o(options)
}
return archiver.Untar(archive, dst, options)
}

// UntarPath untar a file from path to a destination, src is the source tar file path.
func (archiver *Archiver) UntarPath(src, dst string) error {
func (archiver *Archiver) UntarPath(src, dst string, opts ...func(*TarOptions)) error {
archive, err := os.Open(src)
if err != nil {
return err
Expand All @@ -1297,20 +1300,23 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
options := &TarOptions{
IDMap: archiver.IDMapping,
}
for _, o := range opts {
o(options)
}
return archiver.Untar(archive, dst, options)
}

// CopyWithTar creates a tar archive of filesystem path `src`, and
// unpacks it at filesystem path `dst`.
// The archive is streamed directly with fixed buffering and no
// intermediary disk IO.
func (archiver *Archiver) CopyWithTar(src, dst string) error {
func (archiver *Archiver) CopyWithTar(src, dst string, opts ...func(*TarOptions)) error {
srcSt, err := os.Stat(src)
if err != nil {
return err
}
if !srcSt.IsDir() {
return archiver.CopyFileWithTar(src, dst)
return archiver.CopyFileWithTar(src, dst, opts...)
}

// if this Archiver is set up with ID mapping we need to create
Expand All @@ -1321,13 +1327,13 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
if err := idtools.MkdirAllAndChownNew(dst, 0o755, rootIDs); err != nil {
return err
}
return archiver.TarUntar(src, dst)
return archiver.TarUntar(src, dst, opts...)
}

// CopyFileWithTar emulates the behavior of the 'cp' command-line
// for a single file. It copies a regular file from path `src` to
// path `dst`, and preserves all its metadata.
func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
func (archiver *Archiver) CopyFileWithTar(src, dst string, opts ...func(*TarOptions)) (err error) {
srcSt, err := os.Stat(src)
if err != nil {
return err
Expand Down Expand Up @@ -1394,7 +1400,11 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
}
}()

err = archiver.Untar(r, filepath.Dir(dst), nil)
var options TarOptions
for _, o := range opts {
o(&options)
}
err = archiver.Untar(r, filepath.Dir(dst), &options)
if err != nil {
r.CloseWithError(err)
}
Expand All @@ -1406,6 +1416,13 @@ func (archiver *Archiver) IdentityMapping() idtools.IdentityMapping {
return archiver.IDMapping
}

// WithBestEffortXattrs sets the BestEffortXattrs option for the Archiver operation.
func WithBestEffortXattrs(v bool) func(*TarOptions) {
return func(opts *TarOptions) {
opts.BestEffortXattrs = v
}
}

func remapIDs(idMapping idtools.IdentityMapping, hdr *tar.Header) error {
ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
hdr.Uid, hdr.Gid = ids.UID, ids.GID
Expand Down

0 comments on commit b647e79

Please sign in to comment.