github.com/titanous/docker@v1.4.1/pkg/chrootarchive/archive.go (about)

     1  package chrootarchive
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"flag"
     7  	"fmt"
     8  	"io"
     9  	"os"
    10  	"path/filepath"
    11  	"runtime"
    12  	"strings"
    13  	"syscall"
    14  
    15  	"github.com/docker/docker/pkg/archive"
    16  	"github.com/docker/docker/pkg/reexec"
    17  )
    18  
    19  var chrootArchiver = &archive.Archiver{Untar}
    20  
    21  func chroot(path string) error {
    22  	if err := syscall.Chroot(path); err != nil {
    23  		return err
    24  	}
    25  	return syscall.Chdir("/")
    26  }
    27  
    28  func untar() {
    29  	runtime.LockOSThread()
    30  	flag.Parse()
    31  	if err := chroot(flag.Arg(0)); err != nil {
    32  		fatal(err)
    33  	}
    34  	var options *archive.TarOptions
    35  	if err := json.NewDecoder(strings.NewReader(flag.Arg(1))).Decode(&options); err != nil {
    36  		fatal(err)
    37  	}
    38  	if err := archive.Unpack(os.Stdin, "/", options); err != nil {
    39  		fatal(err)
    40  	}
    41  	// fully consume stdin in case it is zero padded
    42  	flush(os.Stdin)
    43  	os.Exit(0)
    44  }
    45  
    46  func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error {
    47  	if tarArchive == nil {
    48  		return fmt.Errorf("Empty archive")
    49  	}
    50  	if options == nil {
    51  		options = &archive.TarOptions{}
    52  	}
    53  	if options.Excludes == nil {
    54  		options.Excludes = []string{}
    55  	}
    56  
    57  	var (
    58  		buf bytes.Buffer
    59  		enc = json.NewEncoder(&buf)
    60  	)
    61  	if err := enc.Encode(options); err != nil {
    62  		return fmt.Errorf("Untar json encode: %v", err)
    63  	}
    64  	if _, err := os.Stat(dest); os.IsNotExist(err) {
    65  		if err := os.MkdirAll(dest, 0777); err != nil {
    66  			return err
    67  		}
    68  	}
    69  	dest = filepath.Clean(dest)
    70  	decompressedArchive, err := archive.DecompressStream(tarArchive)
    71  	if err != nil {
    72  		return err
    73  	}
    74  	defer decompressedArchive.Close()
    75  
    76  	cmd := reexec.Command("docker-untar", dest, buf.String())
    77  	cmd.Stdin = decompressedArchive
    78  	out, err := cmd.CombinedOutput()
    79  	if err != nil {
    80  		return fmt.Errorf("Untar %s %s", err, out)
    81  	}
    82  	return nil
    83  }
    84  
    85  func TarUntar(src, dst string) error {
    86  	return chrootArchiver.TarUntar(src, dst)
    87  }
    88  
    89  // CopyWithTar creates a tar archive of filesystem path `src`, and
    90  // unpacks it at filesystem path `dst`.
    91  // The archive is streamed directly with fixed buffering and no
    92  // intermediary disk IO.
    93  func CopyWithTar(src, dst string) error {
    94  	return chrootArchiver.CopyWithTar(src, dst)
    95  }
    96  
    97  // CopyFileWithTar emulates the behavior of the 'cp' command-line
    98  // for a single file. It copies a regular file from path `src` to
    99  // path `dst`, and preserves all its metadata.
   100  //
   101  // If `dst` ends with a trailing slash '/', the final destination path
   102  // will be `dst/base(src)`.
   103  func CopyFileWithTar(src, dst string) (err error) {
   104  	return chrootArchiver.CopyFileWithTar(src, dst)
   105  }
   106  
   107  // UntarPath is a convenience function which looks for an archive
   108  // at filesystem path `src`, and unpacks it at `dst`.
   109  func UntarPath(src, dst string) error {
   110  	return chrootArchiver.UntarPath(src, dst)
   111  }