Add ADD/COPY --chown flag support to Windows

This implements chown support on Windows. Built-in accounts as well
as accounts included in the SAM database of the container are supported.

NOTE: IDPair is now named Identity and IDMappings is now named
IdentityMapping.

The following are valid examples:
ADD --chown=Guest . <some directory>
COPY --chown=Administrator . <some directory>
COPY --chown=Guests . <some directory>
COPY --chown=ContainerUser . <some directory>

On Windows an owner is only granted the permission to read the security
descriptor and read/write the discretionary access control list. This
fix also grants read/write and execute permissions to the owner.

Signed-off-by: Salahuddin Khan <salah@docker.com>
This commit is contained in:
Salahuddin Khan 2017-11-15 22:20:33 -08:00
parent 1fd7e4c28d
commit 763d839261
64 changed files with 610 additions and 301 deletions

View File

@ -56,21 +56,21 @@ type SessionGetter interface {
// BuildManager is shared across all Builder objects
type BuildManager struct {
idMappings *idtools.IDMappings
backend builder.Backend
pathCache pathCache // TODO: make this persistent
sg SessionGetter
fsCache *fscache.FSCache
idMapping *idtools.IdentityMapping
backend builder.Backend
pathCache pathCache // TODO: make this persistent
sg SessionGetter
fsCache *fscache.FSCache
}
// NewBuildManager creates a BuildManager
func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, idMappings *idtools.IDMappings) (*BuildManager, error) {
func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
bm := &BuildManager{
backend: b,
pathCache: &syncmap.Map{},
sg: sg,
idMappings: idMappings,
fsCache: fsCache,
backend: b,
pathCache: &syncmap.Map{},
sg: sg,
idMapping: identityMapping,
fsCache: fsCache,
}
if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil {
return nil, err
@ -111,7 +111,7 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
ProgressWriter: config.ProgressWriter,
Backend: bm.backend,
PathCache: bm.pathCache,
IDMappings: bm.idMappings,
IDMapping: bm.idMapping,
}
b, err := newBuilder(ctx, builderOptions)
if err != nil {
@ -159,7 +159,7 @@ type builderOptions struct {
Backend builder.Backend
ProgressWriter backend.ProgressWriter
PathCache pathCache
IDMappings *idtools.IDMappings
IDMapping *idtools.IdentityMapping
}
// Builder is a Dockerfile builder
@ -175,7 +175,7 @@ type Builder struct {
docker builder.Backend
clientCtx context.Context
idMappings *idtools.IDMappings
idMapping *idtools.IdentityMapping
disableCommit bool
imageSources *imageSources
pathCache pathCache
@ -199,7 +199,7 @@ func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, er
Aux: options.ProgressWriter.AuxFormatter,
Output: options.ProgressWriter.Output,
docker: options.Backend,
idMappings: options.IDMappings,
idMapping: options.IDMapping,
imageSources: newImageSources(clientCtx, options),
pathCache: options.PathCache,
imageProber: newImageProber(options.Backend, config.CacheFrom, config.NoCache),

View File

@ -451,7 +451,7 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
type copyFileOptions struct {
decompress bool
chownPair idtools.IDPair
identity idtools.Identity
archiver Archiver
}
@ -481,7 +481,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
return errors.Wrapf(err, "source path not found")
}
if src.IsDir() {
return copyDirectory(archiver, srcEndpoint, destEndpoint, options.chownPair)
return copyDirectory(archiver, srcEndpoint, destEndpoint, options.identity)
}
if options.decompress && isArchivePath(source.root, srcPath) && !source.noDecompress {
return archiver.UntarPath(srcPath, destPath)
@ -499,7 +499,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
destPath = dest.root.Join(destPath, source.root.Base(source.path))
destEndpoint = &copyEndpoint{driver: dest.root, path: destPath}
}
return copyFile(archiver, srcEndpoint, destEndpoint, options.chownPair)
return copyFile(archiver, srcEndpoint, destEndpoint, options.identity)
}
func isArchivePath(driver containerfs.ContainerFS, path string) bool {
@ -517,7 +517,7 @@ func isArchivePath(driver containerfs.ContainerFS, path string) bool {
return err == nil
}
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
destExists, err := isExistingDirectory(dest)
if err != nil {
return errors.Wrapf(err, "failed to query destination path")
@ -527,17 +527,17 @@ func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idto
return errors.Wrapf(err, "failed to copy directory")
}
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, chownPair, !destExists)
return fixPermissions(source.path, dest.path, identity, !destExists)
}
func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
func copyFile(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
if runtime.GOOS == "windows" && dest.driver.OS() == "linux" {
// LCOW
if err := dest.driver.MkdirAll(dest.driver.Dir(dest.path), 0755); err != nil {
return errors.Wrapf(err, "failed to create new directory")
}
} else {
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, chownPair); err != nil {
if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, identity); err != nil {
// Normal containers
return errors.Wrapf(err, "failed to create new directory")
}
@ -547,7 +547,7 @@ func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.I
return errors.Wrapf(err, "failed to copy file")
}
// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
return fixPermissions(source.path, dest.path, chownPair, false)
return fixPermissions(source.path, dest.path, identity, false)
}
func endsInSlash(driver containerfs.Driver, path string) bool {

View File

@ -10,7 +10,7 @@ import (
"github.com/docker/docker/pkg/idtools"
)
func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
func fixPermissions(source, destination string, identity idtools.Identity, overrideSkip bool) error {
var (
skipChownRoot bool
err error
@ -39,7 +39,7 @@ func fixPermissions(source, destination string, rootIDs idtools.IDPair, override
}
fullpath = filepath.Join(destination, cleaned)
return os.Lchown(fullpath, rootIDs.UID, rootIDs.GID)
return os.Lchown(fullpath, identity.UID, identity.GID)
})
}

View File

@ -1,11 +1,17 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/Microsoft/go-winio"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
var pathBlacklist = map[string]bool{
@ -13,9 +19,69 @@ var pathBlacklist = map[string]bool{
"c:\\windows": true,
}
func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
// chown is not supported on Windows
return nil
func init() {
reexec.Register("windows-fix-permissions", fixPermissionsReexec)
}
func fixPermissions(source, destination string, identity idtools.Identity, _ bool) error {
if identity.SID == "" {
return nil
}
cmd := reexec.Command("windows-fix-permissions", source, destination, identity.SID)
output, err := cmd.CombinedOutput()
return errors.Wrapf(err, "failed to exec windows-fix-permissions: %s", output)
}
func fixPermissionsReexec() {
err := fixPermissionsWindows(os.Args[1], os.Args[2], os.Args[3])
if err != nil {
fmt.Fprint(os.Stderr, err)
os.Exit(1)
}
}
func fixPermissionsWindows(source, destination, SID string) error {
privileges := []string{winio.SeRestorePrivilege, system.SeTakeOwnershipPrivilege}
err := winio.EnableProcessPrivileges(privileges)
if err != nil {
return err
}
defer winio.DisableProcessPrivileges(privileges)
sid, err := windows.StringToSid(SID)
if err != nil {
return err
}
// Owners on *nix have read/write/delete/read control and write DAC.
// Add an ACE that grants this to the user/group specified with the
// chown option. Currently Windows is not honoring the owner change,
// however, they are aware of this and it should be fixed at some
// point.
sddlString := system.SddlAdministratorsLocalSystem
sddlString += "(A;OICI;GRGWGXRCWDSD;;;" + SID + ")"
securityDescriptor, err := winio.SddlToSecurityDescriptor(sddlString)
if err != nil {
return err
}
var daclPresent uint32
var daclDefaulted uint32
var dacl *byte
err = system.GetSecurityDescriptorDacl(&securityDescriptor[0], &daclPresent, &dacl, &daclDefaulted)
if err != nil {
return err
}
return system.SetNamedSecurityInfo(windows.StringToUTF16Ptr(destination), system.SE_FILE_OBJECT, system.OWNER_SECURITY_INFORMATION|system.DACL_SECURITY_INFORMATION, sid, nil, dacl, nil)
}
func validateCopySourcePath(imageSource *imageMount, origPath, platform string) error {

View File

@ -37,7 +37,7 @@ type Archiver interface {
UntarPath(src, dst string) error
CopyWithTar(src, dst string) error
CopyFileWithTar(src, dst string) error
IDMappings() *idtools.IDMappings
IdentityMapping() *idtools.IdentityMapping
}
// The builder will use the following interfaces if the container fs implements
@ -68,11 +68,11 @@ func tarFunc(i interface{}) containerfs.TarFunc {
func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver {
t, u := tarFunc(src), untarFunc(dst)
return &containerfs.Archiver{
SrcDriver: src,
DstDriver: dst,
Tar: t,
Untar: u,
IDMappingsVar: b.idMappings,
SrcDriver: src,
DstDriver: dst,
Tar: t,
Untar: u,
IDMapping: b.idMapping,
}
}
@ -185,14 +185,18 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
return err
}
chownPair := b.idMappings.RootPair()
identity := b.idMapping.RootPair()
// if a chown was requested, perform the steps to get the uid, gid
// translated (if necessary because of user namespaces), and replace
// the root pair with the chown pair for copy operations
if inst.chownStr != "" {
chownPair, err = parseChownFlag(inst.chownStr, destInfo.root.Path(), b.idMappings)
identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root.Path(), b.idMapping)
if err != nil {
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
if b.options.Platform != "windows" {
return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
}
return errors.Wrapf(err, "unable to map container user account name to SID")
}
}
@ -200,7 +204,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
opts := copyFileOptions{
decompress: inst.allowLocalDecompression,
archiver: b.getArchiver(info.root, destInfo.root),
chownPair: chownPair,
identity: identity,
}
if err := performCopyForInfo(destInfo, info, opts); err != nil {
return errors.Wrapf(err, "failed to copy files")

View File

@ -11,11 +11,11 @@ import (
"github.com/pkg/errors"
)
func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
var userStr, grpStr string
parts := strings.Split(chown, ":")
if len(parts) > 2 {
return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
}
if len(parts) == 1 {
// if no group specified, use the user spec as group as well
@ -26,25 +26,25 @@ func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (
passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
}
groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
}
uid, err := lookupUser(userStr, passwdPath)
if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
}
gid, err := lookupGroup(grpStr, groupPath)
if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
}
// convert as necessary because of user namespaces
chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
if err != nil {
return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
}
return chownPair, nil
}

View File

@ -5,6 +5,7 @@ import (
"path/filepath"
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/pkg/idtools"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
@ -34,7 +35,7 @@ othergrp:x:6666:
},
}
remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
unmapped := &idtools.IDMappings{}
unmapped := &idtools.IdentityMapping{}
contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
defer cleanup()
@ -49,56 +50,72 @@ othergrp:x:6666:
// positive tests
for _, testcase := range []struct {
builder *Builder
name string
chownStr string
idMapping *idtools.IDMappings
expected idtools.IDPair
idMapping *idtools.IdentityMapping
state *dispatchState
expected idtools.Identity
}{
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDNoMap",
chownStr: "1",
idMapping: unmapped,
expected: idtools.IDPair{UID: 1, GID: 1},
state: &dispatchState{},
expected: idtools.Identity{UID: 1, GID: 1},
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDGIDNoMap",
chownStr: "0:1",
idMapping: unmapped,
expected: idtools.IDPair{UID: 0, GID: 1},
state: &dispatchState{},
expected: idtools.Identity{UID: 0, GID: 1},
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDWithMap",
chownStr: "0",
idMapping: remapped,
expected: idtools.IDPair{UID: 100000, GID: 100000},
state: &dispatchState{},
expected: idtools.Identity{UID: 100000, GID: 100000},
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UIDGIDWithMap",
chownStr: "1:33",
idMapping: remapped,
expected: idtools.IDPair{UID: 100001, GID: 100033},
state: &dispatchState{},
expected: idtools.Identity{UID: 100001, GID: 100033},
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UserNoMap",
chownStr: "bin:5555",
idMapping: unmapped,
expected: idtools.IDPair{UID: 1, GID: 5555},
state: &dispatchState{},
expected: idtools.Identity{UID: 1, GID: 5555},
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "GroupWithMap",
chownStr: "0:unicorn",
idMapping: remapped,
expected: idtools.IDPair{UID: 100000, GID: 101002},
state: &dispatchState{},
expected: idtools.Identity{UID: 100000, GID: 101002},
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UserOnlyWithMap",
chownStr: "unicorn",
idMapping: remapped,
expected: idtools.IDPair{UID: 101001, GID: 101002},
state: &dispatchState{},
expected: idtools.Identity{UID: 101001, GID: 101002},
},
} {
t.Run(testcase.name, func(t *testing.T) {
idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
idPair, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
assert.NilError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
assert.Check(t, is.DeepEqual(testcase.expected, idPair), "chown flag mapping failure")
})
@ -106,32 +123,40 @@ othergrp:x:6666:
// error tests
for _, testcase := range []struct {
builder *Builder
name string
chownStr string
idMapping *idtools.IDMappings
idMapping *idtools.IdentityMapping
state *dispatchState
descr string
}{
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "BadChownFlagFormat",
chownStr: "bob:1:555",
idMapping: unmapped,
state: &dispatchState{},
descr: "invalid chown string format: bob:1:555",
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "UserNoExist",
chownStr: "bob",
idMapping: unmapped,
state: &dispatchState{},
descr: "can't find uid for user bob: no such user: bob",
},
{
builder: &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
name: "GroupNoExist",
chownStr: "root:bob",
idMapping: unmapped,
state: &dispatchState{},
descr: "can't find gid for group bob: no such group: bob",
},
} {
t.Run(testcase.name, func(t *testing.T) {
_, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
_, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
assert.Check(t, is.Error(err, testcase.descr), "Expected error string doesn't match")
})
}

View File

@ -1,7 +1,120 @@
package dockerfile // import "github.com/docker/docker/builder/dockerfile"
import "github.com/docker/docker/pkg/idtools"
import (
"bytes"
"os"
"path/filepath"
"strings"
func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
return idMappings.RootPair(), nil
"github.com/containerd/containerd/platforms"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/system"
"github.com/pkg/errors"
"golang.org/x/sys/windows"
)
func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
if builder.options.Platform == "windows" {
return getAccountIdentity(builder, chown, ctrRootPath, state)
}
return identityMapping.RootPair(), nil
}
func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
// If this is potentially a string SID then attempt to convert it to verify
// this, otherwise continue looking for the account.
if strings.HasPrefix(accountName, "S-") || strings.HasPrefix(accountName, "s-") {
sid, err := windows.StringToSid(accountName)
if err == nil {
accountSid, err := sid.String()
if err != nil {
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
}
return idtools.Identity{SID: accountSid}, nil
}
}
// Attempt to obtain the SID using the name.
sid, _, accType, err := windows.LookupSID("", accountName)
// If this is a SID that is built-in and hence the same across all systems then use that.
if err == nil && (accType == windows.SidTypeAlias || accType == windows.SidTypeWellKnownGroup) {
accountSid, err := sid.String()
if err != nil {
return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
}
return idtools.Identity{SID: accountSid}, nil
}
// Check if the account name is one unique to containers.
if strings.EqualFold(accountName, "ContainerAdministrator") {
return idtools.Identity{SID: system.ContainerAdministratorSidString}, nil
} else if strings.EqualFold(accountName, "ContainerUser") {
return idtools.Identity{SID: system.ContainerUserSidString}, nil
}
// All other lookups failed, so therefore determine if the account in
// question exists in the container and if so, obtain its SID.
return lookupNTAccount(builder, accountName, state)
}
func lookupNTAccount(builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
source, _ := filepath.Split(os.Args[0])
target := "C:\\Docker"
targetExecutable := target + "\\containerutility.exe"
optionsPlatform, err := platforms.Parse(builder.options.Platform)
if err != nil {
return idtools.Identity{}, err
}
runConfig := copyRunConfig(state.runConfig,
withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
runConfig.ArgsEscaped = true
runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
hostConfig := &container.HostConfig{Mounts: []mount.Mount{
{
Type: mount.TypeBind,
Source: source,
Target: target,
ReadOnly: true,
},
},
}
container, err := builder.containerManager.Create(runConfig, hostConfig)
if err != nil {
return idtools.Identity{}, err
}
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
if err := builder.containerManager.Run(builder.clientCtx, container.ID, stdout, stderr); err != nil {
if err, ok := err.(*statusCodeError); ok {
return idtools.Identity{}, &jsonmessage.JSONError{
Message: stderr.String(),
Code: err.StatusCode(),
}
}
return idtools.Identity{}, err
}
accountSid := stdout.String()
return idtools.Identity{SID: accountSid}, nil
}

View File

@ -267,7 +267,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
return opts, errors.Wrap(err, "failed to create fscache")
}
manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IDMappings())
manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IdentityMapping())
if err != nil {
return opts, err
}

View File

@ -254,7 +254,7 @@ func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error
}
// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error {
func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity) error {
// TODO @jhowardmsft, @gupta-ak LCOW Support. This will need revisiting.
// We will need to do remote filesystem operations here.
if container.OS != runtime.GOOS {
@ -271,7 +271,7 @@ func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error
return err
}
if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIDs); err != nil {
if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIdentity); err != nil {
pthInfo, err2 := os.Stat(pth)
if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)

View File

@ -9,7 +9,7 @@ import (
func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
return &archive.TarOptions{
NoOverwriteDirNonDir: noOverwriteDirNonDir,
UIDMaps: daemon.idMappings.UIDs(),
GIDMaps: daemon.idMappings.GIDs(),
UIDMaps: daemon.idMapping.UIDs(),
GIDMaps: daemon.idMapping.GIDs(),
}
}

View File

@ -18,8 +18,10 @@ func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwrite
return nil, err
}
identity := idtools.Identity{UID: user.Uid, GID: user.Gid}
return &archive.TarOptions{
NoOverwriteDirNonDir: noOverwriteDirNonDir,
ChownOpts: &idtools.IDPair{UID: user.Uid, GID: user.Gid},
ChownOpts: &identity,
}, nil
}

View File

@ -132,7 +132,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
fallthrough
case ipcMode.IsShareable():
rootIDs := daemon.idMappings.RootPair()
rootIDs := daemon.idMapping.RootPair()
if !c.HasMountFor("/dev/shm") {
shmPath, err := c.ShmResourcePath()
if err != nil {
@ -179,7 +179,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
}
// retrieve possible remapped range start for root UID, GID
rootIDs := daemon.idMappings.RootPair()
rootIDs := daemon.idMapping.RootPair()
for _, s := range c.SecretReferences {
// TODO (ehazlett): use type switch when more are supported
@ -278,7 +278,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
// In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
func (daemon *Daemon) createSecretsDir(c *container.Container) error {
// retrieve possible remapped range start for root UID, GID
rootIDs := daemon.idMappings.RootPair()
rootIDs := daemon.idMapping.RootPair()
dir, err := c.SecretMountPath()
if err != nil {
return errors.Wrap(err, "error getting container secrets dir")
@ -304,7 +304,7 @@ func (daemon *Daemon) remountSecretDir(c *container.Container) error {
if err := label.Relabel(dir, c.MountLabel, false); err != nil {
logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
}
rootIDs := daemon.idMappings.RootPair()
rootIDs := daemon.idMapping.RootPair()
tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
// remount secrets ro
@ -407,5 +407,5 @@ func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
if err != nil {
return err
}
return idtools.MkdirAllAndChown(p, 0700, daemon.idMappings.RootPair())
return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
}

View File

@ -155,13 +155,14 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
}
// Set RWLayer for container after mount labels have been set
rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMappings))
rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMapping))
if err != nil {
return nil, errdefs.System(err)
}
container.RWLayer = rwLayer
rootIDs := daemon.idMappings.RootPair()
rootIDs := daemon.idMapping.RootPair()
if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
return nil, err
}

View File

@ -25,7 +25,7 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con
}
defer daemon.Unmount(container)
rootIDs := daemon.idMappings.RootPair()
rootIDs := daemon.idMapping.RootPair()
if err := container.SetupWorkingDirectory(rootIDs); err != nil {
return err
}

View File

@ -87,7 +87,7 @@ type Daemon struct {
seccompEnabled bool
apparmorEnabled bool
shutdown bool
idMappings *idtools.IDMappings
idMapping *idtools.IdentityMapping
// TODO: move graphDrivers field to an InfoService
graphDrivers map[string]string // By operating system
@ -594,11 +594,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
return nil, err
}
idMappings, err := setupRemappedRoot(config)
idMapping, err := setupRemappedRoot(config)
if err != nil {
return nil, err
}
rootIDs := idMappings.RootPair()
rootIDs := idMapping.RootPair()
if err := setupDaemonProcess(config); err != nil {
return nil, err
}
@ -749,7 +749,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
GraphDriver: gd,
GraphDriverOptions: config.GraphOptions,
IDMappings: idMappings,
IDMapping: idMapping,
PluginGetter: d.PluginStore,
ExperimentalEnabled: config.Experimental,
OS: operatingSystem,
@ -856,7 +856,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
d.EventsService = events.New()
d.root = config.Root
d.idMappings = idMappings
d.idMapping = idMapping
d.seccompEnabled = sysInfo.Seccomp
d.apparmorEnabled = sysInfo.AppArmor
@ -1106,7 +1106,7 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
// prepareTempDir prepares and returns the default directory to use
// for temporary files.
// If it doesn't exist, it is created. If it exists, its content is removed.
func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
func prepareTempDir(rootDir string, rootIdentity idtools.Identity) (string, error) {
var tmpDir string
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
tmpDir = filepath.Join(rootDir, "tmp")
@ -1126,7 +1126,7 @@ func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
}
// We don't remove the content of tmpdir if it's not the default,
// it may hold things that do not belong to us.
return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIDs)
return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIdentity)
}
func (daemon *Daemon) setGenericResources(conf *config.Config) error {
@ -1274,11 +1274,11 @@ func CreateDaemonRoot(config *config.Config) error {
}
}
idMappings, err := setupRemappedRoot(config)
idMapping, err := setupRemappedRoot(config)
if err != nil {
return err
}
return setupDaemonRoot(config, realRoot, idMappings.RootPair())
return setupDaemonRoot(config, realRoot, idMapping.RootPair())
}
// checkpointAndSave grabs a container lock to safely call container.CheckpointTo
@ -1304,9 +1304,9 @@ func (daemon *Daemon) GetAttachmentStore() *network.AttachmentStore {
return &daemon.attachmentStore
}
// IDMappings returns uid/gid mappings for the builder
func (daemon *Daemon) IDMappings() *idtools.IDMappings {
return daemon.idMappings
// IdentityMapping returns uid/gid mapping or a SID (in the case of Windows) for the builder
func (daemon *Daemon) IdentityMapping() *idtools.IdentityMapping {
return daemon.idMapping
}
// ImageService returns the Daemon's ImageService

View File

@ -124,7 +124,7 @@ func TestTmpfsDevShmSizeOverride(t *testing.T) {
mnt := "/dev/shm"
d := Daemon{
idMappings: &idtools.IDMappings{},
idMapping: &idtools.IdentityMapping{},
}
c := &container.Container{
HostConfig: &containertypes.HostConfig{

View File

@ -118,7 +118,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
repository: tmp,
root: tmp,
}
daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.IDPair{UID: 0, GID: 0}, daemon)
daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.Identity{UID: 0, GID: 0}, daemon)
if err != nil {
return nil, err
}

View File

@ -1003,9 +1003,9 @@ func removeDefaultBridgeInterface() {
}
}
func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
return func(initPath containerfs.ContainerFS) error {
return initlayer.Setup(initPath, idMappings.RootPair())
return initlayer.Setup(initPath, idMapping.RootPair())
}
}
@ -1102,7 +1102,7 @@ func parseRemappedRoot(usergrp string) (string, string, error) {
return username, groupname, nil
}
func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
if runtime.GOOS != "linux" && config.RemappedRoot != "" {
return nil, fmt.Errorf("User namespaces are only supported on Linux")
}
@ -1118,22 +1118,22 @@ func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
// effectively
logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
return &idtools.IDMappings{}, nil
return &idtools.IdentityMapping{}, nil
}
logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
// update remapped root setting now that we have resolved them to actual names
config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
mappings, err := idtools.NewIDMappings(username, groupname)
mappings, err := idtools.NewIdentityMapping(username, groupname)
if err != nil {
return nil, errors.Wrap(err, "Can't create ID mappings")
}
return mappings, nil
}
return &idtools.IDMappings{}, nil
return &idtools.IdentityMapping{}, nil
}
func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
config.Root = rootDir
// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
// so that syscalls executing as non-root, operating on subdirectories of the graph root
@ -1158,10 +1158,10 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPa
// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
// `chdir()` to work for containers namespaced to that uid/gid)
if config.RemappedRoot != "" {
config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID))
config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIdentity.UID, rootIdentity.GID))
logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
// Create the root directory if it doesn't exist
if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil {
if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIdentity); err != nil {
return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
}
// we also need to verify that any pre-existing directories in the path to
@ -1174,7 +1174,7 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPa
if dirPath == "/" {
break
}
if !idtools.CanAccess(dirPath, rootIDs) {
if !idtools.CanAccess(dirPath, rootIdentity) {
return fmt.Errorf("a subdirectory in your graphroot path (%s) restricts access to the remapped root uid/gid; please fix by allowing 'o+x' permissions on existing directories", config.Root)
}
}

View File

@ -53,7 +53,7 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
return nil
}
func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
return nil
}
@ -465,11 +465,11 @@ func (daemon *Daemon) cleanupMounts() error {
return nil
}
func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
return &idtools.IDMappings{}, nil
func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
return &idtools.IdentityMapping{}, nil
}
func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
config.Root = rootDir
// Create the root directory if it doesn't exists
if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {

View File

@ -68,8 +68,8 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
archive, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{
Compression: archive.Uncompressed,
UIDMaps: daemon.idMappings.UIDs(),
GIDMaps: daemon.idMappings.GIDs(),
UIDMaps: daemon.idMapping.UIDs(),
GIDMaps: daemon.idMapping.GIDs(),
})
if err != nil {
rwlayer.Unmount()

View File

@ -135,13 +135,13 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err
}
// Create the root aufs driver dir
if err := idtools.MkdirAllAndChown(root, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(root, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}
// Populate the dir structure
for _, p := range paths {
if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}
}
@ -289,7 +289,7 @@ func (a *Driver) createDirsFor(id string) error {
// The path of directories are <aufs_root_path>/mnt/<image_id>
// and <aufs_root_path>/diff/<image_id>
for _, p := range paths {
if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return err
}
}

View File

@ -72,7 +72,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
if err != nil {
return nil, err
}
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}
@ -502,7 +502,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
if err != nil {
return err
}
if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return err
}
if parent == "" {
@ -537,7 +537,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
return err
}
if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return err
}
if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil {

View File

@ -268,7 +268,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
if err != nil {
return "", err
}
if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
return "", err
}
@ -1691,7 +1691,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
if err != nil {
return err
}
if err := idtools.MkdirAndChown(devices.root, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAndChown(devices.root, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
return err
}
if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {

View File

@ -200,11 +200,11 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
}
// Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
d.ctr.Decrement(mp)
return nil, err
}
if err := idtools.MkdirAndChown(mp, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
if err := idtools.MkdirAndChown(mp, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
d.ctr.Decrement(mp)
return nil, err
}
@ -215,7 +215,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
return nil, err
}
if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
d.ctr.Decrement(mp)
d.DeviceSet.UnmountDevice(id, mp)
return nil, err

View File

@ -183,17 +183,17 @@ func InitDriver(dataRoot string, options []string, _, _ []idtools.IDMap) (graphd
}
// Make sure the dataRoot directory is created
if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("%s failed to create '%s': %v", title, dataRoot, err)
}
// Make sure the cache directory is created under dataRoot
if err := idtools.MkdirAllAndChown(cd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
if err := idtools.MkdirAllAndChown(cd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("%s failed to create '%s': %v", title, cd, err)
}
// Make sure the scratch directory is created under dataRoot
if err := idtools.MkdirAllAndChown(sd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
if err := idtools.MkdirAllAndChown(sd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("%s failed to create '%s': %v", title, sd, err)
}

View File

@ -168,7 +168,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err
}
// Create the driver home dir
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}
@ -291,7 +291,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if err != nil {
return err
}
root := idtools.IDPair{UID: rootUID, GID: rootGID}
root := idtools.Identity{UID: rootUID, GID: rootGID}
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
return err
@ -413,7 +413,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
if err != nil {
return nil, err
}
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}
var (

View File

@ -200,7 +200,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err
}
// Create the driver home dir
if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}
@ -378,7 +378,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
if err != nil {
return err
}
root := idtools.IDPair{UID: rootUID, GID: rootGID}
root := idtools.Identity{UID: rootUID, GID: rootGID}
if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
return err
@ -586,7 +586,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
if err != nil {
return nil, err
}
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}

View File

@ -27,10 +27,10 @@ func init() {
// This sets the home directory for the driver and returns NaiveDiffDriver.
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
d := &Driver{
home: home,
idMappings: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
home: home,
idMapping: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
}
rootIDs := d.idMappings.RootPair()
rootIDs := d.idMapping.RootPair()
if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
return nil, err
}
@ -46,8 +46,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
// Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver
type Driver struct {
driverQuota
home string
idMappings *idtools.IDMappings
home string
idMapping *idtools.IdentityMapping
}
func (d *Driver) String() string {
@ -105,7 +105,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
func (d *Driver) create(id, parent string, size uint64) error {
dir := d.dir(id)
rootIDs := d.idMappings.RootPair()
rootIDs := d.idMapping.RootPair()
if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil {
return err
}

View File

@ -95,7 +95,7 @@ func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap)
return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
}
if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
}

View File

@ -106,7 +106,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
if err != nil {
return nil, fmt.Errorf("Failed to get root uid/guid: %v", err)
}
if err := idtools.MkdirAllAndChown(base, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(base, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
}
@ -385,7 +385,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
return nil, err
}
// Create the target directories if they don't exist
if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
return nil, err
}

View File

@ -162,7 +162,7 @@ func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInf
if selinuxEnabled() {
securityOptions = append(securityOptions, "name=selinux")
}
if rootIDs := daemon.idMappings.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
securityOptions = append(securityOptions, "name=userns")
}
v.SecurityOptions = securityOptions

View File

@ -17,7 +17,7 @@ import (
//
// This extra layer is used by all containers as the top-most ro layer. It protects
// the container from unwanted side-effects on the rw layer.
func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
// Since all paths are local to the container, we can just extract initLayerFs.Path()
initLayer := initLayerFs.Path()
@ -42,12 +42,12 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
if os.IsNotExist(err) {
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIDs); err != nil {
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIdentity); err != nil {
return err
}
switch typ {
case "dir":
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIDs); err != nil {
if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIdentity); err != nil {
return err
}
case "file":
@ -55,7 +55,7 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
if err != nil {
return err
}
f.Chown(rootIDs.UID, rootIDs.GID)
f.Chown(rootIdentity.UID, rootIdentity.GID)
f.Close()
default:
if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {

View File

@ -11,6 +11,6 @@ import (
//
// This extra layer is used by all containers as the top-most ro layer. It protects
// the container from unwanted side-effects on the rw layer.
func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.IDPair) error {
func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.Identity) error {
return nil
}

View File

@ -217,13 +217,13 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
userNS := false
// user
if c.HostConfig.UsernsMode.IsPrivate() {
uidMap := daemon.idMappings.UIDs()
uidMap := daemon.idMapping.UIDs()
if uidMap != nil {
userNS = true
ns := specs.LinuxNamespace{Type: "user"}
setNamespace(s, ns)
s.Linux.UIDMappings = specMapping(uidMap)
s.Linux.GIDMappings = specMapping(daemon.idMappings.GIDs())
s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs())
}
}
// network
@ -619,7 +619,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {
if uidMap := daemon.idMapping.UIDs(); uidMap != nil || c.HostConfig.Privileged {
for i, m := range s.Mounts {
if m.Type == "cgroup" {
clearReadOnly(&s.Mounts[i])
@ -642,7 +642,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
Path: c.BaseFS.Path(),
Readonly: c.HostConfig.ReadonlyRootfs,
}
if err := c.SetupWorkingDirectory(daemon.idMappings.RootPair()); err != nil {
if err := c.SetupWorkingDirectory(daemon.idMapping.RootPair()); err != nil {
return err
}
cwd := c.Config.WorkingDir

View File

@ -21,7 +21,7 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
d := Daemon{
// some empty structs to avoid getting a panic
// caused by a null pointer dereference
idMappings: &idtools.IDMappings{},
idMapping: &idtools.IdentityMapping{},
configStore: &config.Config{},
}
c := &container.Container{
@ -58,7 +58,7 @@ func TestIpcPrivateVsReadonly(t *testing.T) {
d := Daemon{
// some empty structs to avoid getting a panic
// caused by a null pointer dereference
idMappings: &idtools.IDMappings{},
idMapping: &idtools.IdentityMapping{},
configStore: &config.Config{},
}
c := &container.Container{

View File

@ -47,7 +47,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
return nil
}
path, err := m.Setup(c.MountLabel, daemon.idMappings.RootPair(), checkfunc)
path, err := m.Setup(c.MountLabel, daemon.idMapping.RootPair(), checkfunc)
if err != nil {
return nil, err
}
@ -77,7 +77,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
// if we are going to mount any of the network files from container
// metadata, the ownership must be set properly for potential container
// remapped root (user namespaces)
rootIDs := daemon.idMappings.RootPair()
rootIDs := daemon.idMapping.RootPair()
for _, mount := range netMounts {
// we should only modify ownership of network files within our own container
// metadata repository. If the user specifies a mount path external, it is

View File

@ -24,7 +24,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil {
return nil, err
}
s, err := mount.Setup(c.MountLabel, idtools.IDPair{UID: 0, GID: 0}, nil)
s, err := mount.Setup(c.MountLabel, idtools.Identity{}, nil)
if err != nil {
return nil, err
}

View File

@ -16,5 +16,5 @@ func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
return err
}
defer daemon.Unmount(container)
return container.SetupWorkingDirectory(daemon.idMappings.RootPair())
return container.SetupWorkingDirectory(daemon.idMapping.RootPair())
}

View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
CONTAINER_UTILITY_COMMIT=e004a1415a433447369e315b9d7df357102be0d2 # v0.9.0
(
git clone https://github.com/docker/windows-container-utility.git "$GOPATH/src/github.com/docker/windows-container-utility"
cd "$GOPATH/src/github.com/docker/windows-container-utility"
git checkout -q "$CONTAINER_UTILITY_COMMIT"
echo Building: ${DEST}/containerutility.exe
(
make
)
mkdir -p ${ABS_DEST}
cp containerutility.exe ${ABS_DEST}/containerutility.exe
)

View File

@ -25,5 +25,7 @@ for platform in $DOCKER_CROSSPLATFORMS; do
mkdir -p "$DEST"
ABS_DEST="$(cd "$DEST" && pwd -P)"
source "${MAKEDIR}/binary-daemon"
source "${MAKEDIR}/cross-platform-dependent"
)
done

View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
if [ $platform == "windows/amd64" ]; then
source "${MAKEDIR}/containerutility"
fi

View File

@ -45,7 +45,7 @@ type StoreOptions struct {
MetadataStorePathTemplate string
GraphDriver string
GraphDriverOptions []string
IDMappings *idtools.IDMappings
IDMapping *idtools.IdentityMapping
PluginGetter plugingetter.PluginGetter
ExperimentalEnabled bool
OS string
@ -56,8 +56,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
Root: options.Root,
DriverOptions: options.GraphDriverOptions,
UIDMaps: options.IDMappings.UIDs(),
GIDMaps: options.IDMappings.GIDs(),
UIDMaps: options.IDMapping.UIDs(),
GIDMaps: options.IDMapping.GIDs(),
ExperimentalEnabled: options.ExperimentalEnabled,
})
if err != nil {

View File

@ -58,7 +58,7 @@ func getSpecUser(ociSpec *specs.Spec) (int, int) {
func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
uid, gid := getSpecUser(ociSpec)
if uid == 0 && gid == 0 {
return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.IDPair{UID: 0, GID: 0})
return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.Identity{UID: 0, GID: 0})
}
p := string(filepath.Separator)
@ -71,7 +71,7 @@ func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
}
if os.IsNotExist(err) || fi.Mode()&1 == 0 {
p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
if err := idtools.MkdirAndChown(p, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
if err := idtools.MkdirAndChown(p, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
return "", err
}
}

View File

@ -52,7 +52,7 @@ type (
NoLchown bool
UIDMaps []idtools.IDMap
GIDMaps []idtools.IDMap
ChownOpts *idtools.IDPair
ChownOpts *idtools.Identity
IncludeSourceDir bool
// WhiteoutFormat is the expected on disk format for whiteout files.
// This format will be converted to the standard format on pack
@ -72,13 +72,13 @@ type (
// 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.
type Archiver struct {
Untar func(io.Reader, string, *TarOptions) error
IDMappingsVar *idtools.IDMappings
Untar func(io.Reader, string, *TarOptions) error
IDMapping *idtools.IdentityMapping
}
// NewDefaultArchiver returns a new Archiver without any IDMappings
// NewDefaultArchiver returns a new Archiver without any IdentityMapping
func NewDefaultArchiver() *Archiver {
return &Archiver{Untar: Untar, IDMappingsVar: &idtools.IDMappings{}}
return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}}
}
// breakoutError is used to differentiate errors related to breaking out
@ -420,9 +420,9 @@ type tarAppender struct {
Buffer *bufio.Writer
// for hardlink mapping
SeenFiles map[uint64]string
IDMappings *idtools.IDMappings
ChownOpts *idtools.IDPair
SeenFiles map[uint64]string
IdentityMapping *idtools.IdentityMapping
ChownOpts *idtools.Identity
// For packing and unpacking whiteout files in the
// non standard format. The whiteout files defined
@ -431,13 +431,13 @@ type tarAppender struct {
WhiteoutConverter tarWhiteoutConverter
}
func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
return &tarAppender{
SeenFiles: make(map[uint64]string),
TarWriter: tar.NewWriter(writer),
Buffer: pools.BufioWriter32KPool.Get(nil),
IDMappings: idMapping,
ChownOpts: chownOpts,
SeenFiles: make(map[uint64]string),
TarWriter: tar.NewWriter(writer),
Buffer: pools.BufioWriter32KPool.Get(nil),
IdentityMapping: idMapping,
ChownOpts: chownOpts,
}
}
@ -502,14 +502,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
//handle re-mapping container ID mappings back to host ID mappings before
//writing tar headers/files. We skip whiteout files because they were written
//by the kernel and already have proper ownership relative to the host
if !isOverlayWhiteout &&
!strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) &&
!ta.IDMappings.Empty() {
if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
fileIDPair, err := getFileUIDGID(fi.Sys())
if err != nil {
return err
}
hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair)
hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIDPair)
if err != nil {
return err
}
@ -572,7 +570,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
return nil
}
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error {
func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.Identity, inUserns bool) error {
// 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,
// so use hdrInfo.Mode() (they differ for e.g. setuid bits)
@ -652,7 +650,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
// Lchown is not supported on Windows.
if Lchown && runtime.GOOS != "windows" {
if chownOpts == nil {
chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
chownOpts = &idtools.Identity{UID: hdr.Uid, GID: hdr.Gid}
}
if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
return err
@ -901,8 +899,8 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
defer pools.BufioReader32KPool.Put(trBuf)
var dirs []*tar.Header
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMappings.RootPair()
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMapping.RootPair()
whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
// Iterate through the files in the archive.
@ -981,7 +979,7 @@ loop:
}
trBuf.Reset(tr)
if err := remapIDs(idMappings, hdr); err != nil {
if err := remapIDs(idMapping, hdr); err != nil {
return err
}
@ -1068,8 +1066,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
}
defer archive.Close()
options := &TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(),
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
}
return archiver.Untar(archive, dst, options)
}
@ -1082,8 +1080,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
}
defer archive.Close()
options := &TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(),
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
}
return archiver.Untar(archive, dst, options)
}
@ -1104,7 +1102,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
// if this Archiver is set up with ID mapping we need to create
// the new destination directory with the remapped root UID/GID pair
// as owner
rootIDs := archiver.IDMappingsVar.RootPair()
rootIDs := archiver.IDMapping.RootPair()
// Create dst, copy src's content into it
logrus.Debugf("Creating dest directory: %s", dst)
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
@ -1164,7 +1162,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
hdr.Name = filepath.Base(dst)
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
if err := remapIDs(archiver.IDMapping, hdr); err != nil {
return err
}
@ -1192,13 +1190,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
return err
}
// IDMappings returns the IDMappings of the archiver.
func (archiver *Archiver) IDMappings() *idtools.IDMappings {
return archiver.IDMappingsVar
// IdentityMapping returns the IdentityMapping of the archiver.
func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
return archiver.IDMapping
}
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
hdr.Uid, hdr.Gid = ids.UID, ids.GID
return err
}

View File

@ -755,11 +755,11 @@ func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) {
expectedUID int
expectedGID int
}{
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1337, GID: 42}}, 1337, 42},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
{&TarOptions{ChownOpts: &idtools.Identity{UID: 1337, GID: 42}}, 1337, 42},
{&TarOptions{ChownOpts: &idtools.Identity{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
{&TarOptions{ChownOpts: &idtools.Identity{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
{&TarOptions{ChownOpts: &idtools.Identity{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
{&TarOptions{ChownOpts: &idtools.Identity{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
}
for _, testCase := range cases {
reader, err := TarWithOptions(filePath, testCase.opts)

View File

@ -68,13 +68,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) {
return
}
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
s, ok := stat.(*syscall.Stat_t)
if !ok {
return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t")
return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t")
}
return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil
return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil
}
// handleTarTypeBlockCharFifo is an OS-specific helper function used by

View File

@ -61,7 +61,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
return nil
}
func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
// no notion of file ownership mapping yet on Windows
return idtools.IDPair{UID: 0, GID: 0}, nil
return idtools.Identity{UID: 0, GID: 0}, nil
}

View File

@ -33,7 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
if options.ExcludePatterns == nil {
options.ExcludePatterns = []string{}
}
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
aufsTempdir := ""
aufsHardlinks := make(map[string]*tar.Header)
@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
srcData = tmpFile
}
if err := remapIDs(idMappings, srcHdr); err != nil {
if err := remapIDs(idMapping, srcHdr); err != nil {
return 0, err
}

View File

@ -12,13 +12,13 @@ import (
)
// NewArchiver returns a new Archiver which uses chrootarchive.Untar
func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver {
if idMappings == nil {
idMappings = &idtools.IDMappings{}
func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
if idMapping == nil {
idMapping = &idtools.IdentityMapping{}
}
return &archive.Archiver{
Untar: Untar,
IDMappingsVar: idMappings,
Untar: Untar,
IDMapping: idMapping,
}
}
@ -49,8 +49,8 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
options.ExcludePatterns = []string{}
}
idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMappings.RootPair()
idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
rootIDs := idMapping.RootPair()
dest = filepath.Clean(dest)
if _, err := os.Stat(dest); os.IsNotExist(err) {

View File

@ -22,11 +22,11 @@ type UntarFunc func(io.Reader, string, *archive.TarOptions) error
// Archiver provides a similar implementation of the archive.Archiver package with the rootfs abstraction
type Archiver struct {
SrcDriver Driver
DstDriver Driver
Tar TarFunc
Untar UntarFunc
IDMappingsVar *idtools.IDMappings
SrcDriver Driver
DstDriver Driver
Tar TarFunc
Untar UntarFunc
IDMapping *idtools.IdentityMapping
}
// TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
@ -39,8 +39,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
}
defer tarArchive.Close()
options := &archive.TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(),
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
}
return archiver.Untar(tarArchive, dst, options)
}
@ -53,8 +53,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
}
defer tarArchive.Close()
options := &archive.TarOptions{
UIDMaps: archiver.IDMappingsVar.UIDs(),
GIDMaps: archiver.IDMappingsVar.GIDs(),
UIDMaps: archiver.IDMapping.UIDs(),
GIDMaps: archiver.IDMapping.GIDs(),
}
return archiver.Untar(tarArchive, dst, options)
}
@ -75,9 +75,11 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
// if this archiver is set up with ID mapping we need to create
// the new destination directory with the remapped root UID/GID pair
// as owner
rootIDs := archiver.IDMappingsVar.RootPair()
identity := idtools.Identity{UID: archiver.IDMapping.RootPair().UID, GID: archiver.IDMapping.RootPair().GID}
// Create dst, copy src's content into it
if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
if err := idtools.MkdirAllAndChownNew(dst, 0755, identity); err != nil {
return err
}
logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
@ -150,7 +152,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
hdr.Mode = int64(os.FileMode(hdr.Mode))
}
if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
if err := remapIDs(archiver.IDMapping, hdr); err != nil {
return err
}
@ -178,13 +180,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
return err
}
// IDMappings returns the IDMappings of the archiver.
func (archiver *Archiver) IDMappings() *idtools.IDMappings {
return archiver.IDMappingsVar
// IdentityMapping returns the IdentityMapping of the archiver.
func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
return archiver.IDMapping
}
func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
hdr.Uid, hdr.Gid = ids.UID, ids.GID
return err
}

View File

@ -37,23 +37,23 @@ const (
// 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, owner IDPair) error {
return mkdirAs(path, mode, owner.UID, owner.GID, true, true)
func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error {
return mkdirAs(path, mode, owner, 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.
// Note that unlike os.Mkdir(), this function does not return IsExist error
// in case path already exists.
func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error {
return mkdirAs(path, mode, owner.UID, owner.GID, false, true)
func MkdirAndChown(path string, mode os.FileMode, owner Identity) error {
return mkdirAs(path, mode, owner, 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, owner IDPair) error {
return mkdirAs(path, mode, owner.UID, owner.GID, true, false)
func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
return mkdirAs(path, mode, owner, true, false)
}
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
@ -102,22 +102,23 @@ func toHost(contID int, idMap []IDMap) (int, error) {
return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
}
// IDPair is a UID and GID pair
type IDPair struct {
// Identity is either a UID and GID pair or a SID (but not both)
type Identity struct {
UID int
GID int
SID string
}
// IDMappings contains a mappings of UIDs and GIDs
type IDMappings struct {
// IdentityMapping contains a mappings of UIDs and GIDs
type IdentityMapping struct {
uids []IDMap
gids []IDMap
}
// NewIDMappings takes a requested user and group name and
// NewIdentityMapping takes a requested user and group name and
// using the data from /etc/sub{uid,gid} ranges, creates the
// proper uid and gid remapping ranges for that user/group pair
func NewIDMappings(username, groupname string) (*IDMappings, error) {
func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) {
subuidRanges, err := parseSubuid(username)
if err != nil {
return nil, err
@ -133,7 +134,7 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
}
return &IDMappings{
return &IdentityMapping{
uids: createIDMap(subuidRanges),
gids: createIDMap(subgidRanges),
}, nil
@ -141,21 +142,21 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
// 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}
func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping {
return &IdentityMapping{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 {
func (i *IdentityMapping) RootPair() Identity {
uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
return IDPair{UID: uid, GID: gid}
return Identity{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) {
func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) {
var err error
target := i.RootPair()
@ -173,7 +174,7 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
}
// ToContainer returns the container UID and GID for the host uid and gid
func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) {
uid, err := toContainer(pair.UID, i.uids)
if err != nil {
return -1, -1, err
@ -183,19 +184,19 @@ func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
}
// Empty returns true if there are no id mappings
func (i *IDMappings) Empty() bool {
func (i *IdentityMapping) 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 {
func (i *IdentityMapping) 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 {
func (i *IdentityMapping) GIDs() []IDMap {
return i.gids
}

View File

@ -21,11 +21,12 @@ var (
getentCmd string
)
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
// make an array containing the original path asked for, plus (for mkAll == true)
// all path components leading up to the complete path that don't exist before we MkdirAll
// so that we can chown all of them properly at the end. If chownExisting is false, we won't
// chown the full directory path if it exists
var paths []string
stat, err := system.Stat(path)
@ -38,7 +39,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
}
// short-circuit--we were called with an existing directory and chown was requested
return lazyChown(path, ownerUID, ownerGID, stat)
return lazyChown(path, owner.UID, owner.GID, stat)
}
if os.IsNotExist(err) {
@ -69,7 +70,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
// even if it existed, we will chown the requested path + any subpaths that
// didn't exist when we called MkdirAll
for _, pathComponent := range paths {
if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil {
if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil {
return err
}
}
@ -78,7 +79,7 @@ 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
// if that uid, gid pair has access (execute bit) to the directory
func CanAccess(path string, pair IDPair) bool {
func CanAccess(path string, pair Identity) bool {
statInfo, err := system.Stat(path)
if err != nil {
return false

View File

@ -46,7 +46,7 @@ func TestMkdirAllAndChown(t *testing.T) {
}
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99}); err != nil {
t.Fatal(err)
}
testTree["usr/share"] = node{99, 99}
@ -59,7 +59,7 @@ func TestMkdirAllAndChown(t *testing.T) {
}
// test 2-deep new directories--both should be owned by the uid/gid pair
if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101}); err != nil {
if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101}); err != nil {
t.Fatal(err)
}
testTree["lib/some"] = node{101, 101}
@ -73,7 +73,7 @@ func TestMkdirAllAndChown(t *testing.T) {
}
// test a directory that already exists; should be chowned, but nothing else
if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102}); err != nil {
t.Fatal(err)
}
testTree["usr"] = node{102, 102}
@ -102,7 +102,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
assert.NilError(t, buildTree(dirName, testTree))
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99})
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99})
assert.NilError(t, err)
testTree["usr/share"] = node{99, 99}
@ -111,7 +111,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
assert.NilError(t, compareTrees(testTree, verifyTree))
// test 2-deep new directories--both should be owned by the uid/gid pair
err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101})
err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101})
assert.NilError(t, err)
testTree["lib/some"] = node{101, 101}
testTree["lib/some/other"] = node{101, 101}
@ -120,7 +120,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
assert.NilError(t, compareTrees(testTree, verifyTree))
// test a directory that already exists; should NOT be chowned
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102})
err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102})
assert.NilError(t, err)
verifyTree, err = readTree(dirName, "")
assert.NilError(t, err)
@ -143,7 +143,7 @@ func TestMkdirAndChown(t *testing.T) {
}
// test a directory that already exists; should just chown to the requested uid/gid
if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 99, GID: 99}); err != nil {
t.Fatal(err)
}
testTree["usr"] = node{99, 99}
@ -156,12 +156,12 @@ func TestMkdirAndChown(t *testing.T) {
}
// create a subdir under a dir which doesn't exist--should fail
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, IDPair{UID: 102, GID: 102}); err == nil {
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, Identity{UID: 102, GID: 102}); err == nil {
t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
}
// create a subdir under an existing dir; should only change the ownership of the new subdir
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, Identity{UID: 102, GID: 102}); err != nil {
t.Fatal(err)
}
testTree["usr/bin"] = node{102, 102}
@ -326,19 +326,19 @@ func TestNewIDMappings(t *testing.T) {
group, err := user.LookupGroupId(string(gids[0]))
assert.Check(t, err)
idMappings, err := NewIDMappings(tempUser.Username, group.Name)
idMapping, err := NewIdentityMapping(tempUser.Username, group.Name)
assert.Check(t, err)
rootUID, rootGID, err := GetRootUIDGID(idMappings.UIDs(), idMappings.GIDs())
rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDs(), idMapping.GIDs())
assert.Check(t, err)
dirName, err := ioutil.TempDir("", "mkdirall")
assert.Check(t, err, "Couldn't create temp directory")
defer os.RemoveAll(dirName)
err = MkdirAllAndChown(dirName, 0700, IDPair{UID: rootUID, GID: rootGID})
err = MkdirAllAndChown(dirName, 0700, Identity{UID: rootUID, GID: rootGID})
assert.Check(t, err, "Couldn't change ownership of file path. Got error")
assert.Check(t, CanAccess(dirName, idMappings.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
assert.Check(t, CanAccess(dirName, idMapping.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
}
func TestLookupUserAndGroup(t *testing.T) {
@ -388,7 +388,7 @@ func TestMkdirIsNotDir(t *testing.T) {
}
defer os.Remove(file.Name())
err = mkdirAs(file.Name(), 0755, 0, 0, false, false)
err = mkdirAs(file.Name(), 0755, Identity{UID: 0, GID: 0}, false, false)
assert.Check(t, is.Error(err, "mkdir "+file.Name()+": not a directory"))
}

View File

@ -6,9 +6,11 @@ import (
"github.com/docker/docker/pkg/system"
)
// Platforms such as Windows do not support the UID/GID concept. So make this
// just a wrapper around system.MkdirAll.
func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
// This is currently a wrapper around MkdirAll, however, since currently
// permissions aren't set through this path, the identity isn't utilized.
// Ownership is handled elsewhere, but in the future could be support here
// too.
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
if err := system.MkdirAll(path, mode, ""); err != nil {
return err
}
@ -18,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
// if that uid, gid pair has access (execute bit) to the directory
// Windows does not require/support this function, so always return true
func CanAccess(path string, pair IDPair) bool {
func CanAccess(path string, identity Identity) bool {
return true
}

View File

@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system"
import (
"fmt"
"syscall"
"unsafe"
"github.com/sirupsen/logrus"
"golang.org/x/sys/windows"
)
const (
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
LABEL_SECURITY_INFORMATION = 0x00000010
ATTRIBUTE_SECURITY_INFORMATION = 0x00000020
SCOPE_SECURITY_INFORMATION = 0x00000040
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100
BACKUP_SECURITY_INFORMATION = 0x00010000
PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000
UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000
UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000
)
const (
SE_UNKNOWN_OBJECT_TYPE = iota
SE_FILE_OBJECT
SE_SERVICE
SE_PRINTER
SE_REGISTRY_KEY
SE_LMSHARE
SE_KERNEL_OBJECT
SE_WINDOW_OBJECT
SE_DS_OBJECT
SE_DS_OBJECT_ALL
SE_PROVIDER_DEFINED_OBJECT
SE_WMIGUID_OBJECT
SE_REGISTRY_WOW64_32KEY
)
const (
SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
)
const (
ContainerAdministratorSidString = "S-1-5-93-2-1"
ContainerUserSidString = "S-1-5-93-2-2"
)
var (
ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
procGetVersionExW = modkernel32.NewProc("GetVersionExW")
procGetProductInfo = modkernel32.NewProc("GetProductInfo")
ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
procGetVersionExW = modkernel32.NewProc("GetVersionExW")
procGetProductInfo = modkernel32.NewProc("GetProductInfo")
procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW")
procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl")
)
// OSVersion is a wrapper for Windows version information
@ -125,3 +171,23 @@ func HasWin32KSupport() bool {
// APIs.
return ntuserApiset.Load() == nil
}
func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) {
r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfo.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0)
if r0 != 0 {
result = syscall.Errno(r0)
}
return
}
func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) {
r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0)
if r1 == 0 {
if e1 != 0 {
result = syscall.Errno(e1)
} else {
result = syscall.EINVAL
}
}
return
}

View File

@ -53,7 +53,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
}
rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName))
if err := initlayer.Setup(rootFS, idtools.IDPair{UID: 0, GID: 0}); err != nil {
if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
return errors.WithStack(err)
}

View File

@ -46,18 +46,18 @@ type activeMount struct {
// New instantiates a new Root instance with the provided scope. Scope
// is the base path that the Root instance uses to store its
// volumes. The base path is created here if it does not exist.
func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
func New(scope string, rootIdentity idtools.Identity) (*Root, error) {
rootDirectory := filepath.Join(scope, volumesPathName)
if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIDs); err != nil {
if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIdentity); err != nil {
return nil, err
}
r := &Root{
scope: scope,
path: rootDirectory,
volumes: make(map[string]*localVolume),
rootIDs: rootIDs,
scope: scope,
path: rootDirectory,
volumes: make(map[string]*localVolume),
rootIdentity: rootIdentity,
}
dirs, err := ioutil.ReadDir(rootDirectory)
@ -101,11 +101,11 @@ func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
// manages the creation/removal of volumes. It uses only standard vfs
// commands to create/remove dirs within its provided scope.
type Root struct {
m sync.Mutex
scope string
path string
volumes map[string]*localVolume
rootIDs idtools.IDPair
m sync.Mutex
scope string
path string
volumes map[string]*localVolume
rootIdentity idtools.Identity
}
// List lists all the volumes
@ -146,7 +146,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
}
path := r.DataPath(name)
if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil {
if err := idtools.MkdirAllAndChown(path, 0755, r.rootIdentity); err != nil {
return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path)
}

View File

@ -38,7 +38,7 @@ func TestRemove(t *testing.T) {
}
defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}
@ -80,7 +80,7 @@ func TestInitializeWithVolumes(t *testing.T) {
}
defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}
@ -90,7 +90,7 @@ func TestInitializeWithVolumes(t *testing.T) {
t.Fatal(err)
}
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}
@ -112,7 +112,7 @@ func TestCreate(t *testing.T) {
}
defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}
@ -149,7 +149,7 @@ func TestCreate(t *testing.T) {
}
}
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}
@ -186,7 +186,7 @@ func TestCreateWithOpts(t *testing.T) {
}
defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}
@ -261,7 +261,7 @@ func TestCreateWithOpts(t *testing.T) {
t.Fatal("expected mount to still be active")
}
r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
r, err = New(rootDir, idtools.Identity{UID: 0, GID: 0})
if err != nil {
t.Fatal(err)
}
@ -283,7 +283,7 @@ func TestRelaodNoOpts(t *testing.T) {
}
defer os.RemoveAll(rootDir)
r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}
@ -311,7 +311,7 @@ func TestRelaodNoOpts(t *testing.T) {
t.Fatal(err)
}
r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
if err != nil {
t.Fatal(err)
}

View File

@ -95,7 +95,7 @@ func (m *MountPoint) Cleanup() error {
// configured, or creating the source directory if supplied.
// 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) {
func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun func(m *MountPoint) error) (path string, err error) {
if m.SkipMountpointCreation {
return m.Source, nil
}

View File

@ -9,7 +9,7 @@ import (
"github.com/pkg/errors"
)
func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.IDPair) error {
func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.Identity) error {
d, err := local.New(root, rootIDs)
if err != nil {
return errors.Wrap(err, "error setting up default driver")

View File

@ -7,4 +7,4 @@ import (
"github.com/docker/docker/volume/drivers"
)
func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.IDPair) error { return nil }
func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.Identity) error { return nil }

View File

@ -35,7 +35,7 @@ type VolumesService struct {
}
// NewVolumeService creates a new volume service
func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.IDPair, logger volumeEventLogger) (*VolumesService, error) {
func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger volumeEventLogger) (*VolumesService, error) {
ds := drivers.NewStore(pg)
if err := setupDefaultDriver(ds, root, rootIDs); err != nil {
return nil, err

View File

@ -25,7 +25,7 @@ func TestLocalVolumeSize(t *testing.T) {
assert.Assert(t, err)
defer os.RemoveAll(dir)
l, err := local.New(dir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
l, err := local.New(dir, idtools.Identity{UID: os.Getuid(), GID: os.Getegid()})
assert.Assert(t, err)
assert.Assert(t, ds.Register(l, volume.DefaultDriverName))
assert.Assert(t, ds.Register(testutils.NewFakeDriver("fake"), "fake"))