@@ -6,36 +6,33 @@ package archive
6
6
7
7
import (
8
8
"archive/tar"
9
- "bufio"
10
9
"context"
11
- "fmt"
12
10
"io"
13
11
"os"
14
12
"os/exec"
15
13
"path"
16
14
"sort"
17
15
"time"
18
16
19
- "github.com/docker/docker/pkg/archive"
20
- "github.com/docker/docker/pkg/idtools"
21
17
"github.com/gitpod-io/gitpod/common-go/log"
22
18
"github.com/gitpod-io/gitpod/common-go/tracing"
23
19
"github.com/opentracing/opentracing-go"
24
20
"golang.org/x/xerrors"
25
21
)
26
22
27
- type tarConfig struct {
23
+ // TarConfig configures tarbal creation/extraction
24
+ type TarConfig struct {
28
25
MaxSizeBytes int64
29
- UIDMaps []idtools. IDMap
30
- GIDMaps []idtools. IDMap
26
+ UIDMaps []IDMapping
27
+ GIDMaps []IDMapping
31
28
}
32
29
33
30
// BuildTarbalOption configures the tarbal creation
34
- type TarOption func (o * tarConfig )
31
+ type TarOption func (o * TarConfig )
35
32
36
33
// TarbalMaxSize limits the size of a tarbal
37
34
func TarbalMaxSize (n int64 ) TarOption {
38
- return func (o * tarConfig ) {
35
+ return func (o * TarConfig ) {
39
36
o .MaxSizeBytes = n
40
37
}
41
38
}
@@ -49,35 +46,21 @@ type IDMapping struct {
49
46
50
47
// WithUIDMapping reverses the given user ID mapping during archive creation
51
48
func WithUIDMapping (mappings []IDMapping ) TarOption {
52
- return func (o * tarConfig ) {
53
- o .UIDMaps = make ([]idtools.IDMap , len (mappings ))
54
- for i , m := range mappings {
55
- o .UIDMaps [i ] = idtools.IDMap {
56
- ContainerID : m .ContainerID ,
57
- HostID : m .HostID ,
58
- Size : m .Size ,
59
- }
60
- }
49
+ return func (o * TarConfig ) {
50
+ o .UIDMaps = mappings
61
51
}
62
52
}
63
53
64
54
// WithGIDMapping reverses the given user ID mapping during archive creation
65
55
func WithGIDMapping (mappings []IDMapping ) TarOption {
66
- return func (o * tarConfig ) {
67
- o .GIDMaps = make ([]idtools.IDMap , len (mappings ))
68
- for i , m := range mappings {
69
- o .GIDMaps [i ] = idtools.IDMap {
70
- ContainerID : m .ContainerID ,
71
- HostID : m .HostID ,
72
- Size : m .Size ,
73
- }
74
- }
56
+ return func (o * TarConfig ) {
57
+ o .GIDMaps = mappings
75
58
}
76
59
}
77
60
78
61
// ExtractTarbal extracts an OCI compatible tar file src to the folder dst, expecting the overlay whiteout format
79
62
func ExtractTarbal (ctx context.Context , src io.Reader , dst string , opts ... TarOption ) (err error ) {
80
- var cfg tarConfig
63
+ var cfg TarConfig
81
64
start := time .Now ()
82
65
for _ , opt := range opts {
83
66
opt (& cfg )
@@ -145,7 +128,7 @@ func ExtractTarbal(ctx context.Context, src io.Reader, dst string, opts ...TarOp
145
128
return nil
146
129
}
147
130
148
- func toHostID (containerID int , idMap []idtools. IDMap ) int {
131
+ func toHostID (containerID int , idMap []IDMapping ) int {
149
132
for _ , m := range idMap {
150
133
if (containerID >= m .ContainerID ) && (containerID <= (m .ContainerID + m .Size - 1 )) {
151
134
hostID := m .HostID + (containerID - m .ContainerID )
@@ -154,98 +137,3 @@ func toHostID(containerID int, idMap []idtools.IDMap) int {
154
137
}
155
138
return containerID
156
139
}
157
-
158
- // BuildTarbal creates an OCI compatible tar file dst from the folder src, expecting the overlay whiteout format
159
- func BuildTarbal (ctx context.Context , src string , dst string , opts ... TarOption ) (err error ) {
160
- var cfg tarConfig
161
- for _ , opt := range opts {
162
- opt (& cfg )
163
- }
164
-
165
- //nolint:staticcheck,ineffassign
166
- span , ctx := opentracing .StartSpanFromContext (ctx , "buildTarbal" )
167
- span .LogKV ("src" , src , "dst" , dst )
168
- defer tracing .FinishSpan (span , & err )
169
-
170
- // ensure the src actually exists before trying to tar it
171
- if _ , err := os .Stat (src ); err != nil {
172
- return fmt .Errorf ("Unable to tar files: %v" , err .Error ())
173
- }
174
-
175
- tarout , err := archive .TarWithOptions (src , & archive.TarOptions {
176
- Compression : archive .Uncompressed ,
177
- WhiteoutFormat : archive .OverlayWhiteoutFormat ,
178
- InUserNS : true ,
179
- UIDMaps : cfg .UIDMaps ,
180
- GIDMaps : cfg .GIDMaps ,
181
- })
182
- if err != nil {
183
- return xerrors .Errorf ("cannot create tar: %w" , err )
184
- }
185
-
186
- fout , err := os .OpenFile (dst , os .O_WRONLY | os .O_CREATE , 0744 )
187
- if err != nil {
188
- return xerrors .Errorf ("cannot open archive for writing: %w" , err )
189
- }
190
- defer fout .Close ()
191
- fbout := bufio .NewWriter (fout )
192
- defer fbout .Flush ()
193
-
194
- targetOut := newLimitWriter (fbout , cfg .MaxSizeBytes )
195
- defer func (e * error ) {
196
- if targetOut .DidMaxOut () {
197
- * e = ErrMaxSizeExceeded
198
- }
199
- }(& err )
200
-
201
- _ , err = io .Copy (targetOut , tarout )
202
- if err != nil {
203
- return xerrors .Errorf ("cannot write tar file: %w" )
204
- }
205
- if err = fbout .Flush (); err != nil {
206
- return xerrors .Errorf ("cannot flush tar out stream: %w" , err )
207
- }
208
-
209
- return nil
210
- }
211
-
212
- // ErrMaxSizeExceeded is emitted by LimitWriter when a write tries to write beyond the max number of bytes allowed
213
- var ErrMaxSizeExceeded = fmt .Errorf ("maximum size exceeded" )
214
-
215
- // newLimitWriter wraps a writer such that a maximum of N bytes can be written. Once that limit is exceeded
216
- // the writer returns io.ErrClosedPipe
217
- func newLimitWriter (out io.Writer , maxSizeBytes int64 ) * limitWriter {
218
- return & limitWriter {
219
- MaxSizeBytes : maxSizeBytes ,
220
- Out : out ,
221
- }
222
- }
223
-
224
- type limitWriter struct {
225
- MaxSizeBytes int64
226
- Out io.Writer
227
- BytesWritten int64
228
-
229
- didMaxOut bool
230
- }
231
-
232
- func (s * limitWriter ) Write (b []byte ) (n int , err error ) {
233
- if s .MaxSizeBytes == 0 {
234
- return s .Out .Write (b )
235
- }
236
-
237
- bsize := int64 (len (b ))
238
- if bsize + s .BytesWritten > s .MaxSizeBytes {
239
- s .didMaxOut = true
240
- return 0 , ErrMaxSizeExceeded
241
- }
242
-
243
- n , err = s .Out .Write (b )
244
- s .BytesWritten += int64 (n )
245
-
246
- return n , err
247
- }
248
-
249
- func (s * limitWriter ) DidMaxOut () bool {
250
- return s .didMaxOut
251
- }
0 commit comments