@@ -17,13 +17,15 @@ limitations under the License.
17
17
package util
18
18
19
19
import (
20
+ "archive/tar"
21
+ "bytes"
20
22
"context"
21
23
"encoding/json"
22
- "errors"
23
24
"fmt"
25
+ "io"
24
26
"io/ioutil"
25
27
"os"
26
- "path/filepath "
28
+ "strings "
27
29
28
30
"github.com/docker/docker/client"
29
31
"github.com/golang/glog"
@@ -49,56 +51,73 @@ func NewClient() (*client.Client, error) {
49
51
return cli , nil
50
52
}
51
53
52
- func getLayersFromManifest (manifestPath string ) ([]string , error ) {
54
+ func getLayersFromManifest (r io. Reader ) ([]string , error ) {
53
55
type Manifest struct {
54
56
Layers []string
55
57
}
56
58
57
- manifestJSON , err := ioutil .ReadFile ( manifestPath )
59
+ manifestJSON , err := ioutil .ReadAll ( r )
58
60
if err != nil {
59
- errMsg := fmt .Sprintf ("Could not open manifest to get layer order: %s" , err )
60
- return []string {}, errors .New (errMsg )
61
+ return nil , err
61
62
}
62
63
63
64
var imageManifest []Manifest
64
- err = json .Unmarshal (manifestJSON , & imageManifest )
65
- if err != nil {
66
- errMsg := fmt .Sprintf ("Could not unmarshal manifest to get layer order: %s" , err )
67
- return []string {}, errors .New (errMsg )
65
+ if err := json .Unmarshal (manifestJSON , & imageManifest ); err != nil {
66
+ return []string {}, fmt .Errorf ("Could not unmarshal manifest to get layer order: %s" , err )
68
67
}
69
68
return imageManifest [0 ].Layers , nil
70
69
}
71
70
72
71
func unpackDockerSave (tarPath string , target string ) error {
73
72
if _ , ok := os .Stat (target ); ok != nil {
74
- os .MkdirAll (target , 0777 )
73
+ os .MkdirAll (target , 0775 )
75
74
}
76
-
77
- tempLayerDir , err := ioutil .TempDir ("" , ".container-diff" )
75
+ f , err := os .Open (tarPath )
78
76
if err != nil {
79
77
return err
80
78
}
81
- defer os .RemoveAll (tempLayerDir )
82
79
83
- if err := UnTar (tarPath , tempLayerDir ); err != nil {
84
- errMsg := fmt .Sprintf ("Could not unpack saved Docker image %s: %s" , tarPath , err )
85
- return errors .New (errMsg )
86
- }
80
+ tr := tar .NewReader (f )
87
81
88
- manifest := filepath .Join (tempLayerDir , "manifest.json" )
89
- layers , err := getLayersFromManifest (manifest )
90
- if err != nil {
91
- return err
92
- }
82
+ // Unpack the layers into a map, since we need to sort out the order later.
83
+ var layers []string
84
+ layerMap := map [string ][]byte {}
85
+ for {
86
+ hdr , err := tr .Next ()
87
+ if err == io .EOF {
88
+ break
89
+ }
90
+ if err != nil {
91
+ return err
92
+ }
93
93
94
- for _ , layer := range layers {
95
- layerTar := filepath .Join (tempLayerDir , layer )
96
- if _ , err := os .Stat (layerTar ); err != nil {
97
- glog .Infof ("Did not unpack layer %s because no layer.tar found" , layer )
94
+ // Docker save contains files and directories. Ignore the directories.
95
+ // We care about the layers and the manifest. The layers look like:
96
+ // $SHA/layer.tar
97
+ // and they are referenced that way in the manifest.
98
+ switch t := hdr .Typeflag ; t {
99
+ case tar .TypeReg :
100
+ if hdr .Name == "manifest.json" {
101
+ layers , err = getLayersFromManifest (tr )
102
+ if err != nil {
103
+ return err
104
+ }
105
+ } else if strings .HasSuffix (hdr .Name , ".tar" ) {
106
+ layerMap [hdr .Name ], err = ioutil .ReadAll (tr )
107
+ if err != nil {
108
+ return err
109
+ }
110
+ }
111
+ case tar .TypeDir :
98
112
continue
113
+ default :
114
+ return fmt .Errorf ("unsupported file type %v found in file %s tar %s" , t , hdr .Name , tarPath )
99
115
}
100
- if err = UnTar (layerTar , target ); err != nil {
101
- glog .Errorf ("Could not unpack layer %s: %s" , layer , err )
116
+ }
117
+
118
+ for _ , layer := range layers {
119
+ if err = UnTar (bytes .NewReader (layerMap [layer ]), target ); err != nil {
120
+ return fmt .Errorf ("Could not unpack layer %s: %s" , layer , err )
102
121
}
103
122
}
104
123
return nil
0 commit comments