summaryrefslogtreecommitdiff
path: root/libpod/container_copy_linux.go
diff options
context:
space:
mode:
authorDoug Rabson <dfr@rabson.org>2022-08-25 08:12:52 +0100
committerDoug Rabson <dfr@rabson.org>2022-09-20 08:36:23 +0100
commit0b02d4cee6e3edd8a98ebe584f03169120ef5be4 (patch)
tree2e2a9e8c2e1c8d4142c4c3ba3ed1e0662c19106f /libpod/container_copy_linux.go
parent24d1290710f79aff53c482f492c3904e4d95ba31 (diff)
downloadpodman-0b02d4cee6e3edd8a98ebe584f03169120ef5be4.tar.gz
podman-0b02d4cee6e3edd8a98ebe584f03169120ef5be4.tar.bz2
podman-0b02d4cee6e3edd8a98ebe584f03169120ef5be4.zip
libpod: Move container_copy_linux.go to container_copy_common.go
[NO NEW TESTS NEEDED] Signed-off-by: Doug Rabson <dfr@rabson.org>
Diffstat (limited to 'libpod/container_copy_linux.go')
-rw-r--r--libpod/container_copy_linux.go290
1 files changed, 0 insertions, 290 deletions
diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go
deleted file mode 100644
index 557fead1e..000000000
--- a/libpod/container_copy_linux.go
+++ /dev/null
@@ -1,290 +0,0 @@
-//go:build linux
-// +build linux
-
-package libpod
-
-import (
- "errors"
- "fmt"
- "io"
- "os"
- "path/filepath"
- "runtime"
- "strings"
-
- buildahCopiah "github.com/containers/buildah/copier"
- "github.com/containers/buildah/pkg/chrootuser"
- "github.com/containers/buildah/util"
- "github.com/containers/podman/v4/libpod/define"
- "github.com/containers/podman/v4/pkg/rootless"
- "github.com/containers/storage/pkg/archive"
- "github.com/containers/storage/pkg/idtools"
- "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/sirupsen/logrus"
- "golang.org/x/sys/unix"
-)
-
-func (c *Container) copyFromArchive(path string, chown, noOverwriteDirNonDir bool, rename map[string]string, reader io.Reader) (func() error, error) {
- var (
- mountPoint string
- resolvedRoot string
- resolvedPath string
- unmount func()
- err error
- )
-
- // Make sure that "/" copies the *contents* of the mount point and not
- // the directory.
- if path == "/" {
- path = "/."
- }
-
- // Optimization: only mount if the container is not already.
- if c.state.Mounted {
- mountPoint = c.state.Mountpoint
- unmount = func() {}
- } else {
- // NOTE: make sure to unmount in error paths.
- mountPoint, err = c.mount()
- if err != nil {
- return nil, err
- }
- unmount = func() {
- if err := c.unmount(false); err != nil {
- logrus.Errorf("Failed to unmount container: %v", err)
- }
- }
- }
-
- if c.state.State == define.ContainerStateRunning {
- resolvedRoot = "/"
- resolvedPath = c.pathAbs(path)
- } else {
- resolvedRoot, resolvedPath, err = c.resolvePath(mountPoint, path)
- if err != nil {
- unmount()
- return nil, err
- }
- }
-
- var idPair *idtools.IDPair
- if chown {
- // Make sure we chown the files to the container's main user and group ID.
- user, err := getContainerUser(c, mountPoint)
- if err != nil {
- unmount()
- return nil, err
- }
- idPair = &idtools.IDPair{UID: int(user.UID), GID: int(user.GID)}
- }
-
- decompressed, err := archive.DecompressStream(reader)
- if err != nil {
- unmount()
- return nil, err
- }
-
- logrus.Debugf("Container copy *to* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID())
-
- return func() error {
- defer unmount()
- defer decompressed.Close()
- putOptions := buildahCopiah.PutOptions{
- UIDMap: c.config.IDMappings.UIDMap,
- GIDMap: c.config.IDMappings.GIDMap,
- ChownDirs: idPair,
- ChownFiles: idPair,
- NoOverwriteDirNonDir: noOverwriteDirNonDir,
- NoOverwriteNonDirDir: noOverwriteDirNonDir,
- Rename: rename,
- }
-
- return c.joinMountAndExec(
- func() error {
- return buildahCopiah.Put(resolvedRoot, resolvedPath, putOptions, decompressed)
- },
- )
- }, nil
-}
-
-func (c *Container) copyToArchive(path string, writer io.Writer) (func() error, error) {
- var (
- mountPoint string
- unmount func()
- err error
- )
-
- // Optimization: only mount if the container is not already.
- if c.state.Mounted {
- mountPoint = c.state.Mountpoint
- unmount = func() {}
- } else {
- // NOTE: make sure to unmount in error paths.
- mountPoint, err = c.mount()
- if err != nil {
- return nil, err
- }
- unmount = func() {
- if err := c.unmount(false); err != nil {
- logrus.Errorf("Failed to unmount container: %v", err)
- }
- }
- }
-
- statInfo, resolvedRoot, resolvedPath, err := c.stat(mountPoint, path)
- if err != nil {
- unmount()
- return nil, err
- }
-
- // We optimistically chown to the host user. In case of a hypothetical
- // container-to-container copy, the reading side will chown back to the
- // container user.
- user, err := getContainerUser(c, mountPoint)
- if err != nil {
- unmount()
- return nil, err
- }
- hostUID, hostGID, err := util.GetHostIDs(
- idtoolsToRuntimeSpec(c.config.IDMappings.UIDMap),
- idtoolsToRuntimeSpec(c.config.IDMappings.GIDMap),
- user.UID,
- user.GID,
- )
- if err != nil {
- unmount()
- return nil, err
- }
- idPair := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
-
- logrus.Debugf("Container copy *from* %q (resolved: %q) on container %q (ID: %s)", path, resolvedPath, c.Name(), c.ID())
-
- return func() error {
- defer unmount()
- getOptions := buildahCopiah.GetOptions{
- // Unless the specified points to ".", we want to copy the base directory.
- KeepDirectoryNames: statInfo.IsDir && filepath.Base(path) != ".",
- UIDMap: c.config.IDMappings.UIDMap,
- GIDMap: c.config.IDMappings.GIDMap,
- ChownDirs: &idPair,
- ChownFiles: &idPair,
- Excludes: []string{"dev", "proc", "sys"},
- // Ignore EPERMs when copying from rootless containers
- // since we cannot read TTY devices. Those are owned
- // by the host's root and hence "nobody" inside the
- // container's user namespace.
- IgnoreUnreadable: rootless.IsRootless() && c.state.State == define.ContainerStateRunning,
- }
- return c.joinMountAndExec(
- func() error {
- return buildahCopiah.Get(resolvedRoot, "", getOptions, []string{resolvedPath}, writer)
- },
- )
- }, nil
-}
-
-// getContainerUser returns the specs.User and ID mappings of the container.
-func getContainerUser(container *Container, mountPoint string) (specs.User, error) {
- userspec := container.config.User
-
- uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
- u := specs.User{
- UID: uid,
- GID: gid,
- Username: userspec,
- }
-
- if !strings.Contains(userspec, ":") {
- groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
- if err2 != nil {
- if !errors.Is(err2, chrootuser.ErrNoSuchUser) && err == nil {
- err = err2
- }
- } else {
- u.AdditionalGids = groups
- }
- }
-
- return u, err
-}
-
-// idtoolsToRuntimeSpec converts idtools ID mapping to the one of the runtime spec.
-func idtoolsToRuntimeSpec(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
- for _, idmap := range idMaps {
- tempIDMap := specs.LinuxIDMapping{
- ContainerID: uint32(idmap.ContainerID),
- HostID: uint32(idmap.HostID),
- Size: uint32(idmap.Size),
- }
- convertedIDMap = append(convertedIDMap, tempIDMap)
- }
- return convertedIDMap
-}
-
-// joinMountAndExec executes the specified function `f` inside the container's
-// mount and PID namespace. That allows for having the exact view on the
-// container's file system.
-//
-// Note, if the container is not running `f()` will be executed as is.
-func (c *Container) joinMountAndExec(f func() error) error {
- if c.state.State != define.ContainerStateRunning {
- return f()
- }
-
- // Container's running, so we need to execute `f()` inside its mount NS.
- errChan := make(chan error)
- go func() {
- runtime.LockOSThread()
-
- // Join the mount and PID NS of the container.
- getFD := func(ns LinuxNS) (*os.File, error) {
- nsPath, err := c.namespacePath(ns)
- if err != nil {
- return nil, err
- }
- return os.Open(nsPath)
- }
-
- mountFD, err := getFD(MountNS)
- if err != nil {
- errChan <- err
- return
- }
- defer mountFD.Close()
-
- inHostPidNS, err := c.inHostPidNS()
- if err != nil {
- errChan <- fmt.Errorf("checking inHostPidNS: %w", err)
- return
- }
- var pidFD *os.File
- if !inHostPidNS {
- pidFD, err = getFD(PIDNS)
- if err != nil {
- errChan <- err
- return
- }
- defer pidFD.Close()
- }
-
- if err := unix.Unshare(unix.CLONE_NEWNS); err != nil {
- errChan <- err
- return
- }
-
- if pidFD != nil {
- if err := unix.Setns(int(pidFD.Fd()), unix.CLONE_NEWPID); err != nil {
- errChan <- err
- return
- }
- }
- if err := unix.Setns(int(mountFD.Fd()), unix.CLONE_NEWNS); err != nil {
- errChan <- err
- return
- }
-
- // Last but not least, execute the workload.
- errChan <- f()
- }()
- return <-errChan
-}