"Fossies" - the Fresh Open Source Software Archive

Member "skopeo-1.11.0/vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go" (26 Jan 2023, 4496 Bytes) of package /linux/misc/skopeo-1.11.0.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. See also the last Fossies "Diffs" side-by-side code changes report for "archive_unix.go": 1.9.2_vs_1.10.0.

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