mirror of https://github.com/docker/cli.git
Merge pull request #166 from thaJeztah/update-term
Bump docker/docker to cd35e4beee13a7c193e2a89008cd87d38fcd0161
This commit is contained in:
commit
a74e715b1a
|
@ -28,6 +28,8 @@ import (
|
||||||
const (
|
const (
|
||||||
// DefaultDockerfileName is the Default filename with Docker commands, read by docker build
|
// DefaultDockerfileName is the Default filename with Docker commands, read by docker build
|
||||||
DefaultDockerfileName string = "Dockerfile"
|
DefaultDockerfileName string = "Dockerfile"
|
||||||
|
// archiveHeaderSize is the number of bytes in an archive header
|
||||||
|
archiveHeaderSize = 512
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidateContextDirectory checks if all the contents of the directory
|
// ValidateContextDirectory checks if all the contents of the directory
|
||||||
|
@ -84,12 +86,12 @@ func ValidateContextDirectory(srcPath string, excludes []string) error {
|
||||||
func GetContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) {
|
func GetContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCloser, relDockerfile string, err error) {
|
||||||
buf := bufio.NewReader(r)
|
buf := bufio.NewReader(r)
|
||||||
|
|
||||||
magic, err := buf.Peek(archive.HeaderSize)
|
magic, err := buf.Peek(archiveHeaderSize)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
return nil, "", errors.Errorf("failed to peek context header from STDIN: %v", err)
|
return nil, "", errors.Errorf("failed to peek context header from STDIN: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if archive.IsArchive(magic) {
|
if IsArchive(magic) {
|
||||||
return ioutils.NewReadCloserWrapper(buf, func() error { return r.Close() }), dockerfileName, nil
|
return ioutils.NewReadCloserWrapper(buf, func() error { return r.Close() }), dockerfileName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +135,18 @@ func GetContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCl
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsArchive checks for the magic bytes of a tar or any supported compression
|
||||||
|
// algorithm.
|
||||||
|
func IsArchive(header []byte) bool {
|
||||||
|
compression := archive.DetectCompression(header)
|
||||||
|
if compression != archive.Uncompressed {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
r := tar.NewReader(bytes.NewBuffer(header))
|
||||||
|
_, err := r.Next()
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetContextFromGitURL uses a Git URL as context for a `docker build`. The
|
// GetContextFromGitURL uses a Git URL as context for a `docker build`. The
|
||||||
// git repo is cloned into a temporary directory used as the context directory.
|
// git repo is cloned into a temporary directory used as the context directory.
|
||||||
// Returns the absolute path to the temporary context directory, the relative
|
// Returns the absolute path to the temporary context directory, the relative
|
||||||
|
|
|
@ -266,3 +266,35 @@ func chdir(t *testing.T, dir string) func() {
|
||||||
require.NoError(t, os.Chdir(dir))
|
require.NoError(t, os.Chdir(dir))
|
||||||
return func() { require.NoError(t, os.Chdir(workingDirectory)) }
|
return func() { require.NoError(t, os.Chdir(workingDirectory)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsArchive(t *testing.T) {
|
||||||
|
var testcases = []struct {
|
||||||
|
doc string
|
||||||
|
header []byte
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
doc: "nil is not a valid header",
|
||||||
|
header: nil,
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
doc: "invalid header bytes",
|
||||||
|
header: []byte{0x00, 0x01, 0x02},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
doc: "header for bzip2 archive",
|
||||||
|
header: []byte{0x42, 0x5A, 0x68},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
doc: "header for 7zip archive is not supported",
|
||||||
|
header: []byte{0x50, 0x4b, 0x03, 0x04},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testcase := range testcases {
|
||||||
|
assert.Equal(t, testcase.expected, IsArchive(testcase.header), testcase.doc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ github.com/coreos/etcd 824277cb3a577a0e8c829ca9ec557b973fe06d20
|
||||||
github.com/cpuguy83/go-md2man a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
|
github.com/cpuguy83/go-md2man a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
|
||||||
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
|
||||||
github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621
|
github.com/docker/distribution b38e5838b7b2f2ad48e06ec4b500011976080621
|
||||||
github.com/docker/docker c8141a1fb1ff33b2bfab85a40e5da9a282f36cdc
|
github.com/docker/docker cd35e4beee13a7c193e2a89008cd87d38fcd0161
|
||||||
github.com/docker/docker-credential-helpers v0.5.1
|
github.com/docker/docker-credential-helpers v0.5.1
|
||||||
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06 #?
|
github.com/docker/go d30aec9fd63c35133f8f79c3412ad91a3b08be06 #?
|
||||||
github.com/docker/go-connections e15c02316c12de00874640cd76311849de2aeed5
|
github.com/docker/go-connections e15c02316c12de00874640cd76311849de2aeed5
|
||||||
|
|
|
@ -216,9 +216,9 @@ func (cli *Client) getAPIPath(p string, query url.Values) string {
|
||||||
var apiPath string
|
var apiPath string
|
||||||
if cli.version != "" {
|
if cli.version != "" {
|
||||||
v := strings.TrimPrefix(cli.version, "v")
|
v := strings.TrimPrefix(cli.version, "v")
|
||||||
apiPath = fmt.Sprintf("%s/v%s%s", cli.basePath, v, p)
|
apiPath = cli.basePath + "/v" + v + p
|
||||||
} else {
|
} else {
|
||||||
apiPath = fmt.Sprintf("%s%s", cli.basePath, p)
|
apiPath = cli.basePath + p
|
||||||
}
|
}
|
||||||
|
|
||||||
u := &url.URL{
|
u := &url.URL{
|
||||||
|
|
|
@ -20,7 +20,7 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
|
query.Set("path", filepath.ToSlash(path)) // Normalize the paths used in the API.
|
||||||
|
|
||||||
urlStr := fmt.Sprintf("/containers/%s/archive", containerID)
|
urlStr := "/containers/" + containerID + "/archive"
|
||||||
response, err := cli.head(ctx, urlStr, query, nil)
|
response, err := cli.head(ctx, urlStr, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ContainerPathStat{}, err
|
return types.ContainerPathStat{}, err
|
||||||
|
@ -42,7 +42,7 @@ func (cli *Client) CopyToContainer(ctx context.Context, container, path string,
|
||||||
query.Set("copyUIDGID", "true")
|
query.Set("copyUIDGID", "true")
|
||||||
}
|
}
|
||||||
|
|
||||||
apiPath := fmt.Sprintf("/containers/%s/archive", container)
|
apiPath := "/containers/" + container + "/archive"
|
||||||
|
|
||||||
response, err := cli.putRaw(ctx, apiPath, query, content, nil)
|
response, err := cli.putRaw(ctx, apiPath, query, content, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -63,7 +63,7 @@ func (cli *Client) CopyFromContainer(ctx context.Context, container, srcPath str
|
||||||
query := make(url.Values, 1)
|
query := make(url.Values, 1)
|
||||||
query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
|
query.Set("path", filepath.ToSlash(srcPath)) // Normalize the paths used in the API.
|
||||||
|
|
||||||
apiPath := fmt.Sprintf("/containers/%s/archive", container)
|
apiPath := "/containers/" + container + "/archive"
|
||||||
response, err := cli.get(ctx, apiPath, query, nil)
|
response, err := cli.get(ctx, apiPath, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, types.ContainerPathStat{}, err
|
return nil, types.ContainerPathStat{}, err
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
@ -10,7 +8,7 @@ import (
|
||||||
// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers
|
// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers
|
||||||
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
|
||||||
var ping types.Ping
|
var ping types.Ping
|
||||||
req, err := cli.buildRequest("GET", fmt.Sprintf("%s/_ping", cli.basePath), nil, nil)
|
req, err := cli.buildRequest("GET", cli.basePath+"/_ping", nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ping, err
|
return ping, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
@ -33,5 +32,5 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types
|
||||||
|
|
||||||
func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) {
|
func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) {
|
||||||
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
|
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
|
||||||
return cli.post(ctx, fmt.Sprintf("/plugins/%s/upgrade", name), query, privileges, headers)
|
return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, headers)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/bzip2"
|
"compress/bzip2"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -31,10 +30,6 @@ type (
|
||||||
Compression int
|
Compression int
|
||||||
// WhiteoutFormat is the format of whiteouts unpacked
|
// WhiteoutFormat is the format of whiteouts unpacked
|
||||||
WhiteoutFormat int
|
WhiteoutFormat int
|
||||||
// TarChownOptions wraps the chown options UID and GID.
|
|
||||||
TarChownOptions struct {
|
|
||||||
UID, GID int
|
|
||||||
}
|
|
||||||
|
|
||||||
// TarOptions wraps the tar options.
|
// TarOptions wraps the tar options.
|
||||||
TarOptions struct {
|
TarOptions struct {
|
||||||
|
@ -44,7 +39,7 @@ type (
|
||||||
NoLchown bool
|
NoLchown bool
|
||||||
UIDMaps []idtools.IDMap
|
UIDMaps []idtools.IDMap
|
||||||
GIDMaps []idtools.IDMap
|
GIDMaps []idtools.IDMap
|
||||||
ChownOpts *TarChownOptions
|
ChownOpts *idtools.IDPair
|
||||||
IncludeSourceDir bool
|
IncludeSourceDir bool
|
||||||
// WhiteoutFormat is the expected on disk format for whiteout files.
|
// WhiteoutFormat is the expected on disk format for whiteout files.
|
||||||
// This format will be converted to the standard format on pack
|
// This format will be converted to the standard format on pack
|
||||||
|
@ -58,33 +53,26 @@ type (
|
||||||
RebaseNames map[string]string
|
RebaseNames map[string]string
|
||||||
InUserNS bool
|
InUserNS bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Archiver allows the reuse of most utility functions of this package
|
|
||||||
// with a pluggable Untar function. Also, to facilitate the passing of
|
|
||||||
// specific id mappings for untar, an archiver can be created with maps
|
|
||||||
// which will then be passed to Untar operations
|
|
||||||
Archiver struct {
|
|
||||||
Untar func(io.Reader, string, *TarOptions) error
|
|
||||||
UIDMaps []idtools.IDMap
|
|
||||||
GIDMaps []idtools.IDMap
|
|
||||||
}
|
|
||||||
|
|
||||||
// breakoutError is used to differentiate errors related to breaking out
|
|
||||||
// When testing archive breakout in the unit tests, this error is expected
|
|
||||||
// in order for the test to pass.
|
|
||||||
breakoutError error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// Archiver allows the reuse of most utility functions of this package
|
||||||
// ErrNotImplemented is the error message of function not implemented.
|
// with a pluggable Untar function. Also, to facilitate the passing of
|
||||||
ErrNotImplemented = errors.New("Function not implemented")
|
// specific id mappings for untar, an archiver can be created with maps
|
||||||
defaultArchiver = &Archiver{Untar: Untar, UIDMaps: nil, GIDMaps: nil}
|
// which will then be passed to Untar operations
|
||||||
)
|
type Archiver struct {
|
||||||
|
Untar func(io.Reader, string, *TarOptions) error
|
||||||
|
IDMappings *idtools.IDMappings
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
// NewDefaultArchiver returns a new Archiver without any IDMappings
|
||||||
// HeaderSize is the size in bytes of a tar header
|
func NewDefaultArchiver() *Archiver {
|
||||||
HeaderSize = 512
|
return &Archiver{Untar: Untar, IDMappings: &idtools.IDMappings{}}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
// breakoutError is used to differentiate errors related to breaking out
|
||||||
|
// When testing archive breakout in the unit tests, this error is expected
|
||||||
|
// in order for the test to pass.
|
||||||
|
type breakoutError error
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Uncompressed represents the uncompressed.
|
// Uncompressed represents the uncompressed.
|
||||||
|
@ -105,18 +93,6 @@ const (
|
||||||
OverlayWhiteoutFormat
|
OverlayWhiteoutFormat
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsArchive checks for the magic bytes of a tar or any supported compression
|
|
||||||
// algorithm.
|
|
||||||
func IsArchive(header []byte) bool {
|
|
||||||
compression := DetectCompression(header)
|
|
||||||
if compression != Uncompressed {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
r := tar.NewReader(bytes.NewBuffer(header))
|
|
||||||
_, err := r.Next()
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsArchivePath checks if the (possibly compressed) file at the given path
|
// IsArchivePath checks if the (possibly compressed) file at the given path
|
||||||
// starts with a tar file header.
|
// starts with a tar file header.
|
||||||
func IsArchivePath(path string) bool {
|
func IsArchivePath(path string) bool {
|
||||||
|
@ -369,9 +345,8 @@ type tarAppender struct {
|
||||||
Buffer *bufio.Writer
|
Buffer *bufio.Writer
|
||||||
|
|
||||||
// for hardlink mapping
|
// for hardlink mapping
|
||||||
SeenFiles map[uint64]string
|
SeenFiles map[uint64]string
|
||||||
UIDMaps []idtools.IDMap
|
IDMappings *idtools.IDMappings
|
||||||
GIDMaps []idtools.IDMap
|
|
||||||
|
|
||||||
// For packing and unpacking whiteout files in the
|
// For packing and unpacking whiteout files in the
|
||||||
// non standard format. The whiteout files defined
|
// non standard format. The whiteout files defined
|
||||||
|
@ -380,6 +355,15 @@ type tarAppender struct {
|
||||||
WhiteoutConverter tarWhiteoutConverter
|
WhiteoutConverter tarWhiteoutConverter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer) *tarAppender {
|
||||||
|
return &tarAppender{
|
||||||
|
SeenFiles: make(map[uint64]string),
|
||||||
|
TarWriter: tar.NewWriter(writer),
|
||||||
|
Buffer: pools.BufioWriter32KPool.Get(nil),
|
||||||
|
IDMappings: idMapping,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// canonicalTarName provides a platform-independent and consistent posix-style
|
// canonicalTarName provides a platform-independent and consistent posix-style
|
||||||
//path for files and directories to be archived regardless of the platform.
|
//path for files and directories to be archived regardless of the platform.
|
||||||
func canonicalTarName(name string, isDir bool) (string, error) {
|
func canonicalTarName(name string, isDir bool) (string, error) {
|
||||||
|
@ -428,21 +412,15 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
||||||
//handle re-mapping container ID mappings back to host ID mappings before
|
//handle re-mapping container ID mappings back to host ID mappings before
|
||||||
//writing tar headers/files. We skip whiteout files because they were written
|
//writing tar headers/files. We skip whiteout files because they were written
|
||||||
//by the kernel and already have proper ownership relative to the host
|
//by the kernel and already have proper ownership relative to the host
|
||||||
if !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && (ta.UIDMaps != nil || ta.GIDMaps != nil) {
|
if !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IDMappings.Empty() {
|
||||||
uid, gid, err := getFileUIDGID(fi.Sys())
|
fileIDPair, err := getFileUIDGID(fi.Sys())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
xUID, err := idtools.ToContainer(uid, ta.UIDMaps)
|
hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
xGID, err := idtools.ToContainer(gid, ta.GIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hdr.Uid = xUID
|
|
||||||
hdr.Gid = xGID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ta.WhiteoutConverter != nil {
|
if ta.WhiteoutConverter != nil {
|
||||||
|
@ -496,7 +474,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *TarChownOptions, inUserns bool) error {
|
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error {
|
||||||
// hdr.Mode is in linux format, which we can use for sycalls,
|
// hdr.Mode is in linux format, which we can use for sycalls,
|
||||||
// but for os.Foo() calls we need the mode converted to os.FileMode,
|
// but for os.Foo() calls we need the mode converted to os.FileMode,
|
||||||
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
|
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
|
||||||
|
@ -576,7 +554,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
|
||||||
// Lchown is not supported on Windows.
|
// Lchown is not supported on Windows.
|
||||||
if Lchown && runtime.GOOS != "windows" {
|
if Lchown && runtime.GOOS != "windows" {
|
||||||
if chownOpts == nil {
|
if chownOpts == nil {
|
||||||
chownOpts = &TarChownOptions{UID: hdr.Uid, GID: hdr.Gid}
|
chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
|
||||||
}
|
}
|
||||||
if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
|
if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -664,14 +642,11 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
ta := &tarAppender{
|
ta := newTarAppender(
|
||||||
TarWriter: tar.NewWriter(compressWriter),
|
idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
|
||||||
Buffer: pools.BufioWriter32KPool.Get(nil),
|
compressWriter,
|
||||||
SeenFiles: make(map[uint64]string),
|
)
|
||||||
UIDMaps: options.UIDMaps,
|
ta.WhiteoutConverter = getWhiteoutConverter(options.WhiteoutFormat)
|
||||||
GIDMaps: options.GIDMaps,
|
|
||||||
WhiteoutConverter: getWhiteoutConverter(options.WhiteoutFormat),
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// Make sure to check the error on Close.
|
// Make sure to check the error on Close.
|
||||||
|
@ -827,10 +802,8 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
|
||||||
defer pools.BufioReader32KPool.Put(trBuf)
|
defer pools.BufioReader32KPool.Put(trBuf)
|
||||||
|
|
||||||
var dirs []*tar.Header
|
var dirs []*tar.Header
|
||||||
remappedRootUID, remappedRootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
|
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||||
if err != nil {
|
rootIDs := idMappings.RootPair()
|
||||||
return err
|
|
||||||
}
|
|
||||||
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
|
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
|
||||||
|
|
||||||
// Iterate through the files in the archive.
|
// Iterate through the files in the archive.
|
||||||
|
@ -864,7 +837,7 @@ loop:
|
||||||
parent := filepath.Dir(hdr.Name)
|
parent := filepath.Dir(hdr.Name)
|
||||||
parentPath := filepath.Join(dest, parent)
|
parentPath := filepath.Join(dest, parent)
|
||||||
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
|
if _, err := os.Lstat(parentPath); err != nil && os.IsNotExist(err) {
|
||||||
err = idtools.MkdirAllNewAs(parentPath, 0777, remappedRootUID, remappedRootGID)
|
err = idtools.MkdirAllAndChownNew(parentPath, 0777, rootIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -909,26 +882,8 @@ loop:
|
||||||
}
|
}
|
||||||
trBuf.Reset(tr)
|
trBuf.Reset(tr)
|
||||||
|
|
||||||
// if the options contain a uid & gid maps, convert header uid/gid
|
if err := remapIDs(idMappings, hdr); err != nil {
|
||||||
// entries using the maps such that lchown sets the proper mapped
|
return err
|
||||||
// uid/gid after writing the file. We only perform this mapping if
|
|
||||||
// the file isn't already owned by the remapped root UID or GID, as
|
|
||||||
// that specific uid/gid has no mapping from container -> host, and
|
|
||||||
// those files already have the proper ownership for inside the
|
|
||||||
// container.
|
|
||||||
if hdr.Uid != remappedRootUID {
|
|
||||||
xUID, err := idtools.ToHost(hdr.Uid, options.UIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hdr.Uid = xUID
|
|
||||||
}
|
|
||||||
if hdr.Gid != remappedRootGID {
|
|
||||||
xGID, err := idtools.ToHost(hdr.Gid, options.GIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hdr.Gid = xGID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if whiteoutConverter != nil {
|
if whiteoutConverter != nil {
|
||||||
|
@ -1013,23 +968,13 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer archive.Close()
|
defer archive.Close()
|
||||||
|
options := &TarOptions{
|
||||||
var options *TarOptions
|
UIDMaps: archiver.IDMappings.UIDs(),
|
||||||
if archiver.UIDMaps != nil || archiver.GIDMaps != nil {
|
GIDMaps: archiver.IDMappings.GIDs(),
|
||||||
options = &TarOptions{
|
|
||||||
UIDMaps: archiver.UIDMaps,
|
|
||||||
GIDMaps: archiver.GIDMaps,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return archiver.Untar(archive, dst, options)
|
return archiver.Untar(archive, dst, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
|
|
||||||
// If either Tar or Untar fails, TarUntar aborts and returns the error.
|
|
||||||
func TarUntar(src, dst string) error {
|
|
||||||
return defaultArchiver.TarUntar(src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UntarPath untar a file from path to a destination, src is the source tar file path.
|
// UntarPath untar a file from path to a destination, src is the source tar file path.
|
||||||
func (archiver *Archiver) UntarPath(src, dst string) error {
|
func (archiver *Archiver) UntarPath(src, dst string) error {
|
||||||
archive, err := os.Open(src)
|
archive, err := os.Open(src)
|
||||||
|
@ -1037,22 +982,13 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer archive.Close()
|
defer archive.Close()
|
||||||
var options *TarOptions
|
options := &TarOptions{
|
||||||
if archiver.UIDMaps != nil || archiver.GIDMaps != nil {
|
UIDMaps: archiver.IDMappings.UIDs(),
|
||||||
options = &TarOptions{
|
GIDMaps: archiver.IDMappings.GIDs(),
|
||||||
UIDMaps: archiver.UIDMaps,
|
|
||||||
GIDMaps: archiver.GIDMaps,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return archiver.Untar(archive, dst, options)
|
return archiver.Untar(archive, dst, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UntarPath is a convenience function which looks for an archive
|
|
||||||
// at filesystem path `src`, and unpacks it at `dst`.
|
|
||||||
func UntarPath(src, dst string) error {
|
|
||||||
return defaultArchiver.UntarPath(src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyWithTar creates a tar archive of filesystem path `src`, and
|
// CopyWithTar creates a tar archive of filesystem path `src`, and
|
||||||
// unpacks it at filesystem path `dst`.
|
// unpacks it at filesystem path `dst`.
|
||||||
// The archive is streamed directly with fixed buffering and no
|
// The archive is streamed directly with fixed buffering and no
|
||||||
|
@ -1069,27 +1005,16 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
|
||||||
// if this archiver is set up with ID mapping we need to create
|
// if this archiver is set up with ID mapping we need to create
|
||||||
// the new destination directory with the remapped root UID/GID pair
|
// the new destination directory with the remapped root UID/GID pair
|
||||||
// as owner
|
// as owner
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(archiver.UIDMaps, archiver.GIDMaps)
|
rootIDs := archiver.IDMappings.RootPair()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Create dst, copy src's content into it
|
// Create dst, copy src's content into it
|
||||||
logrus.Debugf("Creating dest directory: %s", dst)
|
logrus.Debugf("Creating dest directory: %s", dst)
|
||||||
if err := idtools.MkdirAllNewAs(dst, 0755, rootUID, rootGID); err != nil {
|
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
|
||||||
return archiver.TarUntar(src, dst)
|
return archiver.TarUntar(src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyWithTar creates a tar archive of filesystem path `src`, and
|
|
||||||
// unpacks it at filesystem path `dst`.
|
|
||||||
// The archive is streamed directly with fixed buffering and no
|
|
||||||
// intermediary disk IO.
|
|
||||||
func CopyWithTar(src, dst string) error {
|
|
||||||
return defaultArchiver.CopyWithTar(src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyFileWithTar emulates the behavior of the 'cp' command-line
|
// CopyFileWithTar emulates the behavior of the 'cp' command-line
|
||||||
// for a single file. It copies a regular file from path `src` to
|
// for a single file. It copies a regular file from path `src` to
|
||||||
// path `dst`, and preserves all its metadata.
|
// path `dst`, and preserves all its metadata.
|
||||||
|
@ -1131,28 +1056,10 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
||||||
hdr.Name = filepath.Base(dst)
|
hdr.Name = filepath.Base(dst)
|
||||||
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
|
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
|
||||||
|
|
||||||
remappedRootUID, remappedRootGID, err := idtools.GetRootUIDGID(archiver.UIDMaps, archiver.GIDMaps)
|
if err := remapIDs(archiver.IDMappings, hdr); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// only perform mapping if the file being copied isn't already owned by the
|
|
||||||
// uid or gid of the remapped root in the container
|
|
||||||
if remappedRootUID != hdr.Uid {
|
|
||||||
xUID, err := idtools.ToHost(hdr.Uid, archiver.UIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hdr.Uid = xUID
|
|
||||||
}
|
|
||||||
if remappedRootGID != hdr.Gid {
|
|
||||||
xGID, err := idtools.ToHost(hdr.Gid, archiver.GIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hdr.Gid = xGID
|
|
||||||
}
|
|
||||||
|
|
||||||
tw := tar.NewWriter(w)
|
tw := tar.NewWriter(w)
|
||||||
defer tw.Close()
|
defer tw.Close()
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
|
@ -1176,16 +1083,10 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyFileWithTar emulates the behavior of the 'cp' command-line
|
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
|
||||||
// for a single file. It copies a regular file from path `src` to
|
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
|
||||||
// path `dst`, and preserves all its metadata.
|
hdr.Uid, hdr.Gid = ids.UID, ids.GID
|
||||||
//
|
return err
|
||||||
// Destination handling is in an operating specific manner depending
|
|
||||||
// where the daemon is running. If `dst` ends with a trailing slash
|
|
||||||
// the final destination path will be `dst/base(src)` (Linux) or
|
|
||||||
// `dst\base(src)` (Windows).
|
|
||||||
func CopyFileWithTar(src, dst string) (err error) {
|
|
||||||
return defaultArchiver.CopyFileWithTar(src, dst)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmdStream executes a command, and returns its stdout as a stream.
|
// cmdStream executes a command, and returns its stdout as a stream.
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/system"
|
"github.com/docker/docker/pkg/system"
|
||||||
rsystem "github.com/opencontainers/runc/libcontainer/system"
|
rsystem "github.com/opencontainers/runc/libcontainer/system"
|
||||||
)
|
)
|
||||||
|
@ -72,13 +73,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileUIDGID(stat interface{}) (int, int, error) {
|
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
||||||
s, ok := stat.(*syscall.Stat_t)
|
s, ok := stat.(*syscall.Stat_t)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return -1, -1, errors.New("cannot convert stat value to syscall.Stat_t")
|
return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t")
|
||||||
}
|
}
|
||||||
return int(s.Uid), int(s.Gid), nil
|
return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func major(device uint64) uint64 {
|
func major(device uint64) uint64 {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/idtools"
|
||||||
"github.com/docker/docker/pkg/longpath"
|
"github.com/docker/docker/pkg/longpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -72,7 +73,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFileUIDGID(stat interface{}) (int, int, error) {
|
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
|
||||||
// no notion of file ownership mapping yet on Windows
|
// no notion of file ownership mapping yet on Windows
|
||||||
return 0, 0, nil
|
return idtools.IDPair{0, 0}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -394,13 +394,8 @@ func ChangesSize(newDir string, changes []Change) int64 {
|
||||||
func ExportChanges(dir string, changes []Change, uidMaps, gidMaps []idtools.IDMap) (io.ReadCloser, error) {
|
func ExportChanges(dir string, changes []Change, uidMaps, gidMaps []idtools.IDMap) (io.ReadCloser, error) {
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
go func() {
|
go func() {
|
||||||
ta := &tarAppender{
|
ta := newTarAppender(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer)
|
||||||
TarWriter: tar.NewWriter(writer),
|
|
||||||
Buffer: pools.BufioWriter32KPool.Get(nil),
|
|
||||||
SeenFiles: make(map[uint64]string),
|
|
||||||
UIDMaps: uidMaps,
|
|
||||||
GIDMaps: gidMaps,
|
|
||||||
}
|
|
||||||
// this buffer is needed for the duration of this piped stream
|
// this buffer is needed for the duration of this piped stream
|
||||||
defer pools.BufioWriter32KPool.Put(ta.Buffer)
|
defer pools.BufioWriter32KPool.Put(ta.Buffer)
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||||
if options.ExcludePatterns == nil {
|
if options.ExcludePatterns == nil {
|
||||||
options.ExcludePatterns = []string{}
|
options.ExcludePatterns = []string{}
|
||||||
}
|
}
|
||||||
remappedRootUID, remappedRootGID, err := idtools.GetRootUIDGID(options.UIDMaps, options.GIDMaps)
|
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
aufsTempdir := ""
|
aufsTempdir := ""
|
||||||
aufsHardlinks := make(map[string]*tar.Header)
|
aufsHardlinks := make(map[string]*tar.Header)
|
||||||
|
@ -195,27 +192,10 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
|
||||||
srcData = tmpFile
|
srcData = tmpFile
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the options contain a uid & gid maps, convert header uid/gid
|
if err := remapIDs(idMappings, srcHdr); err != nil {
|
||||||
// entries using the maps such that lchown sets the proper mapped
|
return 0, err
|
||||||
// uid/gid after writing the file. We only perform this mapping if
|
|
||||||
// the file isn't already owned by the remapped root UID or GID, as
|
|
||||||
// that specific uid/gid has no mapping from container -> host, and
|
|
||||||
// those files already have the proper ownership for inside the
|
|
||||||
// container.
|
|
||||||
if srcHdr.Uid != remappedRootUID {
|
|
||||||
xUID, err := idtools.ToHost(srcHdr.Uid, options.UIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
srcHdr.Uid = xUID
|
|
||||||
}
|
|
||||||
if srcHdr.Gid != remappedRootGID {
|
|
||||||
xGID, err := idtools.ToHost(srcHdr.Gid, options.GIDMaps)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
srcHdr.Gid = xGID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createTarFile(path, dest, srcHdr, srcData, true, nil, options.InUserNS); err != nil {
|
if err := createTarFile(path, dest, srcHdr, srcData, true, nil, options.InUserNS); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,49 +37,56 @@ const (
|
||||||
// MkdirAllAs creates a directory (include any along the path) and then modifies
|
// MkdirAllAs creates a directory (include any along the path) and then modifies
|
||||||
// ownership to the requested uid/gid. If the directory already exists, this
|
// ownership to the requested uid/gid. If the directory already exists, this
|
||||||
// function will still change ownership to the requested uid/gid pair.
|
// function will still change ownership to the requested uid/gid pair.
|
||||||
|
// Deprecated: Use MkdirAllAndChown
|
||||||
func MkdirAllAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
|
func MkdirAllAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
|
||||||
return mkdirAs(path, mode, ownerUID, ownerGID, true, true)
|
return mkdirAs(path, mode, ownerUID, ownerGID, true, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkdirAllNewAs creates a directory (include any along the path) and then modifies
|
|
||||||
// ownership ONLY of newly created directories to the requested uid/gid. If the
|
|
||||||
// directories along the path exist, no change of ownership will be performed
|
|
||||||
func MkdirAllNewAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
|
|
||||||
return mkdirAs(path, mode, ownerUID, ownerGID, true, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MkdirAs creates a directory and then modifies ownership to the requested uid/gid.
|
// MkdirAs creates a directory and then modifies ownership to the requested uid/gid.
|
||||||
// If the directory already exists, this function still changes ownership
|
// If the directory already exists, this function still changes ownership
|
||||||
|
// Deprecated: Use MkdirAndChown with a IDPair
|
||||||
func MkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
|
func MkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
|
||||||
return mkdirAs(path, mode, ownerUID, ownerGID, false, true)
|
return mkdirAs(path, mode, ownerUID, ownerGID, false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MkdirAllAndChown creates a directory (include any along the path) and then modifies
|
||||||
|
// ownership to the requested uid/gid. If the directory already exists, this
|
||||||
|
// function will still change ownership to the requested uid/gid pair.
|
||||||
|
func MkdirAllAndChown(path string, mode os.FileMode, ids IDPair) error {
|
||||||
|
return mkdirAs(path, mode, ids.UID, ids.GID, true, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
|
||||||
|
// If the directory already exists, this function still changes ownership
|
||||||
|
func MkdirAndChown(path string, mode os.FileMode, ids IDPair) error {
|
||||||
|
return mkdirAs(path, mode, ids.UID, ids.GID, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
|
||||||
|
// ownership ONLY of newly created directories to the requested uid/gid. If the
|
||||||
|
// directories along the path exist, no change of ownership will be performed
|
||||||
|
func MkdirAllAndChownNew(path string, mode os.FileMode, ids IDPair) error {
|
||||||
|
return mkdirAs(path, mode, ids.UID, ids.GID, true, false)
|
||||||
|
}
|
||||||
|
|
||||||
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
|
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
|
||||||
// If the maps are empty, then the root uid/gid will default to "real" 0/0
|
// If the maps are empty, then the root uid/gid will default to "real" 0/0
|
||||||
func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) {
|
func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) {
|
||||||
var uid, gid int
|
uid, err := toHost(0, uidMap)
|
||||||
|
if err != nil {
|
||||||
if uidMap != nil {
|
return -1, -1, err
|
||||||
xUID, err := ToHost(0, uidMap)
|
|
||||||
if err != nil {
|
|
||||||
return -1, -1, err
|
|
||||||
}
|
|
||||||
uid = xUID
|
|
||||||
}
|
}
|
||||||
if gidMap != nil {
|
gid, err := toHost(0, gidMap)
|
||||||
xGID, err := ToHost(0, gidMap)
|
if err != nil {
|
||||||
if err != nil {
|
return -1, -1, err
|
||||||
return -1, -1, err
|
|
||||||
}
|
|
||||||
gid = xGID
|
|
||||||
}
|
}
|
||||||
return uid, gid, nil
|
return uid, gid, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToContainer takes an id mapping, and uses it to translate a
|
// toContainer takes an id mapping, and uses it to translate a
|
||||||
// host ID to the remapped ID. If no map is provided, then the translation
|
// host ID to the remapped ID. If no map is provided, then the translation
|
||||||
// assumes a 1-to-1 mapping and returns the passed in id
|
// assumes a 1-to-1 mapping and returns the passed in id
|
||||||
func ToContainer(hostID int, idMap []IDMap) (int, error) {
|
func toContainer(hostID int, idMap []IDMap) (int, error) {
|
||||||
if idMap == nil {
|
if idMap == nil {
|
||||||
return hostID, nil
|
return hostID, nil
|
||||||
}
|
}
|
||||||
|
@ -92,10 +99,10 @@ func ToContainer(hostID int, idMap []IDMap) (int, error) {
|
||||||
return -1, fmt.Errorf("Host ID %d cannot be mapped to a container ID", hostID)
|
return -1, fmt.Errorf("Host ID %d cannot be mapped to a container ID", hostID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToHost takes an id mapping and a remapped ID, and translates the
|
// toHost takes an id mapping and a remapped ID, and translates the
|
||||||
// ID to the mapped host ID. If no map is provided, then the translation
|
// ID to the mapped host ID. If no map is provided, then the translation
|
||||||
// assumes a 1-to-1 mapping and returns the passed in id #
|
// assumes a 1-to-1 mapping and returns the passed in id #
|
||||||
func ToHost(contID int, idMap []IDMap) (int, error) {
|
func toHost(contID int, idMap []IDMap) (int, error) {
|
||||||
if idMap == nil {
|
if idMap == nil {
|
||||||
return contID, nil
|
return contID, nil
|
||||||
}
|
}
|
||||||
|
@ -108,26 +115,101 @@ func ToHost(contID int, idMap []IDMap) (int, error) {
|
||||||
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
|
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIDMappings takes a requested user and group name and
|
// IDPair is a UID and GID pair
|
||||||
|
type IDPair struct {
|
||||||
|
UID int
|
||||||
|
GID int
|
||||||
|
}
|
||||||
|
|
||||||
|
// IDMappings contains a mappings of UIDs and GIDs
|
||||||
|
type IDMappings struct {
|
||||||
|
uids []IDMap
|
||||||
|
gids []IDMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIDMappings takes a requested user and group name and
|
||||||
// using the data from /etc/sub{uid,gid} ranges, creates the
|
// using the data from /etc/sub{uid,gid} ranges, creates the
|
||||||
// proper uid and gid remapping ranges for that user/group pair
|
// proper uid and gid remapping ranges for that user/group pair
|
||||||
func CreateIDMappings(username, groupname string) ([]IDMap, []IDMap, error) {
|
func NewIDMappings(username, groupname string) (*IDMappings, error) {
|
||||||
subuidRanges, err := parseSubuid(username)
|
subuidRanges, err := parseSubuid(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
subgidRanges, err := parseSubgid(groupname)
|
subgidRanges, err := parseSubgid(groupname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(subuidRanges) == 0 {
|
if len(subuidRanges) == 0 {
|
||||||
return nil, nil, fmt.Errorf("No subuid ranges found for user %q", username)
|
return nil, fmt.Errorf("No subuid ranges found for user %q", username)
|
||||||
}
|
}
|
||||||
if len(subgidRanges) == 0 {
|
if len(subgidRanges) == 0 {
|
||||||
return nil, nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
|
return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
|
||||||
}
|
}
|
||||||
|
|
||||||
return createIDMap(subuidRanges), createIDMap(subgidRanges), nil
|
return &IDMappings{
|
||||||
|
uids: createIDMap(subuidRanges),
|
||||||
|
gids: createIDMap(subgidRanges),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIDMappingsFromMaps creates a new mapping from two slices
|
||||||
|
// Deprecated: this is a temporary shim while transitioning to IDMapping
|
||||||
|
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings {
|
||||||
|
return &IDMappings{uids: uids, gids: gids}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RootPair returns a uid and gid pair for the root user. The error is ignored
|
||||||
|
// because a root user always exists, and the defaults are correct when the uid
|
||||||
|
// and gid maps are empty.
|
||||||
|
func (i *IDMappings) RootPair() IDPair {
|
||||||
|
uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
|
||||||
|
return IDPair{UID: uid, GID: gid}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToHost returns the host UID and GID for the container uid, gid.
|
||||||
|
// Remapping is only performed if the ids aren't already the remapped root ids
|
||||||
|
func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
|
||||||
|
var err error
|
||||||
|
target := i.RootPair()
|
||||||
|
|
||||||
|
if pair.UID != target.UID {
|
||||||
|
target.UID, err = toHost(pair.UID, i.uids)
|
||||||
|
if err != nil {
|
||||||
|
return target, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pair.GID != target.GID {
|
||||||
|
target.GID, err = toHost(pair.GID, i.gids)
|
||||||
|
}
|
||||||
|
return target, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToContainer returns the container UID and GID for the host uid and gid
|
||||||
|
func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
|
||||||
|
uid, err := toContainer(pair.UID, i.uids)
|
||||||
|
if err != nil {
|
||||||
|
return -1, -1, err
|
||||||
|
}
|
||||||
|
gid, err := toContainer(pair.GID, i.gids)
|
||||||
|
return uid, gid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty returns true if there are no id mappings
|
||||||
|
func (i *IDMappings) Empty() bool {
|
||||||
|
return len(i.uids) == 0 && len(i.gids) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// UIDs return the UID mapping
|
||||||
|
// TODO: remove this once everything has been refactored to use pairs
|
||||||
|
func (i *IDMappings) UIDs() []IDMap {
|
||||||
|
return i.uids
|
||||||
|
}
|
||||||
|
|
||||||
|
// GIDs return the UID mapping
|
||||||
|
// TODO: remove this once everything has been refactored to use pairs
|
||||||
|
func (i *IDMappings) GIDs() []IDMap {
|
||||||
|
return i.gids
|
||||||
}
|
}
|
||||||
|
|
||||||
func createIDMap(subidRanges ranges) []IDMap {
|
func createIDMap(subidRanges ranges) []IDMap {
|
||||||
|
|
|
@ -69,15 +69,15 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
||||||
|
|
||||||
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
||||||
// if that uid, gid pair has access (execute bit) to the directory
|
// if that uid, gid pair has access (execute bit) to the directory
|
||||||
func CanAccess(path string, uid, gid int) bool {
|
func CanAccess(path string, pair IDPair) bool {
|
||||||
statInfo, err := system.Stat(path)
|
statInfo, err := system.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
fileMode := os.FileMode(statInfo.Mode())
|
fileMode := os.FileMode(statInfo.Mode())
|
||||||
permBits := fileMode.Perm()
|
permBits := fileMode.Perm()
|
||||||
return accessible(statInfo.UID() == uint32(uid),
|
return accessible(statInfo.UID() == uint32(pair.UID),
|
||||||
statInfo.GID() == uint32(gid), permBits)
|
statInfo.GID() == uint32(pair.GID), permBits)
|
||||||
}
|
}
|
||||||
|
|
||||||
func accessible(isOwner, isGroup bool, perms os.FileMode) bool {
|
func accessible(isOwner, isGroup bool, perms os.FileMode) bool {
|
||||||
|
|
|
@ -20,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
||||||
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
|
||||||
// if that uid, gid pair has access (execute bit) to the directory
|
// if that uid, gid pair has access (execute bit) to the directory
|
||||||
// Windows does not require/support this function, so always return true
|
// Windows does not require/support this function, so always return true
|
||||||
func CanAccess(path string, uid, gid int) bool {
|
func CanAccess(path string, pair IDPair) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func MakeRaw(fd uintptr) (*State, error) {
|
||||||
|
|
||||||
newState := oldState.termios
|
newState := oldState.termios
|
||||||
newState.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
|
newState.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
|
||||||
newState.Oflag |= unix.OPOST
|
newState.Oflag &^= unix.OPOST
|
||||||
newState.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
|
newState.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
|
||||||
newState.Cflag &^= (unix.CSIZE | unix.PARENB)
|
newState.Cflag &^= (unix.CSIZE | unix.PARENB)
|
||||||
newState.Cflag |= unix.CS8
|
newState.Cflag |= unix.CS8
|
||||||
|
|
|
@ -26,7 +26,7 @@ func MakeRaw(fd uintptr) (*State, error) {
|
||||||
newState := oldState.termios
|
newState := oldState.termios
|
||||||
|
|
||||||
newState.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
|
newState.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
|
||||||
newState.Oflag |= unix.OPOST
|
newState.Oflag &^= unix.OPOST
|
||||||
newState.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
|
newState.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
|
||||||
newState.Cflag &^= (unix.CSIZE | unix.PARENB)
|
newState.Cflag &^= (unix.CSIZE | unix.PARENB)
|
||||||
newState.Cflag |= unix.CS8
|
newState.Cflag |= unix.CS8
|
||||||
|
|
|
@ -757,19 +757,6 @@ func (r *Session) SearchRepositories(term string, limit int) (*registrytypes.Sea
|
||||||
return result, json.NewDecoder(res.Body).Decode(result)
|
return result, json.NewDecoder(res.Body).Decode(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAuthConfig returns the authentication settings for a session
|
|
||||||
// TODO(tiborvass): remove this once registry client v2 is vendored
|
|
||||||
func (r *Session) GetAuthConfig(withPasswd bool) *types.AuthConfig {
|
|
||||||
password := ""
|
|
||||||
if withPasswd {
|
|
||||||
password = r.authConfig.Password
|
|
||||||
}
|
|
||||||
return &types.AuthConfig{
|
|
||||||
Username: r.authConfig.Username,
|
|
||||||
Password: password,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isTimeout(err error) bool {
|
func isTimeout(err error) bool {
|
||||||
type timeout interface {
|
type timeout interface {
|
||||||
Timeout() bool
|
Timeout() bool
|
||||||
|
|
|
@ -26,7 +26,7 @@ github.com/imdario/mergo 0.2.1
|
||||||
golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
|
golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
github.com/docker/libnetwork 83e1e49475b88a9f1f8ba89a690a7d5de42e24b9
|
github.com/docker/libnetwork eb57059e91bc54c9da23c5a633b75b3faf910a68
|
||||||
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
|
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
|
||||||
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
|
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
|
||||||
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
|
@ -38,7 +38,7 @@ github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
|
||||||
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
|
github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
|
||||||
github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
|
github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
|
||||||
github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
|
github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
|
||||||
github.com/vishvananda/netlink 1e86b2bee5b6a7d377e4c02bb7f98209d6a7297c
|
github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969
|
||||||
github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
|
github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
|
||||||
github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
|
github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
|
||||||
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
|
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
|
||||||
|
@ -61,7 +61,7 @@ google.golang.org/grpc v1.0.4
|
||||||
github.com/miekg/pkcs11 df8ae6ca730422dba20c768ff38ef7d79077a59f
|
github.com/miekg/pkcs11 df8ae6ca730422dba20c768ff38ef7d79077a59f
|
||||||
|
|
||||||
# When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly
|
# When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly
|
||||||
github.com/opencontainers/runc 992a5be178a62e026f4069f443c6164912adbf09
|
github.com/opencontainers/runc 2d41c047c83e09a6d61d464906feb2a2f3c52aa4 https://github.com/docker/runc
|
||||||
github.com/opencontainers/image-spec f03dbe35d449c54915d235f1a3cf8f585a24babe
|
github.com/opencontainers/image-spec f03dbe35d449c54915d235f1a3cf8f585a24babe
|
||||||
github.com/opencontainers/runtime-spec d42f1eb741e6361e858d83fc75aa6893b66292c4 # specs
|
github.com/opencontainers/runtime-spec d42f1eb741e6361e858d83fc75aa6893b66292c4 # specs
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,9 @@ func (m *MountPoint) Cleanup() error {
|
||||||
|
|
||||||
// Setup sets up a mount point by either mounting the volume if it is
|
// Setup sets up a mount point by either mounting the volume if it is
|
||||||
// configured, or creating the source directory if supplied.
|
// configured, or creating the source directory if supplied.
|
||||||
func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (path string, err error) {
|
// The, optional, checkFun parameter allows doing additional checking
|
||||||
|
// before creating the source directory on the host.
|
||||||
|
func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if label.RelabelNeeded(m.Mode) {
|
if label.RelabelNeeded(m.Mode) {
|
||||||
|
@ -184,9 +186,17 @@ func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int) (path string
|
||||||
|
|
||||||
// system.MkdirAll() produces an error if m.Source exists and is a file (not a directory),
|
// system.MkdirAll() produces an error if m.Source exists and is a file (not a directory),
|
||||||
if m.Type == mounttypes.TypeBind {
|
if m.Type == mounttypes.TypeBind {
|
||||||
|
// Before creating the source directory on the host, invoke checkFun if it's not nil. One of
|
||||||
|
// the use case is to forbid creating the daemon socket as a directory if the daemon is in
|
||||||
|
// the process of shutting down.
|
||||||
|
if checkFun != nil {
|
||||||
|
if err := checkFun(m); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
// idtools.MkdirAllNewAs() produces an error if m.Source exists and is a file (not a directory)
|
// idtools.MkdirAllNewAs() produces an error if m.Source exists and is a file (not a directory)
|
||||||
// also, makes sure that if the directory is created, the correct remapped rootUID/rootGID will own it
|
// also, makes sure that if the directory is created, the correct remapped rootUID/rootGID will own it
|
||||||
if err := idtools.MkdirAllNewAs(m.Source, 0755, rootUID, rootGID); err != nil {
|
if err := idtools.MkdirAllAndChownNew(m.Source, 0755, rootIDs); err != nil {
|
||||||
if perr, ok := err.(*os.PathError); ok {
|
if perr, ok := err.(*os.PathError); ok {
|
||||||
if perr.Err != syscall.ENOTDIR {
|
if perr.Err != syscall.ENOTDIR {
|
||||||
return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source)
|
return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source)
|
||||||
|
|
Loading…
Reference in New Issue