podman

Форк
0
/
fileinfo.go 
105 строк · 2.8 Кб
1
package copy
2

3
import (
4
	"encoding/base64"
5
	"encoding/json"
6
	"errors"
7
	"fmt"
8
	"net/http"
9
	"os"
10
	"path/filepath"
11
	"strings"
12

13
	"github.com/containers/podman/v5/libpod/define"
14
)
15

16
// XDockerContainerPathStatHeader is the *key* in http headers pointing to the
17
// base64 encoded JSON payload of stating a path in a container.
18
const XDockerContainerPathStatHeader = "X-Docker-Container-Path-Stat"
19

20
// ErrENOENT mimics the stdlib's ErrENOENT and can be used to implement custom logic
21
// while preserving the user-visible error message.
22
var ErrENOENT = errors.New("no such file or directory")
23

24
// FileInfo describes a file or directory and is returned by
25
// (*CopyItem).Stat().
26
type FileInfo = define.FileInfo
27

28
// EncodeFileInfo serializes the specified FileInfo as a base64 encoded JSON
29
// payload.  Intended for Docker compat.
30
func EncodeFileInfo(info *FileInfo) (string, error) {
31
	buf, err := json.Marshal(&info)
32
	if err != nil {
33
		return "", fmt.Errorf("failed to serialize file stats: %w", err)
34
	}
35
	return base64.URLEncoding.EncodeToString(buf), nil
36
}
37

38
// ExtractFileInfoFromHeader extracts a base64 encoded JSON payload of a
39
// FileInfo in the http header.  If no such header entry is found, nil is
40
// returned.  Intended for Docker compat.
41
func ExtractFileInfoFromHeader(header *http.Header) (*FileInfo, error) {
42
	rawData := header.Get(XDockerContainerPathStatHeader)
43
	if len(rawData) == 0 {
44
		return nil, nil
45
	}
46

47
	info := FileInfo{}
48
	base64Decoder := base64.NewDecoder(base64.URLEncoding, strings.NewReader(rawData))
49
	if err := json.NewDecoder(base64Decoder).Decode(&info); err != nil {
50
		return nil, err
51
	}
52

53
	return &info, nil
54
}
55

56
// ResolveHostPath resolves the specified, possibly relative, path on the host.
57
func ResolveHostPath(path string) (*FileInfo, error) {
58
	resolvedHostPath, err := filepath.Abs(path)
59
	if err != nil {
60
		return nil, err
61
	}
62
	resolvedHostPath = PreserveBasePath(path, resolvedHostPath)
63

64
	statInfo, err := os.Stat(resolvedHostPath)
65
	if err != nil {
66
		if os.IsNotExist(err) {
67
			return nil, ErrENOENT
68
		}
69
		return nil, err
70
	}
71

72
	return &FileInfo{
73
		Name:       statInfo.Name(),
74
		Size:       statInfo.Size(),
75
		Mode:       statInfo.Mode(),
76
		ModTime:    statInfo.ModTime(),
77
		IsDir:      statInfo.IsDir(),
78
		LinkTarget: resolvedHostPath,
79
	}, nil
80
}
81

82
// PreserveBasePath makes sure that the original base path (e.g., "/" or "./")
83
// is preserved.  The filepath API among tends to clean up a bit too much but
84
// we *must* preserve this data by all means.
85
func PreserveBasePath(original, resolved string) string {
86
	// Handle "/"
87
	if strings.HasSuffix(original, "/") {
88
		if !strings.HasSuffix(resolved, "/") {
89
			resolved += "/"
90
		}
91
		return resolved
92
	}
93

94
	// Handle "/."
95
	if strings.HasSuffix(original, "/.") {
96
		if strings.HasSuffix(resolved, "/") { // could be root!
97
			resolved += "."
98
		} else if !strings.HasSuffix(resolved, "/.") {
99
			resolved += "/."
100
		}
101
		return resolved
102
	}
103

104
	return resolved
105
}
106

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

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

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

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