"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 }