From 6fb0ff4f9a3ee0a470e8f3d48c8d1f456ef54f58 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 1 Nov 2013 05:06:35 +0000 Subject: [PATCH] archive.ApplyLayer(): parse a tar archive as a standard aufs-compatible diff, and apply it on a directory Upstream-commit: 318dd33fb778282c3012ee06d892d6375e98cd6b Component: engine --- components/engine/archive/diff.go | 59 +++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 components/engine/archive/diff.go diff --git a/components/engine/archive/diff.go b/components/engine/archive/diff.go new file mode 100644 index 0000000000..3154a44f36 --- /dev/null +++ b/components/engine/archive/diff.go @@ -0,0 +1,59 @@ +package archive + +import ( + "path/filepath" + "log" + "os" + "strings" +) + +// ApplyLayer parses a diff in the standard layer format from `layer`, and +// applies it to the directory `dest`. +func ApplyLayer(dest string, layer Archive) error { + // Poor man's diff applyer in 2 steps: + + // Step 1: untar everything in place + if err := Untar(layer, dest); err != nil { + return err + } + + // Step 2: walk for whiteouts and apply them, removing them in the process + err := filepath.Walk(dest, func(fullPath string, f os.FileInfo, err error) error { + if err != nil { + return err + } + + // Rebase path + path, err := filepath.Rel(dest, fullPath) + if err != nil { + return err + } + path = filepath.Join("/", path) + + // Skip AUFS metadata + if matched, err := filepath.Match("/.wh..wh.*", path); err != nil { + return err + } else if matched { + log.Printf("Removing aufs metadata %s", fullPath) + _ = os.Remove(fullPath) + } + + filename := filepath.Base(path) + if strings.HasPrefix(filename, ".wh.") { + rmTargetName := filename[len(".wh."):] + rmTargetPath := filepath.Join(filepath.Dir(fullPath), rmTargetName) + // Remove the file targeted by the whiteout + log.Printf("Removing whiteout target %s", rmTargetPath) + _ = os.Remove(rmTargetPath) + // Remove the whiteout itself + log.Printf("Removing whiteout %s", fullPath) + _ = os.Remove(fullPath) + } + return nil + }) + if err != nil { + return err + } + return nil +} +