|
9 | 9 | "errors"
|
10 | 10 | "fmt"
|
11 | 11 | "os"
|
| 12 | + "os/exec" |
12 | 13 | "path/filepath"
|
13 | 14 | "strings"
|
14 | 15 |
|
@@ -281,12 +282,12 @@ func (s3st *s3Storage) BackupObject(name string) string {
|
281 | 282 |
|
282 | 283 | // Download implements DirectAccess
|
283 | 284 | func (s3st *s3Storage) Download(ctx context.Context, destination string, name string, mappings []archive.IDMapping) (found bool, err error) {
|
284 |
| - return s3st.download(ctx, destination, s3st.objectName(name), mappings) |
| 285 | + return s3st.downloadS5cmd(ctx, destination, s3st.objectName(name), mappings) |
285 | 286 | }
|
286 | 287 |
|
287 | 288 | // DownloadSnapshot implements DirectAccess
|
288 | 289 | func (s3st *s3Storage) DownloadSnapshot(ctx context.Context, destination string, name string, mappings []archive.IDMapping) (found bool, err error) {
|
289 |
| - return s3st.download(ctx, destination, name, mappings) |
| 290 | + return s3st.downloadS5cmd(ctx, destination, name, mappings) |
290 | 291 | }
|
291 | 292 |
|
292 | 293 | func (s3st *s3Storage) download(ctx context.Context, destination string, obj string, mappings []archive.IDMapping) (found bool, err error) {
|
@@ -323,6 +324,43 @@ func (s3st *s3Storage) download(ctx context.Context, destination string, obj str
|
323 | 324 | return true, nil
|
324 | 325 | }
|
325 | 326 |
|
| 327 | +// download object using s5cmd |
| 328 | +func (s3st *s3Storage) downloadS5cmd(ctx context.Context, destination string, obj string, mappings []archive.IDMapping) (found bool, err error) { |
| 329 | + tempFile, err := os.CreateTemp("", "temporal-s3-file") |
| 330 | + if err != nil { |
| 331 | + return true, xerrors.Errorf("creating temporal file: %s", err.Error()) |
| 332 | + } |
| 333 | + tempFile.Close() |
| 334 | + |
| 335 | + args := []string{ |
| 336 | + "--numworkers", "20", |
| 337 | + "cp", "--part-size", "25", |
| 338 | + destination, |
| 339 | + tempFile.Name(), |
| 340 | + } |
| 341 | + cmd := exec.Command("s5cmd", args...) |
| 342 | + out, err := cmd.CombinedOutput() |
| 343 | + if err != nil { |
| 344 | + log.WithError(err).WithField("out", string(out)).Error("unexpected error downloading file") |
| 345 | + return true, xerrors.Errorf("unexpected error downloading file") |
| 346 | + } |
| 347 | + |
| 348 | + tempFile, err = os.Open(tempFile.Name()) |
| 349 | + if err != nil { |
| 350 | + return true, xerrors.Errorf("unexpected error opening downloaded file") |
| 351 | + } |
| 352 | + |
| 353 | + defer os.Remove(tempFile.Name()) |
| 354 | + defer tempFile.Close() |
| 355 | + |
| 356 | + err = archive.ExtractTarbal(ctx, tempFile, destination, archive.WithUIDMapping(mappings), archive.WithGIDMapping(mappings)) |
| 357 | + if err != nil { |
| 358 | + return true, xerrors.Errorf("tar %s: %s", destination, err.Error()) |
| 359 | + } |
| 360 | + |
| 361 | + return true, nil |
| 362 | +} |
| 363 | + |
326 | 364 | // EnsureExists implements DirectAccess
|
327 | 365 | func (*s3Storage) EnsureExists(ctx context.Context) error {
|
328 | 366 | return nil
|
|
0 commit comments