Fix copy API (`docker cp`, etc) uid/gid handling
| ... | ... |
@@ -27,7 +27,7 @@ type copyBackend interface {
|
| 27 | 27 |
ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *types.ContainerPathStat, err error) |
| 28 | 28 |
ContainerCopy(name string, res string) (io.ReadCloser, error) |
| 29 | 29 |
ContainerExport(name string, out io.Writer) error |
| 30 |
- ContainerExtractToDir(name, path string, noOverwriteDirNonDir bool, content io.Reader) error |
|
| 30 |
+ ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error |
|
| 31 | 31 |
ContainerStatPath(name string, path string) (stat *types.ContainerPathStat, err error) |
| 32 | 32 |
} |
| 33 | 33 |
|
| ... | ... |
@@ -112,5 +112,7 @@ func (s *containerRouter) putContainersArchive(ctx context.Context, w http.Respo |
| 112 | 112 |
} |
| 113 | 113 |
|
| 114 | 114 |
noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir") |
| 115 |
- return s.backend.ContainerExtractToDir(v.Name, v.Path, noOverwriteDirNonDir, r.Body) |
|
| 115 |
+ copyUIDGID := httputils.BoolValue(r, "copyUIDGID") |
|
| 116 |
+ |
|
| 117 |
+ return s.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body) |
|
| 116 | 118 |
} |
| ... | ... |
@@ -20,6 +20,7 @@ type copyOptions struct {
|
| 20 | 20 |
source string |
| 21 | 21 |
destination string |
| 22 | 22 |
followLink bool |
| 23 |
+ copyUIDGID bool |
|
| 23 | 24 |
} |
| 24 | 25 |
|
| 25 | 26 |
type copyDirection int |
| ... | ... |
@@ -66,6 +67,7 @@ func NewCopyCommand(dockerCli *command.DockerCli) *cobra.Command {
|
| 66 | 66 |
flags := cmd.Flags() |
| 67 | 67 |
|
| 68 | 68 |
flags.BoolVarP(&opts.followLink, "follow-link", "L", false, "Always follow symbol link in SRC_PATH") |
| 69 |
+ flags.BoolVarP(&opts.copyUIDGID, "archive", "a", false, "Archive mode (copy all uid/gid information)") |
|
| 69 | 70 |
|
| 70 | 71 |
return cmd |
| 71 | 72 |
} |
| ... | ... |
@@ -92,7 +94,7 @@ func runCopy(dockerCli *command.DockerCli, opts copyOptions) error {
|
| 92 | 92 |
case fromContainer: |
| 93 | 93 |
return copyFromContainer(ctx, dockerCli, srcContainer, srcPath, dstPath, cpParam) |
| 94 | 94 |
case toContainer: |
| 95 |
- return copyToContainer(ctx, dockerCli, srcPath, dstContainer, dstPath, cpParam) |
|
| 95 |
+ return copyToContainer(ctx, dockerCli, srcPath, dstContainer, dstPath, cpParam, opts.copyUIDGID) |
|
| 96 | 96 |
case acrossContainers: |
| 97 | 97 |
// Copying between containers isn't supported. |
| 98 | 98 |
return errors.New("copying between containers is not supported")
|
| ... | ... |
@@ -175,7 +177,7 @@ func copyFromContainer(ctx context.Context, dockerCli *command.DockerCli, srcCon |
| 175 | 175 |
return archive.CopyTo(preArchive, srcInfo, dstPath) |
| 176 | 176 |
} |
| 177 | 177 |
|
| 178 |
-func copyToContainer(ctx context.Context, dockerCli *command.DockerCli, srcPath, dstContainer, dstPath string, cpParam *cpConfig) (err error) {
|
|
| 178 |
+func copyToContainer(ctx context.Context, dockerCli *command.DockerCli, srcPath, dstContainer, dstPath string, cpParam *cpConfig, copyUIDGID bool) (err error) {
|
|
| 179 | 179 |
if srcPath != "-" {
|
| 180 | 180 |
// Get an absolute source path. |
| 181 | 181 |
srcPath, err = resolveLocalPath(srcPath) |
| ... | ... |
@@ -265,6 +267,7 @@ func copyToContainer(ctx context.Context, dockerCli *command.DockerCli, srcPath, |
| 265 | 265 |
|
| 266 | 266 |
options := types.CopyToContainerOptions{
|
| 267 | 267 |
AllowOverwriteDirWithFile: false, |
| 268 |
+ CopyUIDGID: copyUIDGID, |
|
| 268 | 269 |
} |
| 269 | 270 |
|
| 270 | 271 |
return dockerCli.Client().CopyToContainer(ctx, dstContainer, resolvedDstPath, content, options) |
| ... | ... |
@@ -38,6 +38,10 @@ func (cli *Client) CopyToContainer(ctx context.Context, container, path string, |
| 38 | 38 |
query.Set("noOverwriteDirNonDir", "true")
|
| 39 | 39 |
} |
| 40 | 40 |
|
| 41 |
+ if options.CopyUIDGID {
|
|
| 42 |
+ query.Set("copyUIDGID", "true")
|
|
| 43 |
+ } |
|
| 44 |
+ |
|
| 41 | 45 |
apiPath := fmt.Sprintf("/containers/%s/archive", container)
|
| 42 | 46 |
|
| 43 | 47 |
response, err := cli.putRaw(ctx, apiPath, query, content, nil) |
| ... | ... |
@@ -83,7 +83,7 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io |
| 83 | 83 |
// be ErrExtractPointNotDirectory. If noOverwriteDirNonDir is true then it will |
| 84 | 84 |
// be an error if unpacking the given content would cause an existing directory |
| 85 | 85 |
// to be replaced with a non-directory and vice versa. |
| 86 |
-func (daemon *Daemon) ContainerExtractToDir(name, path string, noOverwriteDirNonDir bool, content io.Reader) error {
|
|
| 86 |
+func (daemon *Daemon) ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error {
|
|
| 87 | 87 |
container, err := daemon.GetContainer(name) |
| 88 | 88 |
if err != nil {
|
| 89 | 89 |
return err |
| ... | ... |
@@ -94,7 +94,7 @@ func (daemon *Daemon) ContainerExtractToDir(name, path string, noOverwriteDirNon |
| 94 | 94 |
return err |
| 95 | 95 |
} |
| 96 | 96 |
|
| 97 |
- return daemon.containerExtractToDir(container, path, noOverwriteDirNonDir, content) |
|
| 97 |
+ return daemon.containerExtractToDir(container, path, copyUIDGID, noOverwriteDirNonDir, content) |
|
| 98 | 98 |
} |
| 99 | 99 |
|
| 100 | 100 |
// containerStatPath stats the filesystem resource at the specified path in this |
| ... | ... |
@@ -196,7 +196,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path |
| 196 | 196 |
// noOverwriteDirNonDir is true then it will be an error if unpacking the |
| 197 | 197 |
// given content would cause an existing directory to be replaced with a non- |
| 198 | 198 |
// directory and vice versa. |
| 199 |
-func (daemon *Daemon) containerExtractToDir(container *container.Container, path string, noOverwriteDirNonDir bool, content io.Reader) (err error) {
|
|
| 199 |
+func (daemon *Daemon) containerExtractToDir(container *container.Container, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) (err error) {
|
|
| 200 | 200 |
container.Lock() |
| 201 | 201 |
defer container.Unlock() |
| 202 | 202 |
|
| ... | ... |
@@ -279,13 +279,18 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path |
| 279 | 279 |
return ErrRootFSReadOnly |
| 280 | 280 |
} |
| 281 | 281 |
|
| 282 |
- uid, gid := daemon.GetRemappedUIDGID() |
|
| 283 |
- options := &archive.TarOptions{
|
|
| 284 |
- NoOverwriteDirNonDir: noOverwriteDirNonDir, |
|
| 285 |
- ChownOpts: &archive.TarChownOptions{
|
|
| 286 |
- UID: uid, GID: gid, // TODO: should all ownership be set to root (either real or remapped)? |
|
| 287 |
- }, |
|
| 282 |
+ options := daemon.defaultTarCopyOptions(noOverwriteDirNonDir) |
|
| 283 |
+ |
|
| 284 |
+ if copyUIDGID {
|
|
| 285 |
+ var err error |
|
| 286 |
+ // tarCopyOptions will appropriately pull in the right uid/gid for the |
|
| 287 |
+ // user/group and will set the options. |
|
| 288 |
+ options, err = daemon.tarCopyOptions(container, noOverwriteDirNonDir) |
|
| 289 |
+ if err != nil {
|
|
| 290 |
+ return err |
|
| 291 |
+ } |
|
| 288 | 292 |
} |
| 293 |
+ |
|
| 289 | 294 |
if err := chrootarchive.Untar(content, resolvedPath, options); err != nil {
|
| 290 | 295 |
return err |
| 291 | 296 |
} |
| 292 | 297 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,16 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "github.com/docker/docker/pkg/archive" |
|
| 4 |
+) |
|
| 5 |
+ |
|
| 6 |
+// defaultTarCopyOptions is the setting that is used when unpacking an archive |
|
| 7 |
+// for a copy API event. |
|
| 8 |
+func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
|
|
| 9 |
+ uidMaps, gidMaps := daemon.GetUIDGIDMaps() |
|
| 10 |
+ return &archive.TarOptions{
|
|
| 11 |
+ NoOverwriteDirNonDir: noOverwriteDirNonDir, |
|
| 12 |
+ UIDMaps: uidMaps, |
|
| 13 |
+ GIDMaps: gidMaps, |
|
| 14 |
+ } |
|
| 15 |
+} |
| 0 | 16 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,28 @@ |
| 0 |
+// +build !windows |
|
| 1 |
+ |
|
| 2 |
+package daemon |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "github.com/docker/docker/container" |
|
| 6 |
+ "github.com/docker/docker/pkg/archive" |
|
| 7 |
+ "github.com/docker/docker/pkg/idtools" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwriteDirNonDir bool) (*archive.TarOptions, error) {
|
|
| 11 |
+ if container.Config.User == "" {
|
|
| 12 |
+ return daemon.defaultTarCopyOptions(noOverwriteDirNonDir), nil |
|
| 13 |
+ } |
|
| 14 |
+ |
|
| 15 |
+ user, err := idtools.LookupUser(container.Config.User) |
|
| 16 |
+ if err != nil {
|
|
| 17 |
+ return nil, err |
|
| 18 |
+ } |
|
| 19 |
+ |
|
| 20 |
+ return &archive.TarOptions{
|
|
| 21 |
+ NoOverwriteDirNonDir: noOverwriteDirNonDir, |
|
| 22 |
+ ChownOpts: &archive.TarChownOptions{
|
|
| 23 |
+ UID: user.Uid, |
|
| 24 |
+ GID: user.Gid, |
|
| 25 |
+ }, |
|
| 26 |
+ }, nil |
|
| 27 |
+} |
| 0 | 28 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,12 @@ |
| 0 |
+// +build windows |
|
| 1 |
+ |
|
| 2 |
+package daemon |
|
| 3 |
+ |
|
| 4 |
+import ( |
|
| 5 |
+ "github.com/docker/docker/container" |
|
| 6 |
+ "github.com/docker/docker/pkg/archive" |
|
| 7 |
+) |
|
| 8 |
+ |
|
| 9 |
+func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwriteDirNonDir bool) (*archive.TarOptions, error) {
|
|
| 10 |
+ return daemon.defaultTarCopyOptions(noOverwriteDirNonDir), nil |
|
| 11 |
+} |
| ... | ... |
@@ -29,7 +29,7 @@ func (s *DockerSuite) TestCpFromErrSrcNotExists(c *check.C) {
|
| 29 | 29 |
tmpDir := getTestDir(c, "test-cp-from-err-src-not-exists") |
| 30 | 30 |
defer os.RemoveAll(tmpDir) |
| 31 | 31 |
|
| 32 |
- err := runDockerCp(c, containerCpPath(containerID, "file1"), tmpDir) |
|
| 32 |
+ err := runDockerCp(c, containerCpPath(containerID, "file1"), tmpDir, nil) |
|
| 33 | 33 |
c.Assert(err, checker.NotNil) |
| 34 | 34 |
|
| 35 | 35 |
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
| ... | ... |
@@ -44,7 +44,7 @@ func (s *DockerSuite) TestCpFromErrSrcNotDir(c *check.C) {
|
| 44 | 44 |
tmpDir := getTestDir(c, "test-cp-from-err-src-not-dir") |
| 45 | 45 |
defer os.RemoveAll(tmpDir) |
| 46 | 46 |
|
| 47 |
- err := runDockerCp(c, containerCpPathTrailingSep(containerID, "file1"), tmpDir) |
|
| 47 |
+ err := runDockerCp(c, containerCpPathTrailingSep(containerID, "file1"), tmpDir, nil) |
|
| 48 | 48 |
c.Assert(err, checker.NotNil) |
| 49 | 49 |
|
| 50 | 50 |
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -65,7 +65,7 @@ func (s *DockerSuite) TestCpFromErrDstParentNotExists(c *check.C) {
|
| 65 | 65 |
srcPath := containerCpPath(containerID, "/file1") |
| 66 | 66 |
dstPath := cpPath(tmpDir, "notExists", "file1") |
| 67 | 67 |
|
| 68 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 68 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 69 | 69 |
c.Assert(err, checker.NotNil) |
| 70 | 70 |
|
| 71 | 71 |
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
| ... | ... |
@@ -73,7 +73,7 @@ func (s *DockerSuite) TestCpFromErrDstParentNotExists(c *check.C) {
|
| 73 | 73 |
// Try with a directory source. |
| 74 | 74 |
srcPath = containerCpPath(containerID, "/dir1") |
| 75 | 75 |
|
| 76 |
- err = runDockerCp(c, srcPath, dstPath) |
|
| 76 |
+ err = runDockerCp(c, srcPath, dstPath, nil) |
|
| 77 | 77 |
c.Assert(err, checker.NotNil) |
| 78 | 78 |
|
| 79 | 79 |
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
| ... | ... |
@@ -94,7 +94,7 @@ func (s *DockerSuite) TestCpFromErrDstNotDir(c *check.C) {
|
| 94 | 94 |
srcPath := containerCpPath(containerID, "/file1") |
| 95 | 95 |
dstPath := cpPathTrailingSep(tmpDir, "file1") |
| 96 | 96 |
|
| 97 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 97 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 98 | 98 |
c.Assert(err, checker.NotNil) |
| 99 | 99 |
|
| 100 | 100 |
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -102,7 +102,7 @@ func (s *DockerSuite) TestCpFromErrDstNotDir(c *check.C) {
|
| 102 | 102 |
// Try with a directory source. |
| 103 | 103 |
srcPath = containerCpPath(containerID, "/dir1") |
| 104 | 104 |
|
| 105 |
- err = runDockerCp(c, srcPath, dstPath) |
|
| 105 |
+ err = runDockerCp(c, srcPath, dstPath, nil) |
|
| 106 | 106 |
c.Assert(err, checker.NotNil) |
| 107 | 107 |
|
| 108 | 108 |
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -124,7 +124,7 @@ func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
|
| 124 | 124 |
srcPath := containerCpPath(containerID, "/file2") |
| 125 | 125 |
dstPath := cpPath(tmpDir, "symlinkToFile1") |
| 126 | 126 |
|
| 127 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 127 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 128 | 128 |
|
| 129 | 129 |
// The symlink should not have been modified. |
| 130 | 130 |
c.Assert(symlinkTargetEquals(c, dstPath, "file1"), checker.IsNil) |
| ... | ... |
@@ -136,7 +136,7 @@ func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
|
| 136 | 136 |
// should copy the file into the symlink target directory. |
| 137 | 137 |
dstPath = cpPath(tmpDir, "symlinkToDir1") |
| 138 | 138 |
|
| 139 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 139 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 140 | 140 |
|
| 141 | 141 |
// The symlink should not have been modified. |
| 142 | 142 |
c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil) |
| ... | ... |
@@ -149,7 +149,7 @@ func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
|
| 149 | 149 |
// the contents of the source file. |
| 150 | 150 |
dstPath = cpPath(tmpDir, "brokenSymlinkToFileX") |
| 151 | 151 |
|
| 152 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 152 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 153 | 153 |
|
| 154 | 154 |
// The symlink should not have been modified. |
| 155 | 155 |
c.Assert(symlinkTargetEquals(c, dstPath, "fileX"), checker.IsNil) |
| ... | ... |
@@ -163,7 +163,7 @@ func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
|
| 163 | 163 |
srcPath = containerCpPath(containerID, "/dir2") |
| 164 | 164 |
dstPath = cpPath(tmpDir, "symlinkToDir1") |
| 165 | 165 |
|
| 166 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 166 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 167 | 167 |
|
| 168 | 168 |
// The symlink should not have been modified. |
| 169 | 169 |
c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil) |
| ... | ... |
@@ -177,7 +177,7 @@ func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
|
| 177 | 177 |
// should not modify the symlink. |
| 178 | 178 |
dstPath = cpPath(tmpDir, "brokenSymlinkToDirX") |
| 179 | 179 |
|
| 180 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 180 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 181 | 181 |
|
| 182 | 182 |
// The symlink should not have been modified. |
| 183 | 183 |
c.Assert(symlinkTargetEquals(c, dstPath, "dirX"), checker.IsNil) |
| ... | ... |
@@ -217,7 +217,7 @@ func (s *DockerSuite) TestCpFromCaseA(c *check.C) {
|
| 217 | 217 |
srcPath := containerCpPath(containerID, "/root/file1") |
| 218 | 218 |
dstPath := cpPath(tmpDir, "itWorks.txt") |
| 219 | 219 |
|
| 220 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 220 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 221 | 221 |
|
| 222 | 222 |
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) |
| 223 | 223 |
} |
| ... | ... |
@@ -235,7 +235,7 @@ func (s *DockerSuite) TestCpFromCaseB(c *check.C) {
|
| 235 | 235 |
srcPath := containerCpPath(containerID, "/file1") |
| 236 | 236 |
dstDir := cpPathTrailingSep(tmpDir, "testDir") |
| 237 | 237 |
|
| 238 |
- err := runDockerCp(c, srcPath, dstDir) |
|
| 238 |
+ err := runDockerCp(c, srcPath, dstDir, nil) |
|
| 239 | 239 |
c.Assert(err, checker.NotNil) |
| 240 | 240 |
|
| 241 | 241 |
c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExists error, but got %T: %s", err, err))
|
| ... | ... |
@@ -260,7 +260,7 @@ func (s *DockerSuite) TestCpFromCaseC(c *check.C) {
|
| 260 | 260 |
// Ensure the local file starts with different content. |
| 261 | 261 |
c.Assert(fileContentEquals(c, dstPath, "file2\n"), checker.IsNil) |
| 262 | 262 |
|
| 263 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 263 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 264 | 264 |
|
| 265 | 265 |
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) |
| 266 | 266 |
} |
| ... | ... |
@@ -285,7 +285,7 @@ func (s *DockerSuite) TestCpFromCaseD(c *check.C) {
|
| 285 | 285 |
_, err := os.Stat(dstPath) |
| 286 | 286 |
c.Assert(os.IsNotExist(err), checker.True, check.Commentf("did not expect dstPath %q to exist", dstPath))
|
| 287 | 287 |
|
| 288 |
- c.Assert(runDockerCp(c, srcPath, dstDir), checker.IsNil) |
|
| 288 |
+ c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil) |
|
| 289 | 289 |
|
| 290 | 290 |
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) |
| 291 | 291 |
|
| ... | ... |
@@ -299,7 +299,7 @@ func (s *DockerSuite) TestCpFromCaseD(c *check.C) {
|
| 299 | 299 |
|
| 300 | 300 |
dstDir = cpPathTrailingSep(tmpDir, "dir1") |
| 301 | 301 |
|
| 302 |
- c.Assert(runDockerCp(c, srcPath, dstDir), checker.IsNil) |
|
| 302 |
+ c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil) |
|
| 303 | 303 |
|
| 304 | 304 |
c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) |
| 305 | 305 |
} |
| ... | ... |
@@ -319,7 +319,7 @@ func (s *DockerSuite) TestCpFromCaseE(c *check.C) {
|
| 319 | 319 |
dstDir := cpPath(tmpDir, "testDir") |
| 320 | 320 |
dstPath := filepath.Join(dstDir, "file1-1") |
| 321 | 321 |
|
| 322 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 322 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 323 | 323 |
|
| 324 | 324 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 325 | 325 |
|
| ... | ... |
@@ -330,7 +330,7 @@ func (s *DockerSuite) TestCpFromCaseE(c *check.C) {
|
| 330 | 330 |
|
| 331 | 331 |
dstDir = cpPathTrailingSep(tmpDir, "testDir") |
| 332 | 332 |
|
| 333 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 333 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 334 | 334 |
|
| 335 | 335 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 336 | 336 |
} |
| ... | ... |
@@ -351,7 +351,7 @@ func (s *DockerSuite) TestCpFromCaseF(c *check.C) {
|
| 351 | 351 |
srcDir := containerCpPath(containerID, "/root/dir1") |
| 352 | 352 |
dstFile := cpPath(tmpDir, "file1") |
| 353 | 353 |
|
| 354 |
- err := runDockerCp(c, srcDir, dstFile) |
|
| 354 |
+ err := runDockerCp(c, srcDir, dstFile, nil) |
|
| 355 | 355 |
c.Assert(err, checker.NotNil) |
| 356 | 356 |
|
| 357 | 357 |
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -376,7 +376,7 @@ func (s *DockerSuite) TestCpFromCaseG(c *check.C) {
|
| 376 | 376 |
resultDir := filepath.Join(dstDir, "dir1") |
| 377 | 377 |
dstPath := filepath.Join(resultDir, "file1-1") |
| 378 | 378 |
|
| 379 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 379 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 380 | 380 |
|
| 381 | 381 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 382 | 382 |
|
| ... | ... |
@@ -390,7 +390,7 @@ func (s *DockerSuite) TestCpFromCaseG(c *check.C) {
|
| 390 | 390 |
|
| 391 | 391 |
dstDir = cpPathTrailingSep(tmpDir, "dir2") |
| 392 | 392 |
|
| 393 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 393 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 394 | 394 |
|
| 395 | 395 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 396 | 396 |
} |
| ... | ... |
@@ -410,7 +410,7 @@ func (s *DockerSuite) TestCpFromCaseH(c *check.C) {
|
| 410 | 410 |
dstDir := cpPath(tmpDir, "testDir") |
| 411 | 411 |
dstPath := filepath.Join(dstDir, "file1-1") |
| 412 | 412 |
|
| 413 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 413 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 414 | 414 |
|
| 415 | 415 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 416 | 416 |
|
| ... | ... |
@@ -421,7 +421,7 @@ func (s *DockerSuite) TestCpFromCaseH(c *check.C) {
|
| 421 | 421 |
|
| 422 | 422 |
dstDir = cpPathTrailingSep(tmpDir, "testDir") |
| 423 | 423 |
|
| 424 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 424 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 425 | 425 |
|
| 426 | 426 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 427 | 427 |
} |
| ... | ... |
@@ -443,7 +443,7 @@ func (s *DockerSuite) TestCpFromCaseI(c *check.C) {
|
| 443 | 443 |
srcDir := containerCpPathTrailingSep(containerID, "/root/dir1") + "." |
| 444 | 444 |
dstFile := cpPath(tmpDir, "file1") |
| 445 | 445 |
|
| 446 |
- err := runDockerCp(c, srcDir, dstFile) |
|
| 446 |
+ err := runDockerCp(c, srcDir, dstFile, nil) |
|
| 447 | 447 |
c.Assert(err, checker.NotNil) |
| 448 | 448 |
|
| 449 | 449 |
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -468,7 +468,7 @@ func (s *DockerSuite) TestCpFromCaseJ(c *check.C) {
|
| 468 | 468 |
dstDir := cpPath(tmpDir, "dir2") |
| 469 | 469 |
dstPath := filepath.Join(dstDir, "file1-1") |
| 470 | 470 |
|
| 471 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 471 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 472 | 472 |
|
| 473 | 473 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 474 | 474 |
|
| ... | ... |
@@ -482,7 +482,7 @@ func (s *DockerSuite) TestCpFromCaseJ(c *check.C) {
|
| 482 | 482 |
|
| 483 | 483 |
dstDir = cpPathTrailingSep(tmpDir, "dir2") |
| 484 | 484 |
|
| 485 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 485 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 486 | 486 |
|
| 487 | 487 |
c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) |
| 488 | 488 |
} |
| ... | ... |
@@ -28,7 +28,7 @@ const ( |
| 28 | 28 |
|
| 29 | 29 |
// Ensure that an all-local path case returns an error. |
| 30 | 30 |
func (s *DockerSuite) TestCpLocalOnly(c *check.C) {
|
| 31 |
- err := runDockerCp(c, "foo", "bar") |
|
| 31 |
+ err := runDockerCp(c, "foo", "bar", nil) |
|
| 32 | 32 |
c.Assert(err, checker.NotNil) |
| 33 | 33 |
|
| 34 | 34 |
c.Assert(err.Error(), checker.Contains, "must specify at least one container source") |
| ... | ... |
@@ -31,7 +31,7 @@ func (s *DockerSuite) TestCpToErrSrcNotExists(c *check.C) {
|
| 31 | 31 |
srcPath := cpPath(tmpDir, "file1") |
| 32 | 32 |
dstPath := containerCpPath(containerID, "file1") |
| 33 | 33 |
|
| 34 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 34 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 35 | 35 |
c.Assert(err, checker.NotNil) |
| 36 | 36 |
|
| 37 | 37 |
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
| ... | ... |
@@ -50,7 +50,7 @@ func (s *DockerSuite) TestCpToErrSrcNotDir(c *check.C) {
|
| 50 | 50 |
srcPath := cpPathTrailingSep(tmpDir, "file1") |
| 51 | 51 |
dstPath := containerCpPath(containerID, "testDir") |
| 52 | 52 |
|
| 53 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 53 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 54 | 54 |
c.Assert(err, checker.NotNil) |
| 55 | 55 |
|
| 56 | 56 |
c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -71,7 +71,7 @@ func (s *DockerSuite) TestCpToErrDstParentNotExists(c *check.C) {
|
| 71 | 71 |
srcPath := cpPath(tmpDir, "file1") |
| 72 | 72 |
dstPath := containerCpPath(containerID, "/notExists", "file1") |
| 73 | 73 |
|
| 74 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 74 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 75 | 75 |
c.Assert(err, checker.NotNil) |
| 76 | 76 |
|
| 77 | 77 |
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
| ... | ... |
@@ -79,7 +79,7 @@ func (s *DockerSuite) TestCpToErrDstParentNotExists(c *check.C) {
|
| 79 | 79 |
// Try with a directory source. |
| 80 | 80 |
srcPath = cpPath(tmpDir, "dir1") |
| 81 | 81 |
|
| 82 |
- err = runDockerCp(c, srcPath, dstPath) |
|
| 82 |
+ err = runDockerCp(c, srcPath, dstPath, nil) |
|
| 83 | 83 |
c.Assert(err, checker.NotNil) |
| 84 | 84 |
|
| 85 | 85 |
c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
| ... | ... |
@@ -104,7 +104,7 @@ func (s *DockerSuite) TestCpToErrDstNotDir(c *check.C) {
|
| 104 | 104 |
// The client should encounter an error trying to stat the destination |
| 105 | 105 |
// and then be unable to copy since the destination is asserted to be a |
| 106 | 106 |
// directory but does not exist. |
| 107 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 107 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 108 | 108 |
c.Assert(err, checker.NotNil) |
| 109 | 109 |
|
| 110 | 110 |
c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExist error, but got %T: %s", err, err))
|
| ... | ... |
@@ -116,7 +116,7 @@ func (s *DockerSuite) TestCpToErrDstNotDir(c *check.C) {
|
| 116 | 116 |
// then decide to extract to the parent directory instead with a rebased |
| 117 | 117 |
// name in the source archive, but this directory would overwrite the |
| 118 | 118 |
// existing file with the same name. |
| 119 |
- err = runDockerCp(c, srcPath, dstPath) |
|
| 119 |
+ err = runDockerCp(c, srcPath, dstPath, nil) |
|
| 120 | 120 |
c.Assert(err, checker.NotNil) |
| 121 | 121 |
|
| 122 | 122 |
c.Assert(isCannotOverwriteNonDirWithDir(err), checker.True, check.Commentf("expected CannotOverwriteNonDirWithDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -144,7 +144,7 @@ func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
|
| 144 | 144 |
srcPath := cpPath(testVol, "file2") |
| 145 | 145 |
dstPath := containerCpPath(containerID, "/vol2/symlinkToFile1") |
| 146 | 146 |
|
| 147 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 147 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 148 | 148 |
|
| 149 | 149 |
// The symlink should not have been modified. |
| 150 | 150 |
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToFile1"), "file1"), checker.IsNil) |
| ... | ... |
@@ -156,7 +156,7 @@ func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
|
| 156 | 156 |
// This should copy the file into the symlink target directory. |
| 157 | 157 |
dstPath = containerCpPath(containerID, "/vol2/symlinkToDir1") |
| 158 | 158 |
|
| 159 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 159 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 160 | 160 |
|
| 161 | 161 |
// The symlink should not have been modified. |
| 162 | 162 |
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToDir1"), "dir1"), checker.IsNil) |
| ... | ... |
@@ -169,7 +169,7 @@ func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
|
| 169 | 169 |
// contents of the source file. |
| 170 | 170 |
dstPath = containerCpPath(containerID, "/vol2/brokenSymlinkToFileX") |
| 171 | 171 |
|
| 172 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 172 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 173 | 173 |
|
| 174 | 174 |
// The symlink should not have been modified. |
| 175 | 175 |
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "brokenSymlinkToFileX"), "fileX"), checker.IsNil) |
| ... | ... |
@@ -183,7 +183,7 @@ func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
|
| 183 | 183 |
srcPath = cpPath(testVol, "/dir2") |
| 184 | 184 |
dstPath = containerCpPath(containerID, "/vol2/symlinkToDir1") |
| 185 | 185 |
|
| 186 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 186 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 187 | 187 |
|
| 188 | 188 |
// The symlink should not have been modified. |
| 189 | 189 |
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "symlinkToDir1"), "dir1"), checker.IsNil) |
| ... | ... |
@@ -197,7 +197,7 @@ func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
|
| 197 | 197 |
// should not modify the symlink. |
| 198 | 198 |
dstPath = containerCpPath(containerID, "/vol2/brokenSymlinkToDirX") |
| 199 | 199 |
|
| 200 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 200 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 201 | 201 |
|
| 202 | 202 |
// The symlink should not have been modified. |
| 203 | 203 |
c.Assert(symlinkTargetEquals(c, cpPath(testVol, "brokenSymlinkToDirX"), "dirX"), checker.IsNil) |
| ... | ... |
@@ -238,7 +238,7 @@ func (s *DockerSuite) TestCpToCaseA(c *check.C) {
|
| 238 | 238 |
srcPath := cpPath(tmpDir, "file1") |
| 239 | 239 |
dstPath := containerCpPath(containerID, "/root/itWorks.txt") |
| 240 | 240 |
|
| 241 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 241 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 242 | 242 |
|
| 243 | 243 |
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil) |
| 244 | 244 |
} |
| ... | ... |
@@ -259,7 +259,7 @@ func (s *DockerSuite) TestCpToCaseB(c *check.C) {
|
| 259 | 259 |
srcPath := cpPath(tmpDir, "file1") |
| 260 | 260 |
dstDir := containerCpPathTrailingSep(containerID, "testDir") |
| 261 | 261 |
|
| 262 |
- err := runDockerCp(c, srcPath, dstDir) |
|
| 262 |
+ err := runDockerCp(c, srcPath, dstDir, nil) |
|
| 263 | 263 |
c.Assert(err, checker.NotNil) |
| 264 | 264 |
|
| 265 | 265 |
c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExists error, but got %T: %s", err, err))
|
| ... | ... |
@@ -285,7 +285,7 @@ func (s *DockerSuite) TestCpToCaseC(c *check.C) {
|
| 285 | 285 |
// Ensure the container's file starts with the original content. |
| 286 | 286 |
c.Assert(containerStartOutputEquals(c, containerID, "file2\n"), checker.IsNil) |
| 287 | 287 |
|
| 288 |
- c.Assert(runDockerCp(c, srcPath, dstPath), checker.IsNil) |
|
| 288 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) |
|
| 289 | 289 |
|
| 290 | 290 |
// Should now contain file1's contents. |
| 291 | 291 |
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil) |
| ... | ... |
@@ -312,7 +312,7 @@ func (s *DockerSuite) TestCpToCaseD(c *check.C) {
|
| 312 | 312 |
// Ensure that dstPath doesn't exist. |
| 313 | 313 |
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil) |
| 314 | 314 |
|
| 315 |
- c.Assert(runDockerCp(c, srcPath, dstDir), checker.IsNil) |
|
| 315 |
+ c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil) |
|
| 316 | 316 |
|
| 317 | 317 |
// Should now contain file1's contents. |
| 318 | 318 |
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil) |
| ... | ... |
@@ -330,7 +330,7 @@ func (s *DockerSuite) TestCpToCaseD(c *check.C) {
|
| 330 | 330 |
// Ensure that dstPath doesn't exist. |
| 331 | 331 |
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil) |
| 332 | 332 |
|
| 333 |
- c.Assert(runDockerCp(c, srcPath, dstDir), checker.IsNil) |
|
| 333 |
+ c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil) |
|
| 334 | 334 |
|
| 335 | 335 |
// Should now contain file1's contents. |
| 336 | 336 |
c.Assert(containerStartOutputEquals(c, containerID, "file1\n"), checker.IsNil) |
| ... | ... |
@@ -353,7 +353,7 @@ func (s *DockerSuite) TestCpToCaseE(c *check.C) {
|
| 353 | 353 |
srcDir := cpPath(tmpDir, "dir1") |
| 354 | 354 |
dstDir := containerCpPath(containerID, "testDir") |
| 355 | 355 |
|
| 356 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 356 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 357 | 357 |
|
| 358 | 358 |
// Should now contain file1-1's contents. |
| 359 | 359 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -367,7 +367,7 @@ func (s *DockerSuite) TestCpToCaseE(c *check.C) {
|
| 367 | 367 |
|
| 368 | 368 |
dstDir = containerCpPathTrailingSep(containerID, "testDir") |
| 369 | 369 |
|
| 370 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 370 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 371 | 371 |
|
| 372 | 372 |
// Should now contain file1-1's contents. |
| 373 | 373 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -389,7 +389,7 @@ func (s *DockerSuite) TestCpToCaseF(c *check.C) {
|
| 389 | 389 |
srcDir := cpPath(tmpDir, "dir1") |
| 390 | 390 |
dstFile := containerCpPath(containerID, "/root/file1") |
| 391 | 391 |
|
| 392 |
- err := runDockerCp(c, srcDir, dstFile) |
|
| 392 |
+ err := runDockerCp(c, srcDir, dstFile, nil) |
|
| 393 | 393 |
c.Assert(err, checker.NotNil) |
| 394 | 394 |
|
| 395 | 395 |
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -416,7 +416,7 @@ func (s *DockerSuite) TestCpToCaseG(c *check.C) {
|
| 416 | 416 |
// Ensure that dstPath doesn't exist. |
| 417 | 417 |
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil) |
| 418 | 418 |
|
| 419 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 419 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 420 | 420 |
|
| 421 | 421 |
// Should now contain file1-1's contents. |
| 422 | 422 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -434,7 +434,7 @@ func (s *DockerSuite) TestCpToCaseG(c *check.C) {
|
| 434 | 434 |
// Ensure that dstPath doesn't exist. |
| 435 | 435 |
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil) |
| 436 | 436 |
|
| 437 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 437 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 438 | 438 |
|
| 439 | 439 |
// Should now contain file1-1's contents. |
| 440 | 440 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -457,7 +457,7 @@ func (s *DockerSuite) TestCpToCaseH(c *check.C) {
|
| 457 | 457 |
srcDir := cpPathTrailingSep(tmpDir, "dir1") + "." |
| 458 | 458 |
dstDir := containerCpPath(containerID, "testDir") |
| 459 | 459 |
|
| 460 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 460 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 461 | 461 |
|
| 462 | 462 |
// Should now contain file1-1's contents. |
| 463 | 463 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -471,7 +471,7 @@ func (s *DockerSuite) TestCpToCaseH(c *check.C) {
|
| 471 | 471 |
|
| 472 | 472 |
dstDir = containerCpPathTrailingSep(containerID, "testDir") |
| 473 | 473 |
|
| 474 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 474 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 475 | 475 |
|
| 476 | 476 |
// Should now contain file1-1's contents. |
| 477 | 477 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -494,7 +494,7 @@ func (s *DockerSuite) TestCpToCaseI(c *check.C) {
|
| 494 | 494 |
srcDir := cpPathTrailingSep(tmpDir, "dir1") + "." |
| 495 | 495 |
dstFile := containerCpPath(containerID, "/root/file1") |
| 496 | 496 |
|
| 497 |
- err := runDockerCp(c, srcDir, dstFile) |
|
| 497 |
+ err := runDockerCp(c, srcDir, dstFile, nil) |
|
| 498 | 498 |
c.Assert(err, checker.NotNil) |
| 499 | 499 |
|
| 500 | 500 |
c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
|
| ... | ... |
@@ -522,7 +522,7 @@ func (s *DockerSuite) TestCpToCaseJ(c *check.C) {
|
| 522 | 522 |
// Ensure that dstPath doesn't exist. |
| 523 | 523 |
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil) |
| 524 | 524 |
|
| 525 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 525 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 526 | 526 |
|
| 527 | 527 |
// Should now contain file1-1's contents. |
| 528 | 528 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -539,7 +539,7 @@ func (s *DockerSuite) TestCpToCaseJ(c *check.C) {
|
| 539 | 539 |
// Ensure that dstPath doesn't exist. |
| 540 | 540 |
c.Assert(containerStartOutputEquals(c, containerID, ""), checker.IsNil) |
| 541 | 541 |
|
| 542 |
- c.Assert(runDockerCp(c, srcDir, dstDir), checker.IsNil) |
|
| 542 |
+ c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) |
|
| 543 | 543 |
|
| 544 | 544 |
// Should now contain file1-1's contents. |
| 545 | 545 |
c.Assert(containerStartOutputEquals(c, containerID, "file1-1\n"), checker.IsNil) |
| ... | ... |
@@ -563,7 +563,7 @@ func (s *DockerSuite) TestCpToErrReadOnlyRootfs(c *check.C) {
|
| 563 | 563 |
srcPath := cpPath(tmpDir, "file1") |
| 564 | 564 |
dstPath := containerCpPath(containerID, "/root/shouldNotExist") |
| 565 | 565 |
|
| 566 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 566 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 567 | 567 |
c.Assert(err, checker.NotNil) |
| 568 | 568 |
|
| 569 | 569 |
c.Assert(isCpCannotCopyReadOnly(err), checker.True, check.Commentf("expected ErrContainerRootfsReadonly error, but got %T: %s", err, err))
|
| ... | ... |
@@ -590,7 +590,7 @@ func (s *DockerSuite) TestCpToErrReadOnlyVolume(c *check.C) {
|
| 590 | 590 |
srcPath := cpPath(tmpDir, "file1") |
| 591 | 591 |
dstPath := containerCpPath(containerID, "/vol_ro/shouldNotExist") |
| 592 | 592 |
|
| 593 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 593 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 594 | 594 |
c.Assert(err, checker.NotNil) |
| 595 | 595 |
|
| 596 | 596 |
c.Assert(isCpCannotCopyReadOnly(err), checker.True, check.Commentf("expected ErrVolumeReadonly error, but got %T: %s", err, err))
|
| ... | ... |
@@ -14,6 +14,29 @@ import ( |
| 14 | 14 |
"github.com/go-check/check" |
| 15 | 15 |
) |
| 16 | 16 |
|
| 17 |
+func (s *DockerSuite) TestCpToContainerWithPermissions(c *check.C) {
|
|
| 18 |
+ testRequires(c, SameHostDaemon, DaemonIsLinux) |
|
| 19 |
+ |
|
| 20 |
+ tmpDir := getTestDir(c, "test-cp-to-host-with-permissions") |
|
| 21 |
+ defer os.RemoveAll(tmpDir) |
|
| 22 |
+ |
|
| 23 |
+ makeTestContentInDir(c, tmpDir) |
|
| 24 |
+ |
|
| 25 |
+ containerName := "permtest" |
|
| 26 |
+ |
|
| 27 |
+ _, exc := dockerCmd(c, "create", "--name", containerName, "debian:jessie", "/bin/bash", "-c", "stat -c '%u %g %a' /permdirtest /permdirtest/permtest") |
|
| 28 |
+ c.Assert(exc, checker.Equals, 0) |
|
| 29 |
+ defer dockerCmd(c, "rm", "-f", containerName) |
|
| 30 |
+ |
|
| 31 |
+ srcPath := cpPath(tmpDir, "permdirtest") |
|
| 32 |
+ dstPath := containerCpPath(containerName, "/") |
|
| 33 |
+ c.Assert(runDockerCp(c, srcPath, dstPath, []string{"-a"}), checker.IsNil)
|
|
| 34 |
+ |
|
| 35 |
+ out, err := startContainerGetOutput(c, containerName) |
|
| 36 |
+ c.Assert(err, checker.IsNil, check.Commentf("output: %v", out))
|
|
| 37 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, "2 2 700\n65534 65534 400", check.Commentf("output: %v", out))
|
|
| 38 |
+} |
|
| 39 |
+ |
|
| 17 | 40 |
// Check ownership is root, both in non-userns and userns enabled modes |
| 18 | 41 |
func (s *DockerSuite) TestCpCheckDestOwnership(c *check.C) {
|
| 19 | 42 |
testRequires(c, DaemonIsLinux, SameHostDaemon) |
| ... | ... |
@@ -29,7 +52,7 @@ func (s *DockerSuite) TestCpCheckDestOwnership(c *check.C) {
|
| 29 | 29 |
srcPath := cpPath(tmpDir, "file1") |
| 30 | 30 |
dstPath := containerCpPath(containerID, "/tmpvol", "file1") |
| 31 | 31 |
|
| 32 |
- err := runDockerCp(c, srcPath, dstPath) |
|
| 32 |
+ err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 33 | 33 |
c.Assert(err, checker.IsNil) |
| 34 | 34 |
|
| 35 | 35 |
stat, err := system.Stat(filepath.Join(tmpVolDir, "file1")) |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"os" |
| 8 | 8 |
"os/exec" |
| 9 | 9 |
"path/filepath" |
| 10 |
+ "runtime" |
|
| 10 | 11 |
"strings" |
| 11 | 12 |
|
| 12 | 13 |
"github.com/docker/docker/integration-cli/checker" |
| ... | ... |
@@ -26,6 +27,9 @@ type fileData struct {
|
| 26 | 26 |
filetype fileType |
| 27 | 27 |
path string |
| 28 | 28 |
contents string |
| 29 |
+ uid int |
|
| 30 |
+ gid int |
|
| 31 |
+ mode int |
|
| 29 | 32 |
} |
| 30 | 33 |
|
| 31 | 34 |
func (fd fileData) creationCommand() string {
|
| ... | ... |
@@ -55,31 +59,33 @@ func mkFilesCommand(fds []fileData) string {
|
| 55 | 55 |
} |
| 56 | 56 |
|
| 57 | 57 |
var defaultFileData = []fileData{
|
| 58 |
- {ftRegular, "file1", "file1"},
|
|
| 59 |
- {ftRegular, "file2", "file2"},
|
|
| 60 |
- {ftRegular, "file3", "file3"},
|
|
| 61 |
- {ftRegular, "file4", "file4"},
|
|
| 62 |
- {ftRegular, "file5", "file5"},
|
|
| 63 |
- {ftRegular, "file6", "file6"},
|
|
| 64 |
- {ftRegular, "file7", "file7"},
|
|
| 65 |
- {ftDir, "dir1", ""},
|
|
| 66 |
- {ftRegular, "dir1/file1-1", "file1-1"},
|
|
| 67 |
- {ftRegular, "dir1/file1-2", "file1-2"},
|
|
| 68 |
- {ftDir, "dir2", ""},
|
|
| 69 |
- {ftRegular, "dir2/file2-1", "file2-1"},
|
|
| 70 |
- {ftRegular, "dir2/file2-2", "file2-2"},
|
|
| 71 |
- {ftDir, "dir3", ""},
|
|
| 72 |
- {ftRegular, "dir3/file3-1", "file3-1"},
|
|
| 73 |
- {ftRegular, "dir3/file3-2", "file3-2"},
|
|
| 74 |
- {ftDir, "dir4", ""},
|
|
| 75 |
- {ftRegular, "dir4/file3-1", "file4-1"},
|
|
| 76 |
- {ftRegular, "dir4/file3-2", "file4-2"},
|
|
| 77 |
- {ftDir, "dir5", ""},
|
|
| 78 |
- {ftSymlink, "symlinkToFile1", "file1"},
|
|
| 79 |
- {ftSymlink, "symlinkToDir1", "dir1"},
|
|
| 80 |
- {ftSymlink, "brokenSymlinkToFileX", "fileX"},
|
|
| 81 |
- {ftSymlink, "brokenSymlinkToDirX", "dirX"},
|
|
| 82 |
- {ftSymlink, "symlinkToAbsDir", "/root"},
|
|
| 58 |
+ {ftRegular, "file1", "file1", 0, 0, 0666},
|
|
| 59 |
+ {ftRegular, "file2", "file2", 0, 0, 0666},
|
|
| 60 |
+ {ftRegular, "file3", "file3", 0, 0, 0666},
|
|
| 61 |
+ {ftRegular, "file4", "file4", 0, 0, 0666},
|
|
| 62 |
+ {ftRegular, "file5", "file5", 0, 0, 0666},
|
|
| 63 |
+ {ftRegular, "file6", "file6", 0, 0, 0666},
|
|
| 64 |
+ {ftRegular, "file7", "file7", 0, 0, 0666},
|
|
| 65 |
+ {ftDir, "dir1", "", 0, 0, 0777},
|
|
| 66 |
+ {ftRegular, "dir1/file1-1", "file1-1", 0, 0, 0666},
|
|
| 67 |
+ {ftRegular, "dir1/file1-2", "file1-2", 0, 0, 0666},
|
|
| 68 |
+ {ftDir, "dir2", "", 0, 0, 0666},
|
|
| 69 |
+ {ftRegular, "dir2/file2-1", "file2-1", 0, 0, 0666},
|
|
| 70 |
+ {ftRegular, "dir2/file2-2", "file2-2", 0, 0, 0666},
|
|
| 71 |
+ {ftDir, "dir3", "", 0, 0, 0666},
|
|
| 72 |
+ {ftRegular, "dir3/file3-1", "file3-1", 0, 0, 0666},
|
|
| 73 |
+ {ftRegular, "dir3/file3-2", "file3-2", 0, 0, 0666},
|
|
| 74 |
+ {ftDir, "dir4", "", 0, 0, 0666},
|
|
| 75 |
+ {ftRegular, "dir4/file3-1", "file4-1", 0, 0, 0666},
|
|
| 76 |
+ {ftRegular, "dir4/file3-2", "file4-2", 0, 0, 0666},
|
|
| 77 |
+ {ftDir, "dir5", "", 0, 0, 0666},
|
|
| 78 |
+ {ftSymlink, "symlinkToFile1", "file1", 0, 0, 0666},
|
|
| 79 |
+ {ftSymlink, "symlinkToDir1", "dir1", 0, 0, 0666},
|
|
| 80 |
+ {ftSymlink, "brokenSymlinkToFileX", "fileX", 0, 0, 0666},
|
|
| 81 |
+ {ftSymlink, "brokenSymlinkToDirX", "dirX", 0, 0, 0666},
|
|
| 82 |
+ {ftSymlink, "symlinkToAbsDir", "/root", 0, 0, 0666},
|
|
| 83 |
+ {ftDir, "permdirtest", "", 2, 2, 0700},
|
|
| 84 |
+ {ftRegular, "permdirtest/permtest", "perm_test", 65534, 65534, 0400},
|
|
| 83 | 85 |
} |
| 84 | 86 |
|
| 85 | 87 |
func defaultMkContentCommand() string {
|
| ... | ... |
@@ -91,12 +97,16 @@ func makeTestContentInDir(c *check.C, dir string) {
|
| 91 | 91 |
path := filepath.Join(dir, filepath.FromSlash(fd.path)) |
| 92 | 92 |
switch fd.filetype {
|
| 93 | 93 |
case ftRegular: |
| 94 |
- c.Assert(ioutil.WriteFile(path, []byte(fd.contents+"\n"), os.FileMode(0666)), checker.IsNil) |
|
| 94 |
+ c.Assert(ioutil.WriteFile(path, []byte(fd.contents+"\n"), os.FileMode(fd.mode)), checker.IsNil) |
|
| 95 | 95 |
case ftDir: |
| 96 |
- c.Assert(os.Mkdir(path, os.FileMode(0777)), checker.IsNil) |
|
| 96 |
+ c.Assert(os.Mkdir(path, os.FileMode(fd.mode)), checker.IsNil) |
|
| 97 | 97 |
case ftSymlink: |
| 98 | 98 |
c.Assert(os.Symlink(fd.contents, path), checker.IsNil) |
| 99 | 99 |
} |
| 100 |
+ |
|
| 101 |
+ if fd.filetype != ftSymlink && runtime.GOOS != "windows" {
|
|
| 102 |
+ c.Assert(os.Chown(path, fd.uid, fd.gid), checker.IsNil) |
|
| 103 |
+ } |
|
| 100 | 104 |
} |
| 101 | 105 |
} |
| 102 | 106 |
|
| ... | ... |
@@ -178,10 +188,16 @@ func containerCpPathTrailingSep(containerID string, pathElements ...string) stri |
| 178 | 178 |
return fmt.Sprintf("%s/", containerCpPath(containerID, pathElements...))
|
| 179 | 179 |
} |
| 180 | 180 |
|
| 181 |
-func runDockerCp(c *check.C, src, dst string) (err error) {
|
|
| 182 |
- c.Logf("running `docker cp %s %s`", src, dst)
|
|
| 181 |
+func runDockerCp(c *check.C, src, dst string, params []string) (err error) {
|
|
| 182 |
+ c.Logf("running `docker cp %s %s %s`", strings.Join(params, " "), src, dst)
|
|
| 183 |
+ |
|
| 184 |
+ args := []string{"cp"}
|
|
| 185 |
+ |
|
| 186 |
+ for _, param := range params {
|
|
| 187 |
+ args = append(args, param) |
|
| 188 |
+ } |
|
| 183 | 189 |
|
| 184 |
- args := []string{"cp", src, dst}
|
|
| 190 |
+ args = append(args, src, dst) |
|
| 185 | 191 |
|
| 186 | 192 |
out, _, err := runCommandWithOutput(exec.Command(dockerBinary, args...)) |
| 187 | 193 |
if err != nil {
|