1
//go:build !remote && (linux || freebsd)
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"
22
func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir bool, rename map[string]string, reader io.Reader) (func() error, error) {
31
// Make sure that "/" copies the *contents* of the mount point and not
37
// Optimization: only mount if the container is not already.
39
mountPoint = c.state.Mountpoint
42
// NOTE: make sure to unmount in error paths.
43
mountPoint, err = c.mount()
48
if err := c.unmount(false); err != nil {
49
logrus.Errorf("Failed to unmount container: %v", err)
54
resolvedRoot, resolvedPath, err = c.resolveCopyTarget(mountPoint, path)
60
var idPair *idtools.IDPair
62
// Make sure we chown the files to the container's main user and group ID.
63
user, err := getContainerUser(c, mountPoint)
68
idPair = &idtools.IDPair{UID: int(user.UID), GID: int(user.GID)}
71
decompressed, err := archive.DecompressStream(reader)
77
logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID())
81
defer decompressed.Close()
82
putOptions := buildahCopiah.PutOptions{
83
UIDMap: c.config.IDMappings.UIDMap,
84
GIDMap: c.config.IDMappings.GIDMap,
87
NoOverwriteDirNonDir: noOverwriteDirNonDir,
88
NoOverwriteNonDirDir: noOverwriteDirNonDir,
92
return c.joinMountAndExec(
94
return buildahCopiah.Put(resolvedRoot, resolvedPath, putOptions, decompressed)
100
func (c *Container) copyToArchive(path string, writer io.Writer) (func() error, error) {
107
// Optimization: only mount if the container is not already.
109
mountPoint = c.state.Mountpoint
112
// NOTE: make sure to unmount in error paths.
113
mountPoint, err = c.mount()
118
if err := c.unmount(false); err != nil {
119
logrus.Errorf("Failed to unmount container: %v", err)
124
statInfo, resolvedRoot, resolvedPath, err := c.stat(mountPoint, path)
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
133
user, err := getContainerUser(c, mountPoint)
138
hostUID, hostGID, err := util.GetHostIDs(
139
idtoolsToRuntimeSpec(c.config.IDMappings.UIDMap),
140
idtoolsToRuntimeSpec(c.config.IDMappings.GIDMap),
148
idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
150
logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID())
152
return func() error {
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,
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,
168
return c.joinMountAndExec(
170
return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedPath}, writer)
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
180
uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
187
if !strings.Contains(userspec, ":") {
188
groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
190
if !errors.Is(err2, chrootuser.ErrNoSuchUser) && err == nil {
194
u.AdditionalGids = groups
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),
209
convertedIDMap = append(convertedIDMap, tempIDMap)
211
return convertedIDMap