github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/pkg/chrootarchive/archive.go (about)

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