mirror of
https://github.com/containers/podman.git
synced 2025-06-21 01:19:15 +08:00
Merge pull request #11065 from vrothberg/cp-cleanups
cp: consolidate and simplify
This commit is contained in:
@ -131,43 +131,17 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
|
|||||||
return errors.Wrapf(err, "%q could not be found on container %s", sourcePath, sourceContainer)
|
return errors.Wrapf(err, "%q could not be found on container %s", sourcePath, sourceContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
var destContainerBaseName string
|
destContainerBaseName, destContainerInfo, destResolvedToParentDir, err := resolvePathOnDestinationContainer(destContainer, destPath, false)
|
||||||
destContainerInfo, destContainerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), destContainer, destPath)
|
|
||||||
if destContainerInfoErr != nil {
|
|
||||||
if strings.HasSuffix(destPath, "/") {
|
|
||||||
return errors.Wrapf(destContainerInfoErr, "%q could not be found on container %s", destPath, destContainer)
|
|
||||||
}
|
|
||||||
// NOTE: containerInfo may actually be set. That happens when
|
|
||||||
// the container path is a symlink into nirvana. In that case,
|
|
||||||
// we must use the symlinked path instead.
|
|
||||||
path := destPath
|
|
||||||
if destContainerInfo != nil {
|
|
||||||
destContainerBaseName = filepath.Base(destContainerInfo.LinkTarget)
|
|
||||||
path = destContainerInfo.LinkTarget
|
|
||||||
} else {
|
|
||||||
destContainerBaseName = filepath.Base(destPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
parentDir, err := containerParentDir(destContainer, path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, destContainer)
|
return err
|
||||||
}
|
|
||||||
destContainerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), destContainer, parentDir)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "%q could not be found on container %s", destPath, destContainer)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the specified path exists on the container, we must use
|
|
||||||
// its base path as it may have changed due to symlink
|
|
||||||
// evaluations.
|
|
||||||
destContainerBaseName = filepath.Base(destContainerInfo.LinkTarget)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sourceContainerInfo.IsDir && !destContainerInfo.IsDir {
|
if sourceContainerInfo.IsDir && !destContainerInfo.IsDir {
|
||||||
return errors.New("destination must be a directory when copying a directory")
|
return errors.New("destination must be a directory when copying a directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceContainerTarget, destContainerTarget := sourceContainerInfo.LinkTarget, destContainerInfo.LinkTarget
|
sourceContainerTarget := sourceContainerInfo.LinkTarget
|
||||||
|
destContainerTarget := destContainerInfo.LinkTarget
|
||||||
if !destContainerInfo.IsDir {
|
if !destContainerInfo.IsDir {
|
||||||
destContainerTarget = filepath.Dir(destPath)
|
destContainerTarget = filepath.Dir(destPath)
|
||||||
}
|
}
|
||||||
@ -180,7 +154,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
|
|||||||
// Hence, whenever "." is the source and the destination does not
|
// Hence, whenever "." is the source and the destination does not
|
||||||
// exist, we copy the source's parent and let the copier package create
|
// exist, we copy the source's parent and let the copier package create
|
||||||
// the destination via the Rename option.
|
// the destination via the Rename option.
|
||||||
if destContainerInfoErr != nil && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") {
|
if destResolvedToParentDir && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") {
|
||||||
sourceContainerTarget = filepath.Dir(sourceContainerTarget)
|
sourceContainerTarget = filepath.Dir(sourceContainerTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +176,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
|
|||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
copyOptions := entities.CopyOptions{Chown: chown}
|
copyOptions := entities.CopyOptions{Chown: chown}
|
||||||
if (!sourceContainerInfo.IsDir && !destContainerInfo.IsDir) || destContainerInfoErr != nil {
|
if (!sourceContainerInfo.IsDir && !destContainerInfo.IsDir) || destResolvedToParentDir {
|
||||||
// If we're having a file-to-file copy, make sure to
|
// If we're having a file-to-file copy, make sure to
|
||||||
// rename accordingly.
|
// rename accordingly.
|
||||||
copyOptions.Rename = map[string]string{filepath.Base(sourceContainerTarget): destContainerBaseName}
|
copyOptions.Rename = map[string]string{filepath.Base(sourceContainerTarget): destContainerBaseName}
|
||||||
@ -239,6 +213,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
var hostBaseName string
|
var hostBaseName string
|
||||||
|
var resolvedToHostParentDir bool
|
||||||
hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath)
|
hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath)
|
||||||
if hostInfoErr != nil {
|
if hostInfoErr != nil {
|
||||||
if strings.HasSuffix(hostPath, "/") {
|
if strings.HasSuffix(hostPath, "/") {
|
||||||
@ -254,6 +229,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
|
|||||||
// it'll be created while copying. Hence, we use it as the
|
// it'll be created while copying. Hence, we use it as the
|
||||||
// base path.
|
// base path.
|
||||||
hostBaseName = filepath.Base(hostPath)
|
hostBaseName = filepath.Base(hostPath)
|
||||||
|
resolvedToHostParentDir = true
|
||||||
} else {
|
} else {
|
||||||
// If the specified path exists on the host, we must use its
|
// If the specified path exists on the host, we must use its
|
||||||
// base path as it may have changed due to symlink evaluations.
|
// base path as it may have changed due to symlink evaluations.
|
||||||
@ -281,7 +257,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
|
|||||||
// we copy the source's parent and let the copier package create the
|
// we copy the source's parent and let the copier package create the
|
||||||
// destination via the Rename option.
|
// destination via the Rename option.
|
||||||
containerTarget := containerInfo.LinkTarget
|
containerTarget := containerInfo.LinkTarget
|
||||||
if hostInfoErr != nil && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
|
if resolvedToHostParentDir && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
|
||||||
containerTarget = filepath.Dir(containerTarget)
|
containerTarget = filepath.Dir(containerTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +298,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
|
|||||||
ChownFiles: &idPair,
|
ChownFiles: &idPair,
|
||||||
IgnoreDevices: true,
|
IgnoreDevices: true,
|
||||||
}
|
}
|
||||||
if (!containerInfo.IsDir && !hostInfo.IsDir) || hostInfoErr != nil {
|
if (!containerInfo.IsDir && !hostInfo.IsDir) || resolvedToHostParentDir {
|
||||||
// If we're having a file-to-file copy, make sure to
|
// If we're having a file-to-file copy, make sure to
|
||||||
// rename accordingly.
|
// rename accordingly.
|
||||||
putOptions.Rename = map[string]string{filepath.Base(containerTarget): hostBaseName}
|
putOptions.Rename = map[string]string{filepath.Base(containerTarget): hostBaseName}
|
||||||
@ -369,42 +345,9 @@ func copyToContainer(container string, containerPath string, hostPath string) er
|
|||||||
return errors.Wrapf(err, "%q could not be found on the host", hostPath)
|
return errors.Wrapf(err, "%q could not be found on the host", hostPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the path on the container does not exist. We need to make sure
|
containerBaseName, containerInfo, containerResolvedToParentDir, err := resolvePathOnDestinationContainer(container, containerPath, isStdin)
|
||||||
// that it's parent directory exists. The destination may be created
|
|
||||||
// while copying.
|
|
||||||
var containerBaseName string
|
|
||||||
containerInfo, containerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
|
|
||||||
if containerInfoErr != nil {
|
|
||||||
if strings.HasSuffix(containerPath, "/") {
|
|
||||||
return errors.Wrapf(containerInfoErr, "%q could not be found on container %s", containerPath, container)
|
|
||||||
}
|
|
||||||
if isStdin {
|
|
||||||
return errors.New("destination must be a directory when copying from stdin")
|
|
||||||
}
|
|
||||||
// NOTE: containerInfo may actually be set. That happens when
|
|
||||||
// the container path is a symlink into nirvana. In that case,
|
|
||||||
// we must use the symlinked path instead.
|
|
||||||
path := containerPath
|
|
||||||
if containerInfo != nil {
|
|
||||||
containerBaseName = filepath.Base(containerInfo.LinkTarget)
|
|
||||||
path = containerInfo.LinkTarget
|
|
||||||
} else {
|
|
||||||
containerBaseName = filepath.Base(containerPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
parentDir, err := containerParentDir(container, path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
|
return err
|
||||||
}
|
|
||||||
containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the specified path exists on the container, we must use
|
|
||||||
// its base path as it may have changed due to symlink
|
|
||||||
// evaluations.
|
|
||||||
containerBaseName = filepath.Base(containerInfo.LinkTarget)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we copy a directory via the "." notation and the container path
|
// If we copy a directory via the "." notation and the container path
|
||||||
@ -416,7 +359,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
|
|||||||
// exist, we copy the source's parent and let the copier package create
|
// exist, we copy the source's parent and let the copier package create
|
||||||
// the destination via the Rename option.
|
// the destination via the Rename option.
|
||||||
hostTarget := hostInfo.LinkTarget
|
hostTarget := hostInfo.LinkTarget
|
||||||
if containerInfoErr != nil && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
|
if containerResolvedToParentDir && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
|
||||||
hostTarget = filepath.Dir(hostTarget)
|
hostTarget = filepath.Dir(hostTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +411,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
|
|||||||
// copy the base directory.
|
// copy the base directory.
|
||||||
KeepDirectoryNames: hostInfo.IsDir && filepath.Base(hostTarget) != ".",
|
KeepDirectoryNames: hostInfo.IsDir && filepath.Base(hostTarget) != ".",
|
||||||
}
|
}
|
||||||
if (!hostInfo.IsDir && !containerInfo.IsDir) || containerInfoErr != nil {
|
if (!hostInfo.IsDir && !containerInfo.IsDir) || containerResolvedToParentDir {
|
||||||
// If we're having a file-to-file copy, make sure to
|
// If we're having a file-to-file copy, make sure to
|
||||||
// rename accordingly.
|
// rename accordingly.
|
||||||
getOptions.Rename = map[string]string{filepath.Base(hostTarget): containerBaseName}
|
getOptions.Rename = map[string]string{filepath.Base(hostTarget): containerBaseName}
|
||||||
@ -499,6 +442,52 @@ func copyToContainer(container string, containerPath string, hostPath string) er
|
|||||||
return doCopy(hostCopy, containerCopy)
|
return doCopy(hostCopy, containerCopy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolvePathOnDestinationContainer resolves the specified path on the
|
||||||
|
// container. If the path does not exist, it attempts to use the parent
|
||||||
|
// directory.
|
||||||
|
func resolvePathOnDestinationContainer(container string, containerPath string, isStdin bool) (baseName string, containerInfo *entities.ContainerStatReport, resolvedToParentDir bool, err error) {
|
||||||
|
containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
|
||||||
|
if err == nil {
|
||||||
|
baseName = filepath.Base(containerInfo.LinkTarget)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(containerPath, "/") {
|
||||||
|
err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if isStdin {
|
||||||
|
err = errors.New("destination must be a directory when copying from stdin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: containerInfo may actually be set. That happens when
|
||||||
|
// the container path is a symlink into nirvana. In that case,
|
||||||
|
// we must use the symlinked path instead.
|
||||||
|
path := containerPath
|
||||||
|
if containerInfo != nil {
|
||||||
|
baseName = filepath.Base(containerInfo.LinkTarget)
|
||||||
|
path = containerInfo.LinkTarget
|
||||||
|
} else {
|
||||||
|
baseName = filepath.Base(containerPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
parentDir, err := containerParentDir(container, path)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedToParentDir = true
|
||||||
|
return baseName, containerInfo, resolvedToParentDir, nil
|
||||||
|
}
|
||||||
|
|
||||||
// containerParentDir returns the parent directory of the specified path on the
|
// containerParentDir returns the parent directory of the specified path on the
|
||||||
// container. If the path is relative, it will be resolved relative to the
|
// container. If the path is relative, it will be resolved relative to the
|
||||||
// container's working directory (or "/" if the work dir isn't set).
|
// container's working directory (or "/" if the work dir isn't set).
|
||||||
|
Reference in New Issue
Block a user