From 3371c9d25ef12320b49137c34cf2efdf3b8e238b Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <vrothberg@redhat.com>
Date: Thu, 10 Nov 2022 16:59:07 +0100
Subject: [PATCH] podman cp: fix copying with "." suffix

Fix a bug for special-casing "." where Podman has mistakenly been
looking for a "." suffix instead of interpreting it as a path.

Add regression tests for the host-to-container, container-to-host and
container-to-container use cases.  Have separate tests for each to
verify that previous Podman versions fail each case.

Fixes: #16421
Signed-off-by: Valentin Rothberg <vrothberg@redhat.com>
---
 cmd/podman/containers/cp.go |  6 +++---
 test/system/065-cp.bats     | 38 +++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/cmd/podman/containers/cp.go b/cmd/podman/containers/cp.go
index 9e63169a0c..5231066a2e 100644
--- a/cmd/podman/containers/cp.go
+++ b/cmd/podman/containers/cp.go
@@ -158,7 +158,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
 	// Hence, whenever "." is the source and the destination does not
 	// exist, we copy the source's parent and let the copier package create
 	// the destination via the Rename option.
-	if destResolvedToParentDir && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") {
+	if destResolvedToParentDir && sourceContainerInfo.IsDir && filepath.Base(sourcePath) == "." {
 		sourceContainerTarget = filepath.Dir(sourceContainerTarget)
 	}
 
@@ -261,7 +261,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
 	// we copy the source's parent and let the copier package create the
 	// destination via the Rename option.
 	containerTarget := containerInfo.LinkTarget
-	if resolvedToHostParentDir && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
+	if resolvedToHostParentDir && containerInfo.IsDir && filepath.Base(containerTarget) == "." {
 		containerTarget = filepath.Dir(containerTarget)
 	}
 
@@ -365,7 +365,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
 	// exist, we copy the source's parent and let the copier package create
 	// the destination via the Rename option.
 	hostTarget := hostInfo.LinkTarget
-	if containerResolvedToParentDir && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
+	if containerResolvedToParentDir && hostInfo.IsDir && filepath.Base(hostTarget) == "." {
 		hostTarget = filepath.Dir(hostTarget)
 	}
 
diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats
index c8ad8468c5..e712810a27 100644
--- a/test/system/065-cp.bats
+++ b/test/system/065-cp.bats
@@ -1047,6 +1047,44 @@ ${randomcontent[1]}" "$description"
     run_podman rm -t 0 -f ctr-file ctr-dir
 }
 
+@test "podman cp - dot notation - host to container" {
+    srcdir=$PODMAN_TMPDIR/src
+    mkdir -p $srcdir
+    mkdir -p $srcdir/test1. $srcdir/test2
+    touch $srcdir/test1./file1 $srcdir/test2/file2
+
+    run_podman run -d --name=test-ctr --rm $IMAGE sleep infinity
+    run_podman cp $srcdir/test1. test-ctr:/tmp/foo
+    run_podman exec test-ctr stat /tmp/foo/file1
+
+    run_podman rm -f -t0 test-ctr
+}
+
+@test "podman cp - dot notation - container to host" {
+    dstdir=$PODMAN_TMPDIR/dst
+    mkdir -p $dstdir
+
+    run_podman run -d --name=test-ctr --rm $IMAGE sh -c "mkdir -p /foo/test1. /foo/test2; touch /foo/test1./file1 /foo/test2/file2; sleep infinity"
+    run_podman cp test-ctr:/foo/test1. $dstdir/foo
+    run stat $dstdir/foo/test1.
+    if [[ -e $dstdir/foo/test2 ]]; then
+        die "the test2 directory should not have been copied over"
+    fi
+
+    run_podman rm -f -t0 test-ctr
+}
+
+@test "podman cp - dot notation - container to container" {
+    run_podman run -d --name=src-ctr --rm $IMAGE sh -c "mkdir -p /foo/test1. /foo/test2; touch /foo/test1./file1 /foo/test2/file2; sleep infinity"
+    run_podman run -d --name=dest-ctr --rm $IMAGE sleep infinity
+    run_podman cp src-ctr:/foo/test1. dest-ctr:/foo
+
+    run_podman exec dest-ctr find /foo
+    run_podman exec dest-ctr stat /foo/file1
+
+    run_podman rm -f -t0 src-ctr dest-ctr
+}
+
 function teardown() {
     # In case any test fails, clean up the container we left behind
     run_podman rm -t 0 -f --ignore cpcontainer