Browse code

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>

Salahuddin Khan authored on 2017/11/16 15:20:33
Showing 64 changed files
... ...
@@ -56,21 +56,21 @@ type SessionGetter interface {
56 56
 
57 57
 // BuildManager is shared across all Builder objects
58 58
 type BuildManager struct {
59
-	idMappings *idtools.IDMappings
60
-	backend    builder.Backend
61
-	pathCache  pathCache // TODO: make this persistent
62
-	sg         SessionGetter
63
-	fsCache    *fscache.FSCache
59
+	idMapping *idtools.IdentityMapping
60
+	backend   builder.Backend
61
+	pathCache pathCache // TODO: make this persistent
62
+	sg        SessionGetter
63
+	fsCache   *fscache.FSCache
64 64
 }
65 65
 
66 66
 // NewBuildManager creates a BuildManager
67
-func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, idMappings *idtools.IDMappings) (*BuildManager, error) {
67
+func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
68 68
 	bm := &BuildManager{
69
-		backend:    b,
70
-		pathCache:  &syncmap.Map{},
71
-		sg:         sg,
72
-		idMappings: idMappings,
73
-		fsCache:    fsCache,
69
+		backend:   b,
70
+		pathCache: &syncmap.Map{},
71
+		sg:        sg,
72
+		idMapping: identityMapping,
73
+		fsCache:   fsCache,
74 74
 	}
75 75
 	if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil {
76 76
 		return nil, err
... ...
@@ -111,7 +111,7 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
111 111
 		ProgressWriter: config.ProgressWriter,
112 112
 		Backend:        bm.backend,
113 113
 		PathCache:      bm.pathCache,
114
-		IDMappings:     bm.idMappings,
114
+		IDMapping:      bm.idMapping,
115 115
 	}
116 116
 	b, err := newBuilder(ctx, builderOptions)
117 117
 	if err != nil {
... ...
@@ -159,7 +159,7 @@ type builderOptions struct {
159 159
 	Backend        builder.Backend
160 160
 	ProgressWriter backend.ProgressWriter
161 161
 	PathCache      pathCache
162
-	IDMappings     *idtools.IDMappings
162
+	IDMapping      *idtools.IdentityMapping
163 163
 }
164 164
 
165 165
 // Builder is a Dockerfile builder
... ...
@@ -175,7 +175,7 @@ type Builder struct {
175 175
 	docker    builder.Backend
176 176
 	clientCtx context.Context
177 177
 
178
-	idMappings       *idtools.IDMappings
178
+	idMapping        *idtools.IdentityMapping
179 179
 	disableCommit    bool
180 180
 	imageSources     *imageSources
181 181
 	pathCache        pathCache
... ...
@@ -199,7 +199,7 @@ func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, er
199 199
 		Aux:              options.ProgressWriter.AuxFormatter,
200 200
 		Output:           options.ProgressWriter.Output,
201 201
 		docker:           options.Backend,
202
-		idMappings:       options.IDMappings,
202
+		idMapping:        options.IDMapping,
203 203
 		imageSources:     newImageSources(clientCtx, options),
204 204
 		pathCache:        options.PathCache,
205 205
 		imageProber:      newImageProber(options.Backend, config.CacheFrom, config.NoCache),
... ...
@@ -451,7 +451,7 @@ func downloadSource(output io.Writer, stdout io.Writer, srcURL string) (remote b
451 451
 
452 452
 type copyFileOptions struct {
453 453
 	decompress bool
454
-	chownPair  idtools.IDPair
454
+	identity   idtools.Identity
455 455
 	archiver   Archiver
456 456
 }
457 457
 
... ...
@@ -481,7 +481,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
481 481
 		return errors.Wrapf(err, "source path not found")
482 482
 	}
483 483
 	if src.IsDir() {
484
-		return copyDirectory(archiver, srcEndpoint, destEndpoint, options.chownPair)
484
+		return copyDirectory(archiver, srcEndpoint, destEndpoint, options.identity)
485 485
 	}
486 486
 	if options.decompress && isArchivePath(source.root, srcPath) && !source.noDecompress {
487 487
 		return archiver.UntarPath(srcPath, destPath)
... ...
@@ -499,7 +499,7 @@ func performCopyForInfo(dest copyInfo, source copyInfo, options copyFileOptions)
499 499
 		destPath = dest.root.Join(destPath, source.root.Base(source.path))
500 500
 		destEndpoint = &copyEndpoint{driver: dest.root, path: destPath}
501 501
 	}
502
-	return copyFile(archiver, srcEndpoint, destEndpoint, options.chownPair)
502
+	return copyFile(archiver, srcEndpoint, destEndpoint, options.identity)
503 503
 }
504 504
 
505 505
 func isArchivePath(driver containerfs.ContainerFS, path string) bool {
... ...
@@ -517,7 +517,7 @@ func isArchivePath(driver containerfs.ContainerFS, path string) bool {
517 517
 	return err == nil
518 518
 }
519 519
 
520
-func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
520
+func copyDirectory(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
521 521
 	destExists, err := isExistingDirectory(dest)
522 522
 	if err != nil {
523 523
 		return errors.Wrapf(err, "failed to query destination path")
... ...
@@ -527,17 +527,17 @@ func copyDirectory(archiver Archiver, source, dest *copyEndpoint, chownPair idto
527 527
 		return errors.Wrapf(err, "failed to copy directory")
528 528
 	}
529 529
 	// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
530
-	return fixPermissions(source.path, dest.path, chownPair, !destExists)
530
+	return fixPermissions(source.path, dest.path, identity, !destExists)
531 531
 }
532 532
 
533
-func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.IDPair) error {
533
+func copyFile(archiver Archiver, source, dest *copyEndpoint, identity idtools.Identity) error {
534 534
 	if runtime.GOOS == "windows" && dest.driver.OS() == "linux" {
535 535
 		// LCOW
536 536
 		if err := dest.driver.MkdirAll(dest.driver.Dir(dest.path), 0755); err != nil {
537 537
 			return errors.Wrapf(err, "failed to create new directory")
538 538
 		}
539 539
 	} else {
540
-		if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, chownPair); err != nil {
540
+		if err := idtools.MkdirAllAndChownNew(filepath.Dir(dest.path), 0755, identity); err != nil {
541 541
 			// Normal containers
542 542
 			return errors.Wrapf(err, "failed to create new directory")
543 543
 		}
... ...
@@ -547,7 +547,7 @@ func copyFile(archiver Archiver, source, dest *copyEndpoint, chownPair idtools.I
547 547
 		return errors.Wrapf(err, "failed to copy file")
548 548
 	}
549 549
 	// TODO: @gupta-ak. Investigate how LCOW permission mappings will work.
550
-	return fixPermissions(source.path, dest.path, chownPair, false)
550
+	return fixPermissions(source.path, dest.path, identity, false)
551 551
 }
552 552
 
553 553
 func endsInSlash(driver containerfs.Driver, path string) bool {
... ...
@@ -10,7 +10,7 @@ import (
10 10
 	"github.com/docker/docker/pkg/idtools"
11 11
 )
12 12
 
13
-func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
13
+func fixPermissions(source, destination string, identity idtools.Identity, overrideSkip bool) error {
14 14
 	var (
15 15
 		skipChownRoot bool
16 16
 		err           error
... ...
@@ -39,7 +39,7 @@ func fixPermissions(source, destination string, rootIDs idtools.IDPair, override
39 39
 		}
40 40
 
41 41
 		fullpath = filepath.Join(destination, cleaned)
42
-		return os.Lchown(fullpath, rootIDs.UID, rootIDs.GID)
42
+		return os.Lchown(fullpath, identity.UID, identity.GID)
43 43
 	})
44 44
 }
45 45
 
... ...
@@ -1,11 +1,17 @@
1 1
 package dockerfile // import "github.com/docker/docker/builder/dockerfile"
2 2
 
3 3
 import (
4
-	"errors"
4
+	"fmt"
5
+	"os"
5 6
 	"path/filepath"
6 7
 	"strings"
7 8
 
9
+	"github.com/Microsoft/go-winio"
8 10
 	"github.com/docker/docker/pkg/idtools"
11
+	"github.com/docker/docker/pkg/reexec"
12
+	"github.com/docker/docker/pkg/system"
13
+	"github.com/pkg/errors"
14
+	"golang.org/x/sys/windows"
9 15
 )
10 16
 
11 17
 var pathBlacklist = map[string]bool{
... ...
@@ -13,9 +19,69 @@ var pathBlacklist = map[string]bool{
13 13
 	"c:\\windows": true,
14 14
 }
15 15
 
16
-func fixPermissions(source, destination string, rootIDs idtools.IDPair, overrideSkip bool) error {
17
-	// chown is not supported on Windows
18
-	return nil
16
+func init() {
17
+	reexec.Register("windows-fix-permissions", fixPermissionsReexec)
18
+}
19
+
20
+func fixPermissions(source, destination string, identity idtools.Identity, _ bool) error {
21
+	if identity.SID == "" {
22
+		return nil
23
+	}
24
+
25
+	cmd := reexec.Command("windows-fix-permissions", source, destination, identity.SID)
26
+	output, err := cmd.CombinedOutput()
27
+
28
+	return errors.Wrapf(err, "failed to exec windows-fix-permissions: %s", output)
29
+}
30
+
31
+func fixPermissionsReexec() {
32
+	err := fixPermissionsWindows(os.Args[1], os.Args[2], os.Args[3])
33
+	if err != nil {
34
+		fmt.Fprint(os.Stderr, err)
35
+		os.Exit(1)
36
+	}
37
+}
38
+
39
+func fixPermissionsWindows(source, destination, SID string) error {
40
+
41
+	privileges := []string{winio.SeRestorePrivilege, system.SeTakeOwnershipPrivilege}
42
+
43
+	err := winio.EnableProcessPrivileges(privileges)
44
+	if err != nil {
45
+		return err
46
+	}
47
+
48
+	defer winio.DisableProcessPrivileges(privileges)
49
+
50
+	sid, err := windows.StringToSid(SID)
51
+	if err != nil {
52
+		return err
53
+	}
54
+
55
+	// Owners on *nix have read/write/delete/read control and write DAC.
56
+	// Add an ACE that grants this to the user/group specified with the
57
+	// chown option. Currently Windows is not honoring the owner change,
58
+	// however, they are aware of this and it should be fixed at some
59
+	// point.
60
+
61
+	sddlString := system.SddlAdministratorsLocalSystem
62
+	sddlString += "(A;OICI;GRGWGXRCWDSD;;;" + SID + ")"
63
+
64
+	securityDescriptor, err := winio.SddlToSecurityDescriptor(sddlString)
65
+	if err != nil {
66
+		return err
67
+	}
68
+
69
+	var daclPresent uint32
70
+	var daclDefaulted uint32
71
+	var dacl *byte
72
+
73
+	err = system.GetSecurityDescriptorDacl(&securityDescriptor[0], &daclPresent, &dacl, &daclDefaulted)
74
+	if err != nil {
75
+		return err
76
+	}
77
+
78
+	return system.SetNamedSecurityInfo(windows.StringToUTF16Ptr(destination), system.SE_FILE_OBJECT, system.OWNER_SECURITY_INFORMATION|system.DACL_SECURITY_INFORMATION, sid, nil, dacl, nil)
19 79
 }
20 80
 
21 81
 func validateCopySourcePath(imageSource *imageMount, origPath, platform string) error {
... ...
@@ -37,7 +37,7 @@ type Archiver interface {
37 37
 	UntarPath(src, dst string) error
38 38
 	CopyWithTar(src, dst string) error
39 39
 	CopyFileWithTar(src, dst string) error
40
-	IDMappings() *idtools.IDMappings
40
+	IdentityMapping() *idtools.IdentityMapping
41 41
 }
42 42
 
43 43
 // The builder will use the following interfaces if the container fs implements
... ...
@@ -68,11 +68,11 @@ func tarFunc(i interface{}) containerfs.TarFunc {
68 68
 func (b *Builder) getArchiver(src, dst containerfs.Driver) Archiver {
69 69
 	t, u := tarFunc(src), untarFunc(dst)
70 70
 	return &containerfs.Archiver{
71
-		SrcDriver:     src,
72
-		DstDriver:     dst,
73
-		Tar:           t,
74
-		Untar:         u,
75
-		IDMappingsVar: b.idMappings,
71
+		SrcDriver: src,
72
+		DstDriver: dst,
73
+		Tar:       t,
74
+		Untar:     u,
75
+		IDMapping: b.idMapping,
76 76
 	}
77 77
 }
78 78
 
... ...
@@ -185,14 +185,18 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
185 185
 		return err
186 186
 	}
187 187
 
188
-	chownPair := b.idMappings.RootPair()
188
+	identity := b.idMapping.RootPair()
189 189
 	// if a chown was requested, perform the steps to get the uid, gid
190 190
 	// translated (if necessary because of user namespaces), and replace
191 191
 	// the root pair with the chown pair for copy operations
192 192
 	if inst.chownStr != "" {
193
-		chownPair, err = parseChownFlag(inst.chownStr, destInfo.root.Path(), b.idMappings)
193
+		identity, err = parseChownFlag(b, state, inst.chownStr, destInfo.root.Path(), b.idMapping)
194 194
 		if err != nil {
195
-			return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
195
+			if b.options.Platform != "windows" {
196
+				return errors.Wrapf(err, "unable to convert uid/gid chown string to host mapping")
197
+			}
198
+
199
+			return errors.Wrapf(err, "unable to map container user account name to SID")
196 200
 		}
197 201
 	}
198 202
 
... ...
@@ -200,7 +204,7 @@ func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
200 200
 		opts := copyFileOptions{
201 201
 			decompress: inst.allowLocalDecompression,
202 202
 			archiver:   b.getArchiver(info.root, destInfo.root),
203
-			chownPair:  chownPair,
203
+			identity:   identity,
204 204
 		}
205 205
 		if err := performCopyForInfo(destInfo, info, opts); err != nil {
206 206
 			return errors.Wrapf(err, "failed to copy files")
... ...
@@ -11,11 +11,11 @@ import (
11 11
 	"github.com/pkg/errors"
12 12
 )
13 13
 
14
-func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
14
+func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
15 15
 	var userStr, grpStr string
16 16
 	parts := strings.Split(chown, ":")
17 17
 	if len(parts) > 2 {
18
-		return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
18
+		return idtools.Identity{}, errors.New("invalid chown string format: " + chown)
19 19
 	}
20 20
 	if len(parts) == 1 {
21 21
 		// if no group specified, use the user spec as group as well
... ...
@@ -26,25 +26,25 @@ func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (
26 26
 
27 27
 	passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
28 28
 	if err != nil {
29
-		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
29
+		return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
30 30
 	}
31 31
 	groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
32 32
 	if err != nil {
33
-		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
33
+		return idtools.Identity{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
34 34
 	}
35 35
 	uid, err := lookupUser(userStr, passwdPath)
36 36
 	if err != nil {
37
-		return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
37
+		return idtools.Identity{}, errors.Wrapf(err, "can't find uid for user "+userStr)
38 38
 	}
39 39
 	gid, err := lookupGroup(grpStr, groupPath)
40 40
 	if err != nil {
41
-		return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
41
+		return idtools.Identity{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
42 42
 	}
43 43
 
44 44
 	// convert as necessary because of user namespaces
45
-	chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
45
+	chownPair, err := identityMapping.ToHost(idtools.Identity{UID: uid, GID: gid})
46 46
 	if err != nil {
47
-		return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
47
+		return idtools.Identity{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
48 48
 	}
49 49
 	return chownPair, nil
50 50
 }
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"path/filepath"
6 6
 	"testing"
7 7
 
8
+	"github.com/docker/docker/api/types"
8 9
 	"github.com/docker/docker/pkg/idtools"
9 10
 	"gotest.tools/assert"
10 11
 	is "gotest.tools/assert/cmp"
... ...
@@ -34,7 +35,7 @@ othergrp:x:6666:
34 34
 		},
35 35
 	}
36 36
 	remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
37
-	unmapped := &idtools.IDMappings{}
37
+	unmapped := &idtools.IdentityMapping{}
38 38
 
39 39
 	contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
40 40
 	defer cleanup()
... ...
@@ -49,56 +50,72 @@ othergrp:x:6666:
49 49
 
50 50
 	// positive tests
51 51
 	for _, testcase := range []struct {
52
+		builder   *Builder
52 53
 		name      string
53 54
 		chownStr  string
54
-		idMapping *idtools.IDMappings
55
-		expected  idtools.IDPair
55
+		idMapping *idtools.IdentityMapping
56
+		state     *dispatchState
57
+		expected  idtools.Identity
56 58
 	}{
57 59
 		{
60
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
58 61
 			name:      "UIDNoMap",
59 62
 			chownStr:  "1",
60 63
 			idMapping: unmapped,
61
-			expected:  idtools.IDPair{UID: 1, GID: 1},
64
+			state:     &dispatchState{},
65
+			expected:  idtools.Identity{UID: 1, GID: 1},
62 66
 		},
63 67
 		{
68
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
64 69
 			name:      "UIDGIDNoMap",
65 70
 			chownStr:  "0:1",
66 71
 			idMapping: unmapped,
67
-			expected:  idtools.IDPair{UID: 0, GID: 1},
72
+			state:     &dispatchState{},
73
+			expected:  idtools.Identity{UID: 0, GID: 1},
68 74
 		},
69 75
 		{
76
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
70 77
 			name:      "UIDWithMap",
71 78
 			chownStr:  "0",
72 79
 			idMapping: remapped,
73
-			expected:  idtools.IDPair{UID: 100000, GID: 100000},
80
+			state:     &dispatchState{},
81
+			expected:  idtools.Identity{UID: 100000, GID: 100000},
74 82
 		},
75 83
 		{
84
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
76 85
 			name:      "UIDGIDWithMap",
77 86
 			chownStr:  "1:33",
78 87
 			idMapping: remapped,
79
-			expected:  idtools.IDPair{UID: 100001, GID: 100033},
88
+			state:     &dispatchState{},
89
+			expected:  idtools.Identity{UID: 100001, GID: 100033},
80 90
 		},
81 91
 		{
92
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
82 93
 			name:      "UserNoMap",
83 94
 			chownStr:  "bin:5555",
84 95
 			idMapping: unmapped,
85
-			expected:  idtools.IDPair{UID: 1, GID: 5555},
96
+			state:     &dispatchState{},
97
+			expected:  idtools.Identity{UID: 1, GID: 5555},
86 98
 		},
87 99
 		{
100
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
88 101
 			name:      "GroupWithMap",
89 102
 			chownStr:  "0:unicorn",
90 103
 			idMapping: remapped,
91
-			expected:  idtools.IDPair{UID: 100000, GID: 101002},
104
+			state:     &dispatchState{},
105
+			expected:  idtools.Identity{UID: 100000, GID: 101002},
92 106
 		},
93 107
 		{
108
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
94 109
 			name:      "UserOnlyWithMap",
95 110
 			chownStr:  "unicorn",
96 111
 			idMapping: remapped,
97
-			expected:  idtools.IDPair{UID: 101001, GID: 101002},
112
+			state:     &dispatchState{},
113
+			expected:  idtools.Identity{UID: 101001, GID: 101002},
98 114
 		},
99 115
 	} {
100 116
 		t.Run(testcase.name, func(t *testing.T) {
101
-			idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
117
+			idPair, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
102 118
 			assert.NilError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
103 119
 			assert.Check(t, is.DeepEqual(testcase.expected, idPair), "chown flag mapping failure")
104 120
 		})
... ...
@@ -106,32 +123,40 @@ othergrp:x:6666:
106 106
 
107 107
 	// error tests
108 108
 	for _, testcase := range []struct {
109
+		builder   *Builder
109 110
 		name      string
110 111
 		chownStr  string
111
-		idMapping *idtools.IDMappings
112
+		idMapping *idtools.IdentityMapping
113
+		state     *dispatchState
112 114
 		descr     string
113 115
 	}{
114 116
 		{
117
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
115 118
 			name:      "BadChownFlagFormat",
116 119
 			chownStr:  "bob:1:555",
117 120
 			idMapping: unmapped,
121
+			state:     &dispatchState{},
118 122
 			descr:     "invalid chown string format: bob:1:555",
119 123
 		},
120 124
 		{
125
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
121 126
 			name:      "UserNoExist",
122 127
 			chownStr:  "bob",
123 128
 			idMapping: unmapped,
129
+			state:     &dispatchState{},
124 130
 			descr:     "can't find uid for user bob: no such user: bob",
125 131
 		},
126 132
 		{
133
+			builder:   &Builder{options: &types.ImageBuildOptions{Platform: "linux"}},
127 134
 			name:      "GroupNoExist",
128 135
 			chownStr:  "root:bob",
129 136
 			idMapping: unmapped,
137
+			state:     &dispatchState{},
130 138
 			descr:     "can't find gid for group bob: no such group: bob",
131 139
 		},
132 140
 	} {
133 141
 		t.Run(testcase.name, func(t *testing.T) {
134
-			_, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
142
+			_, err := parseChownFlag(testcase.builder, testcase.state, testcase.chownStr, contextDir, testcase.idMapping)
135 143
 			assert.Check(t, is.Error(err, testcase.descr), "Expected error string doesn't match")
136 144
 		})
137 145
 	}
... ...
@@ -1,7 +1,120 @@
1 1
 package dockerfile // import "github.com/docker/docker/builder/dockerfile"
2 2
 
3
-import "github.com/docker/docker/pkg/idtools"
3
+import (
4
+	"bytes"
5
+	"os"
6
+	"path/filepath"
7
+	"strings"
4 8
 
5
-func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
6
-	return idMappings.RootPair(), nil
9
+	"github.com/containerd/containerd/platforms"
10
+	"github.com/docker/docker/api/types/container"
11
+	"github.com/docker/docker/api/types/mount"
12
+	"github.com/docker/docker/pkg/idtools"
13
+	"github.com/docker/docker/pkg/jsonmessage"
14
+	"github.com/docker/docker/pkg/system"
15
+	"github.com/pkg/errors"
16
+	"golang.org/x/sys/windows"
17
+)
18
+
19
+func parseChownFlag(builder *Builder, state *dispatchState, chown, ctrRootPath string, identityMapping *idtools.IdentityMapping) (idtools.Identity, error) {
20
+	if builder.options.Platform == "windows" {
21
+		return getAccountIdentity(builder, chown, ctrRootPath, state)
22
+	}
23
+
24
+	return identityMapping.RootPair(), nil
25
+}
26
+
27
+func getAccountIdentity(builder *Builder, accountName string, ctrRootPath string, state *dispatchState) (idtools.Identity, error) {
28
+	// If this is potentially a string SID then attempt to convert it to verify
29
+	// this, otherwise continue looking for the account.
30
+	if strings.HasPrefix(accountName, "S-") || strings.HasPrefix(accountName, "s-") {
31
+		sid, err := windows.StringToSid(accountName)
32
+
33
+		if err == nil {
34
+			accountSid, err := sid.String()
35
+
36
+			if err != nil {
37
+				return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
38
+			}
39
+
40
+			return idtools.Identity{SID: accountSid}, nil
41
+		}
42
+	}
43
+
44
+	// Attempt to obtain the SID using the name.
45
+	sid, _, accType, err := windows.LookupSID("", accountName)
46
+
47
+	// If this is a SID that is built-in and hence the same across all systems then use that.
48
+	if err == nil && (accType == windows.SidTypeAlias || accType == windows.SidTypeWellKnownGroup) {
49
+		accountSid, err := sid.String()
50
+
51
+		if err != nil {
52
+			return idtools.Identity{SID: ""}, errors.Wrapf(err, "error converting SID to string")
53
+		}
54
+
55
+		return idtools.Identity{SID: accountSid}, nil
56
+	}
57
+
58
+	// Check if the account name is one unique to containers.
59
+	if strings.EqualFold(accountName, "ContainerAdministrator") {
60
+		return idtools.Identity{SID: system.ContainerAdministratorSidString}, nil
61
+
62
+	} else if strings.EqualFold(accountName, "ContainerUser") {
63
+		return idtools.Identity{SID: system.ContainerUserSidString}, nil
64
+	}
65
+
66
+	// All other lookups failed, so therefore determine if the account in
67
+	// question exists in the container and if so, obtain its SID.
68
+	return lookupNTAccount(builder, accountName, state)
69
+}
70
+
71
+func lookupNTAccount(builder *Builder, accountName string, state *dispatchState) (idtools.Identity, error) {
72
+
73
+	source, _ := filepath.Split(os.Args[0])
74
+
75
+	target := "C:\\Docker"
76
+	targetExecutable := target + "\\containerutility.exe"
77
+
78
+	optionsPlatform, err := platforms.Parse(builder.options.Platform)
79
+	if err != nil {
80
+		return idtools.Identity{}, err
81
+	}
82
+
83
+	runConfig := copyRunConfig(state.runConfig,
84
+		withCmdCommentString("internal run to obtain NT account information.", optionsPlatform.OS))
85
+
86
+	runConfig.ArgsEscaped = true
87
+	runConfig.Cmd = []string{targetExecutable, "getaccountsid", accountName}
88
+
89
+	hostConfig := &container.HostConfig{Mounts: []mount.Mount{
90
+		{
91
+			Type:     mount.TypeBind,
92
+			Source:   source,
93
+			Target:   target,
94
+			ReadOnly: true,
95
+		},
96
+	},
97
+	}
98
+
99
+	container, err := builder.containerManager.Create(runConfig, hostConfig)
100
+	if err != nil {
101
+		return idtools.Identity{}, err
102
+	}
103
+
104
+	stdout := new(bytes.Buffer)
105
+	stderr := new(bytes.Buffer)
106
+
107
+	if err := builder.containerManager.Run(builder.clientCtx, container.ID, stdout, stderr); err != nil {
108
+		if err, ok := err.(*statusCodeError); ok {
109
+			return idtools.Identity{}, &jsonmessage.JSONError{
110
+				Message: stderr.String(),
111
+				Code:    err.StatusCode(),
112
+			}
113
+		}
114
+		return idtools.Identity{}, err
115
+	}
116
+
117
+	accountSid := stdout.String()
118
+
119
+	return idtools.Identity{SID: accountSid}, nil
7 120
 }
... ...
@@ -267,7 +267,7 @@ func newRouterOptions(config *config.Config, daemon *daemon.Daemon) (routerOptio
267 267
 		return opts, errors.Wrap(err, "failed to create fscache")
268 268
 	}
269 269
 
270
-	manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IDMappings())
270
+	manager, err := dockerfile.NewBuildManager(daemon.BuilderBackend(), sm, buildCache, daemon.IdentityMapping())
271 271
 	if err != nil {
272 272
 		return opts, err
273 273
 	}
... ...
@@ -254,7 +254,7 @@ func (container *Container) WriteHostConfig() (*containertypes.HostConfig, error
254 254
 }
255 255
 
256 256
 // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
257
-func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error {
257
+func (container *Container) SetupWorkingDirectory(rootIdentity idtools.Identity) error {
258 258
 	// TODO @jhowardmsft, @gupta-ak LCOW Support. This will need revisiting.
259 259
 	// We will need to do remote filesystem operations here.
260 260
 	if container.OS != runtime.GOOS {
... ...
@@ -271,7 +271,7 @@ func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error
271 271
 		return err
272 272
 	}
273 273
 
274
-	if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIDs); err != nil {
274
+	if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIdentity); err != nil {
275 275
 		pthInfo, err2 := os.Stat(pth)
276 276
 		if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
277 277
 			return errors.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
... ...
@@ -9,7 +9,7 @@ import (
9 9
 func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
10 10
 	return &archive.TarOptions{
11 11
 		NoOverwriteDirNonDir: noOverwriteDirNonDir,
12
-		UIDMaps:              daemon.idMappings.UIDs(),
13
-		GIDMaps:              daemon.idMappings.GIDs(),
12
+		UIDMaps:              daemon.idMapping.UIDs(),
13
+		GIDMaps:              daemon.idMapping.GIDs(),
14 14
 	}
15 15
 }
... ...
@@ -18,8 +18,10 @@ func (daemon *Daemon) tarCopyOptions(container *container.Container, noOverwrite
18 18
 		return nil, err
19 19
 	}
20 20
 
21
+	identity := idtools.Identity{UID: user.Uid, GID: user.Gid}
22
+
21 23
 	return &archive.TarOptions{
22 24
 		NoOverwriteDirNonDir: noOverwriteDirNonDir,
23
-		ChownOpts:            &idtools.IDPair{UID: user.Uid, GID: user.Gid},
25
+		ChownOpts:            &identity,
24 26
 	}, nil
25 27
 }
... ...
@@ -132,7 +132,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
132 132
 		fallthrough
133 133
 
134 134
 	case ipcMode.IsShareable():
135
-		rootIDs := daemon.idMappings.RootPair()
135
+		rootIDs := daemon.idMapping.RootPair()
136 136
 		if !c.HasMountFor("/dev/shm") {
137 137
 			shmPath, err := c.ShmResourcePath()
138 138
 			if err != nil {
... ...
@@ -179,7 +179,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
179 179
 	}
180 180
 
181 181
 	// retrieve possible remapped range start for root UID, GID
182
-	rootIDs := daemon.idMappings.RootPair()
182
+	rootIDs := daemon.idMapping.RootPair()
183 183
 
184 184
 	for _, s := range c.SecretReferences {
185 185
 		// TODO (ehazlett): use type switch when more are supported
... ...
@@ -278,7 +278,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
278 278
 // In practice this is using a tmpfs mount and is used for both "configs" and "secrets"
279 279
 func (daemon *Daemon) createSecretsDir(c *container.Container) error {
280 280
 	// retrieve possible remapped range start for root UID, GID
281
-	rootIDs := daemon.idMappings.RootPair()
281
+	rootIDs := daemon.idMapping.RootPair()
282 282
 	dir, err := c.SecretMountPath()
283 283
 	if err != nil {
284 284
 		return errors.Wrap(err, "error getting container secrets dir")
... ...
@@ -304,7 +304,7 @@ func (daemon *Daemon) remountSecretDir(c *container.Container) error {
304 304
 	if err := label.Relabel(dir, c.MountLabel, false); err != nil {
305 305
 		logrus.WithError(err).WithField("dir", dir).Warn("Error while attempting to set selinux label")
306 306
 	}
307
-	rootIDs := daemon.idMappings.RootPair()
307
+	rootIDs := daemon.idMapping.RootPair()
308 308
 	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
309 309
 
310 310
 	// remount secrets ro
... ...
@@ -407,5 +407,5 @@ func (daemon *Daemon) setupContainerMountsRoot(c *container.Container) error {
407 407
 	if err != nil {
408 408
 		return err
409 409
 	}
410
-	return idtools.MkdirAllAndChown(p, 0700, daemon.idMappings.RootPair())
410
+	return idtools.MkdirAllAndChown(p, 0700, daemon.idMapping.RootPair())
411 411
 }
... ...
@@ -155,13 +155,14 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
155 155
 	}
156 156
 
157 157
 	// Set RWLayer for container after mount labels have been set
158
-	rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMappings))
158
+	rwLayer, err := daemon.imageService.CreateLayer(container, setupInitLayer(daemon.idMapping))
159 159
 	if err != nil {
160 160
 		return nil, errdefs.System(err)
161 161
 	}
162 162
 	container.RWLayer = rwLayer
163 163
 
164
-	rootIDs := daemon.idMappings.RootPair()
164
+	rootIDs := daemon.idMapping.RootPair()
165
+
165 166
 	if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
166 167
 		return nil, err
167 168
 	}
... ...
@@ -25,7 +25,7 @@ func (daemon *Daemon) createContainerOSSpecificSettings(container *container.Con
25 25
 	}
26 26
 	defer daemon.Unmount(container)
27 27
 
28
-	rootIDs := daemon.idMappings.RootPair()
28
+	rootIDs := daemon.idMapping.RootPair()
29 29
 	if err := container.SetupWorkingDirectory(rootIDs); err != nil {
30 30
 		return err
31 31
 	}
... ...
@@ -87,7 +87,7 @@ type Daemon struct {
87 87
 	seccompEnabled    bool
88 88
 	apparmorEnabled   bool
89 89
 	shutdown          bool
90
-	idMappings        *idtools.IDMappings
90
+	idMapping         *idtools.IdentityMapping
91 91
 	// TODO: move graphDrivers field to an InfoService
92 92
 	graphDrivers map[string]string // By operating system
93 93
 
... ...
@@ -594,11 +594,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
594 594
 		return nil, err
595 595
 	}
596 596
 
597
-	idMappings, err := setupRemappedRoot(config)
597
+	idMapping, err := setupRemappedRoot(config)
598 598
 	if err != nil {
599 599
 		return nil, err
600 600
 	}
601
-	rootIDs := idMappings.RootPair()
601
+	rootIDs := idMapping.RootPair()
602 602
 	if err := setupDaemonProcess(config); err != nil {
603 603
 		return nil, err
604 604
 	}
... ...
@@ -749,7 +749,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
749 749
 			MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
750 750
 			GraphDriver:               gd,
751 751
 			GraphDriverOptions:        config.GraphOptions,
752
-			IDMappings:                idMappings,
752
+			IDMapping:                 idMapping,
753 753
 			PluginGetter:              d.PluginStore,
754 754
 			ExperimentalEnabled:       config.Experimental,
755 755
 			OS:                        operatingSystem,
... ...
@@ -856,7 +856,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
856 856
 
857 857
 	d.EventsService = events.New()
858 858
 	d.root = config.Root
859
-	d.idMappings = idMappings
859
+	d.idMapping = idMapping
860 860
 	d.seccompEnabled = sysInfo.Seccomp
861 861
 	d.apparmorEnabled = sysInfo.AppArmor
862 862
 
... ...
@@ -1106,7 +1106,7 @@ func (daemon *Daemon) Subnets() ([]net.IPNet, []net.IPNet) {
1106 1106
 // prepareTempDir prepares and returns the default directory to use
1107 1107
 // for temporary files.
1108 1108
 // If it doesn't exist, it is created. If it exists, its content is removed.
1109
-func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
1109
+func prepareTempDir(rootDir string, rootIdentity idtools.Identity) (string, error) {
1110 1110
 	var tmpDir string
1111 1111
 	if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
1112 1112
 		tmpDir = filepath.Join(rootDir, "tmp")
... ...
@@ -1126,7 +1126,7 @@ func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
1126 1126
 	}
1127 1127
 	// We don't remove the content of tmpdir if it's not the default,
1128 1128
 	// it may hold things that do not belong to us.
1129
-	return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIDs)
1129
+	return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIdentity)
1130 1130
 }
1131 1131
 
1132 1132
 func (daemon *Daemon) setGenericResources(conf *config.Config) error {
... ...
@@ -1274,11 +1274,11 @@ func CreateDaemonRoot(config *config.Config) error {
1274 1274
 		}
1275 1275
 	}
1276 1276
 
1277
-	idMappings, err := setupRemappedRoot(config)
1277
+	idMapping, err := setupRemappedRoot(config)
1278 1278
 	if err != nil {
1279 1279
 		return err
1280 1280
 	}
1281
-	return setupDaemonRoot(config, realRoot, idMappings.RootPair())
1281
+	return setupDaemonRoot(config, realRoot, idMapping.RootPair())
1282 1282
 }
1283 1283
 
1284 1284
 // checkpointAndSave grabs a container lock to safely call container.CheckpointTo
... ...
@@ -1304,9 +1304,9 @@ func (daemon *Daemon) GetAttachmentStore() *network.AttachmentStore {
1304 1304
 	return &daemon.attachmentStore
1305 1305
 }
1306 1306
 
1307
-// IDMappings returns uid/gid mappings for the builder
1308
-func (daemon *Daemon) IDMappings() *idtools.IDMappings {
1309
-	return daemon.idMappings
1307
+// IdentityMapping returns uid/gid mapping or a SID (in the case of Windows) for the builder
1308
+func (daemon *Daemon) IdentityMapping() *idtools.IdentityMapping {
1309
+	return daemon.idMapping
1310 1310
 }
1311 1311
 
1312 1312
 // ImageService returns the Daemon's ImageService
... ...
@@ -124,7 +124,7 @@ func TestTmpfsDevShmSizeOverride(t *testing.T) {
124 124
 	mnt := "/dev/shm"
125 125
 
126 126
 	d := Daemon{
127
-		idMappings: &idtools.IDMappings{},
127
+		idMapping: &idtools.IdentityMapping{},
128 128
 	}
129 129
 	c := &container.Container{
130 130
 		HostConfig: &containertypes.HostConfig{
... ...
@@ -118,7 +118,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
118 118
 		repository: tmp,
119 119
 		root:       tmp,
120 120
 	}
121
-	daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.IDPair{UID: 0, GID: 0}, daemon)
121
+	daemon.volumes, err = volumesservice.NewVolumeService(tmp, nil, idtools.Identity{UID: 0, GID: 0}, daemon)
122 122
 	if err != nil {
123 123
 		return nil, err
124 124
 	}
... ...
@@ -1003,9 +1003,9 @@ func removeDefaultBridgeInterface() {
1003 1003
 	}
1004 1004
 }
1005 1005
 
1006
-func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
1006
+func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
1007 1007
 	return func(initPath containerfs.ContainerFS) error {
1008
-		return initlayer.Setup(initPath, idMappings.RootPair())
1008
+		return initlayer.Setup(initPath, idMapping.RootPair())
1009 1009
 	}
1010 1010
 }
1011 1011
 
... ...
@@ -1102,7 +1102,7 @@ func parseRemappedRoot(usergrp string) (string, string, error) {
1102 1102
 	return username, groupname, nil
1103 1103
 }
1104 1104
 
1105
-func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
1105
+func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
1106 1106
 	if runtime.GOOS != "linux" && config.RemappedRoot != "" {
1107 1107
 		return nil, fmt.Errorf("User namespaces are only supported on Linux")
1108 1108
 	}
... ...
@@ -1118,22 +1118,22 @@ func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
1118 1118
 			// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
1119 1119
 			// effectively
1120 1120
 			logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
1121
-			return &idtools.IDMappings{}, nil
1121
+			return &idtools.IdentityMapping{}, nil
1122 1122
 		}
1123 1123
 		logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
1124 1124
 		// update remapped root setting now that we have resolved them to actual names
1125 1125
 		config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
1126 1126
 
1127
-		mappings, err := idtools.NewIDMappings(username, groupname)
1127
+		mappings, err := idtools.NewIdentityMapping(username, groupname)
1128 1128
 		if err != nil {
1129 1129
 			return nil, errors.Wrap(err, "Can't create ID mappings")
1130 1130
 		}
1131 1131
 		return mappings, nil
1132 1132
 	}
1133
-	return &idtools.IDMappings{}, nil
1133
+	return &idtools.IdentityMapping{}, nil
1134 1134
 }
1135 1135
 
1136
-func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
1136
+func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
1137 1137
 	config.Root = rootDir
1138 1138
 	// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
1139 1139
 	// 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
1158 1158
 	// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
1159 1159
 	// `chdir()` to work for containers namespaced to that uid/gid)
1160 1160
 	if config.RemappedRoot != "" {
1161
-		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID))
1161
+		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIdentity.UID, rootIdentity.GID))
1162 1162
 		logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
1163 1163
 		// Create the root directory if it doesn't exist
1164
-		if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil {
1164
+		if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIdentity); err != nil {
1165 1165
 			return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
1166 1166
 		}
1167 1167
 		// 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
1174 1174
 			if dirPath == "/" {
1175 1175
 				break
1176 1176
 			}
1177
-			if !idtools.CanAccess(dirPath, rootIDs) {
1177
+			if !idtools.CanAccess(dirPath, rootIdentity) {
1178 1178
 				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)
1179 1179
 			}
1180 1180
 		}
... ...
@@ -53,7 +53,7 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
53 53
 	return nil
54 54
 }
55 55
 
56
-func setupInitLayer(idMappings *idtools.IDMappings) func(containerfs.ContainerFS) error {
56
+func setupInitLayer(idMapping *idtools.IdentityMapping) func(containerfs.ContainerFS) error {
57 57
 	return nil
58 58
 }
59 59
 
... ...
@@ -465,11 +465,11 @@ func (daemon *Daemon) cleanupMounts() error {
465 465
 	return nil
466 466
 }
467 467
 
468
-func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
469
-	return &idtools.IDMappings{}, nil
468
+func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) {
469
+	return &idtools.IdentityMapping{}, nil
470 470
 }
471 471
 
472
-func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
472
+func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
473 473
 	config.Root = rootDir
474 474
 	// Create the root directory if it doesn't exists
475 475
 	if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {
... ...
@@ -68,8 +68,8 @@ func (daemon *Daemon) containerExport(container *container.Container) (arch io.R
68 68
 
69 69
 	archive, err := archivePath(basefs, basefs.Path(), &archive.TarOptions{
70 70
 		Compression: archive.Uncompressed,
71
-		UIDMaps:     daemon.idMappings.UIDs(),
72
-		GIDMaps:     daemon.idMappings.GIDs(),
71
+		UIDMaps:     daemon.idMapping.UIDs(),
72
+		GIDMaps:     daemon.idMapping.GIDs(),
73 73
 	})
74 74
 	if err != nil {
75 75
 		rwlayer.Unmount()
... ...
@@ -135,13 +135,13 @@ func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
135 135
 		return nil, err
136 136
 	}
137 137
 	// Create the root aufs driver dir
138
-	if err := idtools.MkdirAllAndChown(root, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
138
+	if err := idtools.MkdirAllAndChown(root, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
139 139
 		return nil, err
140 140
 	}
141 141
 
142 142
 	// Populate the dir structure
143 143
 	for _, p := range paths {
144
-		if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
144
+		if err := idtools.MkdirAllAndChown(path.Join(root, p), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
145 145
 			return nil, err
146 146
 		}
147 147
 	}
... ...
@@ -289,7 +289,7 @@ func (a *Driver) createDirsFor(id string) error {
289 289
 	// The path of directories are <aufs_root_path>/mnt/<image_id>
290 290
 	// and <aufs_root_path>/diff/<image_id>
291 291
 	for _, p := range paths {
292
-		if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
292
+		if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
293 293
 			return err
294 294
 		}
295 295
 	}
... ...
@@ -72,7 +72,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
72 72
 	if err != nil {
73 73
 		return nil, err
74 74
 	}
75
-	if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
75
+	if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
76 76
 		return nil, err
77 77
 	}
78 78
 
... ...
@@ -502,7 +502,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
502 502
 	if err != nil {
503 503
 		return err
504 504
 	}
505
-	if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
505
+	if err := idtools.MkdirAllAndChown(subvolumes, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
506 506
 		return err
507 507
 	}
508 508
 	if parent == "" {
... ...
@@ -537,7 +537,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
537 537
 		if err := d.setStorageSize(path.Join(subvolumes, id), driver); err != nil {
538 538
 			return err
539 539
 		}
540
-		if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
540
+		if err := idtools.MkdirAllAndChown(quotas, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
541 541
 			return err
542 542
 		}
543 543
 		if err := ioutil.WriteFile(path.Join(quotas, id), []byte(fmt.Sprint(driver.options.size)), 0644); err != nil {
... ...
@@ -268,7 +268,7 @@ func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
268 268
 	if err != nil {
269 269
 		return "", err
270 270
 	}
271
-	if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
271
+	if err := idtools.MkdirAllAndChown(dirname, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
272 272
 		return "", err
273 273
 	}
274 274
 
... ...
@@ -1691,7 +1691,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) (retErr error) {
1691 1691
 	if err != nil {
1692 1692
 		return err
1693 1693
 	}
1694
-	if err := idtools.MkdirAndChown(devices.root, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil {
1694
+	if err := idtools.MkdirAndChown(devices.root, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil {
1695 1695
 		return err
1696 1696
 	}
1697 1697
 	if err := os.MkdirAll(devices.metadataDir(), 0700); err != nil {
... ...
@@ -200,11 +200,11 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
200 200
 	}
201 201
 
202 202
 	// Create the target directories if they don't exist
203
-	if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
203
+	if err := idtools.MkdirAllAndChown(path.Join(d.home, "mnt"), 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
204 204
 		d.ctr.Decrement(mp)
205 205
 		return nil, err
206 206
 	}
207
-	if err := idtools.MkdirAndChown(mp, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
207
+	if err := idtools.MkdirAndChown(mp, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
208 208
 		d.ctr.Decrement(mp)
209 209
 		return nil, err
210 210
 	}
... ...
@@ -215,7 +215,7 @@ func (d *Driver) Get(id, mountLabel string) (containerfs.ContainerFS, error) {
215 215
 		return nil, err
216 216
 	}
217 217
 
218
-	if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.IDPair{UID: uid, GID: gid}); err != nil {
218
+	if err := idtools.MkdirAllAndChown(rootFs, 0755, idtools.Identity{UID: uid, GID: gid}); err != nil {
219 219
 		d.ctr.Decrement(mp)
220 220
 		d.DeviceSet.UnmountDevice(id, mp)
221 221
 		return nil, err
... ...
@@ -183,17 +183,17 @@ func InitDriver(dataRoot string, options []string, _, _ []idtools.IDMap) (graphd
183 183
 	}
184 184
 
185 185
 	// Make sure the dataRoot directory is created
186
-	if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
186
+	if err := idtools.MkdirAllAndChown(dataRoot, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
187 187
 		return nil, fmt.Errorf("%s failed to create '%s': %v", title, dataRoot, err)
188 188
 	}
189 189
 
190 190
 	// Make sure the cache directory is created under dataRoot
191
-	if err := idtools.MkdirAllAndChown(cd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
191
+	if err := idtools.MkdirAllAndChown(cd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
192 192
 		return nil, fmt.Errorf("%s failed to create '%s': %v", title, cd, err)
193 193
 	}
194 194
 
195 195
 	// Make sure the scratch directory is created under dataRoot
196
-	if err := idtools.MkdirAllAndChown(sd, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
196
+	if err := idtools.MkdirAllAndChown(sd, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
197 197
 		return nil, fmt.Errorf("%s failed to create '%s': %v", title, sd, err)
198 198
 	}
199 199
 
... ...
@@ -168,7 +168,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
168 168
 		return nil, err
169 169
 	}
170 170
 	// Create the driver home dir
171
-	if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
171
+	if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
172 172
 		return nil, err
173 173
 	}
174 174
 
... ...
@@ -291,7 +291,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
291 291
 	if err != nil {
292 292
 		return err
293 293
 	}
294
-	root := idtools.IDPair{UID: rootUID, GID: rootGID}
294
+	root := idtools.Identity{UID: rootUID, GID: rootGID}
295 295
 
296 296
 	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
297 297
 		return err
... ...
@@ -413,7 +413,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, err erro
413 413
 	if err != nil {
414 414
 		return nil, err
415 415
 	}
416
-	if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
416
+	if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
417 417
 		return nil, err
418 418
 	}
419 419
 	var (
... ...
@@ -200,7 +200,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
200 200
 		return nil, err
201 201
 	}
202 202
 	// Create the driver home dir
203
-	if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
203
+	if err := idtools.MkdirAllAndChown(path.Join(home, linkDir), 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
204 204
 		return nil, err
205 205
 	}
206 206
 
... ...
@@ -378,7 +378,7 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts) (retErr
378 378
 	if err != nil {
379 379
 		return err
380 380
 	}
381
-	root := idtools.IDPair{UID: rootUID, GID: rootGID}
381
+	root := idtools.Identity{UID: rootUID, GID: rootGID}
382 382
 
383 383
 	if err := idtools.MkdirAllAndChown(path.Dir(dir), 0700, root); err != nil {
384 384
 		return err
... ...
@@ -586,7 +586,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
586 586
 	if err != nil {
587 587
 		return nil, err
588 588
 	}
589
-	if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
589
+	if err := idtools.MkdirAndChown(mergedDir, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
590 590
 		return nil, err
591 591
 	}
592 592
 
... ...
@@ -27,10 +27,10 @@ func init() {
27 27
 // This sets the home directory for the driver and returns NaiveDiffDriver.
28 28
 func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
29 29
 	d := &Driver{
30
-		home:       home,
31
-		idMappings: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
30
+		home:      home,
31
+		idMapping: idtools.NewIDMappingsFromMaps(uidMaps, gidMaps),
32 32
 	}
33
-	rootIDs := d.idMappings.RootPair()
33
+	rootIDs := d.idMapping.RootPair()
34 34
 	if err := idtools.MkdirAllAndChown(home, 0700, rootIDs); err != nil {
35 35
 		return nil, err
36 36
 	}
... ...
@@ -46,8 +46,8 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
46 46
 // Driver must be wrapped in NaiveDiffDriver to be used as a graphdriver.Driver
47 47
 type Driver struct {
48 48
 	driverQuota
49
-	home       string
50
-	idMappings *idtools.IDMappings
49
+	home      string
50
+	idMapping *idtools.IdentityMapping
51 51
 }
52 52
 
53 53
 func (d *Driver) String() string {
... ...
@@ -105,7 +105,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
105 105
 
106 106
 func (d *Driver) create(id, parent string, size uint64) error {
107 107
 	dir := d.dir(id)
108
-	rootIDs := d.idMappings.RootPair()
108
+	rootIDs := d.idMapping.RootPair()
109 109
 	if err := idtools.MkdirAllAndChown(filepath.Dir(dir), 0700, rootIDs); err != nil {
110 110
 		return err
111 111
 	}
... ...
@@ -95,7 +95,7 @@ func InitFilter(home string, options []string, uidMaps, gidMaps []idtools.IDMap)
95 95
 		return nil, fmt.Errorf("%s is on an ReFS volume - ReFS volumes are not supported", home)
96 96
 	}
97 97
 
98
-	if err := idtools.MkdirAllAndChown(home, 0700, idtools.IDPair{UID: 0, GID: 0}); err != nil {
98
+	if err := idtools.MkdirAllAndChown(home, 0700, idtools.Identity{UID: 0, GID: 0}); err != nil {
99 99
 		return nil, fmt.Errorf("windowsfilter failed to create '%s': %v", home, err)
100 100
 	}
101 101
 
... ...
@@ -106,7 +106,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
106 106
 	if err != nil {
107 107
 		return nil, fmt.Errorf("Failed to get root uid/guid: %v", err)
108 108
 	}
109
-	if err := idtools.MkdirAllAndChown(base, 0700, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
109
+	if err := idtools.MkdirAllAndChown(base, 0700, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
110 110
 		return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
111 111
 	}
112 112
 
... ...
@@ -385,7 +385,7 @@ func (d *Driver) Get(id, mountLabel string) (_ containerfs.ContainerFS, retErr e
385 385
 		return nil, err
386 386
 	}
387 387
 	// Create the target directories if they don't exist
388
-	if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.IDPair{UID: rootUID, GID: rootGID}); err != nil {
388
+	if err := idtools.MkdirAllAndChown(mountpoint, 0755, idtools.Identity{UID: rootUID, GID: rootGID}); err != nil {
389 389
 		return nil, err
390 390
 	}
391 391
 
... ...
@@ -162,7 +162,7 @@ func (daemon *Daemon) fillSecurityOptions(v *types.Info, sysInfo *sysinfo.SysInf
162 162
 	if selinuxEnabled() {
163 163
 		securityOptions = append(securityOptions, "name=selinux")
164 164
 	}
165
-	if rootIDs := daemon.idMappings.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
165
+	if rootIDs := daemon.idMapping.RootPair(); rootIDs.UID != 0 || rootIDs.GID != 0 {
166 166
 		securityOptions = append(securityOptions, "name=userns")
167 167
 	}
168 168
 	v.SecurityOptions = securityOptions
... ...
@@ -17,7 +17,7 @@ import (
17 17
 //
18 18
 // This extra layer is used by all containers as the top-most ro layer. It protects
19 19
 // the container from unwanted side-effects on the rw layer.
20
-func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
20
+func Setup(initLayerFs containerfs.ContainerFS, rootIdentity idtools.Identity) error {
21 21
 	// Since all paths are local to the container, we can just extract initLayerFs.Path()
22 22
 	initLayer := initLayerFs.Path()
23 23
 
... ...
@@ -42,12 +42,12 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
42 42
 
43 43
 		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
44 44
 			if os.IsNotExist(err) {
45
-				if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIDs); err != nil {
45
+				if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIdentity); err != nil {
46 46
 					return err
47 47
 				}
48 48
 				switch typ {
49 49
 				case "dir":
50
-					if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIDs); err != nil {
50
+					if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIdentity); err != nil {
51 51
 						return err
52 52
 					}
53 53
 				case "file":
... ...
@@ -55,7 +55,7 @@ func Setup(initLayerFs containerfs.ContainerFS, rootIDs idtools.IDPair) error {
55 55
 					if err != nil {
56 56
 						return err
57 57
 					}
58
-					f.Chown(rootIDs.UID, rootIDs.GID)
58
+					f.Chown(rootIdentity.UID, rootIdentity.GID)
59 59
 					f.Close()
60 60
 				default:
61 61
 					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
... ...
@@ -11,6 +11,6 @@ import (
11 11
 //
12 12
 // This extra layer is used by all containers as the top-most ro layer. It protects
13 13
 // the container from unwanted side-effects on the rw layer.
14
-func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.IDPair) error {
14
+func Setup(initLayer containerfs.ContainerFS, rootIDs idtools.Identity) error {
15 15
 	return nil
16 16
 }
... ...
@@ -217,13 +217,13 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
217 217
 	userNS := false
218 218
 	// user
219 219
 	if c.HostConfig.UsernsMode.IsPrivate() {
220
-		uidMap := daemon.idMappings.UIDs()
220
+		uidMap := daemon.idMapping.UIDs()
221 221
 		if uidMap != nil {
222 222
 			userNS = true
223 223
 			ns := specs.LinuxNamespace{Type: "user"}
224 224
 			setNamespace(s, ns)
225 225
 			s.Linux.UIDMappings = specMapping(uidMap)
226
-			s.Linux.GIDMappings = specMapping(daemon.idMappings.GIDs())
226
+			s.Linux.GIDMappings = specMapping(daemon.idMapping.GIDs())
227 227
 		}
228 228
 	}
229 229
 	// network
... ...
@@ -619,7 +619,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
619 619
 
620 620
 	// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
621 621
 	// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
622
-	if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {
622
+	if uidMap := daemon.idMapping.UIDs(); uidMap != nil || c.HostConfig.Privileged {
623 623
 		for i, m := range s.Mounts {
624 624
 			if m.Type == "cgroup" {
625 625
 				clearReadOnly(&s.Mounts[i])
... ...
@@ -642,7 +642,7 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
642 642
 		Path:     c.BaseFS.Path(),
643 643
 		Readonly: c.HostConfig.ReadonlyRootfs,
644 644
 	}
645
-	if err := c.SetupWorkingDirectory(daemon.idMappings.RootPair()); err != nil {
645
+	if err := c.SetupWorkingDirectory(daemon.idMapping.RootPair()); err != nil {
646 646
 		return err
647 647
 	}
648 648
 	cwd := c.Config.WorkingDir
... ...
@@ -21,7 +21,7 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
21 21
 	d := Daemon{
22 22
 		// some empty structs to avoid getting a panic
23 23
 		// caused by a null pointer dereference
24
-		idMappings:  &idtools.IDMappings{},
24
+		idMapping:   &idtools.IdentityMapping{},
25 25
 		configStore: &config.Config{},
26 26
 	}
27 27
 	c := &container.Container{
... ...
@@ -58,7 +58,7 @@ func TestIpcPrivateVsReadonly(t *testing.T) {
58 58
 	d := Daemon{
59 59
 		// some empty structs to avoid getting a panic
60 60
 		// caused by a null pointer dereference
61
-		idMappings:  &idtools.IDMappings{},
61
+		idMapping:   &idtools.IdentityMapping{},
62 62
 		configStore: &config.Config{},
63 63
 	}
64 64
 	c := &container.Container{
... ...
@@ -47,7 +47,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
47 47
 			return nil
48 48
 		}
49 49
 
50
-		path, err := m.Setup(c.MountLabel, daemon.idMappings.RootPair(), checkfunc)
50
+		path, err := m.Setup(c.MountLabel, daemon.idMapping.RootPair(), checkfunc)
51 51
 		if err != nil {
52 52
 			return nil, err
53 53
 		}
... ...
@@ -77,7 +77,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
77 77
 	// if we are going to mount any of the network files from container
78 78
 	// metadata, the ownership must be set properly for potential container
79 79
 	// remapped root (user namespaces)
80
-	rootIDs := daemon.idMappings.RootPair()
80
+	rootIDs := daemon.idMapping.RootPair()
81 81
 	for _, mount := range netMounts {
82 82
 		// we should only modify ownership of network files within our own container
83 83
 		// metadata repository. If the user specifies a mount path external, it is
... ...
@@ -24,7 +24,7 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
24 24
 		if err := daemon.lazyInitializeVolume(c.ID, mount); err != nil {
25 25
 			return nil, err
26 26
 		}
27
-		s, err := mount.Setup(c.MountLabel, idtools.IDPair{UID: 0, GID: 0}, nil)
27
+		s, err := mount.Setup(c.MountLabel, idtools.Identity{}, nil)
28 28
 		if err != nil {
29 29
 			return nil, err
30 30
 		}
... ...
@@ -16,5 +16,5 @@ func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
16 16
 		return err
17 17
 	}
18 18
 	defer daemon.Unmount(container)
19
-	return container.SetupWorkingDirectory(daemon.idMappings.RootPair())
19
+	return container.SetupWorkingDirectory(daemon.idMapping.RootPair())
20 20
 }
21 21
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+#!/usr/bin/env bash
1
+set -e
2
+
3
+CONTAINER_UTILITY_COMMIT=e004a1415a433447369e315b9d7df357102be0d2 # v0.9.0
4
+
5
+(
6
+	git clone https://github.com/docker/windows-container-utility.git "$GOPATH/src/github.com/docker/windows-container-utility"
7
+	cd "$GOPATH/src/github.com/docker/windows-container-utility"
8
+	git checkout -q "$CONTAINER_UTILITY_COMMIT"
9
+
10
+	echo Building: ${DEST}/containerutility.exe
11
+
12
+	(
13
+		make
14
+	)
15
+
16
+	mkdir -p ${ABS_DEST}
17
+
18
+	cp containerutility.exe ${ABS_DEST}/containerutility.exe
19
+)
... ...
@@ -25,5 +25,7 @@ for platform in $DOCKER_CROSSPLATFORMS; do
25 25
 		mkdir -p "$DEST"
26 26
 		ABS_DEST="$(cd "$DEST" && pwd -P)"
27 27
 		source "${MAKEDIR}/binary-daemon"
28
+
29
+		source "${MAKEDIR}/cross-platform-dependent"
28 30
 	)
29 31
 done
30 32
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+#!/usr/bin/env bash
1
+set -e
2
+
3
+if [ $platform == "windows/amd64" ]; then
4
+	source "${MAKEDIR}/containerutility"
5
+fi
... ...
@@ -45,7 +45,7 @@ type StoreOptions struct {
45 45
 	MetadataStorePathTemplate string
46 46
 	GraphDriver               string
47 47
 	GraphDriverOptions        []string
48
-	IDMappings                *idtools.IDMappings
48
+	IDMapping                 *idtools.IdentityMapping
49 49
 	PluginGetter              plugingetter.PluginGetter
50 50
 	ExperimentalEnabled       bool
51 51
 	OS                        string
... ...
@@ -56,8 +56,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
56 56
 	driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
57 57
 		Root:                options.Root,
58 58
 		DriverOptions:       options.GraphDriverOptions,
59
-		UIDMaps:             options.IDMappings.UIDs(),
60
-		GIDMaps:             options.IDMappings.GIDs(),
59
+		UIDMaps:             options.IDMapping.UIDs(),
60
+		GIDMaps:             options.IDMapping.GIDs(),
61 61
 		ExperimentalEnabled: options.ExperimentalEnabled,
62 62
 	})
63 63
 	if err != nil {
... ...
@@ -58,7 +58,7 @@ func getSpecUser(ociSpec *specs.Spec) (int, int) {
58 58
 func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
59 59
 	uid, gid := getSpecUser(ociSpec)
60 60
 	if uid == 0 && gid == 0 {
61
-		return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.IDPair{UID: 0, GID: 0})
61
+		return bundleDir, idtools.MkdirAllAndChownNew(bundleDir, 0755, idtools.Identity{UID: 0, GID: 0})
62 62
 	}
63 63
 
64 64
 	p := string(filepath.Separator)
... ...
@@ -71,7 +71,7 @@ func prepareBundleDir(bundleDir string, ociSpec *specs.Spec) (string, error) {
71 71
 		}
72 72
 		if os.IsNotExist(err) || fi.Mode()&1 == 0 {
73 73
 			p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
74
-			if err := idtools.MkdirAndChown(p, 0700, idtools.IDPair{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
74
+			if err := idtools.MkdirAndChown(p, 0700, idtools.Identity{UID: uid, GID: gid}); err != nil && !os.IsExist(err) {
75 75
 				return "", err
76 76
 			}
77 77
 		}
... ...
@@ -52,7 +52,7 @@ type (
52 52
 		NoLchown         bool
53 53
 		UIDMaps          []idtools.IDMap
54 54
 		GIDMaps          []idtools.IDMap
55
-		ChownOpts        *idtools.IDPair
55
+		ChownOpts        *idtools.Identity
56 56
 		IncludeSourceDir bool
57 57
 		// WhiteoutFormat is the expected on disk format for whiteout files.
58 58
 		// This format will be converted to the standard format on pack
... ...
@@ -72,13 +72,13 @@ type (
72 72
 // this package with a pluggable Untar function. Also, to facilitate the passing of specific id
73 73
 // mappings for untar, an Archiver can be created with maps which will then be passed to Untar operations.
74 74
 type Archiver struct {
75
-	Untar         func(io.Reader, string, *TarOptions) error
76
-	IDMappingsVar *idtools.IDMappings
75
+	Untar     func(io.Reader, string, *TarOptions) error
76
+	IDMapping *idtools.IdentityMapping
77 77
 }
78 78
 
79
-// NewDefaultArchiver returns a new Archiver without any IDMappings
79
+// NewDefaultArchiver returns a new Archiver without any IdentityMapping
80 80
 func NewDefaultArchiver() *Archiver {
81
-	return &Archiver{Untar: Untar, IDMappingsVar: &idtools.IDMappings{}}
81
+	return &Archiver{Untar: Untar, IDMapping: &idtools.IdentityMapping{}}
82 82
 }
83 83
 
84 84
 // breakoutError is used to differentiate errors related to breaking out
... ...
@@ -420,9 +420,9 @@ type tarAppender struct {
420 420
 	Buffer    *bufio.Writer
421 421
 
422 422
 	// for hardlink mapping
423
-	SeenFiles  map[uint64]string
424
-	IDMappings *idtools.IDMappings
425
-	ChownOpts  *idtools.IDPair
423
+	SeenFiles       map[uint64]string
424
+	IdentityMapping *idtools.IdentityMapping
425
+	ChownOpts       *idtools.Identity
426 426
 
427 427
 	// For packing and unpacking whiteout files in the
428 428
 	// non standard format. The whiteout files defined
... ...
@@ -431,13 +431,13 @@ type tarAppender struct {
431 431
 	WhiteoutConverter tarWhiteoutConverter
432 432
 }
433 433
 
434
-func newTarAppender(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarAppender {
434
+func newTarAppender(idMapping *idtools.IdentityMapping, writer io.Writer, chownOpts *idtools.Identity) *tarAppender {
435 435
 	return &tarAppender{
436
-		SeenFiles:  make(map[uint64]string),
437
-		TarWriter:  tar.NewWriter(writer),
438
-		Buffer:     pools.BufioWriter32KPool.Get(nil),
439
-		IDMappings: idMapping,
440
-		ChownOpts:  chownOpts,
436
+		SeenFiles:       make(map[uint64]string),
437
+		TarWriter:       tar.NewWriter(writer),
438
+		Buffer:          pools.BufioWriter32KPool.Get(nil),
439
+		IdentityMapping: idMapping,
440
+		ChownOpts:       chownOpts,
441 441
 	}
442 442
 }
443 443
 
... ...
@@ -502,14 +502,12 @@ func (ta *tarAppender) addTarFile(path, name string) error {
502 502
 	//handle re-mapping container ID mappings back to host ID mappings before
503 503
 	//writing tar headers/files. We skip whiteout files because they were written
504 504
 	//by the kernel and already have proper ownership relative to the host
505
-	if !isOverlayWhiteout &&
506
-		!strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) &&
507
-		!ta.IDMappings.Empty() {
505
+	if !isOverlayWhiteout && !strings.HasPrefix(filepath.Base(hdr.Name), WhiteoutPrefix) && !ta.IdentityMapping.Empty() {
508 506
 		fileIDPair, err := getFileUIDGID(fi.Sys())
509 507
 		if err != nil {
510 508
 			return err
511 509
 		}
512
-		hdr.Uid, hdr.Gid, err = ta.IDMappings.ToContainer(fileIDPair)
510
+		hdr.Uid, hdr.Gid, err = ta.IdentityMapping.ToContainer(fileIDPair)
513 511
 		if err != nil {
514 512
 			return err
515 513
 		}
... ...
@@ -572,7 +570,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
572 572
 	return nil
573 573
 }
574 574
 
575
-func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.IDPair, inUserns bool) error {
575
+func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, Lchown bool, chownOpts *idtools.Identity, inUserns bool) error {
576 576
 	// hdr.Mode is in linux format, which we can use for sycalls,
577 577
 	// but for os.Foo() calls we need the mode converted to os.FileMode,
578 578
 	// 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
652 652
 	// Lchown is not supported on Windows.
653 653
 	if Lchown && runtime.GOOS != "windows" {
654 654
 		if chownOpts == nil {
655
-			chownOpts = &idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid}
655
+			chownOpts = &idtools.Identity{UID: hdr.Uid, GID: hdr.Gid}
656 656
 		}
657 657
 		if err := os.Lchown(path, chownOpts.UID, chownOpts.GID); err != nil {
658 658
 			return err
... ...
@@ -901,8 +899,8 @@ func Unpack(decompressedArchive io.Reader, dest string, options *TarOptions) err
901 901
 	defer pools.BufioReader32KPool.Put(trBuf)
902 902
 
903 903
 	var dirs []*tar.Header
904
-	idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
905
-	rootIDs := idMappings.RootPair()
904
+	idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
905
+	rootIDs := idMapping.RootPair()
906 906
 	whiteoutConverter := getWhiteoutConverter(options.WhiteoutFormat)
907 907
 
908 908
 	// Iterate through the files in the archive.
... ...
@@ -981,7 +979,7 @@ loop:
981 981
 		}
982 982
 		trBuf.Reset(tr)
983 983
 
984
-		if err := remapIDs(idMappings, hdr); err != nil {
984
+		if err := remapIDs(idMapping, hdr); err != nil {
985 985
 			return err
986 986
 		}
987 987
 
... ...
@@ -1068,8 +1066,8 @@ func (archiver *Archiver) TarUntar(src, dst string) error {
1068 1068
 	}
1069 1069
 	defer archive.Close()
1070 1070
 	options := &TarOptions{
1071
-		UIDMaps: archiver.IDMappingsVar.UIDs(),
1072
-		GIDMaps: archiver.IDMappingsVar.GIDs(),
1071
+		UIDMaps: archiver.IDMapping.UIDs(),
1072
+		GIDMaps: archiver.IDMapping.GIDs(),
1073 1073
 	}
1074 1074
 	return archiver.Untar(archive, dst, options)
1075 1075
 }
... ...
@@ -1082,8 +1080,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
1082 1082
 	}
1083 1083
 	defer archive.Close()
1084 1084
 	options := &TarOptions{
1085
-		UIDMaps: archiver.IDMappingsVar.UIDs(),
1086
-		GIDMaps: archiver.IDMappingsVar.GIDs(),
1085
+		UIDMaps: archiver.IDMapping.UIDs(),
1086
+		GIDMaps: archiver.IDMapping.GIDs(),
1087 1087
 	}
1088 1088
 	return archiver.Untar(archive, dst, options)
1089 1089
 }
... ...
@@ -1104,7 +1102,7 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
1104 1104
 	// if this Archiver is set up with ID mapping we need to create
1105 1105
 	// the new destination directory with the remapped root UID/GID pair
1106 1106
 	// as owner
1107
-	rootIDs := archiver.IDMappingsVar.RootPair()
1107
+	rootIDs := archiver.IDMapping.RootPair()
1108 1108
 	// Create dst, copy src's content into it
1109 1109
 	logrus.Debugf("Creating dest directory: %s", dst)
1110 1110
 	if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
... ...
@@ -1164,7 +1162,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
1164 1164
 			hdr.Name = filepath.Base(dst)
1165 1165
 			hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
1166 1166
 
1167
-			if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
1167
+			if err := remapIDs(archiver.IDMapping, hdr); err != nil {
1168 1168
 				return err
1169 1169
 			}
1170 1170
 
... ...
@@ -1192,13 +1190,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
1192 1192
 	return err
1193 1193
 }
1194 1194
 
1195
-// IDMappings returns the IDMappings of the archiver.
1196
-func (archiver *Archiver) IDMappings() *idtools.IDMappings {
1197
-	return archiver.IDMappingsVar
1195
+// IdentityMapping returns the IdentityMapping of the archiver.
1196
+func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
1197
+	return archiver.IDMapping
1198 1198
 }
1199 1199
 
1200
-func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
1201
-	ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
1200
+func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
1201
+	ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
1202 1202
 	hdr.Uid, hdr.Gid = ids.UID, ids.GID
1203 1203
 	return err
1204 1204
 }
... ...
@@ -755,11 +755,11 @@ func TestTarWithOptionsChownOptsAlwaysOverridesIdPair(t *testing.T) {
755 755
 		expectedUID int
756 756
 		expectedGID int
757 757
 	}{
758
-		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1337, GID: 42}}, 1337, 42},
759
-		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
760
-		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
761
-		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
762
-		{&TarOptions{ChownOpts: &idtools.IDPair{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
758
+		{&TarOptions{ChownOpts: &idtools.Identity{UID: 1337, GID: 42}}, 1337, 42},
759
+		{&TarOptions{ChownOpts: &idtools.Identity{UID: 100001, GID: 100001}, UIDMaps: idMaps, GIDMaps: idMaps}, 100001, 100001},
760
+		{&TarOptions{ChownOpts: &idtools.Identity{UID: 0, GID: 0}, NoLchown: false}, 0, 0},
761
+		{&TarOptions{ChownOpts: &idtools.Identity{UID: 1, GID: 1}, NoLchown: true}, 1, 1},
762
+		{&TarOptions{ChownOpts: &idtools.Identity{UID: 1000, GID: 1000}, NoLchown: true}, 1000, 1000},
763 763
 	}
764 764
 	for _, testCase := range cases {
765 765
 		reader, err := TarWithOptions(filePath, testCase.opts)
... ...
@@ -68,13 +68,13 @@ func getInodeFromStat(stat interface{}) (inode uint64, err error) {
68 68
 	return
69 69
 }
70 70
 
71
-func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
71
+func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
72 72
 	s, ok := stat.(*syscall.Stat_t)
73 73
 
74 74
 	if !ok {
75
-		return idtools.IDPair{}, errors.New("cannot convert stat value to syscall.Stat_t")
75
+		return idtools.Identity{}, errors.New("cannot convert stat value to syscall.Stat_t")
76 76
 	}
77
-	return idtools.IDPair{UID: int(s.Uid), GID: int(s.Gid)}, nil
77
+	return idtools.Identity{UID: int(s.Uid), GID: int(s.Gid)}, nil
78 78
 }
79 79
 
80 80
 // handleTarTypeBlockCharFifo is an OS-specific helper function used by
... ...
@@ -61,7 +61,7 @@ func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
61 61
 	return nil
62 62
 }
63 63
 
64
-func getFileUIDGID(stat interface{}) (idtools.IDPair, error) {
64
+func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
65 65
 	// no notion of file ownership mapping yet on Windows
66
-	return idtools.IDPair{UID: 0, GID: 0}, nil
66
+	return idtools.Identity{UID: 0, GID: 0}, nil
67 67
 }
... ...
@@ -33,7 +33,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
33 33
 	if options.ExcludePatterns == nil {
34 34
 		options.ExcludePatterns = []string{}
35 35
 	}
36
-	idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
36
+	idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
37 37
 
38 38
 	aufsTempdir := ""
39 39
 	aufsHardlinks := make(map[string]*tar.Header)
... ...
@@ -192,7 +192,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
192 192
 				srcData = tmpFile
193 193
 			}
194 194
 
195
-			if err := remapIDs(idMappings, srcHdr); err != nil {
195
+			if err := remapIDs(idMapping, srcHdr); err != nil {
196 196
 				return 0, err
197 197
 			}
198 198
 
... ...
@@ -12,13 +12,13 @@ import (
12 12
 )
13 13
 
14 14
 // NewArchiver returns a new Archiver which uses chrootarchive.Untar
15
-func NewArchiver(idMappings *idtools.IDMappings) *archive.Archiver {
16
-	if idMappings == nil {
17
-		idMappings = &idtools.IDMappings{}
15
+func NewArchiver(idMapping *idtools.IdentityMapping) *archive.Archiver {
16
+	if idMapping == nil {
17
+		idMapping = &idtools.IdentityMapping{}
18 18
 	}
19 19
 	return &archive.Archiver{
20
-		Untar:         Untar,
21
-		IDMappingsVar: idMappings,
20
+		Untar:     Untar,
21
+		IDMapping: idMapping,
22 22
 	}
23 23
 }
24 24
 
... ...
@@ -49,8 +49,8 @@ func untarHandler(tarArchive io.Reader, dest string, options *archive.TarOptions
49 49
 		options.ExcludePatterns = []string{}
50 50
 	}
51 51
 
52
-	idMappings := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
53
-	rootIDs := idMappings.RootPair()
52
+	idMapping := idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps)
53
+	rootIDs := idMapping.RootPair()
54 54
 
55 55
 	dest = filepath.Clean(dest)
56 56
 	if _, err := os.Stat(dest); os.IsNotExist(err) {
... ...
@@ -22,11 +22,11 @@ type UntarFunc func(io.Reader, string, *archive.TarOptions) error
22 22
 
23 23
 // Archiver provides a similar implementation of the archive.Archiver package with the rootfs abstraction
24 24
 type Archiver struct {
25
-	SrcDriver     Driver
26
-	DstDriver     Driver
27
-	Tar           TarFunc
28
-	Untar         UntarFunc
29
-	IDMappingsVar *idtools.IDMappings
25
+	SrcDriver Driver
26
+	DstDriver Driver
27
+	Tar       TarFunc
28
+	Untar     UntarFunc
29
+	IDMapping *idtools.IdentityMapping
30 30
 }
31 31
 
32 32
 // 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 {
39 39
 	}
40 40
 	defer tarArchive.Close()
41 41
 	options := &archive.TarOptions{
42
-		UIDMaps: archiver.IDMappingsVar.UIDs(),
43
-		GIDMaps: archiver.IDMappingsVar.GIDs(),
42
+		UIDMaps: archiver.IDMapping.UIDs(),
43
+		GIDMaps: archiver.IDMapping.GIDs(),
44 44
 	}
45 45
 	return archiver.Untar(tarArchive, dst, options)
46 46
 }
... ...
@@ -53,8 +53,8 @@ func (archiver *Archiver) UntarPath(src, dst string) error {
53 53
 	}
54 54
 	defer tarArchive.Close()
55 55
 	options := &archive.TarOptions{
56
-		UIDMaps: archiver.IDMappingsVar.UIDs(),
57
-		GIDMaps: archiver.IDMappingsVar.GIDs(),
56
+		UIDMaps: archiver.IDMapping.UIDs(),
57
+		GIDMaps: archiver.IDMapping.GIDs(),
58 58
 	}
59 59
 	return archiver.Untar(tarArchive, dst, options)
60 60
 }
... ...
@@ -75,9 +75,11 @@ func (archiver *Archiver) CopyWithTar(src, dst string) error {
75 75
 	// if this archiver is set up with ID mapping we need to create
76 76
 	// the new destination directory with the remapped root UID/GID pair
77 77
 	// as owner
78
-	rootIDs := archiver.IDMappingsVar.RootPair()
78
+
79
+	identity := idtools.Identity{UID: archiver.IDMapping.RootPair().UID, GID: archiver.IDMapping.RootPair().GID}
80
+
79 81
 	// Create dst, copy src's content into it
80
-	if err := idtools.MkdirAllAndChownNew(dst, 0755, rootIDs); err != nil {
82
+	if err := idtools.MkdirAllAndChownNew(dst, 0755, identity); err != nil {
81 83
 		return err
82 84
 	}
83 85
 	logrus.Debugf("Calling TarUntar(%s, %s)", src, dst)
... ...
@@ -150,7 +152,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
150 150
 				hdr.Mode = int64(os.FileMode(hdr.Mode))
151 151
 			}
152 152
 
153
-			if err := remapIDs(archiver.IDMappingsVar, hdr); err != nil {
153
+			if err := remapIDs(archiver.IDMapping, hdr); err != nil {
154 154
 				return err
155 155
 			}
156 156
 
... ...
@@ -178,13 +180,13 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
178 178
 	return err
179 179
 }
180 180
 
181
-// IDMappings returns the IDMappings of the archiver.
182
-func (archiver *Archiver) IDMappings() *idtools.IDMappings {
183
-	return archiver.IDMappingsVar
181
+// IdentityMapping returns the IdentityMapping of the archiver.
182
+func (archiver *Archiver) IdentityMapping() *idtools.IdentityMapping {
183
+	return archiver.IDMapping
184 184
 }
185 185
 
186
-func remapIDs(idMappings *idtools.IDMappings, hdr *tar.Header) error {
187
-	ids, err := idMappings.ToHost(idtools.IDPair{UID: hdr.Uid, GID: hdr.Gid})
186
+func remapIDs(idMapping *idtools.IdentityMapping, hdr *tar.Header) error {
187
+	ids, err := idMapping.ToHost(idtools.Identity{UID: hdr.Uid, GID: hdr.Gid})
188 188
 	hdr.Uid, hdr.Gid = ids.UID, ids.GID
189 189
 	return err
190 190
 }
... ...
@@ -37,23 +37,23 @@ const (
37 37
 // MkdirAllAndChown creates a directory (include any along the path) and then modifies
38 38
 // ownership to the requested uid/gid.  If the directory already exists, this
39 39
 // function will still change ownership to the requested uid/gid pair.
40
-func MkdirAllAndChown(path string, mode os.FileMode, owner IDPair) error {
41
-	return mkdirAs(path, mode, owner.UID, owner.GID, true, true)
40
+func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error {
41
+	return mkdirAs(path, mode, owner, true, true)
42 42
 }
43 43
 
44 44
 // MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
45 45
 // If the directory already exists, this function still changes ownership.
46 46
 // Note that unlike os.Mkdir(), this function does not return IsExist error
47 47
 // in case path already exists.
48
-func MkdirAndChown(path string, mode os.FileMode, owner IDPair) error {
49
-	return mkdirAs(path, mode, owner.UID, owner.GID, false, true)
48
+func MkdirAndChown(path string, mode os.FileMode, owner Identity) error {
49
+	return mkdirAs(path, mode, owner, false, true)
50 50
 }
51 51
 
52 52
 // MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
53 53
 // ownership ONLY of newly created directories to the requested uid/gid. If the
54 54
 // directories along the path exist, no change of ownership will be performed
55
-func MkdirAllAndChownNew(path string, mode os.FileMode, owner IDPair) error {
56
-	return mkdirAs(path, mode, owner.UID, owner.GID, true, false)
55
+func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
56
+	return mkdirAs(path, mode, owner, true, false)
57 57
 }
58 58
 
59 59
 // 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) {
102 102
 	return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
103 103
 }
104 104
 
105
-// IDPair is a UID and GID pair
106
-type IDPair struct {
105
+// Identity is either a UID and GID pair or a SID (but not both)
106
+type Identity struct {
107 107
 	UID int
108 108
 	GID int
109
+	SID string
109 110
 }
110 111
 
111
-// IDMappings contains a mappings of UIDs and GIDs
112
-type IDMappings struct {
112
+// IdentityMapping contains a mappings of UIDs and GIDs
113
+type IdentityMapping struct {
113 114
 	uids []IDMap
114 115
 	gids []IDMap
115 116
 }
116 117
 
117
-// NewIDMappings takes a requested user and group name and
118
+// NewIdentityMapping takes a requested user and group name and
118 119
 // using the data from /etc/sub{uid,gid} ranges, creates the
119 120
 // proper uid and gid remapping ranges for that user/group pair
120
-func NewIDMappings(username, groupname string) (*IDMappings, error) {
121
+func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) {
121 122
 	subuidRanges, err := parseSubuid(username)
122 123
 	if err != nil {
123 124
 		return nil, err
... ...
@@ -133,7 +134,7 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
133 133
 		return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
134 134
 	}
135 135
 
136
-	return &IDMappings{
136
+	return &IdentityMapping{
137 137
 		uids: createIDMap(subuidRanges),
138 138
 		gids: createIDMap(subgidRanges),
139 139
 	}, nil
... ...
@@ -141,21 +142,21 @@ func NewIDMappings(username, groupname string) (*IDMappings, error) {
141 141
 
142 142
 // NewIDMappingsFromMaps creates a new mapping from two slices
143 143
 // Deprecated: this is a temporary shim while transitioning to IDMapping
144
-func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IDMappings {
145
-	return &IDMappings{uids: uids, gids: gids}
144
+func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping {
145
+	return &IdentityMapping{uids: uids, gids: gids}
146 146
 }
147 147
 
148 148
 // RootPair returns a uid and gid pair for the root user. The error is ignored
149 149
 // because a root user always exists, and the defaults are correct when the uid
150 150
 // and gid maps are empty.
151
-func (i *IDMappings) RootPair() IDPair {
151
+func (i *IdentityMapping) RootPair() Identity {
152 152
 	uid, gid, _ := GetRootUIDGID(i.uids, i.gids)
153
-	return IDPair{UID: uid, GID: gid}
153
+	return Identity{UID: uid, GID: gid}
154 154
 }
155 155
 
156 156
 // ToHost returns the host UID and GID for the container uid, gid.
157 157
 // Remapping is only performed if the ids aren't already the remapped root ids
158
-func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
158
+func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) {
159 159
 	var err error
160 160
 	target := i.RootPair()
161 161
 
... ...
@@ -173,7 +174,7 @@ func (i *IDMappings) ToHost(pair IDPair) (IDPair, error) {
173 173
 }
174 174
 
175 175
 // ToContainer returns the container UID and GID for the host uid and gid
176
-func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
176
+func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) {
177 177
 	uid, err := toContainer(pair.UID, i.uids)
178 178
 	if err != nil {
179 179
 		return -1, -1, err
... ...
@@ -183,19 +184,19 @@ func (i *IDMappings) ToContainer(pair IDPair) (int, int, error) {
183 183
 }
184 184
 
185 185
 // Empty returns true if there are no id mappings
186
-func (i *IDMappings) Empty() bool {
186
+func (i *IdentityMapping) Empty() bool {
187 187
 	return len(i.uids) == 0 && len(i.gids) == 0
188 188
 }
189 189
 
190 190
 // UIDs return the UID mapping
191 191
 // TODO: remove this once everything has been refactored to use pairs
192
-func (i *IDMappings) UIDs() []IDMap {
192
+func (i *IdentityMapping) UIDs() []IDMap {
193 193
 	return i.uids
194 194
 }
195 195
 
196 196
 // GIDs return the UID mapping
197 197
 // TODO: remove this once everything has been refactored to use pairs
198
-func (i *IDMappings) GIDs() []IDMap {
198
+func (i *IdentityMapping) GIDs() []IDMap {
199 199
 	return i.gids
200 200
 }
201 201
 
... ...
@@ -21,11 +21,12 @@ var (
21 21
 	getentCmd string
22 22
 )
23 23
 
24
-func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
24
+func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
25 25
 	// make an array containing the original path asked for, plus (for mkAll == true)
26 26
 	// all path components leading up to the complete path that don't exist before we MkdirAll
27 27
 	// so that we can chown all of them properly at the end.  If chownExisting is false, we won't
28 28
 	// chown the full directory path if it exists
29
+
29 30
 	var paths []string
30 31
 
31 32
 	stat, err := system.Stat(path)
... ...
@@ -38,7 +39,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
38 38
 		}
39 39
 
40 40
 		// short-circuit--we were called with an existing directory and chown was requested
41
-		return lazyChown(path, ownerUID, ownerGID, stat)
41
+		return lazyChown(path, owner.UID, owner.GID, stat)
42 42
 	}
43 43
 
44 44
 	if os.IsNotExist(err) {
... ...
@@ -69,7 +70,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
69 69
 	// even if it existed, we will chown the requested path + any subpaths that
70 70
 	// didn't exist when we called MkdirAll
71 71
 	for _, pathComponent := range paths {
72
-		if err := lazyChown(pathComponent, ownerUID, ownerGID, nil); err != nil {
72
+		if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil {
73 73
 			return err
74 74
 		}
75 75
 	}
... ...
@@ -78,7 +79,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
78 78
 
79 79
 // CanAccess takes a valid (existing) directory and a uid, gid pair and determines
80 80
 // if that uid, gid pair has access (execute bit) to the directory
81
-func CanAccess(path string, pair IDPair) bool {
81
+func CanAccess(path string, pair Identity) bool {
82 82
 	statInfo, err := system.Stat(path)
83 83
 	if err != nil {
84 84
 		return false
... ...
@@ -46,7 +46,7 @@ func TestMkdirAllAndChown(t *testing.T) {
46 46
 	}
47 47
 
48 48
 	// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
49
-	if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
49
+	if err := MkdirAllAndChown(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99}); err != nil {
50 50
 		t.Fatal(err)
51 51
 	}
52 52
 	testTree["usr/share"] = node{99, 99}
... ...
@@ -59,7 +59,7 @@ func TestMkdirAllAndChown(t *testing.T) {
59 59
 	}
60 60
 
61 61
 	// test 2-deep new directories--both should be owned by the uid/gid pair
62
-	if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101}); err != nil {
62
+	if err := MkdirAllAndChown(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101}); err != nil {
63 63
 		t.Fatal(err)
64 64
 	}
65 65
 	testTree["lib/some"] = node{101, 101}
... ...
@@ -73,7 +73,7 @@ func TestMkdirAllAndChown(t *testing.T) {
73 73
 	}
74 74
 
75 75
 	// test a directory that already exists; should be chowned, but nothing else
76
-	if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
76
+	if err := MkdirAllAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102}); err != nil {
77 77
 		t.Fatal(err)
78 78
 	}
79 79
 	testTree["usr"] = node{102, 102}
... ...
@@ -102,7 +102,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
102 102
 	assert.NilError(t, buildTree(dirName, testTree))
103 103
 
104 104
 	// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
105
-	err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, IDPair{UID: 99, GID: 99})
105
+	err = MkdirAllAndChownNew(filepath.Join(dirName, "usr", "share"), 0755, Identity{UID: 99, GID: 99})
106 106
 	assert.NilError(t, err)
107 107
 
108 108
 	testTree["usr/share"] = node{99, 99}
... ...
@@ -111,7 +111,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
111 111
 	assert.NilError(t, compareTrees(testTree, verifyTree))
112 112
 
113 113
 	// test 2-deep new directories--both should be owned by the uid/gid pair
114
-	err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, IDPair{UID: 101, GID: 101})
114
+	err = MkdirAllAndChownNew(filepath.Join(dirName, "lib", "some", "other"), 0755, Identity{UID: 101, GID: 101})
115 115
 	assert.NilError(t, err)
116 116
 	testTree["lib/some"] = node{101, 101}
117 117
 	testTree["lib/some/other"] = node{101, 101}
... ...
@@ -120,7 +120,7 @@ func TestMkdirAllAndChownNew(t *testing.T) {
120 120
 	assert.NilError(t, compareTrees(testTree, verifyTree))
121 121
 
122 122
 	// test a directory that already exists; should NOT be chowned
123
-	err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 102, GID: 102})
123
+	err = MkdirAllAndChownNew(filepath.Join(dirName, "usr"), 0755, Identity{UID: 102, GID: 102})
124 124
 	assert.NilError(t, err)
125 125
 	verifyTree, err = readTree(dirName, "")
126 126
 	assert.NilError(t, err)
... ...
@@ -143,7 +143,7 @@ func TestMkdirAndChown(t *testing.T) {
143 143
 	}
144 144
 
145 145
 	// test a directory that already exists; should just chown to the requested uid/gid
146
-	if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, IDPair{UID: 99, GID: 99}); err != nil {
146
+	if err := MkdirAndChown(filepath.Join(dirName, "usr"), 0755, Identity{UID: 99, GID: 99}); err != nil {
147 147
 		t.Fatal(err)
148 148
 	}
149 149
 	testTree["usr"] = node{99, 99}
... ...
@@ -156,12 +156,12 @@ func TestMkdirAndChown(t *testing.T) {
156 156
 	}
157 157
 
158 158
 	// create a subdir under a dir which doesn't exist--should fail
159
-	if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, IDPair{UID: 102, GID: 102}); err == nil {
159
+	if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, Identity{UID: 102, GID: 102}); err == nil {
160 160
 		t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
161 161
 	}
162 162
 
163 163
 	// create a subdir under an existing dir; should only change the ownership of the new subdir
164
-	if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, IDPair{UID: 102, GID: 102}); err != nil {
164
+	if err := MkdirAndChown(filepath.Join(dirName, "usr", "bin"), 0755, Identity{UID: 102, GID: 102}); err != nil {
165 165
 		t.Fatal(err)
166 166
 	}
167 167
 	testTree["usr/bin"] = node{102, 102}
... ...
@@ -326,19 +326,19 @@ func TestNewIDMappings(t *testing.T) {
326 326
 	group, err := user.LookupGroupId(string(gids[0]))
327 327
 	assert.Check(t, err)
328 328
 
329
-	idMappings, err := NewIDMappings(tempUser.Username, group.Name)
329
+	idMapping, err := NewIdentityMapping(tempUser.Username, group.Name)
330 330
 	assert.Check(t, err)
331 331
 
332
-	rootUID, rootGID, err := GetRootUIDGID(idMappings.UIDs(), idMappings.GIDs())
332
+	rootUID, rootGID, err := GetRootUIDGID(idMapping.UIDs(), idMapping.GIDs())
333 333
 	assert.Check(t, err)
334 334
 
335 335
 	dirName, err := ioutil.TempDir("", "mkdirall")
336 336
 	assert.Check(t, err, "Couldn't create temp directory")
337 337
 	defer os.RemoveAll(dirName)
338 338
 
339
-	err = MkdirAllAndChown(dirName, 0700, IDPair{UID: rootUID, GID: rootGID})
339
+	err = MkdirAllAndChown(dirName, 0700, Identity{UID: rootUID, GID: rootGID})
340 340
 	assert.Check(t, err, "Couldn't change ownership of file path. Got error")
341
-	assert.Check(t, CanAccess(dirName, idMappings.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
341
+	assert.Check(t, CanAccess(dirName, idMapping.RootPair()), fmt.Sprintf("Unable to access %s directory with user UID:%d and GID:%d", dirName, rootUID, rootGID))
342 342
 }
343 343
 
344 344
 func TestLookupUserAndGroup(t *testing.T) {
... ...
@@ -388,7 +388,7 @@ func TestMkdirIsNotDir(t *testing.T) {
388 388
 	}
389 389
 	defer os.Remove(file.Name())
390 390
 
391
-	err = mkdirAs(file.Name(), 0755, 0, 0, false, false)
391
+	err = mkdirAs(file.Name(), 0755, Identity{UID: 0, GID: 0}, false, false)
392 392
 	assert.Check(t, is.Error(err, "mkdir "+file.Name()+": not a directory"))
393 393
 }
394 394
 
... ...
@@ -6,9 +6,11 @@ import (
6 6
 	"github.com/docker/docker/pkg/system"
7 7
 )
8 8
 
9
-// Platforms such as Windows do not support the UID/GID concept. So make this
10
-// just a wrapper around system.MkdirAll.
11
-func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chownExisting bool) error {
9
+// This is currently a wrapper around MkdirAll, however, since currently
10
+// permissions aren't set through this path, the identity isn't utilized.
11
+// Ownership is handled elsewhere, but in the future could be support here
12
+// too.
13
+func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
12 14
 	if err := system.MkdirAll(path, mode, ""); err != nil {
13 15
 		return err
14 16
 	}
... ...
@@ -18,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
18 18
 // CanAccess takes a valid (existing) directory and a uid, gid pair and determines
19 19
 // if that uid, gid pair has access (execute bit) to the directory
20 20
 // Windows does not require/support this function, so always return true
21
-func CanAccess(path string, pair IDPair) bool {
21
+func CanAccess(path string, identity Identity) bool {
22 22
 	return true
23 23
 }
... ...
@@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system"
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"syscall"
5 6
 	"unsafe"
6 7
 
7 8
 	"github.com/sirupsen/logrus"
8 9
 	"golang.org/x/sys/windows"
9 10
 )
10 11
 
12
+const (
13
+	OWNER_SECURITY_INFORMATION               = 0x00000001
14
+	GROUP_SECURITY_INFORMATION               = 0x00000002
15
+	DACL_SECURITY_INFORMATION                = 0x00000004
16
+	SACL_SECURITY_INFORMATION                = 0x00000008
17
+	LABEL_SECURITY_INFORMATION               = 0x00000010
18
+	ATTRIBUTE_SECURITY_INFORMATION           = 0x00000020
19
+	SCOPE_SECURITY_INFORMATION               = 0x00000040
20
+	PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
21
+	ACCESS_FILTER_SECURITY_INFORMATION       = 0x00000100
22
+	BACKUP_SECURITY_INFORMATION              = 0x00010000
23
+	PROTECTED_DACL_SECURITY_INFORMATION      = 0x80000000
24
+	PROTECTED_SACL_SECURITY_INFORMATION      = 0x40000000
25
+	UNPROTECTED_DACL_SECURITY_INFORMATION    = 0x20000000
26
+	UNPROTECTED_SACL_SECURITY_INFORMATION    = 0x10000000
27
+)
28
+
29
+const (
30
+	SE_UNKNOWN_OBJECT_TYPE = iota
31
+	SE_FILE_OBJECT
32
+	SE_SERVICE
33
+	SE_PRINTER
34
+	SE_REGISTRY_KEY
35
+	SE_LMSHARE
36
+	SE_KERNEL_OBJECT
37
+	SE_WINDOW_OBJECT
38
+	SE_DS_OBJECT
39
+	SE_DS_OBJECT_ALL
40
+	SE_PROVIDER_DEFINED_OBJECT
41
+	SE_WMIGUID_OBJECT
42
+	SE_REGISTRY_WOW64_32KEY
43
+)
44
+
45
+const (
46
+	SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege"
47
+)
48
+
49
+const (
50
+	ContainerAdministratorSidString = "S-1-5-93-2-1"
51
+	ContainerUserSidString          = "S-1-5-93-2-2"
52
+)
53
+
11 54
 var (
12
-	ntuserApiset       = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
13
-	procGetVersionExW  = modkernel32.NewProc("GetVersionExW")
14
-	procGetProductInfo = modkernel32.NewProc("GetProductInfo")
55
+	ntuserApiset                  = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0")
56
+	modadvapi32                   = windows.NewLazySystemDLL("advapi32.dll")
57
+	procGetVersionExW             = modkernel32.NewProc("GetVersionExW")
58
+	procGetProductInfo            = modkernel32.NewProc("GetProductInfo")
59
+	procSetNamedSecurityInfo      = modadvapi32.NewProc("SetNamedSecurityInfoW")
60
+	procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl")
15 61
 )
16 62
 
17 63
 // OSVersion is a wrapper for Windows version information
... ...
@@ -125,3 +171,23 @@ func HasWin32KSupport() bool {
125 125
 	// APIs.
126 126
 	return ntuserApiset.Load() == nil
127 127
 }
128
+
129
+func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) {
130
+	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)
131
+	if r0 != 0 {
132
+		result = syscall.Errno(r0)
133
+	}
134
+	return
135
+}
136
+
137
+func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) {
138
+	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)
139
+	if r1 == 0 {
140
+		if e1 != 0 {
141
+			result = syscall.Errno(e1)
142
+		} else {
143
+			result = syscall.EINVAL
144
+		}
145
+	}
146
+	return
147
+}
... ...
@@ -53,7 +53,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
53 53
 	}
54 54
 
55 55
 	rootFS := containerfs.NewLocalContainerFS(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName))
56
-	if err := initlayer.Setup(rootFS, idtools.IDPair{UID: 0, GID: 0}); err != nil {
56
+	if err := initlayer.Setup(rootFS, idtools.Identity{UID: 0, GID: 0}); err != nil {
57 57
 		return errors.WithStack(err)
58 58
 	}
59 59
 
... ...
@@ -46,18 +46,18 @@ type activeMount struct {
46 46
 // New instantiates a new Root instance with the provided scope. Scope
47 47
 // is the base path that the Root instance uses to store its
48 48
 // volumes. The base path is created here if it does not exist.
49
-func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
49
+func New(scope string, rootIdentity idtools.Identity) (*Root, error) {
50 50
 	rootDirectory := filepath.Join(scope, volumesPathName)
51 51
 
52
-	if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIDs); err != nil {
52
+	if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIdentity); err != nil {
53 53
 		return nil, err
54 54
 	}
55 55
 
56 56
 	r := &Root{
57
-		scope:   scope,
58
-		path:    rootDirectory,
59
-		volumes: make(map[string]*localVolume),
60
-		rootIDs: rootIDs,
57
+		scope:        scope,
58
+		path:         rootDirectory,
59
+		volumes:      make(map[string]*localVolume),
60
+		rootIdentity: rootIdentity,
61 61
 	}
62 62
 
63 63
 	dirs, err := ioutil.ReadDir(rootDirectory)
... ...
@@ -101,11 +101,11 @@ func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
101 101
 // manages the creation/removal of volumes. It uses only standard vfs
102 102
 // commands to create/remove dirs within its provided scope.
103 103
 type Root struct {
104
-	m       sync.Mutex
105
-	scope   string
106
-	path    string
107
-	volumes map[string]*localVolume
108
-	rootIDs idtools.IDPair
104
+	m            sync.Mutex
105
+	scope        string
106
+	path         string
107
+	volumes      map[string]*localVolume
108
+	rootIdentity idtools.Identity
109 109
 }
110 110
 
111 111
 // List lists all the volumes
... ...
@@ -146,7 +146,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
146 146
 	}
147 147
 
148 148
 	path := r.DataPath(name)
149
-	if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil {
149
+	if err := idtools.MkdirAllAndChown(path, 0755, r.rootIdentity); err != nil {
150 150
 		return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path)
151 151
 	}
152 152
 
... ...
@@ -38,7 +38,7 @@ func TestRemove(t *testing.T) {
38 38
 	}
39 39
 	defer os.RemoveAll(rootDir)
40 40
 
41
-	r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
41
+	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
42 42
 	if err != nil {
43 43
 		t.Fatal(err)
44 44
 	}
... ...
@@ -80,7 +80,7 @@ func TestInitializeWithVolumes(t *testing.T) {
80 80
 	}
81 81
 	defer os.RemoveAll(rootDir)
82 82
 
83
-	r, err := New(rootDir, idtools.IDPair{UID: os.Geteuid(), GID: os.Getegid()})
83
+	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
84 84
 	if err != nil {
85 85
 		t.Fatal(err)
86 86
 	}
... ...
@@ -90,7 +90,7 @@ func TestInitializeWithVolumes(t *testing.T) {
90 90
 		t.Fatal(err)
91 91
 	}
92 92
 
93
-	r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
93
+	r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
94 94
 	if err != nil {
95 95
 		t.Fatal(err)
96 96
 	}
... ...
@@ -112,7 +112,7 @@ func TestCreate(t *testing.T) {
112 112
 	}
113 113
 	defer os.RemoveAll(rootDir)
114 114
 
115
-	r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
115
+	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
116 116
 	if err != nil {
117 117
 		t.Fatal(err)
118 118
 	}
... ...
@@ -149,7 +149,7 @@ func TestCreate(t *testing.T) {
149 149
 		}
150 150
 	}
151 151
 
152
-	r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
152
+	r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
153 153
 	if err != nil {
154 154
 		t.Fatal(err)
155 155
 	}
... ...
@@ -186,7 +186,7 @@ func TestCreateWithOpts(t *testing.T) {
186 186
 	}
187 187
 	defer os.RemoveAll(rootDir)
188 188
 
189
-	r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
189
+	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
190 190
 	if err != nil {
191 191
 		t.Fatal(err)
192 192
 	}
... ...
@@ -261,7 +261,7 @@ func TestCreateWithOpts(t *testing.T) {
261 261
 		t.Fatal("expected mount to still be active")
262 262
 	}
263 263
 
264
-	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
264
+	r, err = New(rootDir, idtools.Identity{UID: 0, GID: 0})
265 265
 	if err != nil {
266 266
 		t.Fatal(err)
267 267
 	}
... ...
@@ -283,7 +283,7 @@ func TestRelaodNoOpts(t *testing.T) {
283 283
 	}
284 284
 	defer os.RemoveAll(rootDir)
285 285
 
286
-	r, err := New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
286
+	r, err := New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
287 287
 	if err != nil {
288 288
 		t.Fatal(err)
289 289
 	}
... ...
@@ -311,7 +311,7 @@ func TestRelaodNoOpts(t *testing.T) {
311 311
 		t.Fatal(err)
312 312
 	}
313 313
 
314
-	r, err = New(rootDir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
314
+	r, err = New(rootDir, idtools.Identity{UID: os.Geteuid(), GID: os.Getegid()})
315 315
 	if err != nil {
316 316
 		t.Fatal(err)
317 317
 	}
... ...
@@ -95,7 +95,7 @@ func (m *MountPoint) Cleanup() error {
95 95
 // configured, or creating the source directory if supplied.
96 96
 // The, optional, checkFun parameter allows doing additional checking
97 97
 // before creating the source directory on the host.
98
-func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) {
98
+func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.Identity, checkFun func(m *MountPoint) error) (path string, err error) {
99 99
 	if m.SkipMountpointCreation {
100 100
 		return m.Source, nil
101 101
 	}
... ...
@@ -9,7 +9,7 @@ import (
9 9
 	"github.com/pkg/errors"
10 10
 )
11 11
 
12
-func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.IDPair) error {
12
+func setupDefaultDriver(store *drivers.Store, root string, rootIDs idtools.Identity) error {
13 13
 	d, err := local.New(root, rootIDs)
14 14
 	if err != nil {
15 15
 		return errors.Wrap(err, "error setting up default driver")
... ...
@@ -7,4 +7,4 @@ import (
7 7
 	"github.com/docker/docker/volume/drivers"
8 8
 )
9 9
 
10
-func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.IDPair) error { return nil }
10
+func setupDefaultDriver(_ *drivers.Store, _ string, _ idtools.Identity) error { return nil }
... ...
@@ -35,7 +35,7 @@ type VolumesService struct {
35 35
 }
36 36
 
37 37
 // NewVolumeService creates a new volume service
38
-func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.IDPair, logger volumeEventLogger) (*VolumesService, error) {
38
+func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger volumeEventLogger) (*VolumesService, error) {
39 39
 	ds := drivers.NewStore(pg)
40 40
 	if err := setupDefaultDriver(ds, root, rootIDs); err != nil {
41 41
 		return nil, err
... ...
@@ -25,7 +25,7 @@ func TestLocalVolumeSize(t *testing.T) {
25 25
 	assert.Assert(t, err)
26 26
 	defer os.RemoveAll(dir)
27 27
 
28
-	l, err := local.New(dir, idtools.IDPair{UID: os.Getuid(), GID: os.Getegid()})
28
+	l, err := local.New(dir, idtools.Identity{UID: os.Getuid(), GID: os.Getegid()})
29 29
 	assert.Assert(t, err)
30 30
 	assert.Assert(t, ds.Register(l, volume.DefaultDriverName))
31 31
 	assert.Assert(t, ds.Register(testutils.NewFakeDriver("fake"), "fake"))