diff --git a/archive/archive.go b/archive/archive.go index eea8db364d..01ed298733 100644 --- a/archive/archive.go +++ b/archive/archive.go @@ -390,10 +390,18 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) // identity (uncompressed), gzip, bzip2, xz. // FIXME: specify behavior when target path exists vs. doesn't exist. func Untar(archive io.Reader, dest string, options *TarOptions) error { + if options == nil { + options = &TarOptions{} + } + if archive == nil { return fmt.Errorf("Empty archive") } + if options.Excludes == nil { + options.Excludes = []string{} + } + decompressedArchive, err := DecompressStream(archive) if err != nil { return err @@ -406,6 +414,7 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { var dirs []*tar.Header // Iterate through the files in the archive. +loop: for { hdr, err := tr.Next() if err == io.EOF { @@ -419,6 +428,12 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { // Normalize name, for safety and for a simple is-root check hdr.Name = filepath.Clean(hdr.Name) + for _, exclude := range options.Excludes { + if strings.HasPrefix(hdr.Name, exclude) { + continue loop + } + } + if !strings.HasSuffix(hdr.Name, "/") { // Not the root directory, ensure that the parent directory exists parent := filepath.Dir(hdr.Name) @@ -448,7 +463,7 @@ func Untar(archive io.Reader, dest string, options *TarOptions) error { } } trBuf.Reset(tr) - if err := createTarFile(path, dest, hdr, trBuf, options == nil || !options.NoLchown); err != nil { + if err := createTarFile(path, dest, hdr, trBuf, !options.NoLchown); err != nil { return err } diff --git a/archive/archive_test.go b/archive/archive_test.go index 6afe298317..b46f953228 100644 --- a/archive/archive_test.go +++ b/archive/archive_test.go @@ -109,6 +109,9 @@ func TestTarUntar(t *testing.T) { if err := ioutil.WriteFile(path.Join(origin, "2"), []byte("welcome!"), 0700); err != nil { t.Fatal(err) } + if err := ioutil.WriteFile(path.Join(origin, "3"), []byte("will be ignored"), 0700); err != nil { + t.Fatal(err) + } for _, c := range []Compression{ Uncompressed, @@ -116,13 +119,14 @@ func TestTarUntar(t *testing.T) { } { changes, err := tarUntar(t, origin, &TarOptions{ Compression: c, + Excludes: []string{"3"}, }) if err != nil { t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err) } - if len(changes) != 0 { + if len(changes) != 1 || changes[0].Path != "/3" { t.Fatalf("Unexpected differences after tarUntar: %v", changes) } } diff --git a/graph/load.go b/graph/load.go index 5d84b82c28..b34c83a65a 100644 --- a/graph/load.go +++ b/graph/load.go @@ -43,7 +43,17 @@ func (s *TagStore) CmdLoad(job *engine.Job) engine.Status { if err := os.Mkdir(repoDir, os.ModeDir); err != nil { return job.Error(err) } - if err := archive.Untar(repoFile, repoDir, nil); err != nil { + images, err := s.graph.Map() + if err != nil { + return job.Error(err) + } + excludes := make([]string, len(images)) + i := 0 + for k := range images { + excludes[i] = k + i++ + } + if err := archive.Untar(repoFile, repoDir, &archive.TarOptions{Excludes: excludes}); err != nil { return job.Error(err) }