Przeglądaj źródła

archive.ApplyLayer(): parse a tar archive as a standard aufs-compatible diff, and apply it on a directory

Solomon Hykes 11 lat temu
rodzic
commit
318dd33fb7
1 zmienionych plików z 59 dodań i 0 usunięć
  1. 59 0
      archive/diff.go

+ 59 - 0
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
+}
+