From adcb3a7a609ba756f8b9de17521f0e3dce3b778e Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Fri, 11 Dec 2020 11:00:25 +0100 Subject: remote copy Implement `podman-remote cp` and break out the logic from the previously added `pkg/copy` into it's basic building blocks and move them up into the `ContainerEngine` interface and `cmd/podman`. The `--pause` and `--extract` flags are now deprecated and turned into nops. Note that this commit is vendoring a non-release version of Buildah to pull in updates to the copier package. Signed-off-by: Valentin Rothberg --- pkg/copy/fileinfo.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'pkg/copy/fileinfo.go') diff --git a/pkg/copy/fileinfo.go b/pkg/copy/fileinfo.go index 08b4eb377..50b0ca9a1 100644 --- a/pkg/copy/fileinfo.go +++ b/pkg/copy/fileinfo.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net/http" "os" + "path/filepath" "strings" "time" @@ -15,6 +16,10 @@ import ( // base64 encoded JSON payload of stating a path in a container. const XDockerContainerPathStatHeader = "X-Docker-Container-Path-Stat" +// ENOENT mimics the stdlib's ENONENT and can be used to implement custom logic +// while preserving the user-visible error message. +var ENOENT = errors.New("No such file or directory") + // FileInfo describes a file or directory and is returned by // (*CopyItem).Stat(). type FileInfo struct { @@ -23,7 +28,6 @@ type FileInfo struct { Mode os.FileMode `json:"mode"` ModTime time.Time `json:"mtime"` IsDir bool `json:"isDir"` - IsStream bool `json:"isStream"` LinkTarget string `json:"linkTarget"` } @@ -54,3 +58,54 @@ func ExtractFileInfoFromHeader(header *http.Header) (*FileInfo, error) { return &info, nil } + +// ResolveHostPath resolves the specified, possibly relative, path on the host. +func ResolveHostPath(path string) (*FileInfo, error) { + resolvedHostPath, err := filepath.Abs(path) + if err != nil { + return nil, err + } + resolvedHostPath = PreserveBasePath(path, resolvedHostPath) + + statInfo, err := os.Stat(resolvedHostPath) + if err != nil { + if os.IsNotExist(err) { + return nil, ENOENT + } + return nil, err + } + + return &FileInfo{ + Name: statInfo.Name(), + Size: statInfo.Size(), + Mode: statInfo.Mode(), + ModTime: statInfo.ModTime(), + IsDir: statInfo.IsDir(), + LinkTarget: resolvedHostPath, + }, nil +} + +// PreserveBasePath makes sure that the original base path (e.g., "/" or "./") +// is preserved. The filepath API among tends to clean up a bit too much but +// we *must* preserve this data by all means. +func PreserveBasePath(original, resolved string) string { + // Handle "/" + if strings.HasSuffix(original, "/") { + if !strings.HasSuffix(resolved, "/") { + resolved += "/" + } + return resolved + } + + // Handle "/." + if strings.HasSuffix(original, "/.") { + if strings.HasSuffix(resolved, "/") { // could be root! + resolved += "." + } else if !strings.HasSuffix(resolved, "/.") { + resolved += "/." + } + return resolved + } + + return resolved +} -- cgit v1.2.3-54-g00ecf