mirror of
https://github.com/containers/podman.git
synced 2025-06-28 06:18:57 +08:00
archive: move stat-header handling into copy package
Move handling the stat header into `pkg/copy`. All copy-related should ideally be located in this package to increase locality and reduce scattering where possible. Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
This commit is contained in:
@ -1,13 +1,8 @@
|
|||||||
package compat
|
package compat
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/containers/podman/v2/libpod"
|
"github.com/containers/podman/v2/libpod"
|
||||||
"github.com/containers/podman/v2/libpod/define"
|
"github.com/containers/podman/v2/libpod/define"
|
||||||
@ -71,12 +66,12 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
|
|||||||
utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
|
utils.Error(w, "Not found.", http.StatusNotFound, errors.Wrapf(err, "error stating container path %q", query.Path))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
statHeader, err := fileInfoToDockerStats(info)
|
statHeader, err := copy.EncodeFileInfo(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
|
utils.Error(w, "Something went wrong", http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Header().Add("X-Docker-Container-Path-Stat", statHeader)
|
w.Header().Add(copy.XDockerContainerPathStatHeader, statHeader)
|
||||||
|
|
||||||
// Our work is done when the user is interested in the header only.
|
// Our work is done when the user is interested in the header only.
|
||||||
if r.Method == http.MethodHead {
|
if r.Method == http.MethodHead {
|
||||||
@ -98,42 +93,6 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileInfoToDockerStats(info *copy.FileInfo) (string, error) {
|
|
||||||
dockerStats := struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Size int64 `json:"size"`
|
|
||||||
Mode os.FileMode `json:"mode"`
|
|
||||||
ModTime time.Time `json:"mtime"`
|
|
||||||
LinkTarget string `json:"linkTarget"`
|
|
||||||
}{
|
|
||||||
Name: info.Name,
|
|
||||||
Size: info.Size,
|
|
||||||
Mode: info.Mode,
|
|
||||||
ModTime: info.ModTime,
|
|
||||||
LinkTarget: info.LinkTarget,
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonBytes, err := json.Marshal(&dockerStats)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "failed to serialize file stats")
|
|
||||||
}
|
|
||||||
|
|
||||||
buff := bytes.NewBuffer(make([]byte, 0, 128))
|
|
||||||
base64encoder := base64.NewEncoder(base64.StdEncoding, buff)
|
|
||||||
|
|
||||||
_, err = base64encoder.Write(jsonBytes)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = base64encoder.Close()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return buff.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) {
|
func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) {
|
||||||
query := struct {
|
query := struct {
|
||||||
Path string `schema:"path"`
|
Path string `schema:"path"`
|
||||||
|
@ -114,7 +114,6 @@ func enforceCopyRules(source, destination *CopyItem) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source is a *stream*.
|
|
||||||
if source.info.IsStream {
|
if source.info.IsStream {
|
||||||
if !(destination.info.IsDir || destination.info.IsStream) {
|
if !(destination.info.IsDir || destination.info.IsStream) {
|
||||||
return errors.New("destination must be a directory or stream when copying from a stream")
|
return errors.New("destination must be a directory or stream when copying from a stream")
|
||||||
|
56
pkg/copy/fileinfo.go
Normal file
56
pkg/copy/fileinfo.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package copy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// XDockerContainerPathStatHeader is the *key* in http headers pointing to the
|
||||||
|
// base64 encoded JSON payload of stating a path in a container.
|
||||||
|
const XDockerContainerPathStatHeader = "X-Docker-Container-Path-Stat"
|
||||||
|
|
||||||
|
// FileInfo describes a file or directory and is returned by
|
||||||
|
// (*CopyItem).Stat().
|
||||||
|
type FileInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Mode os.FileMode `json:"mode"`
|
||||||
|
ModTime time.Time `json:"mtime"`
|
||||||
|
IsDir bool `json:"isDir"`
|
||||||
|
IsStream bool `json:"isStream"`
|
||||||
|
LinkTarget string `json:"linkTarget"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeFileInfo serializes the specified FileInfo as a base64 encoded JSON
|
||||||
|
// payload. Intended for Docker compat.
|
||||||
|
func EncodeFileInfo(info *FileInfo) (string, error) {
|
||||||
|
buf, err := json.Marshal(&info)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to serialize file stats")
|
||||||
|
}
|
||||||
|
return base64.URLEncoding.EncodeToString(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtractFileInfoFromHeader extracts a base64 encoded JSON payload of a
|
||||||
|
// FileInfo in the http header. If no such header entry is found, nil is
|
||||||
|
// returned. Intended for Docker compat.
|
||||||
|
func ExtractFileInfoFromHeader(header *http.Header) (*FileInfo, error) {
|
||||||
|
rawData := header.Get(XDockerContainerPathStatHeader)
|
||||||
|
if len(rawData) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
info := FileInfo{}
|
||||||
|
base64Decoder := base64.NewDecoder(base64.URLEncoding, strings.NewReader(rawData))
|
||||||
|
if err := json.NewDecoder(base64Decoder).Decode(&info); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &info, nil
|
||||||
|
}
|
@ -5,7 +5,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
buildahCopiah "github.com/containers/buildah/copier"
|
buildahCopiah "github.com/containers/buildah/copier"
|
||||||
"github.com/containers/buildah/pkg/chrootuser"
|
"github.com/containers/buildah/pkg/chrootuser"
|
||||||
@ -75,18 +74,6 @@ type CopyItem struct {
|
|||||||
// deferFunc allows for returning functions that must be deferred at call sites.
|
// deferFunc allows for returning functions that must be deferred at call sites.
|
||||||
type deferFunc func()
|
type deferFunc func()
|
||||||
|
|
||||||
// FileInfo describes a file or directory and is returned by
|
|
||||||
// (*CopyItem).Stat().
|
|
||||||
type FileInfo struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Size int64 `json:"size"`
|
|
||||||
Mode os.FileMode `json:"mode"`
|
|
||||||
ModTime time.Time `json:"mtime"`
|
|
||||||
IsDir bool `json:"isDir"`
|
|
||||||
IsStream bool `json:"isStream"`
|
|
||||||
LinkTarget string `json:"linkTarget"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stat returns the FileInfo.
|
// Stat returns the FileInfo.
|
||||||
func (item *CopyItem) Stat() (*FileInfo, error) {
|
func (item *CopyItem) Stat() (*FileInfo, error) {
|
||||||
return &item.info, item.statError
|
return &item.info, item.statError
|
||||||
|
Reference in New Issue
Block a user