diff.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. package archive
  2. import (
  3. "log"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. )
  8. // ApplyLayer parses a diff in the standard layer format from `layer`, and
  9. // applies it to the directory `dest`.
  10. func ApplyLayer(dest string, layer Archive) error {
  11. // Poor man's diff applyer in 2 steps:
  12. // Step 1: untar everything in place
  13. if err := Untar(layer, dest); err != nil {
  14. return err
  15. }
  16. // Step 2: walk for whiteouts and apply them, removing them in the process
  17. err := filepath.Walk(dest, func(fullPath string, f os.FileInfo, err error) error {
  18. if err != nil {
  19. return err
  20. }
  21. // Rebase path
  22. path, err := filepath.Rel(dest, fullPath)
  23. if err != nil {
  24. return err
  25. }
  26. path = filepath.Join("/", path)
  27. // Skip AUFS metadata
  28. if matched, err := filepath.Match("/.wh..wh.*", path); err != nil {
  29. return err
  30. } else if matched {
  31. log.Printf("Removing aufs metadata %s", fullPath)
  32. _ = os.RemoveAll(fullPath)
  33. }
  34. filename := filepath.Base(path)
  35. if strings.HasPrefix(filename, ".wh.") {
  36. rmTargetName := filename[len(".wh."):]
  37. rmTargetPath := filepath.Join(filepath.Dir(fullPath), rmTargetName)
  38. // Remove the file targeted by the whiteout
  39. log.Printf("Removing whiteout target %s", rmTargetPath)
  40. _ = os.Remove(rmTargetPath)
  41. // Remove the whiteout itself
  42. log.Printf("Removing whiteout %s", fullPath)
  43. _ = os.RemoveAll(fullPath)
  44. }
  45. return nil
  46. })
  47. if err != nil {
  48. return err
  49. }
  50. return nil
  51. }