func ExtractTar(rs io.Reader, dir string, overwrite bool, uidRange *user.UidRange, pwl PathWhitelistMap) error {
	r, w, err := os.Pipe()
	if err != nil {
		return err
	}
	defer w.Close()
	enc := json.NewEncoder(w)
	cmd := mcEntrypoint.Cmd(dir, strconv.FormatBool(overwrite),
		strconv.FormatUint(uint64(uidRange.Shift), 10),
		strconv.FormatUint(uint64(uidRange.Count), 10))
	cmd.ExtraFiles = []*os.File{r}
	cmd.Stdin = rs
	encodeCh := make(chan error)
	go func() {
		encodeCh <- enc.Encode(pwl)
	}()
	out, err := cmd.CombinedOutput()
	encodeErr := <-encodeCh
	if err != nil {
		return fmt.Errorf("extracttar error: %v, output: %s", err, out)
	}
	if encodeErr != nil {
		return errwrap.Wrap(errors.New("extracttar failed to json encode filemap"), encodeErr)
	}
	return nil
}
ExtractTar extracts a tarball (from a io.Reader) into the given directory
if pwl is not nil, only the paths in the map are extracted.
If overwrite is true, existing files will be overwritten.
The extraction is executed by fork/exec()ing a new process. The new process
needs the CAP_SYS_CHROOT capability.
package tar
import (
	"archive/tar"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"syscall"
	"github.com/coreos/rkt/pkg/multicall"
	"github.com/coreos/rkt/pkg/sys"
	"github.com/coreos/rkt/pkg/user"
	"github.com/hashicorp/errwrap"
)
const (
	multicallName = "extracttar"
	fileMapFdNum  = 3
)
var mcEntrypoint multicall.Entrypoint
func init() {
	mcEntrypoint = multicall.Add(multicallName, extractTarCommand)
}
func extractTarCommand() error {
	if len(os.Args) != 5 {
		return fmt.Errorf("incorrect number of arguments. Usage: %s DIR {true|false} uidShift uidCount", multicallName)
	}
	if !sys.HasChrootCapability() {
		return fmt.Errorf("chroot capability not available.")
	}
	dir := os.Args[1]
	if !filepath.IsAbs(dir) {
		return fmt.Errorf("dir %s must be an absolute path", dir)
	}
	overwrite, err := strconv.ParseBool(os.Args[2])
	if err != nil {
		return errwrap.Wrap(errors.New("error parsing overwrite argument"), err)
	}
	us, err := strconv.ParseUint(os.Args[3], 10, 32)
	if err != nil {
		return errwrap.Wrap(errors.New("error parsing uidShift argument"), err)
	}
	uc, err := strconv.ParseUint(os.Args[4], 10, 32)
	if err != nil {
		return errwrap.Wrap(errors.New("error parsing uidShift argument"), err)
	}
	uidRange := &user.UidRange{Shift: uint32(us), Count: uint32(uc)}
	if err := syscall.Chroot(dir); err != nil {
		return errwrap.Wrap(fmt.Errorf("failed to chroot in %s", dir), err)
	}
	if err := syscall.Chdir("/"); err != nil {
		return errwrap.Wrap(errors.New("failed to chdir"), err)
	}
	fileMapFile := os.NewFile(uintptr(fileMapFdNum), "fileMap")
	fileMap := map[string]struct{}{}
	if err := json.NewDecoder(fileMapFile).Decode(&fileMap); err != nil {
		return errwrap.Wrap(errors.New("error decoding fileMap"), err)
	}
	editor, err := NewUidShiftingFilePermEditor(uidRange)
	if err != nil {
		return errwrap.Wrap(errors.New("error determining current user"), err)
	}
	if err := ExtractTarInsecure(tar.NewReader(os.Stdin), "/", overwrite, fileMap, editor); err != nil {
		return errwrap.Wrap(errors.New("error extracting tar"), err)
	}
	io.Copy(ioutil.Discard, os.Stdin)
	return nil
}