// applyLayer is the entry-point for docker-applylayer on re-exec. This is not // used on Windows as it does not support chroot, hence no point sandboxing // through chroot and rexec. func applyLayer() { var ( tmpDir string err error options *archive.TarOptions ) runtime.LockOSThread() flag.Parse() inUserns := rsystem.RunningInUserNS() if err := chroot(flag.Arg(0)); err != nil { fatal(err) } // We need to be able to set any perms oldmask, err := system.Umask(0) defer system.Umask(oldmask) if err != nil { fatal(err) } if err := json.Unmarshal([]byte(os.Getenv("OPT")), &options); err != nil { fatal(err) } if inUserns { options.InUserNS = true } if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil { fatal(err) } os.Setenv("TMPDIR", tmpDir) size, err := archive.UnpackLayer("/", os.Stdin, options) os.RemoveAll(tmpDir) if err != nil { fatal(err) } encoder := json.NewEncoder(os.Stdout) if err := encoder.Encode(applyLayerResponse{size}); err != nil { fatal(fmt.Errorf("unable to encode layerSize JSON: %s", err)) } if _, err := flush(os.Stdin); err != nil { fatal(err) } os.Exit(0) }
func do_export(ctx *context, ctrl *ext.Controller) bool { r := ctrl.Request if r.MethodToLower() != "get" { ctrl.JsonError(http.StatusMethodNotAllowed, errors.New("method not allowed")) return true } directory := path.Join(ctx.app.Options.Root, r.TrimSuffixURI(".export")) var tarOpt archive.TarOptions tarOpt.ExcludePatterns = append(tarOpt.ExcludePatterns, ".tmp", ".h2object", "h2object.pid", "h2object.conf") tarOpt.Compression = archive.Gzip rd, err := archive.TarWithOptions(directory, &tarOpt) if err != nil { ctrl.JsonError(http.StatusInternalServerError, err) return true } defer rd.Close() _, fname := path.Split(r.TrimSuffixURI(".export")) if fname == "" { fname = "h2object" } fname = fname + ".tar.gz" fn := path.Join(ctx.app.Options.TempRoot, fname) fd, err := os.Create(fn) if err != nil { ctrl.JsonError(http.StatusInternalServerError, err) return true } if _, err := io.Copy(fd, rd); err != nil { ctrl.JsonError(http.StatusInternalServerError, err) return true } fd.Close() fout, err := os.Open(fn) if err != nil { ctrl.JsonError(http.StatusInternalServerError, err) return true } fstat, err := fout.Stat() if err != nil { ctrl.JsonError(http.StatusInternalServerError, err) return true } ctrl.Binary(fname, fout, fstat.Size()) return true }
// Untar reads a stream of bytes from `archive`, parses it as a tar archive, // and unpacks it into the directory at `dest`. // The archive may be compressed with one of the following algorithms: // identity (uncompressed), gzip, bzip2, xz. func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error { if tarArchive == nil { return fmt.Errorf("Empty archive") } if options == nil { options = &archive.TarOptions{} } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } dest = filepath.Clean(dest) if _, err := os.Stat(dest); os.IsNotExist(err) { if err := system.MkdirAll(dest, 0777); err != nil { return err } } decompressedArchive, err := archive.DecompressStream(tarArchive) if err != nil { return err } defer decompressedArchive.Close() return invokeUnpack(decompressedArchive, dest, options) }
// applyLayerHandler parses a diff in the standard layer format from `layer`, and // applies it to the directory `dest`. Returns the size in bytes of the // contents of the layer. func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions, decompress bool) (size int64, err error) { dest = filepath.Clean(dest) if decompress { decompressed, err := archive.DecompressStream(layer) if err != nil { return 0, err } defer decompressed.Close() layer = decompressed } if options == nil { options = &archive.TarOptions{} if rsystem.RunningInUserNS() { options.InUserNS = true } } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } data, err := json.Marshal(options) if err != nil { return 0, fmt.Errorf("ApplyLayer json encode: %v", err) } cmd := reexec.Command("docker-applyLayer", dest) cmd.Stdin = layer cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data)) outBuf, errBuf := new(bytes.Buffer), new(bytes.Buffer) cmd.Stdout, cmd.Stderr = outBuf, errBuf if err = cmd.Run(); err != nil { return 0, fmt.Errorf("ApplyLayer %s stdout: %s stderr: %s", err, outBuf, errBuf) } // Stdout should be a valid JSON struct representing an applyLayerResponse. response := applyLayerResponse{} decoder := json.NewDecoder(outBuf) if err = decoder.Decode(&response); err != nil { return 0, fmt.Errorf("unable to decode ApplyLayer JSON response: %s", err) } return response.LayerSize, nil }
func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error { if tarArchive == nil { return fmt.Errorf("Empty archive") } if options == nil { options = &archive.TarOptions{} } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } dest = filepath.Clean(dest) if _, err := os.Stat(dest); os.IsNotExist(err) { if err := os.MkdirAll(dest, 0777); err != nil { return err } } decompressedArchive, err := archive.DecompressStream(tarArchive) if err != nil { return err } defer decompressedArchive.Close() // We can't pass a potentially large exclude list directly via cmd line // because we easily overrun the kernel's max argument/environment size // when the full image list is passed (e.g. when this is used by // `docker load`). We will marshall the options via a pipe to the // child r, w, err := os.Pipe() if err != nil { return fmt.Errorf("Untar pipe failure: %v", err) } cmd := reexec.Command("docker-untar", dest) cmd.Stdin = decompressedArchive cmd.ExtraFiles = append(cmd.ExtraFiles, r) var output bytes.Buffer cmd.Stdout = &output cmd.Stderr = &output if err := cmd.Start(); err != nil { return fmt.Errorf("Untar error on re-exec cmd: %v", err) } //write the options to the pipe for the untar exec to read if err := json.NewEncoder(w).Encode(options); err != nil { return fmt.Errorf("Untar json encode to pipe failed: %v", err) } w.Close() if err := cmd.Wait(); err != nil { return fmt.Errorf("Untar re-exec error: %v: output: %s", err, output) } return nil }
func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error { if tarArchive == nil { return fmt.Errorf("Empty archive") } if options == nil { options = &archive.TarOptions{} } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } dest = filepath.Clean(dest) if _, err := os.Stat(dest); os.IsNotExist(err) { if err := os.MkdirAll(dest, 0777); err != nil { return err } } // We can't pass the exclude list directly via cmd line // because we easily overrun the shell max argument list length // when the full image list is passed (e.g. when this is used // by `docker load`). Instead we will add the JSON marshalled // and placed in the env, which has significantly larger // max size data, err := json.Marshal(options) if err != nil { return fmt.Errorf("Untar json encode: %v", err) } decompressedArchive, err := archive.DecompressStream(tarArchive) if err != nil { return err } defer decompressedArchive.Close() cmd := reexec.Command("docker-untar", dest) cmd.Stdin = decompressedArchive cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data)) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("Untar %s %s", err, out) } return nil }
func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error { if tarArchive == nil { return fmt.Errorf("Empty archive") } if options == nil { options = &archive.TarOptions{} } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } var ( buf bytes.Buffer enc = json.NewEncoder(&buf) ) if err := enc.Encode(options); err != nil { return fmt.Errorf("Untar json encode: %v", err) } if _, err := os.Stat(dest); os.IsNotExist(err) { if err := os.MkdirAll(dest, 0777); err != nil { return err } } dest = filepath.Clean(dest) decompressedArchive, err := archive.DecompressStream(tarArchive) if err != nil { return err } defer decompressedArchive.Close() cmd := reexec.Command("docker-untar", dest, buf.String()) cmd.Stdin = decompressedArchive out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("Untar %s %s", err, out) } return nil }
// Handler for teasing out the automatic decompression func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions, decompress bool) error { if tarArchive == nil { return fmt.Errorf("Empty archive") } if options == nil { options = &archive.TarOptions{} } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } rootUID, rootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps) if err != nil { return err } dest = filepath.Clean(dest) if _, err := os.Stat(dest); os.IsNotExist(err) { if err := idtools.MkdirAllNewAs(dest, 0755, rootUID, rootGID); err != nil { return err } } r := ioutil.NopCloser(tarArchive) if decompress { decompressedArchive, err := archive.DecompressStream(tarArchive) if err != nil { return err } defer decompressedArchive.Close() r = decompressedArchive } return invokeUnpack(r, dest, options) }
func Untar(tarArchive io.Reader, dest string, options *archive.TarOptions) error { if tarArchive == nil { return fmt.Errorf("Empty archive") } if options == nil { options = &archive.TarOptions{} } if options.ExcludePatterns == nil { options.ExcludePatterns = []string{} } dest = filepath.Clean(dest) if _, err := os.Stat(dest); os.IsNotExist(err) { if err := system.MkdirAll(dest, 0777); err != nil { return err } } decompressedArchive, err := archive.DecompressStream(tarArchive) if err != nil { return err } var data []byte var r, w *os.File defer decompressedArchive.Close() if runtime.GOOS != "windows" { // We can't pass a potentially large exclude list directly via cmd line // because we easily overrun the kernel's max argument/environment size // when the full image list is passed (e.g. when this is used by // `docker load`). We will marshall the options via a pipe to the // child // This solution won't work on Windows as it will fail in golang // exec_windows.go as at the lowest layer because attr.Files > 3 r, w, err = os.Pipe() if err != nil { return fmt.Errorf("Untar pipe failure: %v", err) } } else { // We can't pass the exclude list directly via cmd line // because we easily overrun the shell max argument list length // when the full image list is passed (e.g. when this is used // by `docker load`). Instead we will add the JSON marshalled // and placed in the env, which has significantly larger // max size data, err = json.Marshal(options) if err != nil { return fmt.Errorf("Untar json encode: %v", err) } } cmd := reexec.Command("docker-untar", dest) cmd.Stdin = decompressedArchive if runtime.GOOS != "windows" { cmd.ExtraFiles = append(cmd.ExtraFiles, r) output := bytes.NewBuffer(nil) cmd.Stdout = output cmd.Stderr = output if err := cmd.Start(); err != nil { return fmt.Errorf("Untar error on re-exec cmd: %v", err) } //write the options to the pipe for the untar exec to read if err := json.NewEncoder(w).Encode(options); err != nil { return fmt.Errorf("Untar json encode to pipe failed: %v", err) } w.Close() if err := cmd.Wait(); err != nil { return fmt.Errorf("Untar re-exec error: %v: output: %s", err, output) } return nil } else { cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data)) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("Untar %s %s", err, out) } return nil } }
func themePushCommand(ctx *cli.Context) { workdir := ctx.GlobalString("workdir") if workdir == "" { fmt.Println("unknown working directory, please use -w to provide.") os.Exit(1) } // directory directory, err := filepath.Abs(workdir) if err != nil { fmt.Println("workdir:", err) return } stdout := os.Stdout stderr := os.Stderr // auth check config, err := LoadConfigFile(directory) if err != nil { fmt.Fprintln(stderr, err.Error()) os.Exit(1) } if config.Auth.Token == "" || config.Auth.Secret == "" { fmt.Fprintln(stdout, "theme push need login first. ") os.Exit(1) } h2oconf, err := app.LoadCONFIG(path.Join(directory, "h2object.conf")) if err != nil { fmt.Fprintln(stdout, err) os.Exit(1) } host := ctx.String("Host") port := ctx.Int("Port") client := NewClient(directory, host, port) var pkg Package h2oconf.SetSection("theme") pkg.Provider = h2oconf.StringDefault("provider", "") if pkg.Provider == "" { fmt.Fprintln(stderr, "please set h2object.conf [theme]provider first.") os.Exit(1) } pkg.Name = h2oconf.StringDefault("name", "") if pkg.Name == "" { fmt.Fprintln(stderr, "please set h2object.conf [theme]name first.") os.Exit(1) } pkg.Description = h2oconf.StringDefault("description", "") if pkg.Description == "" { fmt.Fprintln(stderr, "please set h2object.conf [theme]description first.") os.Exit(1) } pkg.Version = h2oconf.StringDefault("version", "1.0.0") public := h2oconf.BoolDefault("public", false) pkg.Status = 1 if public == true { pkg.Status = 2 } pkg.Price = h2oconf.FloatDefault("price", 0.0) pkg.Catagory = int64(h2oconf.IntDefault("catagory", 1)) var tarOpt archive.TarOptions tarOpt.ExcludePatterns = append(tarOpt.ExcludePatterns, ".h2object") tarOpt.Compression = archive.Gzip rd, err := archive.TarWithOptions(directory, &tarOpt) if err != nil { fmt.Fprintln(stderr, err.Error()) os.Exit(1) } defer rd.Close() pkg.ArchiveReader = rd pkg.ArchiveName = pkg.Version + ".tar.gz" if err := client.ThemePush(config.Auth.Token, &pkg); err != nil { fmt.Fprintln(stderr, err.Error()) os.Exit(1) } os.Exit(0) }