"Fossies" - the Fresh Open Source Software Archive

Member "skopeo-1.2.1/vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go" (10 Jan 2021, 4490 Bytes) of package /linux/misc/skopeo-1.2.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // +build !windows
    2 
    3 package chrootarchive
    4 
    5 import (
    6     "bytes"
    7     "encoding/json"
    8     "flag"
    9     "fmt"
   10     "io"
   11     "io/ioutil"
   12     "os"
   13     "path/filepath"
   14     "runtime"
   15     "strings"
   16 
   17     "github.com/containers/storage/pkg/archive"
   18     "github.com/containers/storage/pkg/reexec"
   19     "github.com/pkg/errors"
   20 )
   21 
   22 // untar is the entry-point for storage-untar on re-exec. This is not used on
   23 // Windows as it does not support chroot, hence no point sandboxing through
   24 // chroot and rexec.
   25 func untar() {
   26     runtime.LockOSThread()
   27     flag.Parse()
   28 
   29     var options archive.TarOptions
   30 
   31     //read the options from the pipe "ExtraFiles"
   32     if err := json.NewDecoder(os.NewFile(3, "options")).Decode(&options); err != nil {
   33         fatal(err)
   34     }
   35 
   36     dst := flag.Arg(0)
   37     var root string
   38     if len(flag.Args()) > 1 {
   39         root = flag.Arg(1)
   40     }
   41 
   42     if root == "" {
   43         root = dst
   44     }
   45 
   46     if err := chroot(root); err != nil {
   47         fatal(err)
   48     }
   49 
   50     if err := archive.Unpack(os.Stdin, dst, &options); err != nil {
   51         fatal(err)
   52     }
   53     // fully consume stdin in case it is zero padded
   54     if _, err := flush(os.Stdin); err != nil {
   55         fatal(err)
   56     }
   57 
   58     os.Exit(0)
   59 }
   60 
   61 func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.TarOptions, root string) error {
   62     if root == "" {
   63         return errors.New("must specify a root to chroot to")
   64     }
   65 
   66     // We can't pass a potentially large exclude list directly via cmd line
   67     // because we easily overrun the kernel's max argument/environment size
   68     // when the full image list is passed (e.g. when this is used by
   69     // `docker load`). We will marshall the options via a pipe to the
   70     // child
   71     r, w, err := os.Pipe()
   72     if err != nil {
   73         return fmt.Errorf("Untar pipe failure: %v", err)
   74     }
   75 
   76     if root != "" {
   77         relDest, err := filepath.Rel(root, dest)
   78         if err != nil {
   79             return err
   80         }
   81         if relDest == "." {
   82             relDest = "/"
   83         }
   84         if relDest[0] != '/' {
   85             relDest = "/" + relDest
   86         }
   87         dest = relDest
   88     }
   89 
   90     cmd := reexec.Command("storage-untar", dest, root)
   91     cmd.Stdin = decompressedArchive
   92 
   93     cmd.ExtraFiles = append(cmd.ExtraFiles, r)
   94     output := bytes.NewBuffer(nil)
   95     cmd.Stdout = output
   96     cmd.Stderr = output
   97 
   98     if err := cmd.Start(); err != nil {
   99         w.Close()
  100         return fmt.Errorf("Untar error on re-exec cmd: %v", err)
  101     }
  102 
  103     //write the options to the pipe for the untar exec to read
  104     if err := json.NewEncoder(w).Encode(options); err != nil {
  105         w.Close()
  106         return fmt.Errorf("Untar json encode to pipe failed: %v", err)
  107     }
  108     w.Close()
  109 
  110     if err := cmd.Wait(); err != nil {
  111         // when `xz -d -c -q | storage-untar ...` failed on storage-untar side,
  112         // we need to exhaust `xz`'s output, otherwise the `xz` side will be
  113         // pending on write pipe forever
  114         io.Copy(ioutil.Discard, decompressedArchive)
  115 
  116         return fmt.Errorf("Error processing tar file(%v): %s", err, output)
  117     }
  118     return nil
  119 }
  120 
  121 func tar() {
  122     runtime.LockOSThread()
  123     flag.Parse()
  124 
  125     src := flag.Arg(0)
  126     var root string
  127     if len(flag.Args()) > 1 {
  128         root = flag.Arg(1)
  129     }
  130 
  131     if root == "" {
  132         root = src
  133     }
  134 
  135     if err := realChroot(root); err != nil {
  136         fatal(err)
  137     }
  138 
  139     var options archive.TarOptions
  140     if err := json.NewDecoder(os.Stdin).Decode(&options); err != nil {
  141         fatal(err)
  142     }
  143 
  144     rdr, err := archive.TarWithOptions(src, &options)
  145     if err != nil {
  146         fatal(err)
  147     }
  148     defer rdr.Close()
  149 
  150     if _, err := io.Copy(os.Stdout, rdr); err != nil {
  151         fatal(err)
  152     }
  153 
  154     os.Exit(0)
  155 }
  156 
  157 func invokePack(srcPath string, options *archive.TarOptions, root string) (io.ReadCloser, error) {
  158     if root == "" {
  159         return nil, errors.New("root path must not be empty")
  160     }
  161 
  162     relSrc, err := filepath.Rel(root, srcPath)
  163     if err != nil {
  164         return nil, err
  165     }
  166     if relSrc == "." {
  167         relSrc = "/"
  168     }
  169     if relSrc[0] != '/' {
  170         relSrc = "/" + relSrc
  171     }
  172 
  173     // make sure we didn't trim a trailing slash with the call to `Rel`
  174     if strings.HasSuffix(srcPath, "/") && !strings.HasSuffix(relSrc, "/") {
  175         relSrc += "/"
  176     }
  177 
  178     cmd := reexec.Command("storage-tar", relSrc, root)
  179 
  180     errBuff := bytes.NewBuffer(nil)
  181     cmd.Stderr = errBuff
  182 
  183     tarR, tarW := io.Pipe()
  184     cmd.Stdout = tarW
  185 
  186     stdin, err := cmd.StdinPipe()
  187     if err != nil {
  188         return nil, errors.Wrap(err, "error getting options pipe for tar process")
  189     }
  190 
  191     if err := cmd.Start(); err != nil {
  192         return nil, errors.Wrap(err, "tar error on re-exec cmd")
  193     }
  194 
  195     go func() {
  196         err := cmd.Wait()
  197         err = errors.Wrapf(err, "error processing tar file: %s", errBuff)
  198         tarW.CloseWithError(err)
  199     }()
  200 
  201     if err := json.NewEncoder(stdin).Encode(options); err != nil {
  202         stdin.Close()
  203         return nil, errors.Wrap(err, "tar json encode to pipe failed")
  204     }
  205     stdin.Close()
  206 
  207     return tarR, nil
  208 }