@@ -33,16 +33,53 @@ type UnpackResult struct {
33
33
VersionedHome string `json:"versioned-home" yaml:"versioned-home"`
34
34
}
35
35
36
+ type copyFunc func (dst io.Writer , src io.Reader ) (written int64 , err error )
37
+ type mkdirAllFunc func (name string , perm fs.FileMode ) error
38
+ type openFileFunc func (name string , flag int , perm fs.FileMode ) (* os.File , error )
39
+ type unarchiveFunc func (log * logger.Logger , archivePath , dataDir string , flavor string , copy copyFunc , mkdirAll mkdirAllFunc , openFile openFileFunc ) (UnpackResult , error )
40
+
41
+ type unpacker struct {
42
+ log * logger.Logger
43
+ // Abstractsions for testability
44
+ unzip unarchiveFunc
45
+ untar unarchiveFunc
46
+ // stdlib abstractions for testability
47
+ copy copyFunc
48
+ mkdirAll mkdirAllFunc
49
+ openFile openFileFunc
50
+ }
51
+
52
+ func newUnpacker (log * logger.Logger ) * unpacker {
53
+ return & unpacker {
54
+ log : log ,
55
+ unzip : unzip ,
56
+ untar : untar ,
57
+ copy : io .Copy ,
58
+ mkdirAll : os .MkdirAll ,
59
+ openFile : os .OpenFile ,
60
+ }
61
+ }
62
+
36
63
// unpack unpacks archive correctly, skips root (symlink, config...) unpacks data/*
64
+ << << << < HEAD
37
65
func (u * Upgrader ) unpack (version , archivePath , dataDir string ) (UnpackResult , error ) {
66
+ == == == =
67
+ func (u * unpacker ) unpack (version , archivePath , dataDir string , flavor string ) (UnpackResult , error ) {
68
+ >> >> >> > f70ff023f (Enhancement / 5235 handle insufficient disk space errors in artifact unpack (#9322 ))
38
69
// unpack must occur in directory that holds the installation directory
39
70
// or the extraction will be double nested
40
71
var unpackRes UnpackResult
41
72
var err error
42
73
if runtime .GOOS == windows {
74
+ << << << < HEAD
43
75
unpackRes , err = unzip (u .log , archivePath , dataDir )
44
76
} else {
45
77
unpackRes , err = untar (u .log , archivePath , dataDir )
78
+ == == == =
79
+ unpackRes , err = u .unzip (u .log , archivePath , dataDir , flavor , u .copy , u .mkdirAll , u .openFile )
80
+ } else {
81
+ unpackRes , err = u .untar (u .log , archivePath , dataDir , flavor , u .copy , u .mkdirAll , u .openFile )
82
+ >> >> >> > f70ff023f (Enhancement / 5235 handle insufficient disk space errors in artifact unpack (#9322 ))
46
83
}
47
84
48
85
if err != nil {
@@ -59,7 +96,7 @@ type packageMetadata struct {
59
96
hash string
60
97
}
61
98
62
- func (u * Upgrader ) getPackageMetadata (archivePath string ) (packageMetadata , error ) {
99
+ func (u * unpacker ) getPackageMetadata (archivePath string ) (packageMetadata , error ) {
63
100
ext := filepath .Ext (archivePath )
64
101
if ext == ".gz" {
65
102
// if we got gzip extension we need another extension before last
@@ -76,7 +113,12 @@ func (u *Upgrader) getPackageMetadata(archivePath string) (packageMetadata, erro
76
113
}
77
114
}
78
115
116
+ << << << < HEAD
79
117
func unzip (log * logger.Logger , archivePath , dataDir string ) (UnpackResult , error ) {
118
+ == == == =
119
+ // injecting copy, mkdirAll and openFile for testability
120
+ func unzip (log * logger.Logger , archivePath , dataDir string , flavor string , copy copyFunc , mkdirAll mkdirAllFunc , openFile openFileFunc ) (UnpackResult , error ) {
121
+ >> >> >> > f70ff023f (Enhancement / 5235 handle insufficient disk space errors in artifact unpack (#9322 ))
80
122
var hash , rootDir string
81
123
r , err := zip .OpenReader (archivePath )
82
124
if err != nil {
@@ -136,8 +178,10 @@ func unzip(log *logger.Logger, archivePath, dataDir string) (UnpackResult, error
136
178
// check if the directory already exists
137
179
_ , err = os .Stat (dstPath )
138
180
if errors .Is (err , fs .ErrNotExist ) {
139
- // the directory does not exist, create it and any non-existing parent directory with the same permissions
140
- if err := os .MkdirAll (dstPath , f .Mode ().Perm ()& 0770 ); err != nil {
181
+ // the directory does not exist, create it and any non-existing
182
+ // parent directory with the same permissions.
183
+ // Using mkdirAll instead of os.MkdirAll so that we can mock it in tests.
184
+ if err := mkdirAll (dstPath , f .Mode ().Perm ()& 0770 ); err != nil {
141
185
return fmt .Errorf ("creating directory %q: %w" , dstPath , err )
142
186
}
143
187
} else if err != nil {
@@ -150,13 +194,23 @@ func unzip(log *logger.Logger, archivePath, dataDir string) (UnpackResult, error
150
194
}
151
195
}
152
196
153
- _ = os .MkdirAll (dstPath , f .Mode ()& 0770 )
197
+ // Using mkdirAll instead of os.MkdirAll so that we can mock it in tests.
198
+ err = mkdirAll (dstPath , f .Mode ()& 0770 )
199
+ if err != nil {
200
+ return fmt .Errorf ("creating directory %q: %w" , dstPath , err )
201
+ }
154
202
} else {
155
203
log .Debugw ("Unpacking file" , "archive" , "zip" , "file.path" , dstPath )
156
204
// create non-existing containing folders with 0770 permissions right now, we'll fix the permission of each
157
- // directory as we come across them while processing the other package entries
158
- _ = os .MkdirAll (filepath .Dir (dstPath ), 0770 )
159
- f , err := os .OpenFile (dstPath , os .O_WRONLY | os .O_CREATE | os .O_TRUNC , f .Mode ()& 0770 )
205
+ // directory as we come across them while processing the other
206
+ // package entries
207
+ // Using mkdirAll instead of os.MkdirAll so that we can mock it in tests.
208
+ err = mkdirAll (filepath .Dir (dstPath ), 0770 )
209
+ if err != nil {
210
+ return fmt .Errorf ("creating directory %q: %w" , dstPath , err )
211
+ }
212
+ // Using openFile instead of os.OpenFile so that we can mock it in tests.
213
+ f , err := openFile (dstPath , os .O_WRONLY | os .O_CREATE | os .O_TRUNC , f .Mode ()& 0770 )
160
214
if err != nil {
161
215
return err
162
216
}
@@ -166,7 +220,9 @@ func unzip(log *logger.Logger, archivePath, dataDir string) (UnpackResult, error
166
220
}
167
221
}()
168
222
169
- if _ , err = io .Copy (f , rc ); err != nil { //nolint:gosec // legacy
223
+ // Using copy instead of io.Copy so that we can
224
+ // mock it in tests.
225
+ if _ , err = copy (f , rc ); err != nil {
170
226
return err
171
227
}
172
228
}
@@ -240,8 +296,13 @@ func getPackageMetadataFromZipReader(r *zip.ReadCloser, fileNamePrefix string) (
240
296
return ret , nil
241
297
}
242
298
299
+ << << << < HEAD
243
300
func untar (log * logger.Logger , archivePath , dataDir string ) (UnpackResult , error ) {
244
301
302
+ == == == =
303
+ // injecting copy, mkdirAll and openFile for testability
304
+ func untar (log * logger.Logger , archivePath , dataDir string , flavor string , copy copyFunc , mkdirAll mkdirAllFunc , openFile openFileFunc ) (UnpackResult , error ) {
305
+ >> >> >> > f70ff023f (Enhancement / 5235 handle insufficient disk space errors in artifact unpack (#9322 ))
245
306
var versionedHome string
246
307
var rootDir string
247
308
var hash string
@@ -330,17 +391,23 @@ func untar(log *logger.Logger, archivePath, dataDir string) (UnpackResult, error
330
391
log .Debugw ("Unpacking file" , "archive" , "tar" , "file.path" , abs )
331
392
// create non-existing containing folders with 0750 permissions right now, we'll fix the permission of each
332
393
// directory as we come across them while processing the other package entries
333
- if err = os .MkdirAll (filepath .Dir (abs ), 0750 ); err != nil {
334
- return UnpackResult {}, errors .New (err , "TarInstaller: creating directory for file " + abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs ))
394
+ // Using mkdirAll instead of os.MkdirAll so that we can
395
+ // mock it in tests.
396
+ if err = mkdirAll (filepath .Dir (abs ), 0750 ); err != nil {
397
+ return UnpackResult {}, goerrors .Join (err , errors .New ("TarInstaller: creating directory for file " + abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs )))
335
398
}
336
399
337
400
// remove any world permissions from the file
338
- wf , err := os .OpenFile (abs , os .O_RDWR | os .O_CREATE | os .O_TRUNC , mode .Perm ()& 0770 )
401
+ // Using openFile instead of os.OpenFile so that we can
402
+ // mock it in tests.
403
+ wf , err := openFile (abs , os .O_RDWR | os .O_CREATE | os .O_TRUNC , mode .Perm ()& 0770 )
339
404
if err != nil {
340
- return UnpackResult {}, errors . New (err , "TarInstaller: creating file " + abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs ))
405
+ return UnpackResult {}, goerrors . Join (err , errors . New ( "TarInstaller: creating file " + abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs ) ))
341
406
}
342
407
343
- _ , err = io .Copy (wf , tr ) //nolint:gosec // legacy
408
+ // Using copy instead of io.Copy so that we can
409
+ // mock it in tests.
410
+ _ , err = copy (wf , tr )
344
411
if closeErr := wf .Close (); closeErr != nil && err == nil {
345
412
err = closeErr
346
413
}
@@ -352,17 +419,20 @@ func untar(log *logger.Logger, archivePath, dataDir string) (UnpackResult, error
352
419
// check if the directory already exists
353
420
_ , err = os .Stat (abs )
354
421
if errors .Is (err , fs .ErrNotExist ) {
355
- // the directory does not exist, create it and any non-existing parent directory with the same permissions
356
- if err := os .MkdirAll (abs , mode .Perm ()& 0770 ); err != nil {
357
- return UnpackResult {}, errors .New (err , "TarInstaller: creating directory for file " + abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs ))
422
+ // the directory does not exist, create it and any non-existing
423
+ // parent directory with the same permissions.
424
+ // Using mkdirAll instead of os.MkdirAll so that we can
425
+ // mock it in tests.
426
+ if err := mkdirAll (abs , mode .Perm ()& 0770 ); err != nil {
427
+ return UnpackResult {}, goerrors .Join (err , errors .New ("TarInstaller: creating directory for file " + abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs )))
358
428
}
359
429
} else if err != nil {
360
430
return UnpackResult {}, errors .New (err , "TarInstaller: stat() directory for file " + abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs ))
361
431
} else {
362
432
// directory already exists, set the appropriate permissions
363
433
err = os .Chmod (abs , mode .Perm ()& 0770 )
364
434
if err != nil {
365
- return UnpackResult {}, errors . New (err , fmt . Sprintf ("TarInstaller: setting permissions %O for directory %q" , mode .Perm ()& 0770 , abs ) , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs ))
435
+ return UnpackResult {}, goerrors . Join (err , errors . New ("TarInstaller: setting permissions %O for directory %q" , mode .Perm ()& 0770 , abs , errors .TypeFilesystem , errors .M (errors .MetaKeyPath , abs ) ))
366
436
}
367
437
}
368
438
default :
0 commit comments