diff --git a/daemon/archive.go b/daemon/archive.go index 8130a5040c..f7bb19f0f7 100644 --- a/daemon/archive.go +++ b/daemon/archive.go @@ -57,16 +57,16 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io // ContainerExtractToDir extracts the given archive to the specified location // in the filesystem of the container identified by the given name. The given // path must be of a directory in the container. If it is not, the error will -// be an errdefs.InvalidParameter. If noOverwriteDirNonDir is true then it will -// be an error if unpacking the given content would cause an existing directory -// to be replaced with a non-directory and vice versa. -func (daemon *Daemon) ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error { +// be an errdefs.InvalidParameter. It returns an error if unpacking the given +// content would cause an existing directory to be replaced with a non-directory +// or vice versa, unless allowOverwriteDirWithFile is set to true. +func (daemon *Daemon) ContainerExtractToDir(name, path string, copyUIDGID, allowOverwriteDirWithFile bool, content io.Reader) error { ctr, err := daemon.GetContainer(name) if err != nil { return err } - err = daemon.containerExtractToDir(ctr, path, copyUIDGID, noOverwriteDirNonDir, content) + err = daemon.containerExtractToDir(ctr, path, copyUIDGID, allowOverwriteDirWithFile, content) if err != nil { if os.IsNotExist(err) { return containerFileNotFound{path, name} diff --git a/daemon/archive_tarcopyoptions.go b/daemon/archive_tarcopyoptions.go index 4848cfbb40..03bd09fa69 100644 --- a/daemon/archive_tarcopyoptions.go +++ b/daemon/archive_tarcopyoptions.go @@ -6,9 +6,9 @@ import ( // defaultTarCopyOptions is the setting that is used when unpacking an archive // for a copy API event. -func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions { +func (daemon *Daemon) defaultTarCopyOptions(allowOverwriteDirWithFile bool) *archive.TarOptions { return &archive.TarOptions{ - NoOverwriteDirNonDir: noOverwriteDirNonDir, + NoOverwriteDirNonDir: !allowOverwriteDirWithFile, IDMap: daemon.idMapping, } } diff --git a/daemon/archive_tarcopyoptions_unix.go b/daemon/archive_tarcopyoptions_unix.go index 86b77a5e2a..64daa50803 100644 --- a/daemon/archive_tarcopyoptions_unix.go +++ b/daemon/archive_tarcopyoptions_unix.go @@ -14,9 +14,9 @@ import ( "github.com/moby/sys/user" ) -func (daemon *Daemon) tarCopyOptions(ctr *container.Container, noOverwriteDirNonDir bool) (*archive.TarOptions, error) { +func (daemon *Daemon) tarCopyOptions(ctr *container.Container, allowOverwriteDirWithFile bool) (*archive.TarOptions, error) { if ctr.Config.User == "" { - return daemon.defaultTarCopyOptions(noOverwriteDirNonDir), nil + return daemon.defaultTarCopyOptions(allowOverwriteDirWithFile), nil } uid, gid, err := getUIDGID(ctr.Config.User) @@ -25,7 +25,7 @@ func (daemon *Daemon) tarCopyOptions(ctr *container.Container, noOverwriteDirNon } return &archive.TarOptions{ - NoOverwriteDirNonDir: noOverwriteDirNonDir, + NoOverwriteDirNonDir: !allowOverwriteDirWithFile, ChownOpts: &archive.ChownOpts{UID: uid, GID: gid}, }, nil } diff --git a/daemon/archive_unix.go b/daemon/archive_unix.go index 9fc2241bc7..89d922ca4e 100644 --- a/daemon/archive_unix.go +++ b/daemon/archive_unix.go @@ -97,7 +97,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path // noOverwriteDirNonDir is true then it will be an error if unpacking the // given content would cause an existing directory to be replaced with a non- // directory and vice versa. -func (daemon *Daemon) containerExtractToDir(container *container.Container, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error { +func (daemon *Daemon) containerExtractToDir(container *container.Container, path string, copyUIDGID, allowOverwriteDirWithFile bool, content io.Reader) error { container.Lock() defer container.Unlock() @@ -131,13 +131,13 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path return err } - options := daemon.defaultTarCopyOptions(noOverwriteDirNonDir) + options := daemon.defaultTarCopyOptions(allowOverwriteDirWithFile) if copyUIDGID { var err error // tarCopyOptions will appropriately pull in the right uid/gid for the // user/group and will set the options. - options, err = daemon.tarCopyOptions(container, noOverwriteDirNonDir) + options, err = daemon.tarCopyOptions(container, allowOverwriteDirWithFile) if err != nil { return err } diff --git a/daemon/archive_windows.go b/daemon/archive_windows.go index 830fb105d0..4e3a674779 100644 --- a/daemon/archive_windows.go +++ b/daemon/archive_windows.go @@ -148,7 +148,7 @@ func (daemon *Daemon) containerArchivePath(container *container.Container, path // directory and vice versa. // // FIXME(thaJeztah): copyUIDGID is not supported on Windows, but currently ignored silently -func (daemon *Daemon) containerExtractToDir(container *container.Container, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error { +func (daemon *Daemon) containerExtractToDir(container *container.Container, path string, copyUIDGID, allowOverwriteDirWithFile bool, content io.Reader) error { container.Lock() defer container.Unlock() @@ -213,7 +213,7 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path // return err // } - options := daemon.defaultTarCopyOptions(noOverwriteDirNonDir) + options := daemon.defaultTarCopyOptions(allowOverwriteDirWithFile) if err := chrootarchive.UntarWithRoot(content, resolvedPath, options, container.BaseFS); err != nil { return err } diff --git a/daemon/server/router/container/backend.go b/daemon/server/router/container/backend.go index e7824933d0..991ebbe7fd 100644 --- a/daemon/server/router/container/backend.go +++ b/daemon/server/router/container/backend.go @@ -23,7 +23,7 @@ type execBackend interface { type copyBackend interface { ContainerArchivePath(name string, path string) (content io.ReadCloser, stat *container.PathStat, err error) ContainerExport(ctx context.Context, name string, out io.Writer) error - ContainerExtractToDir(name, path string, copyUIDGID, noOverwriteDirNonDir bool, content io.Reader) error + ContainerExtractToDir(name, path string, copyUIDGID, allowOverwriteDirWithFile bool, content io.Reader) error ContainerStatPath(name string, path string) (stat *container.PathStat, err error) } diff --git a/daemon/server/router/container/copy.go b/daemon/server/router/container/copy.go index bde6786b40..53881d6861 100644 --- a/daemon/server/router/container/copy.go +++ b/daemon/server/router/container/copy.go @@ -92,8 +92,10 @@ func (c *containerRouter) putContainersArchive(ctx context.Context, w http.Respo return err } - noOverwriteDirNonDir := httputils.BoolValue(r, "noOverwriteDirNonDir") + // TODO(thaJeztah): reverse the default: deprecate noOverwriteDirNonDir and add "allowOverwriteDirWithFile" (or similar) argument to opt-in. + allowOverwriteDirWithFile := !r.Form.Has("noOverwriteDirNonDir") || !httputils.BoolValue(r, "noOverwriteDirNonDir") + copyUIDGID := httputils.BoolValue(r, "copyUIDGID") - return c.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, noOverwriteDirNonDir, r.Body) + return c.backend.ContainerExtractToDir(v.Name, v.Path, copyUIDGID, allowOverwriteDirWithFile, r.Body) }