podman

Форк
0
/
container_copy_common.go 
212 строк · 5.7 Кб
1
//go:build !remote && (linux || freebsd)
2

3
package libpod
4

5
import (
6
	"errors"
7
	"io"
8
	"path/filepath"
9
	"strings"
10

11
	buildahCopiah "github.com/containers/buildah/copier"
12
	"github.com/containers/buildah/pkg/chrootuser"
13
	"github.com/containers/buildah/util"
14
	"github.com/containers/podman/v5/libpod/define"
15
	"github.com/containers/podman/v5/pkg/rootless"
16
	"github.com/containers/storage/pkg/archive"
17
	"github.com/containers/storage/pkg/idtools"
18
	"github.com/opencontainers/runtime-spec/specs-go"
19
	"github.com/sirupsen/logrus"
20
)
21

22
func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir bool, rename map[string]string, reader io.Reader) (func() error, error) {
23
	var (
24
		mountPoint   string
25
		resolvedRoot string
26
		resolvedPath string
27
		unmount      func()
28
		err          error
29
	)
30

31
	// Make sure that "/" copies the *contents* of the mount point and not
32
	// the directory.
33
	if path == "/" {
34
		path = "/."
35
	}
36

37
	// Optimization: only mount if the container is not already.
38
	if c.state.Mounted {
39
		mountPoint = c.state.Mountpoint
40
		unmount = func() {}
41
	} else {
42
		// NOTE: make sure to unmount in error paths.
43
		mountPoint, err = c.mount()
44
		if err != nil {
45
			return nil, err
46
		}
47
		unmount = func() {
48
			if err := c.unmount(false); err != nil {
49
				logrus.Errorf("Failed to unmount container: %v", err)
50
			}
51
		}
52
	}
53

54
	resolvedRoot, resolvedPath, err = c.resolveCopyTarget(mountPoint, path)
55
	if err != nil {
56
		unmount()
57
		return nil, err
58
	}
59

60
	var idPair *idtools.IDPair
61
	if chown {
62
		// Make sure we chown the files to the container's main user and group ID.
63
		user, err := getContainerUser(c, mountPoint)
64
		if err != nil {
65
			unmount()
66
			return nil, err
67
		}
68
		idPair = &idtools.IDPair{UID: int(user.UID), GID: int(user.GID)}
69
	}
70

71
	decompressed, err := archive.DecompressStream(reader)
72
	if err != nil {
73
		unmount()
74
		return nil, err
75
	}
76

77
	logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID())
78

79
	return func() error {
80
		defer unmount()
81
		defer decompressed.Close()
82
		putOptions := buildahCopiah.PutOptions{
83
			UIDMap:               c.config.IDMappings.UIDMap,
84
			GIDMap:               c.config.IDMappings.GIDMap,
85
			ChownDirs:            idPair,
86
			ChownFiles:           idPair,
87
			NoOverwriteDirNonDir: noOverwriteDirNonDir,
88
			NoOverwriteNonDirDir: noOverwriteDirNonDir,
89
			Rename:               rename,
90
		}
91

92
		return c.joinMountAndExec(
93
			func() error {
94
				return buildahCopiah.Put(resolvedRoot, resolvedPath, putOptions, decompressed)
95
			},
96
		)
97
	}, nil
98
}
99

100
func (c *Container) copyToArchive(path string, writer io.Writer) (func() error, error) {
101
	var (
102
		mountPoint string
103
		unmount    func()
104
		err        error
105
	)
106

107
	// Optimization: only mount if the container is not already.
108
	if c.state.Mounted {
109
		mountPoint = c.state.Mountpoint
110
		unmount = func() {}
111
	} else {
112
		// NOTE: make sure to unmount in error paths.
113
		mountPoint, err = c.mount()
114
		if err != nil {
115
			return nil, err
116
		}
117
		unmount = func() {
118
			if err := c.unmount(false); err != nil {
119
				logrus.Errorf("Failed to unmount container: %v", err)
120
			}
121
		}
122
	}
123

124
	statInfo, resolvedRoot, resolvedPath, err := c.stat(mountPoint, path)
125
	if err != nil {
126
		unmount()
127
		return nil, err
128
	}
129

130
	// We optimistically chown to the host user.  In case of a hypothetical
131
	// container-to-container copy, the reading side will chown back to the
132
	// container user.
133
	user, err := getContainerUser(c, mountPoint)
134
	if err != nil {
135
		unmount()
136
		return nil, err
137
	}
138
	hostUID, hostGID, err := util.GetHostIDs(
139
		idtoolsToRuntimeSpec(c.config.IDMappings.UIDMap),
140
		idtoolsToRuntimeSpec(c.config.IDMappings.GIDMap),
141
		user.UID,
142
		user.GID,
143
	)
144
	if err != nil {
145
		unmount()
146
		return nil, err
147
	}
148
	idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
149

150
	logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID())
151

152
	return func() error {
153
		defer unmount()
154
		getOptions := buildahCopiah.GetOptions{
155
			// Unless the specified points to ".", we want to copy the base directory.
156
			KeepDirectoryNames: statInfo.IsDir && filepath.Base(path) != ".",
157
			UIDMap:             c.config.IDMappings.UIDMap,
158
			GIDMap:             c.config.IDMappings.GIDMap,
159
			ChownDirs:          &idPair,
160
			ChownFiles:         &idPair,
161
			Excludes:           []string{"dev", "proc", "sys"},
162
			// Ignore EPERMs when copying from rootless containers
163
			// since we cannot read TTY devices.  Those are owned
164
			// by the host's root and hence "nobody" inside the
165
			// container's user namespace.
166
			IgnoreUnreadable: rootless.IsRootless() && c.state.State == define.ContainerStateRunning,
167
		}
168
		return c.joinMountAndExec(
169
			func() error {
170
				return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedPath}, writer)
171
			},
172
		)
173
	}, nil
174
}
175

176
// getContainerUser returns the specs.User and ID mappings of the container.
177
func getContainerUser(container *Container, mountPoint string) (specs.User, error) {
178
	userspec := container.config.User
179

180
	uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
181
	u := specs.User{
182
		UID:      uid,
183
		GID:      gid,
184
		Username: userspec,
185
	}
186

187
	if !strings.Contains(userspec, ":") {
188
		groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
189
		if err2 != nil {
190
			if !errors.Is(err2, chrootuser.ErrNoSuchUser) && err == nil {
191
				err = err2
192
			}
193
		} else {
194
			u.AdditionalGids = groups
195
		}
196
	}
197

198
	return u, err
199
}
200

201
// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec.
202
func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
203
	for _, idmap := range idMaps {
204
		tempIDMap := specs.LinuxIDMapping{
205
			ContainerID: uint32(idmap.ContainerID),
206
			HostID:      uint32(idmap.HostID),
207
			Size:        uint32(idmap.Size),
208
		}
209
		convertedIDMap = append(convertedIDMap, tempIDMap)
210
	}
211
	return convertedIDMap
212
}
213

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

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

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

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