mirror of
https://github.com/containers/podman.git
synced 2025-06-21 01:19:15 +08:00
cp: consolidate and simplify
Consolidate and simplify code in `podman cp` a bit. PR #11049 introduced some code duplicates that were worth tackling. [NO TESTS NEEDED] Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
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)
|
||||
}
|
||||
|
||||
var destContainerBaseName string
|
||||
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)
|
||||
destContainerBaseName, destContainerInfo, destResolvedToParentDir, err := resolvePathOnDestinationContainer(destContainer, destPath, false)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, destContainer)
|
||||
}
|
||||
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)
|
||||
return err
|
||||
}
|
||||
|
||||
if sourceContainerInfo.IsDir && !destContainerInfo.IsDir {
|
||||
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 {
|
||||
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
|
||||
// exist, we copy the source's parent and let the copier package create
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -202,7 +176,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
|
||||
defer reader.Close()
|
||||
|
||||
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
|
||||
// rename accordingly.
|
||||
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 resolvedToHostParentDir bool
|
||||
hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath)
|
||||
if hostInfoErr != nil {
|
||||
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
|
||||
// base path.
|
||||
hostBaseName = filepath.Base(hostPath)
|
||||
resolvedToHostParentDir = true
|
||||
} else {
|
||||
// If the specified path exists on the host, we must use its
|
||||
// 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
|
||||
// destination via the Rename option.
|
||||
containerTarget := containerInfo.LinkTarget
|
||||
if hostInfoErr != nil && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
|
||||
if resolvedToHostParentDir && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
|
||||
containerTarget = filepath.Dir(containerTarget)
|
||||
}
|
||||
|
||||
@ -322,7 +298,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
|
||||
ChownFiles: &idPair,
|
||||
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
|
||||
// rename accordingly.
|
||||
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)
|
||||
}
|
||||
|
||||
// If the path on the container does not exist. We need to make sure
|
||||
// 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)
|
||||
containerBaseName, containerInfo, containerResolvedToParentDir, err := resolvePathOnDestinationContainer(container, containerPath, isStdin)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
|
||||
}
|
||||
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)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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
|
||||
// the destination via the Rename option.
|
||||
hostTarget := hostInfo.LinkTarget
|
||||
if containerInfoErr != nil && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
|
||||
if containerResolvedToParentDir && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
|
||||
hostTarget = filepath.Dir(hostTarget)
|
||||
}
|
||||
|
||||
@ -468,7 +411,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
|
||||
// copy the base directory.
|
||||
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
|
||||
// rename accordingly.
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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).
|
||||
|
Reference in New Issue
Block a user