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 }