summaryrefslogtreecommitdiff
path: root/pkg/copy/fileinfo.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/copy/fileinfo.go')
-rw-r--r--pkg/copy/fileinfo.go57
1 files changed, 56 insertions, 1 deletions
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
+}