diff --git a/cmd/podman/containers/cp.go b/cmd/podman/containers/cp.go index be8c8c1a3c..648c7d5f55 100644 --- a/cmd/podman/containers/cp.go +++ b/cmd/podman/containers/cp.go @@ -339,16 +339,18 @@ func copyToContainer(container string, containerPath string, hostPath string) er return err } + hostInfo := ©.FileInfo{} + var err error + isStdin := false if hostPath == "-" { - hostPath = os.Stdin.Name() isStdin = true - } - - // Make sure that host path exists. - hostInfo, err := copy.ResolveHostPath(hostPath) - if err != nil { - return fmt.Errorf("%q could not be found on the host: %w", hostPath, err) + } else { + // Make sure that host path exists if not copying from stdin. + hostInfo, err = copy.ResolveHostPath(hostPath) + if err != nil { + return fmt.Errorf("%q could not be found on the host: %w", hostPath, err) + } } containerBaseName, containerInfo, containerResolvedToParentDir, err := resolvePathOnDestinationContainer(container, containerPath, isStdin) diff --git a/pkg/machine/e2e/basic_test.go b/pkg/machine/e2e/basic_test.go index c060479cd9..753066b9fb 100644 --- a/pkg/machine/e2e/basic_test.go +++ b/pkg/machine/e2e/basic_test.go @@ -1,8 +1,11 @@ package e2e_test import ( + "archive/tar" + "bytes" "fmt" "io" + "io/fs" "net" "net/http" "net/url" @@ -253,6 +256,87 @@ var _ = Describe("run basic podman commands", func() { Expect(run).To(Exit(0)) Expect(build.outputToString()).To(ContainSubstring(name)) }) + + It("Copy ops", func() { + var ( + stdinDirectory = "stdin-dir" + stdinFile = "file.txt" + ) + + now := time.Now() + + tarBuffer := &bytes.Buffer{} + tw := tar.NewWriter(tarBuffer) + + // Write a directory header to the tar + err := tw.WriteHeader(&tar.Header{ + Name: stdinDirectory, + Mode: int64(0640 | fs.ModeDir), + Gid: 1000, + ModTime: now, + ChangeTime: now, + AccessTime: now, + Typeflag: tar.TypeDir, + }) + Expect(err).ToNot(HaveOccurred()) + + // Write a file header to the tar + err = tw.WriteHeader(&tar.Header{ + Name: path.Join(stdinDirectory, stdinFile), + Mode: 0755, + Uid: 1000, + ModTime: now, + ChangeTime: now, + AccessTime: now, + }) + Expect(err).ToNot(HaveOccurred()) + + err = tw.Close() + Expect(err).ToNot(HaveOccurred()) + + name := randomString() + i := new(initMachine) + session, err := mb.setName(name).setCmd(i.withImage(mb.imagePath).withNow()).run() + Expect(err).ToNot(HaveOccurred()) + Expect(session).To(Exit(0)) + + bm := basicMachine{} + newImgs, err := mb.setCmd(bm.withPodmanCommand([]string{"pull", "quay.io/libpod/alpine_nginx"})).run() + Expect(err).ToNot(HaveOccurred()) + Expect(newImgs).To(Exit(0)) + Expect(newImgs.outputToStringSlice()).To(HaveLen(1)) + + createAlp, err := mb.setCmd(bm.withPodmanCommand([]string{"create", "quay.io/libpod/alpine_nginx"})).run() + Expect(err).ToNot(HaveOccurred()) + Expect(createAlp).To(Exit(0)) + Expect(createAlp.outputToStringSlice()).To(HaveLen(1)) + + // Testing stdin copy with archive mode disabled (ownership will be determined by the tar file) + containerID := createAlp.outputToStringSlice()[0] + cpTar, err := mb.setCmd(bm.withPodmanCommand([]string{"cp", "-a=false", "-", containerID + ":/tmp"})).setStdin(tarBuffer).run() + Expect(err).ToNot(HaveOccurred()) + Expect(cpTar).To(Exit(0)) + + start, err := mb.setCmd(bm.withPodmanCommand([]string{"start", containerID})).run() + Expect(err).ToNot(HaveOccurred()) + Expect(start).To(Exit(0)) + + // Check the directory is created with the appropriate mode, uid, gid + exec, err := mb.setCmd(bm.withPodmanCommand([]string{"exec", containerID, "stat", "-c", "%a %u %g", "/tmp/stdin-dir"})).run() + Expect(err).ToNot(HaveOccurred()) + Expect(exec).To(Exit(0)) + execStdOut := exec.outputToStringSlice() + Expect(execStdOut).To(HaveLen(1)) + Expect(execStdOut[0]).To(Equal("640 0 1000")) + + // Check the file is created with the appropriate mode, uid, gid + exec, err = mb.setCmd(bm.withPodmanCommand([]string{"exec", containerID, "stat", "-c", "%a %u %g", "/tmp/stdin-dir/file.txt"})).run() + Expect(err).ToNot(HaveOccurred()) + Expect(exec).To(Exit(0)) + execStdOut = exec.outputToStringSlice() + Expect(execStdOut).To(HaveLen(1)) + Expect(execStdOut[0]).To(Equal("755 1000 0")) + }) }) func testHTTPServer(port string, shouldErr bool, expectedResponse string) { diff --git a/pkg/machine/e2e/config_test.go b/pkg/machine/e2e/config_test.go index 7d2d420c70..388cdc272e 100644 --- a/pkg/machine/e2e/config_test.go +++ b/pkg/machine/e2e/config_test.go @@ -3,6 +3,7 @@ package e2e_test import ( "encoding/json" "fmt" + "io" "os" "os/exec" "path/filepath" @@ -44,6 +45,7 @@ type machineSession struct { type machineTestBuilder struct { cmd []string + stdin io.Reader imagePath string name string names []string @@ -139,6 +141,13 @@ func (m *machineTestBuilder) setCmd(mc machineCommand) *machineTestBuilder { m.names = append(m.names, m.name) } m.cmd = mc.buildCmd(m) + m.stdin = nil + return m +} + +// setStdin sets the stdin for the next command to be run +func (m *machineTestBuilder) setStdin(data io.Reader) *machineTestBuilder { + m.stdin = data return m } @@ -152,7 +161,7 @@ func (m *machineTestBuilder) setTimeout(timeout time.Duration) *machineTestBuild func (m *machineTestBuilder) toQemuInspectInfo() ([]machine.InspectInfo, int, error) { args := []string{"machine", "inspect"} args = append(args, m.names...) - session, err := runWrapper(m.podmanBinary, args, defaultTimeout, true) + session, err := runWrapper(m.podmanBinary, args, nil, defaultTimeout, true) if err != nil { return nil, -1, err } @@ -162,20 +171,24 @@ func (m *machineTestBuilder) toQemuInspectInfo() ([]machine.InspectInfo, int, er } func (m *machineTestBuilder) runWithoutWait() (*machineSession, error) { - return runWrapper(m.podmanBinary, m.cmd, m.timeout, false) + return runWrapper(m.podmanBinary, m.cmd, m.stdin, m.timeout, false) } func (m *machineTestBuilder) run() (*machineSession, error) { - s, err := runWrapper(m.podmanBinary, m.cmd, m.timeout, true) + s, err := runWrapper(m.podmanBinary, m.cmd, m.stdin, m.timeout, true) return s, err } -func runWrapper(podmanBinary string, cmdArgs []string, timeout time.Duration, wait bool) (*machineSession, error) { +func runWrapper(podmanBinary string, cmdArgs []string, stdinData io.Reader, timeout time.Duration, wait bool) (*machineSession, error) { if len(os.Getenv("DEBUG")) > 0 { cmdArgs = append([]string{"--log-level=debug"}, cmdArgs...) } GinkgoWriter.Println(podmanBinary + " " + strings.Join(cmdArgs, " ")) c := exec.Command(podmanBinary, cmdArgs...) + if stdinData != nil { + c.Stdin = stdinData + } + session, err := Start(c, GinkgoWriter, GinkgoWriter) if err != nil { Fail(fmt.Sprintf("Unable to start session: %q", err))