Skip to content

Commit

Permalink
archive, chrootarchive: split out decompression
Browse files Browse the repository at this point in the history
In `ApplyLayer` and `Untar`, the stream is magically decompressed. Since
this is not able to be toggled, rather than break this ./pkg/ API, add
an `ApplyUncompressedLayer` and `UntarUncompressed` that does not
magically decompress the layer stream.

Signed-off-by: Vincent Batts <[email protected]>
  • Loading branch information
vbatts committed Jul 28, 2015
1 parent 77adf6a commit 56bf275
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 28 deletions.
32 changes: 25 additions & 7 deletions pkg/archive/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,20 @@ loop:
// The archive may be compressed with one of the following algorithms:
// identity (uncompressed), gzip, bzip2, xz.
// FIXME: specify behavior when target path exists vs. doesn't exist.
func Untar(archive io.Reader, dest string, options *TarOptions) error {
if archive == nil {
func Untar(tarArchive io.Reader, dest string, options *TarOptions) error {
return untarHandler(tarArchive, dest, options, true)
}

// Untar reads a stream of bytes from `archive`, parses it as a tar archive,
// and unpacks it into the directory at `dest`.
// The archive must be an uncompressed stream.
func UntarUncompressed(tarArchive io.Reader, dest string, options *TarOptions) error {
return untarHandler(tarArchive, dest, options, false)
}

// Handler for teasing out the automatic decompression
func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decompress bool) error {
if tarArchive == nil {
return fmt.Errorf("Empty archive")
}
dest = filepath.Clean(dest)
Expand All @@ -644,12 +656,18 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
if options.ExcludePatterns == nil {
options.ExcludePatterns = []string{}
}
decompressedArchive, err := DecompressStream(archive)
if err != nil {
return err

var r io.Reader = tarArchive
if decompress {
decompressedArchive, err := DecompressStream(tarArchive)
if err != nil {
return err
}
defer decompressedArchive.Close()
r = decompressedArchive
}
defer decompressedArchive.Close()
return Unpack(decompressedArchive, dest, options)

return Unpack(r, dest, options)
}

func (archiver *Archiver) TarUntar(src, dst string) error {
Expand Down
28 changes: 22 additions & 6 deletions pkg/archive/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,24 @@ func UnpackLayer(dest string, layer ArchiveReader) (size int64, err error) {
return size, nil
}

// ApplyLayer parses a diff in the standard layer format from `layer`, and
// applies it to the directory `dest`. Returns the size in bytes of the
// contents of the layer.
// ApplyLayer parses a diff in the standard layer format from `layer`,
// and applies it to the directory `dest`. The stream `layer` can be
// compressed or uncompressed.
// Returns the size in bytes of the contents of the layer.
func ApplyLayer(dest string, layer ArchiveReader) (int64, error) {
return applyLayerHandler(dest, layer, true)
}

// ApplyUncompressedLayer parses a diff in the standard layer format from
// `layer`, and applies it to the directory `dest`. The stream `layer`
// can only be uncompressed.
// Returns the size in bytes of the contents of the layer.
func ApplyUncompressedLayer(dest string, layer ArchiveReader) (int64, error) {
return applyLayerHandler(dest, layer, false)
}

// do the bulk load of ApplyLayer, but allow for not calling DecompressStream
func applyLayerHandler(dest string, layer ArchiveReader, decompress bool) (int64, error) {
dest = filepath.Clean(dest)

// We need to be able to set any perms
Expand All @@ -186,9 +200,11 @@ func ApplyLayer(dest string, layer ArchiveReader) (int64, error) {
}
defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform

layer, err = DecompressStream(layer)
if err != nil {
return 0, err
if decompress {
layer, err = DecompressStream(layer)
if err != nil {
return 0, err
}
}
return UnpackLayer(dest, layer)
}
27 changes: 22 additions & 5 deletions pkg/chrootarchive/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package chrootarchive
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"

Expand All @@ -17,6 +18,18 @@ var chrootArchiver = &archive.Archiver{Untar: Untar}
// The archive may be compressed with one of the following algorithms:
// identity (uncompressed), gzip, bzip2, xz.
func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
return untarHandler(tarArchive, dest, options, true)
}

// UntarUncompressed reads a stream of bytes from `archive`, parses it as a tar archive,
// and unpacks it into the directory at `dest`.
// The archive must be an uncompressed stream.
func UntarUncompressed(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
return untarHandler(tarArchive, dest, options, false)
}

// Handler for teasing out the automatic decompression
func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool) error {

if tarArchive == nil {
return fmt.Errorf("Empty archive")
Expand All @@ -35,13 +48,17 @@ func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error
}
}

decompressedArchive, err := archive.DecompressStream(tarArchive)
if err != nil {
return err
r := ioutil.NopCloser(tarArchive)
if decompress {
decompressedArchive, err := archive.DecompressStream(tarArchive)
if err != nil {
return err
}
defer decompressedArchive.Close()
r = decompressedArchive
}
defer decompressedArchive.Close()

return invokeUnpack(decompressedArchive, dest, options)
return invokeUnpack(r, dest, options)
}

// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
Expand Down
2 changes: 1 addition & 1 deletion pkg/chrootarchive/archive_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func untar() {
os.Exit(0)
}

func invokeUnpack(decompressedArchive io.ReadCloser, dest string, options *archive.TarOptions) error {
func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions) error {

// We can't pass a potentially large exclude list directly via cmd line
// because we easily overrun the kernel's max argument/environment size
Expand Down
34 changes: 25 additions & 9 deletions pkg/chrootarchive/diff_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,36 @@ func applyLayer() {
os.Exit(0)
}

// ApplyLayer parses a diff in the standard layer format from `layer`, and
// applies it to the directory `dest`. Returns the size in bytes of the
// contents of the layer.
// ApplyLayer parses a diff in the standard layer format from `layer`,
// and applies it to the directory `dest`. The stream `layer` can only be
// uncompressed.
// Returns the size in bytes of the contents of the layer.
func ApplyLayer(dest string, layer archive.ArchiveReader) (size int64, err error) {
return applyLayerHandler(dest, layer, true)
}

// ApplyUncompressedLayer parses a diff in the standard layer format from
// `layer`, and applies it to the directory `dest`. The stream `layer`
// can only be uncompressed.
// Returns the size in bytes of the contents of the layer.
func ApplyUncompressedLayer(dest string, layer archive.ArchiveReader) (int64, error) {
return applyLayerHandler(dest, layer, false)
}

func applyLayerHandler(dest string, layer archive.ArchiveReader, decompress bool) (size int64, err error) {
dest = filepath.Clean(dest)
decompressed, err := archive.DecompressStream(layer)
if err != nil {
return 0, err
if decompress {
decompressed, err := archive.DecompressStream(layer)
if err != nil {
return 0, err
}
defer decompressed.Close()

layer = decompressed
}

defer decompressed.Close()

cmd := reexec.Command("docker-applyLayer", dest)
cmd.Stdin = decompressed
cmd.Stdin = layer

outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer)
cmd.Stdout, cmd.Stderr = outBuf, errBuf
Expand Down

0 comments on commit 56bf275

Please sign in to comment.