talos

Форк
0
/
untar.go 
90 строк · 2.0 Кб
1
// This Source Code Form is subject to the terms of the Mozilla Public
2
// License, v. 2.0. If a copy of the MPL was not distributed with this
3
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
package archiver
6

7
import (
8
	"archive/tar"
9
	"context"
10
	"errors"
11
	"fmt"
12
	"io"
13
	"os"
14
	"path/filepath"
15

16
	"github.com/siderolabs/talos/pkg/safepath"
17
)
18

19
// Untar extracts .tar archive from r into filesystem under rootPath.
20
//
21
//nolint:gocyclo
22
func Untar(ctx context.Context, r io.Reader, rootPath string) error {
23
	tr := tar.NewReader(r)
24

25
	for {
26
		select {
27
		case <-ctx.Done():
28
			return ctx.Err()
29
		default:
30
		}
31

32
		hdr, err := tr.Next()
33
		if err != nil {
34
			if err == io.EOF {
35
				break
36
			}
37

38
			return fmt.Errorf("error reading tar header: %s", err)
39
		}
40

41
		hdrPath := safepath.CleanPath(hdr.Name)
42
		if hdrPath == "" {
43
			return errors.New("empty tar header path")
44
		}
45

46
		path := filepath.Join(rootPath, hdrPath)
47

48
		switch hdr.Typeflag {
49
		case tar.TypeDir:
50
			mode := hdr.FileInfo().Mode()
51
			mode |= 0o700 // make rwx for the owner
52

53
			if err = os.Mkdir(path, mode); err != nil {
54
				return fmt.Errorf("error creating directory %q mode %s: %w", path, mode, err)
55
			}
56

57
			if err = os.Chmod(path, mode); err != nil {
58
				return fmt.Errorf("error updating mode %s for %q: %w", mode, path, err)
59
			}
60

61
		case tar.TypeSymlink:
62
			if err = os.Symlink(hdr.Linkname, path); err != nil {
63
				return fmt.Errorf("error creating symlink %q -> %q: %w", path, hdr.Linkname, err)
64
			}
65

66
		default:
67
			mode := hdr.FileInfo().Mode()
68

69
			fp, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_EXCL, mode)
70
			if err != nil {
71
				return fmt.Errorf("error creating file %q mode %s: %w", path, mode, err)
72
			}
73

74
			_, err = io.Copy(fp, tr)
75
			if err != nil {
76
				return fmt.Errorf("error copying data to %q: %w", path, err)
77
			}
78

79
			if err = fp.Close(); err != nil {
80
				return fmt.Errorf("error closing %q: %w", path, err)
81
			}
82

83
			if err = os.Chmod(path, mode); err != nil {
84
				return fmt.Errorf("error updating mode %s for %q: %w", mode, path, err)
85
			}
86
		}
87
	}
88

89
	return nil
90
}
91

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.