|
@@ -23,7 +23,7 @@ import (
|
|
|
|
|
|
type imageDescriptor struct {
|
|
type imageDescriptor struct {
|
|
refs []reference.NamedTagged
|
|
refs []reference.NamedTagged
|
|
- layers []string
|
|
|
|
|
|
+ layers []digest.Digest
|
|
image *image.Image
|
|
image *image.Image
|
|
layerRef layer.Layer
|
|
layerRef layer.Layer
|
|
}
|
|
}
|
|
@@ -204,18 +204,18 @@ func (s *saveSession) save(outStream io.Writer) error {
|
|
if _, ok := reposLegacy[familiarName]; !ok {
|
|
if _, ok := reposLegacy[familiarName]; !ok {
|
|
reposLegacy[familiarName] = make(map[string]string)
|
|
reposLegacy[familiarName] = make(map[string]string)
|
|
}
|
|
}
|
|
- reposLegacy[familiarName][ref.Tag()] = imageDescr.layers[len(imageDescr.layers)-1]
|
|
|
|
|
|
+ reposLegacy[familiarName][ref.Tag()] = imageDescr.layers[len(imageDescr.layers)-1].Encoded()
|
|
repoTags = append(repoTags, reference.FamiliarString(ref))
|
|
repoTags = append(repoTags, reference.FamiliarString(ref))
|
|
}
|
|
}
|
|
|
|
|
|
for _, l := range imageDescr.layers {
|
|
for _, l := range imageDescr.layers {
|
|
// IMPORTANT: We use path, not filepath here to ensure the layers
|
|
// IMPORTANT: We use path, not filepath here to ensure the layers
|
|
// in the manifest use Unix-style forward-slashes.
|
|
// in the manifest use Unix-style forward-slashes.
|
|
- layers = append(layers, path.Join(l, legacyLayerFileName))
|
|
|
|
|
|
+ layers = append(layers, path.Join("blobs", l.Algorithm().String(), l.Encoded()))
|
|
}
|
|
}
|
|
|
|
|
|
manifest = append(manifest, manifestItem{
|
|
manifest = append(manifest, manifestItem{
|
|
- Config: id.Digest().Encoded() + ".json",
|
|
|
|
|
|
+ Config: path.Join("blobs", id.Digest().Algorithm().String(), id.Digest().Encoded()),
|
|
RepoTags: repoTags,
|
|
RepoTags: repoTags,
|
|
Layers: layers,
|
|
Layers: layers,
|
|
LayerSources: foreignSrcs,
|
|
LayerSources: foreignSrcs,
|
|
@@ -285,9 +285,9 @@ func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]distribution.Desc
|
|
}
|
|
}
|
|
|
|
|
|
var parent digest.Digest
|
|
var parent digest.Digest
|
|
- var layers []string
|
|
|
|
|
|
+ var layers []digest.Digest
|
|
var foreignSrcs map[layer.DiffID]distribution.Descriptor
|
|
var foreignSrcs map[layer.DiffID]distribution.Descriptor
|
|
- for i := range img.RootFS.DiffIDs {
|
|
|
|
|
|
+ for i, diffID := range img.RootFS.DiffIDs {
|
|
v1Img := image.V1Image{
|
|
v1Img := image.V1Image{
|
|
// This is for backward compatibility used for
|
|
// This is for backward compatibility used for
|
|
// pre v1.9 docker.
|
|
// pre v1.9 docker.
|
|
@@ -313,7 +313,8 @@ func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]distribution.Desc
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
- layers = append(layers, v1Img.ID)
|
|
|
|
|
|
+
|
|
|
|
+ layers = append(layers, digest.Digest(diffID))
|
|
parent = v1ID
|
|
parent = v1ID
|
|
if src.Digest != "" {
|
|
if src.Digest != "" {
|
|
if foreignSrcs == nil {
|
|
if foreignSrcs == nil {
|
|
@@ -323,7 +324,21 @@ func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]distribution.Desc
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- configFile := filepath.Join(s.outDir, id.Digest().Encoded()+".json")
|
|
|
|
|
|
+ data := img.RawJSON()
|
|
|
|
+ dgst := digest.FromBytes(data)
|
|
|
|
+
|
|
|
|
+ blobDir := filepath.Join(s.outDir, "blobs", dgst.Algorithm().String())
|
|
|
|
+ if err := os.MkdirAll(blobDir, 0o755); err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ if err := system.Chtimes(blobDir, img.Created, img.Created); err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+ if err := system.Chtimes(filepath.Dir(blobDir), img.Created, img.Created); err != nil {
|
|
|
|
+ return nil, err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ configFile := filepath.Join(blobDir, dgst.Encoded())
|
|
if err := os.WriteFile(configFile, img.RawJSON(), 0o644); err != nil {
|
|
if err := os.WriteFile(configFile, img.RawJSON(), 0o644); err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
@@ -340,47 +355,46 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
|
|
return distribution.Descriptor{}, nil
|
|
return distribution.Descriptor{}, nil
|
|
}
|
|
}
|
|
|
|
|
|
- outDir := filepath.Join(s.outDir, legacyImg.ID)
|
|
|
|
- if err := os.Mkdir(outDir, 0755); err != nil {
|
|
|
|
- return distribution.Descriptor{}, err
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // todo: why is this version file here?
|
|
|
|
- if err := os.WriteFile(filepath.Join(outDir, legacyVersionFileName), []byte("1.0"), 0644); err != nil {
|
|
|
|
- return distribution.Descriptor{}, err
|
|
|
|
- }
|
|
|
|
|
|
+ outDir := filepath.Join(s.outDir, "blobs")
|
|
|
|
|
|
imageConfig, err := json.Marshal(legacyImg)
|
|
imageConfig, err := json.Marshal(legacyImg)
|
|
if err != nil {
|
|
if err != nil {
|
|
return distribution.Descriptor{}, err
|
|
return distribution.Descriptor{}, err
|
|
}
|
|
}
|
|
|
|
|
|
- if err := os.WriteFile(filepath.Join(outDir, legacyConfigFileName), imageConfig, 0644); err != nil {
|
|
|
|
|
|
+ cfgDgst := digest.FromBytes(imageConfig)
|
|
|
|
+ configPath := filepath.Join(outDir, cfgDgst.Algorithm().String(), cfgDgst.Encoded())
|
|
|
|
+ if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
|
|
|
|
+ return distribution.Descriptor{}, fmt.Errorf("could not create layer dir parent: %w", err)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if err := os.WriteFile(configPath, imageConfig, 0644); err != nil {
|
|
return distribution.Descriptor{}, err
|
|
return distribution.Descriptor{}, err
|
|
}
|
|
}
|
|
|
|
|
|
// serialize filesystem
|
|
// serialize filesystem
|
|
- layerPath := filepath.Join(outDir, legacyLayerFileName)
|
|
|
|
l, err := s.lss.Get(id)
|
|
l, err := s.lss.Get(id)
|
|
if err != nil {
|
|
if err != nil {
|
|
return distribution.Descriptor{}, err
|
|
return distribution.Descriptor{}, err
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ lDgst := digest.Digest(l.DiffID())
|
|
|
|
+ layerPath := filepath.Join(outDir, lDgst.Algorithm().String(), lDgst.Encoded())
|
|
defer layer.ReleaseAndLog(s.lss, l)
|
|
defer layer.ReleaseAndLog(s.lss, l)
|
|
|
|
|
|
- if oldPath, exists := s.diffIDPaths[l.DiffID()]; exists {
|
|
|
|
- relPath, err := filepath.Rel(outDir, oldPath)
|
|
|
|
- if err != nil {
|
|
|
|
|
|
+ if _, err = os.Stat(layerPath); err != nil {
|
|
|
|
+ if !os.IsNotExist(err) {
|
|
return distribution.Descriptor{}, err
|
|
return distribution.Descriptor{}, err
|
|
}
|
|
}
|
|
- if err := os.Symlink(relPath, layerPath); err != nil {
|
|
|
|
- return distribution.Descriptor{}, errors.Wrap(err, "error creating symlink while saving layer")
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
|
|
+
|
|
// We use sequential file access to avoid depleting the standby list on
|
|
// We use sequential file access to avoid depleting the standby list on
|
|
// Windows. On Linux, this equates to a regular os.Create.
|
|
// Windows. On Linux, this equates to a regular os.Create.
|
|
|
|
+ if err := os.MkdirAll(filepath.Dir(layerPath), 0755); err != nil {
|
|
|
|
+ return distribution.Descriptor{}, fmt.Errorf("could not create layer dir parent: %w", err)
|
|
|
|
+ }
|
|
tarFile, err := sequential.Create(layerPath)
|
|
tarFile, err := sequential.Create(layerPath)
|
|
if err != nil {
|
|
if err != nil {
|
|
- return distribution.Descriptor{}, err
|
|
|
|
|
|
+ return distribution.Descriptor{}, fmt.Errorf("error creating layer file: %w", err)
|
|
}
|
|
}
|
|
defer tarFile.Close()
|
|
defer tarFile.Close()
|
|
|
|
|
|
@@ -394,16 +408,16 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
|
|
return distribution.Descriptor{}, err
|
|
return distribution.Descriptor{}, err
|
|
}
|
|
}
|
|
|
|
|
|
- for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
|
|
|
|
|
|
+ for _, fname := range []string{outDir, configPath, layerPath} {
|
|
// todo: maybe save layer created timestamp?
|
|
// todo: maybe save layer created timestamp?
|
|
- if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
|
|
|
|
|
|
+ if err := system.Chtimes(fname, createdTime, createdTime); err != nil {
|
|
return distribution.Descriptor{}, err
|
|
return distribution.Descriptor{}, err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
s.diffIDPaths[l.DiffID()] = layerPath
|
|
s.diffIDPaths[l.DiffID()] = layerPath
|
|
|
|
+ s.savedLayers[legacyImg.ID] = struct{}{}
|
|
}
|
|
}
|
|
- s.savedLayers[legacyImg.ID] = struct{}{}
|
|
|
|
|
|
|
|
var src distribution.Descriptor
|
|
var src distribution.Descriptor
|
|
if fs, ok := l.(distribution.Describable); ok {
|
|
if fs, ok := l.(distribution.Describable); ok {
|