github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/api/client/lib/copy.go (about)

     1  package lib
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"net/url"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/docker/docker/api/types"
    14  )
    15  
    16  // ContainerStatPath returns Stat information about a path inside the container filesystem.
    17  func (cli *Client) ContainerStatPath(containerID, path string) (types.ContainerPathStat, error) {
    18  	query := url.Values{}
    19  	query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
    20  
    21  	urlStr := fmt.Sprintf("/containers/%s/archive", containerID)
    22  	response, err := cli.head(urlStr, query, nil)
    23  	if err != nil {
    24  		return types.ContainerPathStat{}, err
    25  	}
    26  	defer ensureReaderClosed(response)
    27  	return getContainerPathStatFromHeader(response.header)
    28  }
    29  
    30  // CopyToContainer copies content into the container filesystem.
    31  func (cli *Client) CopyToContainer(options types.CopyToContainerOptions) error {
    32  	query := url.Values{}
    33  	query.Set("path", filepath.ToSlash(options.Path)) // Normalize the paths used in the API.
    34  	// Do not allow for an existing directory to be overwritten by a non-directory and vice versa.
    35  	if !options.AllowOverwriteDirWithFile {
    36  		query.Set("noOverwriteDirNonDir", "true")
    37  	}
    38  
    39  	path := fmt.Sprintf("/containers/%s/archive", options.ContainerID)
    40  
    41  	response, err := cli.putRaw(path, query, options.Content, nil)
    42  	if err != nil {
    43  		return err
    44  	}
    45  	defer ensureReaderClosed(response)
    46  
    47  	if response.statusCode != http.StatusOK {
    48  		return fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
    49  	}
    50  
    51  	return nil
    52  }
    53  
    54  // CopyFromContainer get the content from the container and return it as a Reader
    55  // to manipulate it in the host. It's up to the caller to close the reader.
    56  func (cli *Client) CopyFromContainer(containerID, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) {
    57  	query := make(url.Values, 1)
    58  	query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
    59  
    60  	apiPath := fmt.Sprintf("/containers/%s/archive", containerID)
    61  	response, err := cli.get(apiPath, query, nil)
    62  	if err != nil {
    63  		return nil, types.ContainerPathStat{}, err
    64  	}
    65  
    66  	if response.statusCode != http.StatusOK {
    67  		return nil, types.ContainerPathStat{}, fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
    68  	}
    69  
    70  	// In order to get the copy behavior right, we need to know information
    71  	// about both the source and the destination. The response headers include
    72  	// stat info about the source that we can use in deciding exactly how to
    73  	// copy it locally. Along with the stat info about the local destination,
    74  	// we have everything we need to handle the multiple possibilities there
    75  	// can be when copying a file/dir from one location to another file/dir.
    76  	stat, err := getContainerPathStatFromHeader(response.header)
    77  	if err != nil {
    78  		return nil, stat, fmt.Errorf("unable to get resource stat from response: %s", err)
    79  	}
    80  	return response.body, stat, err
    81  }
    82  
    83  func getContainerPathStatFromHeader(header http.Header) (types.ContainerPathStat, error) {
    84  	var stat types.ContainerPathStat
    85  
    86  	encodedStat := header.Get("X-Docker-Container-Path-Stat")
    87  	statDecoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encodedStat))
    88  
    89  	err := json.NewDecoder(statDecoder).Decode(&stat)
    90  	if err != nil {
    91  		err = fmt.Errorf("unable to decode container path stat header: %s", err)
    92  	}
    93  
    94  	return stat, err
    95  }