Browse Source

Fix for zero-sized layers

Moved a defer up to a better spot.

Fixed TestUntarPathWithInvalidDest to actually fail for the right reason

Closes #18170

Signed-off-by: Doug Davis <dug@us.ibm.com>
Doug Davis 9 years ago
parent
commit
7bb9fc415a

+ 2 - 2
image/tarexport/load.go

@@ -112,12 +112,12 @@ func (l *tarexporter) loadLayer(filename string, rootFS image.RootFS) (layer.Lay
 		logrus.Debugf("Error reading embedded tar: %v", err)
 		logrus.Debugf("Error reading embedded tar: %v", err)
 		return nil, err
 		return nil, err
 	}
 	}
+	defer rawTar.Close()
+
 	inflatedLayerData, err := archive.DecompressStream(rawTar)
 	inflatedLayerData, err := archive.DecompressStream(rawTar)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-
-	defer rawTar.Close()
 	defer inflatedLayerData.Close()
 	defer inflatedLayerData.Close()
 
 
 	return l.ls.Register(inflatedLayerData, rootFS.ChainID())
 	return l.ls.Register(inflatedLayerData, rootFS.ChainID())

+ 9 - 0
integration-cli/docker_cli_save_load_test.go

@@ -291,3 +291,12 @@ func (s *DockerSuite) TestSaveDirectoryPermissions(c *check.C) {
 	c.Assert(found, checker.Equals, true, check.Commentf("failed to find the layer with the right content listing"))
 	c.Assert(found, checker.Equals, true, check.Commentf("failed to find the layer with the right content listing"))
 
 
 }
 }
+
+// Test loading a weird image where one of the layers is of zero size.
+// The layer.tar file is actually zero bytes, no padding or anything else.
+// See issue: 18170
+func (s *DockerSuite) TestLoadZeroSizeLayer(c *check.C) {
+	testRequires(c, DaemonIsLinux)
+
+	dockerCmd(c, "load", "-i", "fixtures/load/emptyLayer.tar")
+}

BIN
integration-cli/fixtures/load/emptyLayer.tar


+ 7 - 1
pkg/archive/archive.go

@@ -128,7 +128,13 @@ func DecompressStream(archive io.Reader) (io.ReadCloser, error) {
 	p := pools.BufioReader32KPool
 	p := pools.BufioReader32KPool
 	buf := p.Get(archive)
 	buf := p.Get(archive)
 	bs, err := buf.Peek(10)
 	bs, err := buf.Peek(10)
-	if err != nil {
+	if err != nil && err != io.EOF {
+		// Note: we'll ignore any io.EOF error because there are some odd
+		// cases where the layer.tar file will be empty (zero bytes) and
+		// that results in an io.EOF from the Peek() call. So, in those
+		// cases we'll just treat it as a non-compressed stream and
+		// that means just create an empty layer.
+		// See Issue 18170
 		return nil, err
 		return nil, err
 	}
 	}
 
 

+ 8 - 3
pkg/archive/archive_test.go

@@ -216,11 +216,16 @@ func TestUntarPathWithInvalidDest(t *testing.T) {
 	invalidDestFolder := path.Join(tempFolder, "invalidDest")
 	invalidDestFolder := path.Join(tempFolder, "invalidDest")
 	// Create a src file
 	// Create a src file
 	srcFile := path.Join(tempFolder, "src")
 	srcFile := path.Join(tempFolder, "src")
-	_, err = os.Create(srcFile)
+	tarFile := path.Join(tempFolder, "src.tar")
+	os.Create(srcFile)
+	os.Create(invalidDestFolder) // being a file (not dir) should cause an error
+	cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
+	_, err = cmd.CombinedOutput()
 	if err != nil {
 	if err != nil {
-		t.Fatalf("Fail to create the source file")
+		t.Fatal(err)
 	}
 	}
-	err = UntarPath(srcFile, invalidDestFolder)
+
+	err = UntarPath(tarFile, invalidDestFolder)
 	if err == nil {
 	if err == nil {
 		t.Fatalf("UntarPath with invalid destination path should throw an error.")
 		t.Fatalf("UntarPath with invalid destination path should throw an error.")
 	}
 	}