@@ -25,7 +25,6 @@ import (
2525 "os"
2626 "path/filepath"
2727 "strings"
28- "time"
2928
3029 "github.com/opencontainers/image-spec/schema"
3130 "github.com/pkg/errors"
@@ -107,7 +106,7 @@ func (m *manifest) unpack(w walker, dest string) error {
107106 }
108107
109108 dd , err := filepath .Rel ("blobs" , filepath .Clean (path ))
110- if err != nil || d .Digest != dd {
109+ if err != nil || d .getDigest () != dd {
111110 return nil // ignore
112111 }
113112
@@ -134,6 +133,7 @@ func unpackLayer(dest string, r io.Reader) error {
134133 }
135134 defer gz .Close ()
136135
136+ var dirs []* tar.Header
137137 tr := tar .NewReader (gz )
138138
139139loop:
@@ -148,7 +148,22 @@ loop:
148148 return errors .Wrapf (err , "error advancing tar stream" )
149149 }
150150
151- path := filepath .Join (dest , filepath .Clean (hdr .Name ))
151+ hdr .Name = filepath .Clean (hdr .Name )
152+ // After calling filepath.Clean(hdr.Name) above, hdr.Name will now be in
153+ // the filepath format for the OS on which the daemon is running. Hence
154+ // the check for a slash-suffix MUST be done in an OS-agnostic way.
155+ if ! strings .HasSuffix (hdr .Name , string (os .PathSeparator )) {
156+ // Not the root directory, ensure that the parent directory exists
157+ parent := filepath .Dir (hdr .Name )
158+ parentPath := filepath .Join (dest , parent )
159+ if _ , err := os .Lstat (parentPath ); err != nil && os .IsNotExist (err ) {
160+ err = os .MkdirAll (parentPath , 0777 )
161+ if err != nil {
162+ return err
163+ }
164+ }
165+ }
166+ path := filepath .Join (dest , hdr .Name )
152167 info := hdr .FileInfo ()
153168
154169 if strings .HasPrefix (info .Name (), ".wh." ) {
@@ -163,8 +178,10 @@ loop:
163178
164179 switch hdr .Typeflag {
165180 case tar .TypeDir :
166- if err := os .MkdirAll (path , info .Mode ()); err != nil {
167- return errors .Wrap (err , "error creating directory" )
181+ if fi , err := os .Lstat (path ); ! (err == nil && fi .IsDir ()) {
182+ if err := os .MkdirAll (path , info .Mode ()); err != nil {
183+ return errors .Wrap (err , "error creating directory" )
184+ }
168185 }
169186
170187 case tar .TypeReg , tar .TypeRegA :
@@ -200,13 +217,19 @@ loop:
200217 if err := os .Symlink (hdr .Linkname , path ); err != nil {
201218 return err
202219 }
203-
204220 }
221+ // Directory mtimes must be handled at the end to avoid further
222+ // file creation in them to modify the directory mtime
223+ if hdr .Typeflag == tar .TypeDir {
224+ dirs = append (dirs , hdr )
225+ }
226+ }
227+ for _ , hdr := range dirs {
228+ path := filepath .Join (dest , hdr .Name )
205229
206- if err := os .Chtimes (path , time . Now (). UTC (), info .ModTime () ); err != nil {
230+ if err := os .Chtimes (path , hdr . AccessTime , hdr .ModTime ); err != nil {
207231 return errors .Wrap (err , "error changing time" )
208232 }
209233 }
210-
211234 return nil
212235}
0 commit comments