Bump github.com/containers/image/v5 from 5.15.2 to 5.16.0

Bumps [github.com/containers/image/v5](https://github.com/containers/image) from 5.15.2 to 5.16.0.
- [Release notes](https://github.com/containers/image/releases)
- [Commits](https://github.com/containers/image/compare/v5.15.2...v5.16.0)

---
updated-dependencies:
- dependency-name: github.com/containers/image/v5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2021-08-26 08:30:41 +00:00
committed by GitHub
parent 4fda005a3e
commit a2d083ca84
121 changed files with 4919 additions and 3811 deletions

View File

@@ -1 +1 @@
1.34.1
1.35.0

View File

@@ -16,7 +16,7 @@ require (
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible
github.com/moby/sys/mountinfo v0.4.1
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/runc v1.0.1
github.com/opencontainers/runc v1.0.2
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
github.com/opencontainers/selinux v1.8.4
github.com/pkg/errors v0.9.1
@@ -25,8 +25,8 @@ require (
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
github.com/tchap/go-patricia v2.3.0+incompatible
github.com/ulikunitz/xz v0.5.10
github.com/vbatts/tar-split v0.11.1
github.com/vbatts/tar-split v0.11.2
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55
gotest.tools v2.2.0+incompatible
)

View File

@@ -469,8 +469,8 @@ github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59P
github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
github.com/opencontainers/runc v1.0.1 h1:G18PGckGdAm3yVQRWDVQ1rLSLntiniKJ0cNRT2Tm5gs=
github.com/opencontainers/runc v1.0.1/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runc v1.0.2 h1:opHZMaswlyxz1OuGpBE53Dwe4/xF7EZTY0A2L/FpCOg=
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@@ -585,8 +585,9 @@ github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbatts/tar-split v0.11.1 h1:0Odu65rhcZ3JZaPHxl7tCI3V/C/Q9Zf82UFravl02dE=
github.com/vbatts/tar-split v0.11.1/go.mod h1:LEuURwDEiWjRjwu46yU3KVGuUdVv/dcnpcEPSzR8z6g=
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlIME=
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
@@ -770,8 +771,9 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 h1:rw6UNGRMfarCepjI8qOepea/SXwIBVfTKjztZ5gBbq4=
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@@ -803,7 +803,7 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab
r.driver.Remove(id)
return nil, -1, err
}
size, err = r.ApplyDiff(layer.ID, diff)
size, err = r.applyDiffWithOptions(layer.ID, moreOptions, diff)
if err != nil {
if r.Delete(layer.ID) != nil {
// Either a driver error or an error saving.
@@ -1505,6 +1505,10 @@ func (r *layerStore) DiffSize(from, to string) (size int64, err error) {
}
func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error) {
return r.applyDiffWithOptions(to, nil, diff)
}
func (r *layerStore) applyDiffWithOptions(to string, layerOptions *LayerOptions, diff io.Reader) (size int64, err error) {
if !r.IsReadWrite() {
return -1, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to modify layer contents at %q", r.layerspath())
}
@@ -1519,11 +1523,33 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
if err != nil && err != io.EOF {
return -1, err
}
compression := archive.DetectCompression(header[:n])
compressedDigest := digest.Canonical.Digester()
compressedCounter := ioutils.NewWriteCounter(compressedDigest.Hash())
defragmented := io.TeeReader(io.MultiReader(bytes.NewBuffer(header[:n]), diff), compressedCounter)
defragmented := io.MultiReader(bytes.NewBuffer(header[:n]), diff)
// Decide if we need to compute digests
var compressedDigest, uncompressedDigest digest.Digest // = ""
var compressedDigester, uncompressedDigester digest.Digester // = nil
if layerOptions != nil && layerOptions.OriginalDigest != "" &&
layerOptions.OriginalDigest.Algorithm() == digest.Canonical {
compressedDigest = layerOptions.OriginalDigest
} else {
compressedDigester = digest.Canonical.Digester()
}
if layerOptions != nil && layerOptions.UncompressedDigest != "" &&
layerOptions.UncompressedDigest.Algorithm() == digest.Canonical {
uncompressedDigest = layerOptions.UncompressedDigest
} else {
uncompressedDigester = digest.Canonical.Digester()
}
var compressedWriter io.Writer
if compressedDigester != nil {
compressedWriter = compressedDigester.Hash()
} else {
compressedWriter = ioutil.Discard
}
compressedCounter := ioutils.NewWriteCounter(compressedWriter)
defragmented = io.TeeReader(defragmented, compressedCounter)
tsdata := bytes.Buffer{}
compressor, err := pgzip.NewWriterLevel(&tsdata, pgzip.BestSpeed)
@@ -1539,8 +1565,6 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
return -1, err
}
defer uncompressed.Close()
uncompressedDigest := digest.Canonical.Digester()
uncompressedCounter := ioutils.NewWriteCounter(uncompressedDigest.Hash())
uidLog := make(map[uint32]struct{})
gidLog := make(map[uint32]struct{})
idLogger, err := tarlog.NewLogger(func(h *tar.Header) {
@@ -1553,7 +1577,12 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
return -1, err
}
defer idLogger.Close()
payload, err := asm.NewInputTarStream(io.TeeReader(uncompressed, io.MultiWriter(uncompressedCounter, idLogger)), metadata, storage.NewDiscardFilePutter())
uncompressedCounter := ioutils.NewWriteCounter(idLogger)
uncompressedWriter := (io.Writer)(uncompressedCounter)
if uncompressedDigester != nil {
uncompressedWriter = io.MultiWriter(uncompressedWriter, uncompressedDigester.Hash())
}
payload, err := asm.NewInputTarStream(io.TeeReader(uncompressed, uncompressedWriter), metadata, storage.NewDiscardFilePutter())
if err != nil {
return -1, err
}
@@ -1575,6 +1604,12 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
return -1, err
}
}
if compressedDigester != nil {
compressedDigest = compressedDigester.Digest()
}
if uncompressedDigester != nil {
uncompressedDigest = uncompressedDigester.Digest()
}
updateDigestMap := func(m *map[digest.Digest][]string, oldvalue, newvalue digest.Digest, id string) {
var newList []string
@@ -1594,11 +1629,11 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
(*m)[newvalue] = append((*m)[newvalue], id)
}
}
updateDigestMap(&r.bycompressedsum, layer.CompressedDigest, compressedDigest.Digest(), layer.ID)
layer.CompressedDigest = compressedDigest.Digest()
updateDigestMap(&r.bycompressedsum, layer.CompressedDigest, compressedDigest, layer.ID)
layer.CompressedDigest = compressedDigest
layer.CompressedSize = compressedCounter.Count
updateDigestMap(&r.byuncompressedsum, layer.UncompressedDigest, uncompressedDigest.Digest(), layer.ID)
layer.UncompressedDigest = uncompressedDigest.Digest()
updateDigestMap(&r.byuncompressedsum, layer.UncompressedDigest, uncompressedDigest, layer.ID)
layer.UncompressedDigest = uncompressedDigest
layer.UncompressedSize = uncompressedCounter.Count
layer.CompressionType = compression
layer.UIDs = make([]uint32, 0, len(uidLog))

View File

@@ -32,7 +32,7 @@ import (
const (
maxNumberMissingChunks = 1024
newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_WRONLY | unix.O_EXCL)
newFileFlags = (unix.O_CREAT | unix.O_TRUNC | unix.O_EXCL | unix.O_WRONLY)
containersOverrideXattr = "user.containers.override_stat"
bigDataKey = "zstd-chunked-manifest"
)
@@ -54,7 +54,8 @@ func timeToTimespec(time time.Time) (ts unix.Timespec) {
return unix.NsecToTimespec(time.UnixNano())
}
func copyFileContent(src, destFile, root string, dirfd int, missingDirsMode, mode os.FileMode) (*os.File, int64, error) {
func copyFileContent(srcFd int, destFile string, dirfd int, mode os.FileMode, useHardLinks bool) (*os.File, int64, error) {
src := fmt.Sprintf("/proc/self/fd/%d", srcFd)
st, err := os.Stat(src)
if err != nil {
return nil, -1, err
@@ -62,8 +63,32 @@ func copyFileContent(src, destFile, root string, dirfd int, missingDirsMode, mod
copyWithFileRange, copyWithFileClone := true, true
if useHardLinks {
destDirPath := filepath.Dir(destFile)
destBase := filepath.Base(destFile)
destDir, err := openFileUnderRoot(destDirPath, dirfd, 0, mode)
if err == nil {
defer destDir.Close()
doLink := func() error {
return unix.Linkat(srcFd, "", int(destDir.Fd()), destBase, unix.AT_EMPTY_PATH)
}
err := doLink()
// if the destination exists, unlink it first and try again
if err != nil && os.IsExist(err) {
unix.Unlinkat(int(destDir.Fd()), destBase, 0)
err = doLink()
}
if err == nil {
return nil, st.Size(), nil
}
}
}
// If the destination file already exists, we shouldn't blow it away
dstFile, err := openFileUnderRoot(destFile, root, dirfd, newFileFlags, mode)
dstFile, err := openFileUnderRoot(destFile, dirfd, newFileFlags, mode)
if err != nil {
return nil, -1, err
}
@@ -148,7 +173,39 @@ func makeZstdChunkedDiffer(ctx context.Context, store storage.Store, blobSize in
}, nil
}
func findFileInOtherLayers(file internal.ZstdFileMetadata, root string, dirfd int, layersMetadata map[string]map[string]*internal.ZstdFileMetadata, layersTarget map[string]string, missingDirsMode os.FileMode) (*os.File, int64, error) {
// copyFileFromOtherLayer copies a file from another layer
// file is the file to look for.
// source is the path to the source layer checkout.
// otherFile contains the metadata for the file.
// dirfd is an open file descriptor to the destination root directory.
// useHardLinks defines whether the deduplication can be performed using hard links.
func copyFileFromOtherLayer(file internal.ZstdFileMetadata, source string, otherFile *internal.ZstdFileMetadata, dirfd int, useHardLinks bool) (bool, *os.File, int64, error) {
srcDirfd, err := unix.Open(source, unix.O_RDONLY, 0)
if err != nil {
return false, nil, 0, err
}
defer unix.Close(srcDirfd)
srcFile, err := openFileUnderRoot(otherFile.Name, srcDirfd, unix.O_RDONLY, 0)
if err != nil {
return false, nil, 0, err
}
defer srcFile.Close()
dstFile, written, err := copyFileContent(int(srcFile.Fd()), file.Name, dirfd, 0, useHardLinks)
if err != nil {
return false, nil, 0, err
}
return true, dstFile, written, err
}
// findFileInOtherLayers finds the specified file in other layers.
// file is the file to look for.
// dirfd is an open file descriptor to the checkout root directory.
// layersMetadata contains the metadata for each layer in the storage.
// layersTarget maps each layer to its checkout on disk.
// useHardLinks defines whether the deduplication can be performed using hard links.
func findFileInOtherLayers(file internal.ZstdFileMetadata, dirfd int, layersMetadata map[string]map[string]*internal.ZstdFileMetadata, layersTarget map[string]string, useHardLinks bool) (bool, *os.File, int64, error) {
// this is ugly, needs to be indexed
for layerID, checksums := range layersMetadata {
m, found := checksums[file.Digest]
@@ -161,27 +218,12 @@ func findFileInOtherLayers(file internal.ZstdFileMetadata, root string, dirfd in
continue
}
srcDirfd, err := unix.Open(source, unix.O_RDONLY, 0)
if err != nil {
continue
found, dstFile, written, err := copyFileFromOtherLayer(file, source, m, dirfd, useHardLinks)
if found && err == nil {
return found, dstFile, written, err
}
defer unix.Close(srcDirfd)
srcFile, err := openFileUnderRoot(m.Name, source, srcDirfd, unix.O_RDONLY, 0)
if err != nil {
continue
}
defer srcFile.Close()
srcPath := fmt.Sprintf("/proc/self/fd/%d", srcFile.Fd())
dstFile, written, err := copyFileContent(srcPath, file.Name, root, dirfd, missingDirsMode, 0)
if err != nil {
continue
}
return dstFile, written, nil
}
return nil, 0, nil
return false, nil, 0, nil
}
func getFileDigest(f *os.File) (digest.Digest, error) {
@@ -195,25 +237,28 @@ func getFileDigest(f *os.File) (digest.Digest, error) {
// findFileOnTheHost checks whether the requested file already exist on the host and copies the file content from there if possible.
// It is currently implemented to look only at the file with the same path. Ideally it can detect the same content also at different
// paths.
func findFileOnTheHost(file internal.ZstdFileMetadata, root string, dirfd int, missingDirsMode os.FileMode) (*os.File, int64, error) {
// file is the file to look for.
// dirfd is an open fd to the destination checkout.
// useHardLinks defines whether the deduplication can be performed using hard links.
func findFileOnTheHost(file internal.ZstdFileMetadata, dirfd int, useHardLinks bool) (bool, *os.File, int64, error) {
sourceFile := filepath.Clean(filepath.Join("/", file.Name))
if !strings.HasPrefix(sourceFile, "/usr/") {
// limit host deduplication to files under /usr.
return nil, 0, nil
return false, nil, 0, nil
}
st, err := os.Stat(sourceFile)
if err != nil || !st.Mode().IsRegular() {
return nil, 0, nil
return false, nil, 0, nil
}
if st.Size() != file.Size {
return nil, 0, nil
return false, nil, 0, nil
}
fd, err := unix.Open(sourceFile, unix.O_RDONLY|unix.O_NONBLOCK, 0)
if err != nil {
return nil, 0, nil
return false, nil, 0, nil
}
f := os.NewFile(uintptr(fd), "fd")
@@ -221,35 +266,38 @@ func findFileOnTheHost(file internal.ZstdFileMetadata, root string, dirfd int, m
manifestChecksum, err := digest.Parse(file.Digest)
if err != nil {
return nil, 0, err
return false, nil, 0, err
}
checksum, err := getFileDigest(f)
if err != nil {
return nil, 0, err
return false, nil, 0, err
}
if checksum != manifestChecksum {
return nil, 0, nil
return false, nil, 0, nil
}
dstFile, written, err := copyFileContent(fmt.Sprintf("/proc/self/fd/%d", fd), file.Name, root, dirfd, missingDirsMode, 0)
dstFile, written, err := copyFileContent(fd, file.Name, dirfd, 0, useHardLinks)
if err != nil {
return nil, 0, nil
return false, nil, 0, nil
}
// calculate the checksum again to make sure the file wasn't modified while it was copied
if _, err := f.Seek(0, 0); err != nil {
return nil, 0, err
dstFile.Close()
return false, nil, 0, err
}
checksum, err = getFileDigest(f)
if err != nil {
return nil, 0, err
dstFile.Close()
return false, nil, 0, err
}
if checksum != manifestChecksum {
return nil, 0, nil
dstFile.Close()
return false, nil, 0, nil
}
return dstFile, written, nil
return true, dstFile, written, nil
}
func maybeDoIDRemap(manifest []internal.ZstdFileMetadata, options *archive.TarOptions) error {
@@ -292,6 +340,7 @@ type missingChunk struct {
Files []missingFile
}
// setFileAttrs sets the file attributes for file given metadata
func setFileAttrs(file *os.File, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
if file == nil || file.Fd() < 0 {
return errors.Errorf("invalid file")
@@ -333,7 +382,12 @@ func setFileAttrs(file *os.File, mode os.FileMode, metadata *internal.ZstdFileMe
return nil
}
func openFileUnderRoot(name, root string, dirfd int, flags uint64, mode os.FileMode) (*os.File, error) {
// openFileUnderRoot safely opens a file under the specified root directory using openat2
// name is the path to open relative to dirfd.
// dirfd is an open file descriptor to the target checkout directory.
// flags are the flags top pass to the open syscall.
// mode specifies the mode to use for newly created files.
func openFileUnderRoot(name string, dirfd int, flags uint64, mode os.FileMode) (*os.File, error) {
how := unix.OpenHow{
Flags: flags,
Mode: uint64(mode & 07777),
@@ -347,8 +401,8 @@ func openFileUnderRoot(name, root string, dirfd int, flags uint64, mode os.FileM
return os.NewFile(uintptr(fd), name), nil
}
func createFileFromZstdStream(dest string, dirfd int, reader io.Reader, missingDirsMode, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) (err error) {
file, err := openFileUnderRoot(metadata.Name, dest, dirfd, newFileFlags, 0)
func createFileFromZstdStream(dest string, dirfd int, reader io.Reader, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) (err error) {
file, err := openFileUnderRoot(metadata.Name, dirfd, newFileFlags, 0)
if err != nil {
return err
}
@@ -381,7 +435,7 @@ func createFileFromZstdStream(dest string, dirfd int, reader io.Reader, missingD
return setFileAttrs(file, mode, metadata, options)
}
func storeMissingFiles(streams chan io.ReadCloser, errs chan error, dest string, dirfd int, missingChunks []missingChunk, missingDirsMode os.FileMode, options *archive.TarOptions) error {
func storeMissingFiles(streams chan io.ReadCloser, errs chan error, dest string, dirfd int, missingChunks []missingChunk, options *archive.TarOptions) error {
for mc := 0; ; mc++ {
var part io.ReadCloser
select {
@@ -412,7 +466,7 @@ func storeMissingFiles(streams chan io.ReadCloser, errs chan error, dest string,
limitReader := io.LimitReader(part, mf.Length())
if err := createFileFromZstdStream(dest, dirfd, limitReader, missingDirsMode, os.FileMode(mf.File.Mode), mf.File, options); err != nil {
if err := createFileFromZstdStream(dest, dirfd, limitReader, os.FileMode(mf.File.Mode), mf.File, options); err != nil {
part.Close()
return err
}
@@ -462,7 +516,7 @@ func mergeMissingChunks(missingChunks []missingChunk, target int) []missingChunk
return newMissingChunks
}
func retrieveMissingFiles(input *chunkedZstdDiffer, dest string, dirfd int, missingChunks []missingChunk, missingDirsMode os.FileMode, options *archive.TarOptions) error {
func retrieveMissingFiles(input *chunkedZstdDiffer, dest string, dirfd int, missingChunks []missingChunk, options *archive.TarOptions) error {
var chunksToRequest []ImageSourceChunk
for _, c := range missingChunks {
chunksToRequest = append(chunksToRequest, c.RawChunk)
@@ -492,19 +546,19 @@ func retrieveMissingFiles(input *chunkedZstdDiffer, dest string, dirfd int, miss
return err
}
if err := storeMissingFiles(streams, errs, dest, dirfd, missingChunks, missingDirsMode, options); err != nil {
if err := storeMissingFiles(streams, errs, dest, dirfd, missingChunks, options); err != nil {
return err
}
return nil
}
func safeMkdir(target string, dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
func safeMkdir(dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
parent := filepath.Dir(metadata.Name)
base := filepath.Base(metadata.Name)
parentFd := dirfd
if parent != "." {
parentFile, err := openFileUnderRoot(parent, target, dirfd, unix.O_DIRECTORY|unix.O_PATH|unix.O_RDONLY, 0)
parentFile, err := openFileUnderRoot(parent, dirfd, unix.O_DIRECTORY|unix.O_PATH|unix.O_RDONLY, 0)
if err != nil {
return err
}
@@ -518,7 +572,7 @@ func safeMkdir(target string, dirfd int, mode os.FileMode, metadata *internal.Zs
}
}
file, err := openFileUnderRoot(metadata.Name, target, dirfd, unix.O_RDONLY, 0)
file, err := openFileUnderRoot(metadata.Name, dirfd, unix.O_RDONLY, 0)
if err != nil {
return err
}
@@ -527,8 +581,8 @@ func safeMkdir(target string, dirfd int, mode os.FileMode, metadata *internal.Zs
return setFileAttrs(file, mode, metadata, options)
}
func safeLink(target string, dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
sourceFile, err := openFileUnderRoot(metadata.Linkname, target, dirfd, unix.O_RDONLY, 0)
func safeLink(dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
sourceFile, err := openFileUnderRoot(metadata.Linkname, dirfd, unix.O_RDONLY, 0)
if err != nil {
return err
}
@@ -537,7 +591,7 @@ func safeLink(target string, dirfd int, mode os.FileMode, metadata *internal.Zst
destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name)
destDirFd := dirfd
if destDir != "." {
f, err := openFileUnderRoot(destDir, target, dirfd, unix.O_RDONLY, 0)
f, err := openFileUnderRoot(destDir, dirfd, unix.O_RDONLY, 0)
if err != nil {
return err
}
@@ -550,7 +604,7 @@ func safeLink(target string, dirfd int, mode os.FileMode, metadata *internal.Zst
return err
}
newFile, err := openFileUnderRoot(metadata.Name, target, dirfd, unix.O_WRONLY, 0)
newFile, err := openFileUnderRoot(metadata.Name, dirfd, unix.O_WRONLY, 0)
if err != nil {
return err
}
@@ -559,11 +613,11 @@ func safeLink(target string, dirfd int, mode os.FileMode, metadata *internal.Zst
return setFileAttrs(newFile, mode, metadata, options)
}
func safeSymlink(target string, dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
func safeSymlink(dirfd int, mode os.FileMode, metadata *internal.ZstdFileMetadata, options *archive.TarOptions) error {
destDir, destBase := filepath.Dir(metadata.Name), filepath.Base(metadata.Name)
destDirFd := dirfd
if destDir != "." {
f, err := openFileUnderRoot(destDir, target, dirfd, unix.O_RDONLY, 0)
f, err := openFileUnderRoot(destDir, dirfd, unix.O_RDONLY, 0)
if err != nil {
return err
}
@@ -580,7 +634,7 @@ type whiteoutHandler struct {
}
func (d whiteoutHandler) Setxattr(path, name string, value []byte) error {
file, err := openFileUnderRoot(path, d.Root, d.Dirfd, unix.O_RDONLY, 0)
file, err := openFileUnderRoot(path, d.Dirfd, unix.O_RDONLY, 0)
if err != nil {
return err
}
@@ -595,7 +649,7 @@ func (d whiteoutHandler) Mknod(path string, mode uint32, dev int) error {
dirfd := d.Dirfd
if dir != "" {
dir, err := openFileUnderRoot(dir, d.Root, d.Dirfd, unix.O_RDONLY, 0)
dir, err := openFileUnderRoot(dir, d.Dirfd, unix.O_RDONLY, 0)
if err != nil {
return err
}
@@ -615,7 +669,7 @@ func checkChownErr(err error, name string, uid, gid int) error {
}
func (d whiteoutHandler) Chown(path string, uid, gid int) error {
file, err := openFileUnderRoot(path, d.Root, d.Dirfd, unix.O_PATH, 0)
file, err := openFileUnderRoot(path, d.Dirfd, unix.O_PATH, 0)
if err != nil {
return err
}
@@ -640,6 +694,13 @@ type hardLinkToCreate struct {
metadata *internal.ZstdFileMetadata
}
func parseBooleanPullOption(storeOpts *storage.StoreOptions, name string, def bool) bool {
if value, ok := storeOpts.PullOptions[name]; ok {
return strings.ToLower(value) == "true"
}
return def
}
func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions) (graphdriver.DriverWithDifferOutput, error) {
bigData := map[string][]byte{
bigDataKey: d.manifest,
@@ -654,11 +715,16 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
return output, err
}
enableHostDedup := false
if value := storeOpts.PullOptions["enable_host_deduplication"]; strings.ToLower(value) == "true" {
enableHostDedup = true
if !parseBooleanPullOption(&storeOpts, "enable_partial_images", false) {
return output, errors.New("enable_partial_images not configured")
}
enableHostDedup := parseBooleanPullOption(&storeOpts, "enable_host_deduplication", false)
// When the hard links deduplication is used, file attributes are ignored because setting them
// modifies the source file as well.
useHardLinks := parseBooleanPullOption(&storeOpts, "use_hard_links", false)
// Generate the manifest
var toc internal.ZstdTOC
if err := json.Unmarshal(d.manifest, &toc); err != nil {
@@ -704,11 +770,6 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
otherLayersCache := prepareOtherLayersCache(d.layersMetadata)
missingDirsMode := os.FileMode(0700)
if options.ForceMask != nil {
missingDirsMode = *options.ForceMask
}
// hardlinks can point to missing files. So create them after all files
// are retrieved
var hardLinks []hardLinkToCreate
@@ -758,7 +819,7 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
if r.Size == 0 {
// Used to have a scope for cleanup.
createEmptyFile := func() error {
file, err := openFileUnderRoot(r.Name, dest, dirfd, newFileFlags, 0)
file, err := openFileUnderRoot(r.Name, dirfd, newFileFlags, 0)
if err != nil {
return err
}
@@ -775,7 +836,7 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
}
case tar.TypeDir:
if err := safeMkdir(dest, dirfd, mode, &r, options); err != nil {
if err := safeMkdir(dirfd, mode, &r, options); err != nil {
return output, err
}
continue
@@ -794,7 +855,7 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
continue
case tar.TypeSymlink:
if err := safeSymlink(dest, dirfd, mode, &r, options); err != nil {
if err := safeSymlink(dirfd, mode, &r, options); err != nil {
return output, err
}
continue
@@ -809,7 +870,7 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
totalChunksSize += r.Size
dstFile, _, err := findFileInOtherLayers(r, dest, dirfd, otherLayersCache, d.layersTarget, missingDirsMode)
found, dstFile, _, err := findFileInOtherLayers(r, dirfd, otherLayersCache, d.layersTarget, useHardLinks)
if err != nil {
return output, err
}
@@ -819,11 +880,13 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
return output, err
}
dstFile.Close()
}
if found {
continue
}
if enableHostDedup {
dstFile, _, err = findFileOnTheHost(r, dest, dirfd, missingDirsMode)
found, dstFile, _, err = findFileOnTheHost(r, dirfd, useHardLinks)
if err != nil {
return output, err
}
@@ -833,6 +896,8 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
return output, err
}
dstFile.Close()
}
if found {
continue
}
}
@@ -857,13 +922,13 @@ func (d *chunkedZstdDiffer) ApplyDiff(dest string, options *archive.TarOptions)
// There are some missing files. Prepare a multirange request for the missing chunks.
if len(missingChunks) > 0 {
missingChunks = mergeMissingChunks(missingChunks, maxNumberMissingChunks)
if err := retrieveMissingFiles(d, dest, dirfd, missingChunks, missingDirsMode, options); err != nil {
if err := retrieveMissingFiles(d, dest, dirfd, missingChunks, options); err != nil {
return output, err
}
}
for _, m := range hardLinks {
if err := safeLink(m.dest, m.dirfd, m.mode, m.metadata, options); err != nil {
if err := safeLink(m.dirfd, m.mode, m.metadata, options); err != nil {
return output, err
}
}

View File

@@ -17,8 +17,25 @@ func (r *readCloserWrapper) Close() error {
return r.closer()
}
type readWriteToCloserWrapper struct {
io.Reader
io.WriterTo
closer func() error
}
func (r *readWriteToCloserWrapper) Close() error {
return r.closer()
}
// NewReadCloserWrapper returns a new io.ReadCloser.
func NewReadCloserWrapper(r io.Reader, closer func() error) io.ReadCloser {
if wt, ok := r.(io.WriterTo); ok {
return &readWriteToCloserWrapper{
Reader: r,
WriterTo: wt,
closer: closer,
}
}
return &readCloserWrapper{
Reader: r,
closer: closer,

View File

@@ -547,6 +547,15 @@ type LayerOptions struct {
// initialize this layer. If set, it should be a child of the layer
// which we want to use as the parent of the new layer.
TemplateLayer string
// OriginalDigest specifies a digest of the tarstream (diff), if one is
// provided along with these LayerOptions, and reliably known by the caller.
// Use the default "" if this fields is not applicable or the value is not known.
OriginalDigest digest.Digest
// UncompressedDigest specifies a digest of the uncompressed version (“DiffID”)
// of the tarstream (diff), if one is provided along with these LayerOptions,
// and reliably known by the caller.
// Use the default "" if this fields is not applicable or the value is not known.
UncompressedDigest digest.Digest
}
// ImageOptions is used for passing options to a Store's CreateImage() method.
@@ -1031,20 +1040,21 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
gidMap = s.gidMap
}
}
var layerOptions *LayerOptions
layerOptions := LayerOptions{
OriginalDigest: options.OriginalDigest,
UncompressedDigest: options.UncompressedDigest,
}
if s.canUseShifting(uidMap, gidMap) {
layerOptions = &LayerOptions{IDMappingOptions: types.IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}}
layerOptions.IDMappingOptions = types.IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}
} else {
layerOptions = &LayerOptions{
IDMappingOptions: types.IDMappingOptions{
HostUIDMapping: options.HostUIDMapping,
HostGIDMapping: options.HostGIDMapping,
UIDMap: copyIDMap(uidMap),
GIDMap: copyIDMap(gidMap),
},
layerOptions.IDMappingOptions = types.IDMappingOptions{
HostUIDMapping: options.HostUIDMapping,
HostGIDMapping: options.HostGIDMapping,
UIDMap: copyIDMap(uidMap),
GIDMap: copyIDMap(gidMap),
}
}
return rlstore.Put(id, parentLayer, names, mountLabel, nil, layerOptions, writeable, nil, diff)
return rlstore.Put(id, parentLayer, names, mountLabel, nil, &layerOptions, writeable, nil, diff)
}
func (s *store) CreateLayer(id, parent string, names []string, mountLabel string, writeable bool, options *LayerOptions) (*Layer, error) {