github.com/grange74/docker@v1.6.0-rc3/pkg/chrootarchive/archive.go (about) 1 package chrootarchive 2 3 import ( 4 "encoding/json" 5 "flag" 6 "fmt" 7 "io" 8 "os" 9 "path/filepath" 10 "runtime" 11 "syscall" 12 13 "github.com/docker/docker/pkg/archive" 14 "github.com/docker/docker/pkg/reexec" 15 ) 16 17 var chrootArchiver = &archive.Archiver{Untar: Untar} 18 19 func chroot(path string) error { 20 if err := syscall.Chroot(path); err != nil { 21 return err 22 } 23 return syscall.Chdir("/") 24 } 25 26 func untar() { 27 runtime.LockOSThread() 28 flag.Parse() 29 30 var options *archive.TarOptions 31 32 if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil { 33 fatal(err) 34 } 35 36 if err := chroot(flag.Arg(0)); err != nil { 37 fatal(err) 38 } 39 if err := archive.Unpack(os.Stdin, "/", options); err != nil { 40 fatal(err) 41 } 42 // fully consume stdin in case it is zero padded 43 flush(os.Stdin) 44 os.Exit(0) 45 } 46 47 func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error { 48 if tarArchive == nil { 49 return fmt.Errorf("Empty archive") 50 } 51 if options == nil { 52 options = &archive.TarOptions{} 53 } 54 if options.ExcludePatterns == nil { 55 options.ExcludePatterns = []string{} 56 } 57 58 dest = filepath.Clean(dest) 59 if _, err := os.Stat(dest); os.IsNotExist(err) { 60 if err := os.MkdirAll(dest, 0777); err != nil { 61 return err 62 } 63 } 64 65 // We can't pass the exclude list directly via cmd line 66 // because we easily overrun the shell max argument list length 67 // when the full image list is passed (e.g. when this is used 68 // by `docker load`). Instead we will add the JSON marshalled 69 // and placed in the env, which has significantly larger 70 // max size 71 data, err := json.Marshal(options) 72 if err != nil { 73 return fmt.Errorf("Untar json encode: %v", err) 74 } 75 decompressedArchive, err := archive.DecompressStream(tarArchive) 76 if err != nil { 77 return err 78 } 79 defer decompressedArchive.Close() 80 81 cmd := reexec.Command("docker-untar", dest) 82 cmd.Stdin = decompressedArchive 83 cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data)) 84 out, err := cmd.CombinedOutput() 85 if err != nil { 86 return fmt.Errorf("Untar %s %s", err, out) 87 } 88 return nil 89 } 90 91 func TarUntar(src, dst string) error { 92 return chrootArchiver.TarUntar(src, dst) 93 } 94 95 // CopyWithTar creates a tar archive of filesystem path `src`, and 96 // unpacks it at filesystem path `dst`. 97 // The archive is streamed directly with fixed buffering and no 98 // intermediary disk IO. 99 func CopyWithTar(src, dst string) error { 100 return chrootArchiver.CopyWithTar(src, dst) 101 } 102 103 // CopyFileWithTar emulates the behavior of the 'cp' command-line 104 // for a single file. It copies a regular file from path `src` to 105 // path `dst`, and preserves all its metadata. 106 // 107 // If `dst` ends with a trailing slash '/', the final destination path 108 // will be `dst/base(src)`. 109 func CopyFileWithTar(src, dst string) (err error) { 110 return chrootArchiver.CopyFileWithTar(src, dst) 111 } 112 113 // UntarPath is a convenience function which looks for an archive 114 // at filesystem path `src`, and unpacks it at `dst`. 115 func UntarPath(src, dst string) error { 116 return chrootArchiver.UntarPath(src, dst) 117 }