diff --git a/container.go b/container.go index c272a34621..a9dafa9e83 100644 --- a/container.go +++ b/container.go @@ -1382,7 +1382,8 @@ func (container *Container) ExportRw() (archive.Archive, error) { if container.runtime == nil { return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID) } - return container.runtime.driver.Diff(container.ID) + + return container.runtime.Diff(container) } func (container *Container) Export() (archive.Archive, error) { diff --git a/devmapper/driver.go b/devmapper/driver.go index e095b33be5..c23f5288f2 100644 --- a/devmapper/driver.go +++ b/devmapper/driver.go @@ -2,7 +2,6 @@ package devmapper import ( "fmt" - "github.com/dotcloud/docker/archive" "github.com/dotcloud/docker/graphdriver" "os" "path" @@ -57,10 +56,6 @@ func (d *Driver) Get(id string) (string, error) { return mp, nil } -func (d *Driver) Diff(id string) (archive.Archive, error) { - return nil, fmt.Errorf("Not implemented") -} - func (d *Driver) DiffSize(id string) (int64, error) { return -1, fmt.Errorf("Not implemented") } diff --git a/graphdriver/driver.go b/graphdriver/driver.go index 4bb129dfb2..e96f6bfa5e 100644 --- a/graphdriver/driver.go +++ b/graphdriver/driver.go @@ -16,7 +16,6 @@ type Driver interface { Get(id string) (dir string, err error) - Diff(id string) (archive.Archive, error) DiffSize(id string) (bytes int64, err error) Cleanup() error @@ -26,6 +25,10 @@ type Changer interface { Changes(id string) ([]archive.Change, error) } +type Differ interface { + Diff(id string) (archive.Archive, error) +} + var ( // All registred drivers drivers map[string]InitFunc diff --git a/graphdriver/dummy/driver.go b/graphdriver/dummy/driver.go index 41a3e62a1f..eb05aacb5d 100644 --- a/graphdriver/dummy/driver.go +++ b/graphdriver/dummy/driver.go @@ -73,14 +73,6 @@ func (d *Driver) Get(id string) (string, error) { return dir, nil } -func (d *Driver) Diff(id string) (archive.Archive, error) { - p, err := d.Get(id) - if err != nil { - return nil, err - } - return archive.Tar(p, archive.Uncompressed) -} - func (d *Driver) DiffSize(id string) (int64, error) { return -1, fmt.Errorf("Not implemented") } diff --git a/runtime.go b/runtime.go index bda59afce5..d8ec2a90d4 100644 --- a/runtime.go +++ b/runtime.go @@ -18,6 +18,7 @@ import ( "os" "os/exec" "path" + "path/filepath" "sort" "strings" "time" @@ -747,6 +748,37 @@ func (runtime *Runtime) Changes(container *Container) ([]archive.Change, error) return archive.ChangesDirs(cDir, initDir) } +func (runtime *Runtime) Diff(container *Container) (archive.Archive, error) { + if differ, ok := runtime.driver.(graphdriver.Differ); ok { + return differ.Diff(container.ID) + } + + changes, err := runtime.Changes(container) + if err != nil { + return nil, err + } + + cDir, err := runtime.driver.Get(container.ID) + if err != nil { + return nil, fmt.Errorf("Error getting container rootfs %s from driver %s: %s", container.ID, container.runtime.driver, err) + } + + files := make([]string, 0) + deletions := make([]string, 0) + for _, change := range changes { + if change.Kind == archive.ChangeModify || change.Kind == archive.ChangeAdd { + files = append(files, change.Path) + } + if change.Kind == archive.ChangeDelete { + base := filepath.Base(change.Path) + dir := filepath.Dir(change.Path) + deletions = append(deletions, filepath.Join(dir, ".wh."+base)) + } + } + + return archive.TarFilter(cDir, archive.Uncompressed, files, false, deletions) +} + func linkLxcStart(root string) error { sourcePath, err := exec.LookPath("lxc-start") if err != nil {