archive_unix.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. //go:build !windows
  2. // +build !windows
  3. package chrootarchive // import "github.com/docker/docker/pkg/chrootarchive"
  4. import (
  5. "io"
  6. "path/filepath"
  7. "strings"
  8. "github.com/docker/docker/pkg/archive"
  9. "github.com/pkg/errors"
  10. )
  11. func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions, root string) error {
  12. relDest, err := resolvePathInChroot(root, dest)
  13. if err != nil {
  14. return err
  15. }
  16. done := make(chan error)
  17. err = goInChroot(root, func() { done <- archive.Unpack(decompressedArchive, relDest, options) })
  18. if err != nil {
  19. return err
  20. }
  21. return <-done
  22. }
  23. func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
  24. relSrc, err := resolvePathInChroot(root, srcPath)
  25. if err != nil {
  26. return nil, err
  27. }
  28. // make sure we didn't trim a trailing slash with the call to `resolvePathInChroot`
  29. if strings.HasSuffix(srcPath, "/") && !strings.HasSuffix(relSrc, "/") {
  30. relSrc += "/"
  31. }
  32. tb, err := archive.NewTarballer(relSrc, options)
  33. if err != nil {
  34. return nil, errors.Wrap(err, "error processing tar file")
  35. }
  36. err = goInChroot(root, tb.Do)
  37. if err != nil {
  38. return nil, errors.Wrap(err, "could not chroot")
  39. }
  40. return tb.Reader(), nil
  41. }
  42. // resolvePathInChroot returns the equivalent to path inside a chroot rooted at root.
  43. // The returned path always begins with '/'.
  44. //
  45. // - resolvePathInChroot("/a/b", "/a/b/c/d") -> "/c/d"
  46. // - resolvePathInChroot("/a/b", "/a/b") -> "/"
  47. //
  48. // The implementation is buggy, and some bugs may be load-bearing.
  49. // Here be dragons.
  50. func resolvePathInChroot(root, path string) (string, error) {
  51. if root == "" {
  52. return "", errors.New("root path must not be empty")
  53. }
  54. rel, err := filepath.Rel(root, path)
  55. if err != nil {
  56. return "", err
  57. }
  58. if rel == "." {
  59. rel = "/"
  60. }
  61. if rel[0] != '/' {
  62. rel = "/" + rel
  63. }
  64. return rel, nil
  65. }