Explorar o código

Fix duplicate layers in exported tar

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 41bf7de73be5d35f40aca9eb68064aa3e8bb9a54)
Tonis Tiigi %!s(int64=9) %!d(string=hai) anos
pai
achega
88cb79d400
Modificáronse 1 ficheiros con 31 adicións e 18 borrados
  1. 31 18
      image/tarexport/save.go

+ 31 - 18
image/tarexport/save.go

@@ -29,6 +29,7 @@ type saveSession struct {
 	outDir      string
 	images      map[image.ID]*imageDescriptor
 	savedLayers map[string]struct{}
+	diffIDPaths map[layer.DiffID]string // cache every diffID blob to avoid duplicates
 }
 
 func (l *tarexporter) Save(names []string, outStream io.Writer) error {
@@ -117,6 +118,7 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
 
 func (s *saveSession) save(outStream io.Writer) error {
 	s.savedLayers = make(map[string]struct{})
+	s.diffIDPaths = make(map[layer.DiffID]string)
 
 	// get image json
 	tempDir, err := ioutil.TempDir("", "docker-export-")
@@ -297,35 +299,46 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
 	}
 
 	// serialize filesystem
-	tarFile, err := os.Create(filepath.Join(outDir, legacyLayerFileName))
-	if err != nil {
-		return distribution.Descriptor{}, err
-	}
-	defer tarFile.Close()
-
+	layerPath := filepath.Join(outDir, legacyLayerFileName)
 	l, err := s.ls.Get(id)
 	if err != nil {
 		return distribution.Descriptor{}, err
 	}
 	defer layer.ReleaseAndLog(s.ls, l)
 
-	arch, err := l.TarStream()
-	if err != nil {
-		return distribution.Descriptor{}, err
-	}
-	defer arch.Close()
+	if oldPath, exists := s.diffIDPaths[l.DiffID()]; exists {
+		relPath, err := filepath.Rel(layerPath, oldPath)
+		if err != nil {
+			return distribution.Descriptor{}, err
+		}
+		os.Symlink(relPath, layerPath)
+	} else {
 
-	if _, err := io.Copy(tarFile, arch); err != nil {
-		return distribution.Descriptor{}, err
-	}
+		tarFile, err := os.Create(layerPath)
+		if err != nil {
+			return distribution.Descriptor{}, err
+		}
+		defer tarFile.Close()
 
-	for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
-		// todo: maybe save layer created timestamp?
-		if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
+		arch, err := l.TarStream()
+		if err != nil {
 			return distribution.Descriptor{}, err
 		}
-	}
+		defer arch.Close()
+
+		if _, err := io.Copy(tarFile, arch); err != nil {
+			return distribution.Descriptor{}, err
+		}
+
+		for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
+			// todo: maybe save layer created timestamp?
+			if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
+				return distribution.Descriptor{}, err
+			}
+		}
 
+		s.diffIDPaths[l.DiffID()] = layerPath
+	}
 	s.savedLayers[legacyImg.ID] = struct{}{}
 
 	var src distribution.Descriptor