diff_unix.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. //+build !windows
  2. package chrootarchive
  3. import (
  4. "bytes"
  5. "encoding/json"
  6. "flag"
  7. "fmt"
  8. "io/ioutil"
  9. "os"
  10. "path/filepath"
  11. "runtime"
  12. "github.com/docker/docker/pkg/archive"
  13. "github.com/docker/docker/pkg/reexec"
  14. "github.com/docker/docker/pkg/system"
  15. rsystem "github.com/opencontainers/runc/libcontainer/system"
  16. )
  17. type applyLayerResponse struct {
  18. LayerSize int64 `json:"layerSize"`
  19. }
  20. // applyLayer is the entry-point for docker-applylayer on re-exec. This is not
  21. // used on Windows as it does not support chroot, hence no point sandboxing
  22. // through chroot and rexec.
  23. func applyLayer() {
  24. var (
  25. tmpDir = ""
  26. err error
  27. options *archive.TarOptions
  28. )
  29. runtime.LockOSThread()
  30. flag.Parse()
  31. inUserns := rsystem.RunningInUserNS()
  32. if err := chroot(flag.Arg(0)); err != nil {
  33. fatal(err)
  34. }
  35. // We need to be able to set any perms
  36. oldmask, err := system.Umask(0)
  37. defer system.Umask(oldmask)
  38. if err != nil {
  39. fatal(err)
  40. }
  41. if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil {
  42. fatal(err)
  43. }
  44. if inUserns {
  45. options.InUserNS = true
  46. }
  47. if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil {
  48. fatal(err)
  49. }
  50. os.Setenv("TMPDIR", tmpDir)
  51. size, err := archive.UnpackLayer("/", os.Stdin, options)
  52. os.RemoveAll(tmpDir)
  53. if err != nil {
  54. fatal(err)
  55. }
  56. encoder := json.NewEncoder(os.Stdout)
  57. if err := encoder.Encode(applyLayerResponse{size}); err != nil {
  58. fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err))
  59. }
  60. if _, err := flush(os.Stdin); err != nil {
  61. fatal(err)
  62. }
  63. os.Exit(0)
  64. }
  65. // applyLayerHandler parses a diff in the standard layer format from `layer`, and
  66. // applies it to the directory `dest`. Returns the size in bytes of the
  67. // contents of the layer.
  68. func applyLayerHandler(dest string, layer archive.Reader, options *archive.TarOptions, decompress bool) (size int64, err error) {
  69. dest = filepath.Clean(dest)
  70. if decompress {
  71. decompressed, err := archive.DecompressStream(layer)
  72. if err != nil {
  73. return 0, err
  74. }
  75. defer decompressed.Close()
  76. layer = decompressed
  77. }
  78. if options == nil {
  79. options = &archive.TarOptions{}
  80. if rsystem.RunningInUserNS() {
  81. options.InUserNS = true
  82. }
  83. }
  84. if options.ExcludePatterns == nil {
  85. options.ExcludePatterns = []string{}
  86. }
  87. data, err := json.Marshal(options)
  88. if err != nil {
  89. return 0, fmt.Errorf("ApplyLayer json encode: %v", err)
  90. }
  91. cmd := reexec.Command("docker-applyLayer", dest)
  92. cmd.Stdin = layer
  93. cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data))
  94. outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer)
  95. cmd.Stdout, cmd.Stderr = outBuf, errBuf
  96. if err = cmd.Run(); err != nil {
  97. return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf)
  98. }
  99. // Stdout should be a valid JSON struct representing an applyLayerResponse.
  100. response := applyLayerResponse{}
  101. decoder := json.NewDecoder(outBuf)
  102. if err = decoder.Decode(&response); err != nil {
  103. return 0, fmt.Errorf("unable to decode ApplyLayer JSON response: %s", err)
  104. }
  105. return response.LayerSize, nil
  106. }