archive.go 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package chrootarchive
  2. import (
  3. "fmt"
  4. "io"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "github.com/docker/docker/pkg/archive"
  9. "github.com/docker/docker/pkg/idtools"
  10. )
  11. var chrootArchiver = &archive.Archiver{Untar: Untar}
  12. // Untar reads a stream of bytes from `archive`, parses it as a tar archive,
  13. // and unpacks it into the directory at `dest`.
  14. // The archive may be compressed with one of the following algorithms:
  15. // identity (uncompressed), gzip, bzip2, xz.
  16. func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
  17. return untarHandler(tarArchive, dest, options, true)
  18. }
  19. // UntarUncompressed reads a stream of bytes from `archive`, parses it as a tar archive,
  20. // and unpacks it into the directory at `dest`.
  21. // The archive must be an uncompressed stream.
  22. func UntarUncompressed(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
  23. return untarHandler(tarArchive, dest, options, false)
  24. }
  25. // Handler for teasing out the automatic decompression
  26. func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool) error {
  27. if tarArchive == nil {
  28. return fmt.Errorf("Empty archive")
  29. }
  30. if options == nil {
  31. options = &archive.TarOptions{}
  32. }
  33. if options.ExcludePatterns == nil {
  34. options.ExcludePatterns = []string{}
  35. }
  36. rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
  37. if err != nil {
  38. return err
  39. }
  40. dest = filepath.Clean(dest)
  41. if _, err := os.Stat(dest); os.IsNotExist(err) {
  42. if err := idtools.MkdirAllNewAs(dest, 0755, rootUID, rootGID); err != nil {
  43. return err
  44. }
  45. }
  46. r := ioutil.NopCloser(tarArchive)
  47. if decompress {
  48. decompressedArchive, err := archive.DecompressStream(tarArchive)
  49. if err != nil {
  50. return err
  51. }
  52. defer decompressedArchive.Close()
  53. r = decompressedArchive
  54. }
  55. return invokeUnpack(r, dest, options)
  56. }
  57. // TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
  58. // If either Tar or Untar fails, TarUntar aborts and returns the error.
  59. func TarUntar(src, dst string) error {
  60. return chrootArchiver.TarUntar(src, dst)
  61. }
  62. // CopyWithTar creates a tar archive of filesystem path `src`, and
  63. // unpacks it at filesystem path `dst`.
  64. // The archive is streamed directly with fixed buffering and no
  65. // intermediary disk IO.
  66. func CopyWithTar(src, dst string) error {
  67. return chrootArchiver.CopyWithTar(src, dst)
  68. }
  69. // CopyFileWithTar emulates the behavior of the 'cp' command-line
  70. // for a single file. It copies a regular file from path `src` to
  71. // path `dst`, and preserves all its metadata.
  72. //
  73. // If `dst` ends with a trailing slash '/' ('\' on Windows), the final
  74. // destination path will be `dst/base(src)` or `dst\base(src)`
  75. func CopyFileWithTar(src, dst string) (err error) {
  76. return chrootArchiver.CopyFileWithTar(src, dst)
  77. }
  78. // UntarPath is a convenience function which looks for an archive
  79. // at filesystem path `src`, and unpacks it at `dst`.
  80. func UntarPath(src, dst string) error {
  81. return chrootArchiver.UntarPath(src, dst)
  82. }