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 <vbatts@redhat.com>
| ... | ... |
@@ -633,8 +633,20 @@ loop: |
| 633 | 633 |
// The archive may be compressed with one of the following algorithms: |
| 634 | 634 |
// identity (uncompressed), gzip, bzip2, xz. |
| 635 | 635 |
// FIXME: specify behavior when target path exists vs. doesn't exist. |
| 636 |
-func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
|
| 637 |
- if archive == nil {
|
|
| 636 |
+func Untar(tarArchive io.Reader, dest string, options *TarOptions) error {
|
|
| 637 |
+ return untarHandler(tarArchive, dest, options, true) |
|
| 638 |
+} |
|
| 639 |
+ |
|
| 640 |
+// Untar reads a stream of bytes from `archive`, parses it as a tar archive, |
|
| 641 |
+// and unpacks it into the directory at `dest`. |
|
| 642 |
+// The archive must be an uncompressed stream. |
|
| 643 |
+func UntarUncompressed(tarArchive io.Reader, dest string, options *TarOptions) error {
|
|
| 644 |
+ return untarHandler(tarArchive, dest, options, false) |
|
| 645 |
+} |
|
| 646 |
+ |
|
| 647 |
+// Handler for teasing out the automatic decompression |
|
| 648 |
+func untarHandler(tarArchive io.Reader, dest string, options *TarOptions, decompress bool) error {
|
|
| 649 |
+ if tarArchive == nil {
|
|
| 638 | 650 |
return fmt.Errorf("Empty archive")
|
| 639 | 651 |
} |
| 640 | 652 |
dest = filepath.Clean(dest) |
| ... | ... |
@@ -644,12 +656,18 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error {
|
| 644 | 644 |
if options.ExcludePatterns == nil {
|
| 645 | 645 |
options.ExcludePatterns = []string{}
|
| 646 | 646 |
} |
| 647 |
- decompressedArchive, err := DecompressStream(archive) |
|
| 648 |
- if err != nil {
|
|
| 649 |
- return err |
|
| 647 |
+ |
|
| 648 |
+ var r io.Reader = tarArchive |
|
| 649 |
+ if decompress {
|
|
| 650 |
+ decompressedArchive, err := DecompressStream(tarArchive) |
|
| 651 |
+ if err != nil {
|
|
| 652 |
+ return err |
|
| 653 |
+ } |
|
| 654 |
+ defer decompressedArchive.Close() |
|
| 655 |
+ r = decompressedArchive |
|
| 650 | 656 |
} |
| 651 |
- defer decompressedArchive.Close() |
|
| 652 |
- return Unpack(decompressedArchive, dest, options) |
|
| 657 |
+ |
|
| 658 |
+ return Unpack(r, dest, options) |
|
| 653 | 659 |
} |
| 654 | 660 |
|
| 655 | 661 |
func (archiver *Archiver) TarUntar(src, dst string) error {
|
| ... | ... |
@@ -173,10 +173,24 @@ func UnpackLayer(dest string, layer ArchiveReader) (size int64, err error) {
|
| 173 | 173 |
return size, nil |
| 174 | 174 |
} |
| 175 | 175 |
|
| 176 |
-// ApplyLayer parses a diff in the standard layer format from `layer`, and |
|
| 177 |
-// applies it to the directory `dest`. Returns the size in bytes of the |
|
| 178 |
-// contents of the layer. |
|
| 176 |
+// ApplyLayer parses a diff in the standard layer format from `layer`, |
|
| 177 |
+// and applies it to the directory `dest`. The stream `layer` can be |
|
| 178 |
+// compressed or uncompressed. |
|
| 179 |
+// Returns the size in bytes of the contents of the layer. |
|
| 179 | 180 |
func ApplyLayer(dest string, layer ArchiveReader) (int64, error) {
|
| 181 |
+ return applyLayerHandler(dest, layer, true) |
|
| 182 |
+} |
|
| 183 |
+ |
|
| 184 |
+// ApplyUncompressedLayer parses a diff in the standard layer format from |
|
| 185 |
+// `layer`, and applies it to the directory `dest`. The stream `layer` |
|
| 186 |
+// can only be uncompressed. |
|
| 187 |
+// Returns the size in bytes of the contents of the layer. |
|
| 188 |
+func ApplyUncompressedLayer(dest string, layer ArchiveReader) (int64, error) {
|
|
| 189 |
+ return applyLayerHandler(dest, layer, false) |
|
| 190 |
+} |
|
| 191 |
+ |
|
| 192 |
+// do the bulk load of ApplyLayer, but allow for not calling DecompressStream |
|
| 193 |
+func applyLayerHandler(dest string, layer ArchiveReader, decompress bool) (int64, error) {
|
|
| 180 | 194 |
dest = filepath.Clean(dest) |
| 181 | 195 |
|
| 182 | 196 |
// We need to be able to set any perms |
| ... | ... |
@@ -186,9 +200,11 @@ func ApplyLayer(dest string, layer ArchiveReader) (int64, error) {
|
| 186 | 186 |
} |
| 187 | 187 |
defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform |
| 188 | 188 |
|
| 189 |
- layer, err = DecompressStream(layer) |
|
| 190 |
- if err != nil {
|
|
| 191 |
- return 0, err |
|
| 189 |
+ if decompress {
|
|
| 190 |
+ layer, err = DecompressStream(layer) |
|
| 191 |
+ if err != nil {
|
|
| 192 |
+ return 0, err |
|
| 193 |
+ } |
|
| 192 | 194 |
} |
| 193 | 195 |
return UnpackLayer(dest, layer) |
| 194 | 196 |
} |
| ... | ... |
@@ -3,6 +3,7 @@ package chrootarchive |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"io" |
| 6 |
+ "io/ioutil" |
|
| 6 | 7 |
"os" |
| 7 | 8 |
"path/filepath" |
| 8 | 9 |
|
| ... | ... |
@@ -17,6 +18,18 @@ var chrootArchiver = &archive.Archiver{Untar: Untar}
|
| 17 | 17 |
// The archive may be compressed with one of the following algorithms: |
| 18 | 18 |
// identity (uncompressed), gzip, bzip2, xz. |
| 19 | 19 |
func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
|
| 20 |
+ return untarHandler(tarArchive, dest, options, true) |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+// UntarUncompressed reads a stream of bytes from `archive`, parses it as a tar archive, |
|
| 24 |
+// and unpacks it into the directory at `dest`. |
|
| 25 |
+// The archive must be an uncompressed stream. |
|
| 26 |
+func UntarUncompressed(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
|
|
| 27 |
+ return untarHandler(tarArchive, dest, options, false) |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+// Handler for teasing out the automatic decompression |
|
| 31 |
+func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool) error {
|
|
| 20 | 32 |
|
| 21 | 33 |
if tarArchive == nil {
|
| 22 | 34 |
return fmt.Errorf("Empty archive")
|
| ... | ... |
@@ -35,13 +48,17 @@ func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error |
| 35 | 35 |
} |
| 36 | 36 |
} |
| 37 | 37 |
|
| 38 |
- decompressedArchive, err := archive.DecompressStream(tarArchive) |
|
| 39 |
- if err != nil {
|
|
| 40 |
- return err |
|
| 38 |
+ r := ioutil.NopCloser(tarArchive) |
|
| 39 |
+ if decompress {
|
|
| 40 |
+ decompressedArchive, err := archive.DecompressStream(tarArchive) |
|
| 41 |
+ if err != nil {
|
|
| 42 |
+ return err |
|
| 43 |
+ } |
|
| 44 |
+ defer decompressedArchive.Close() |
|
| 45 |
+ r = decompressedArchive |
|
| 41 | 46 |
} |
| 42 |
- defer decompressedArchive.Close() |
|
| 43 | 47 |
|
| 44 |
- return invokeUnpack(decompressedArchive, dest, options) |
|
| 48 |
+ return invokeUnpack(r, dest, options) |
|
| 45 | 49 |
} |
| 46 | 50 |
|
| 47 | 51 |
// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other. |
| ... | ... |
@@ -49,7 +49,7 @@ func untar() {
|
| 49 | 49 |
os.Exit(0) |
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
-func invokeUnpack(decompressedArchive io.ReadCloser, dest string, options *archive.TarOptions) error {
|
|
| 52 |
+func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions) error {
|
|
| 53 | 53 |
|
| 54 | 54 |
// We can't pass a potentially large exclude list directly via cmd line |
| 55 | 55 |
// because we easily overrun the kernel's max argument/environment size |
| ... | ... |
@@ -65,20 +65,36 @@ func applyLayer() {
|
| 65 | 65 |
os.Exit(0) |
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 |
-// ApplyLayer parses a diff in the standard layer format from `layer`, and |
|
| 69 |
-// applies it to the directory `dest`. Returns the size in bytes of the |
|
| 70 |
-// contents of the layer. |
|
| 68 |
+// ApplyLayer parses a diff in the standard layer format from `layer`, |
|
| 69 |
+// and applies it to the directory `dest`. The stream `layer` can only be |
|
| 70 |
+// uncompressed. |
|
| 71 |
+// Returns the size in bytes of the contents of the layer. |
|
| 71 | 72 |
func ApplyLayer(dest string, layer archive.ArchiveReader) (size int64, err error) {
|
| 73 |
+ return applyLayerHandler(dest, layer, true) |
|
| 74 |
+} |
|
| 75 |
+ |
|
| 76 |
+// ApplyUncompressedLayer parses a diff in the standard layer format from |
|
| 77 |
+// `layer`, and applies it to the directory `dest`. The stream `layer` |
|
| 78 |
+// can only be uncompressed. |
|
| 79 |
+// Returns the size in bytes of the contents of the layer. |
|
| 80 |
+func ApplyUncompressedLayer(dest string, layer archive.ArchiveReader) (int64, error) {
|
|
| 81 |
+ return applyLayerHandler(dest, layer, false) |
|
| 82 |
+} |
|
| 83 |
+ |
|
| 84 |
+func applyLayerHandler(dest string, layer archive.ArchiveReader, decompress bool) (size int64, err error) {
|
|
| 72 | 85 |
dest = filepath.Clean(dest) |
| 73 |
- decompressed, err := archive.DecompressStream(layer) |
|
| 74 |
- if err != nil {
|
|
| 75 |
- return 0, err |
|
| 86 |
+ if decompress {
|
|
| 87 |
+ decompressed, err := archive.DecompressStream(layer) |
|
| 88 |
+ if err != nil {
|
|
| 89 |
+ return 0, err |
|
| 90 |
+ } |
|
| 91 |
+ defer decompressed.Close() |
|
| 92 |
+ |
|
| 93 |
+ layer = decompressed |
|
| 76 | 94 |
} |
| 77 | 95 |
|
| 78 |
- defer decompressed.Close() |
|
| 79 |
- |
|
| 80 | 96 |
cmd := reexec.Command("docker-applyLayer", dest)
|
| 81 |
- cmd.Stdin = decompressed |
|
| 97 |
+ cmd.Stdin = layer |
|
| 82 | 98 |
|
| 83 | 99 |
outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer) |
| 84 | 100 |
cmd.Stdout, cmd.Stderr = outBuf, errBuf |