Merge pull request #166 from thaJeztah/update-term

Bump docker/docker to cd35e4beee13a7c193e2a89008cd87d38fcd0161
This commit is contained in:
Victor Vieux 2017-06-08 13:45:32 -07:00 committed by GitHub
commit a74e715b1a
20 changed files with 261 additions and 261 deletions

View File

@ -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

View File

@ -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)
}
}

View File

@ -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

View File

@ -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{

View File

@ -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

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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 // Archiver allows the reuse of most utility functions of this package
// with a pluggable Untar function. Also, to facilitate the passing of // with a pluggable Untar function. Also, to facilitate the passing of
// specific id mappings for untar, an archiver can be created with maps // specific id mappings for untar, an archiver can be created with maps
// which will then be passed to Untar operations // which will then be passed to Untar operations
Archiver struct { type Archiver struct {
Untar func(io.Reader, string, *TarOptions) error Untar func(io.Reader, string, *TarOptions) error
UIDMaps []idtools.IDMap IDMappings *idtools.IDMappings
GIDMaps []idtools.IDMap }
// NewDefaultArchiver returns a new Archiver without any IDMappings
func NewDefaultArchiver() *Archiver {
return &Archiver{Untar: Untar, IDMappings: &idtools.IDMappings{}}
} }
// breakoutError is used to differentiate errors related to breaking out // breakoutError is used to differentiate errors related to breaking out
// When testing archive breakout in the unit tests, this error is expected // When testing archive breakout in the unit tests, this error is expected
// in order for the test to pass. // in order for the test to pass.
breakoutError error type breakoutError error
)
var (
// ErrNotImplemented is the error message of function not implemented.
ErrNotImplemented = errors.New("Function not implemented")
defaultArchiver = &Archiver{Untar: Untar, UIDMaps: nil, GIDMaps: nil}
)
const (
// HeaderSize is the size in bytes of a tar header
HeaderSize = 512
)
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 {
@ -370,8 +346,7 @@ type tarAppender struct {
// 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,27 +882,9 @@ 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
// 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 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 {
writeFile, err := whiteoutConverter.ConvertRead(hdr, path) writeFile, err := whiteoutConverter.ConvertRead(hdr, path)
@ -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.

View File

@ -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 {

View File

@ -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
} }

View File

@ -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)

View File

@ -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
// 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 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
} }

View File

@ -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 uidMap != nil {
xUID, err := ToHost(0, uidMap)
if err != nil { if err != nil {
return -1, -1, err return -1, -1, err
} }
uid = xUID gid, err := toHost(0, gidMap)
}
if gidMap != nil {
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 {

View File

@ -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 {

View File

@ -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
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)