Browse code

Partial refactor of UID/GID usage to use a unified struct.

Signed-off-by: Daniel Nephin <dnephin@docker.com>

Daniel Nephin authored on 2017/05/20 07:06:46
Showing 28 changed files
... ...
@@ -216,7 +216,7 @@ func (container *Container) WriteHostConfig() error {
216 216
 }
217 217
 
218 218
 // SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir
219
-func (container *Container) SetupWorkingDirectory(rootUID, rootGID int) error {
219
+func (container *Container) SetupWorkingDirectory(rootIDs idtools.IDPair) error {
220 220
 	if container.Config.WorkingDir == "" {
221 221
 		return nil
222 222
 	}
... ...
@@ -228,7 +228,7 @@ func (container *Container) SetupWorkingDirectory(rootUID, rootGID int) error {
228 228
 		return err
229 229
 	}
230 230
 
231
-	if err := idtools.MkdirAllNewAs(pth, 0755, rootUID, rootGID); err != nil {
231
+	if err := idtools.MkdirAllAndChownNew(pth, 0755, rootIDs); err != nil {
232 232
 		pthInfo, err2 := os.Stat(pth)
233 233
 		if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
234 234
 			return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
... ...
@@ -375,7 +375,7 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp
375 375
 
376 376
 	destExists := true
377 377
 	destDir := false
378
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
378
+	rootIDs, _ := daemon.idMappings.RootPair()
379 379
 
380 380
 	// Work in daemon-local OS specific file paths
381 381
 	destPath = filepath.FromSlash(destPath)
... ...
@@ -413,11 +413,10 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp
413 413
 		destExists = false
414 414
 	}
415 415
 
416
-	uidMaps, gidMaps := daemon.GetUIDGIDMaps()
417 416
 	archiver := &archive.Archiver{
418 417
 		Untar:   chrootarchive.Untar,
419
-		UIDMaps: uidMaps,
420
-		GIDMaps: gidMaps,
418
+		UIDMaps: daemon.idMappings.UIDs(),
419
+		GIDMaps: daemon.idMappings.GIDs(),
421 420
 	}
422 421
 
423 422
 	src, err := os.Stat(fullSrcPath)
... ...
@@ -430,7 +429,7 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp
430 430
 		if err := archiver.CopyWithTar(fullSrcPath, destPath); err != nil {
431 431
 			return err
432 432
 		}
433
-		return fixPermissions(fullSrcPath, destPath, rootUID, rootGID, destExists)
433
+		return fixPermissions(fullSrcPath, destPath, rootIDs.UID, rootIDs.GID, destExists)
434 434
 	}
435 435
 	if decompress && archive.IsArchivePath(fullSrcPath) {
436 436
 		// Only try to untar if it is a file and that we've been told to decompress (when ADD-ing a remote file)
... ...
@@ -459,12 +458,12 @@ func (daemon *Daemon) CopyOnBuild(cID, destPath, srcRoot, srcPath string, decomp
459 459
 		destPath = filepath.Join(destPath, filepath.Base(srcPath))
460 460
 	}
461 461
 
462
-	if err := idtools.MkdirAllNewAs(filepath.Dir(destPath), 0755, rootUID, rootGID); err != nil {
462
+	if err := idtools.MkdirAllAndChownNew(filepath.Dir(destPath), 0755, rootIDs); err != nil {
463 463
 		return err
464 464
 	}
465 465
 	if err := archiver.CopyFileWithTar(fullSrcPath, destPath); err != nil {
466 466
 		return err
467 467
 	}
468 468
 
469
-	return fixPermissions(fullSrcPath, destPath, rootUID, rootGID, destExists)
469
+	return fixPermissions(fullSrcPath, destPath, rootIDs.UID, rootIDs.GID, destExists)
470 470
 }
... ...
@@ -7,10 +7,9 @@ import (
7 7
 // defaultTarCopyOptions is the setting that is used when unpacking an archive
8 8
 // for a copy API event.
9 9
 func (daemon *Daemon) defaultTarCopyOptions(noOverwriteDirNonDir bool) *archive.TarOptions {
10
-	uidMaps, gidMaps := daemon.GetUIDGIDMaps()
11 10
 	return &archive.TarOptions{
12 11
 		NoOverwriteDirNonDir: noOverwriteDirNonDir,
13
-		UIDMaps:              uidMaps,
14
-		GIDMaps:              gidMaps,
12
+		UIDMaps:              daemon.idMappings.UIDs(),
13
+		GIDMaps:              daemon.idMappings.GIDs(),
15 14
 	}
16 15
 }
... ...
@@ -109,14 +109,14 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
109 109
 		}
110 110
 		c.ShmPath = "/dev/shm"
111 111
 	} else {
112
-		rootUID, rootGID := daemon.GetRemappedUIDGID()
112
+		rootIDs, _ := daemon.idMappings.RootPair()
113 113
 		if !c.HasMountFor("/dev/shm") {
114 114
 			shmPath, err := c.ShmResourcePath()
115 115
 			if err != nil {
116 116
 				return err
117 117
 			}
118 118
 
119
-			if err := idtools.MkdirAllAs(shmPath, 0700, rootUID, rootGID); err != nil {
119
+			if err := idtools.MkdirAllAndChown(shmPath, 0700, rootIDs); err != nil {
120 120
 				return err
121 121
 			}
122 122
 
... ...
@@ -128,7 +128,7 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
128 128
 			if err := syscall.Mount("shm", shmPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel(shmproperty, c.GetMountLabel())); err != nil {
129 129
 				return fmt.Errorf("mounting shm tmpfs: %s", err)
130 130
 			}
131
-			if err := os.Chown(shmPath, rootUID, rootGID); err != nil {
131
+			if err := os.Chown(shmPath, rootIDs.UID, rootIDs.GID); err != nil {
132 132
 				return err
133 133
 			}
134 134
 		}
... ...
@@ -147,9 +147,9 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
147 147
 	logrus.Debugf("secrets: setting up secret dir: %s", localMountPath)
148 148
 
149 149
 	// retrieve possible remapped range start for root UID, GID
150
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
150
+	rootIDs, _ := daemon.idMappings.RootPair()
151 151
 	// create tmpfs
152
-	if err := idtools.MkdirAllAs(localMountPath, 0700, rootUID, rootGID); err != nil {
152
+	if err := idtools.MkdirAllAndChown(localMountPath, 0700, rootIDs); err != nil {
153 153
 		return errors.Wrap(err, "error creating secret local mount path")
154 154
 	}
155 155
 
... ...
@@ -164,7 +164,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
164 164
 		}
165 165
 	}()
166 166
 
167
-	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootUID, rootGID)
167
+	tmpfsOwnership := fmt.Sprintf("uid=%d,gid=%d", rootIDs.UID, rootIDs.GID)
168 168
 	if err := mount.Mount("tmpfs", localMountPath, "tmpfs", "nodev,nosuid,noexec,"+tmpfsOwnership); err != nil {
169 169
 		return errors.Wrap(err, "unable to setup secret mount")
170 170
 	}
... ...
@@ -183,7 +183,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
183 183
 		// secrets are created in the SecretMountPath on the host, at a
184 184
 		// single level
185 185
 		fPath := c.SecretFilePath(*s)
186
-		if err := idtools.MkdirAllAs(filepath.Dir(fPath), 0700, rootUID, rootGID); err != nil {
186
+		if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
187 187
 			return errors.Wrap(err, "error creating secret mount path")
188 188
 		}
189 189
 
... ...
@@ -208,7 +208,7 @@ func (daemon *Daemon) setupSecretDir(c *container.Container) (setupErr error) {
208 208
 			return err
209 209
 		}
210 210
 
211
-		if err := os.Chown(fPath, rootUID+uid, rootGID+gid); err != nil {
211
+		if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
212 212
 			return errors.Wrap(err, "error setting ownership for secret")
213 213
 		}
214 214
 	}
... ...
@@ -232,9 +232,9 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
232 232
 	logrus.Debugf("configs: setting up config dir: %s", localPath)
233 233
 
234 234
 	// retrieve possible remapped range start for root UID, GID
235
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
235
+	rootIDs, _ := daemon.idMappings.RootPair()
236 236
 	// create tmpfs
237
-	if err := idtools.MkdirAllAs(localPath, 0700, rootUID, rootGID); err != nil {
237
+	if err := idtools.MkdirAllAndChown(localPath, 0700, rootIDs); err != nil {
238 238
 		return errors.Wrap(err, "error creating config dir")
239 239
 	}
240 240
 
... ...
@@ -261,7 +261,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
261 261
 
262 262
 		log := logrus.WithFields(logrus.Fields{"name": configRef.File.Name, "path": fPath})
263 263
 
264
-		if err := idtools.MkdirAllAs(filepath.Dir(fPath), 0700, rootUID, rootGID); err != nil {
264
+		if err := idtools.MkdirAllAndChown(filepath.Dir(fPath), 0700, rootIDs); err != nil {
265 265
 			return errors.Wrap(err, "error creating config path")
266 266
 		}
267 267
 
... ...
@@ -283,7 +283,7 @@ func (daemon *Daemon) setupConfigDir(c *container.Container) (setupErr error) {
283 283
 			return err
284 284
 		}
285 285
 
286
-		if err := os.Chown(fPath, rootUID+uid, rootGID+gid); err != nil {
286
+		if err := os.Chown(fPath, rootIDs.UID+uid, rootIDs.GID+gid); err != nil {
287 287
 			return errors.Wrap(err, "error setting ownership for config")
288 288
 		}
289 289
 	}
... ...
@@ -117,14 +117,14 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
117 117
 		return nil, err
118 118
 	}
119 119
 
120
-	rootUID, rootGID, err := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps)
120
+	rootIDs, err := daemon.idMappings.RootPair()
121 121
 	if err != nil {
122 122
 		return nil, err
123 123
 	}
124
-	if err := idtools.MkdirAs(container.Root, 0700, rootUID, rootGID); err != nil {
124
+	if err := idtools.MkdirAndChown(container.Root, 0700, rootIDs); err != nil {
125 125
 		return nil, err
126 126
 	}
127
-	if err := idtools.MkdirAs(container.CheckpointDir(), 0700, rootUID, rootGID); err != nil {
127
+	if err := idtools.MkdirAndChown(container.CheckpointDir(), 0700, rootIDs); err != nil {
128 128
 		return nil, err
129 129
 	}
130 130
 
... ...
@@ -22,8 +22,8 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
22 22
 	}
23 23
 	defer daemon.Unmount(container)
24 24
 
25
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
26
-	if err := container.SetupWorkingDirectory(rootUID, rootGID); err != nil {
25
+	rootIDs, _ := daemon.idMappings.RootPair()
26
+	if err := container.SetupWorkingDirectory(rootIDs); err != nil {
27 27
 		return err
28 28
 	}
29 29
 
... ...
@@ -94,8 +94,7 @@ type Daemon struct {
94 94
 	seccompEnabled            bool
95 95
 	apparmorEnabled           bool
96 96
 	shutdown                  bool
97
-	uidMaps                   []idtools.IDMap
98
-	gidMaps                   []idtools.IDMap
97
+	idMappings                *idtools.IDMappings
99 98
 	layerStore                layer.Store
100 99
 	imageStore                image.Store
101 100
 	PluginStore               *plugin.Store // todo: remove
... ...
@@ -524,11 +523,11 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
524 524
 		return nil, err
525 525
 	}
526 526
 
527
-	uidMaps, gidMaps, err := setupRemappedRoot(config)
527
+	idMappings, err := setupRemappedRoot(config)
528 528
 	if err != nil {
529 529
 		return nil, err
530 530
 	}
531
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
531
+	rootIDs, err := idMappings.RootPair()
532 532
 	if err != nil {
533 533
 		return nil, err
534 534
 	}
... ...
@@ -538,7 +537,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
538 538
 	}
539 539
 
540 540
 	// set up the tmpDir to use a canonical path
541
-	tmp, err := prepareTempDir(config.Root, rootUID, rootGID)
541
+	tmp, err := prepareTempDir(config.Root, rootIDs)
542 542
 	if err != nil {
543 543
 		return nil, fmt.Errorf("Unable to get the TempDir under %s: %s", config.Root, err)
544 544
 	}
... ...
@@ -587,7 +586,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
587 587
 	}
588 588
 
589 589
 	daemonRepo := filepath.Join(config.Root, "containers")
590
-	if err := idtools.MkdirAllAs(daemonRepo, 0700, rootUID, rootGID); err != nil && !os.IsExist(err) {
590
+	if err := idtools.MkdirAllAndChown(daemonRepo, 0700, rootIDs); err != nil && !os.IsExist(err) {
591 591
 		return nil, err
592 592
 	}
593 593
 
... ...
@@ -632,8 +631,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
632 632
 		MetadataStorePathTemplate: filepath.Join(config.Root, "image", "%s", "layerdb"),
633 633
 		GraphDriver:               driverName,
634 634
 		GraphDriverOptions:        config.GraphOptions,
635
-		UIDMaps:                   uidMaps,
636
-		GIDMaps:                   gidMaps,
635
+		IDMappings:                idMappings,
637 636
 		PluginGetter:              d.PluginStore,
638 637
 		ExperimentalEnabled:       config.Experimental,
639 638
 	})
... ...
@@ -665,7 +663,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
665 665
 	}
666 666
 
667 667
 	// Configure the volumes driver
668
-	volStore, err := d.configureVolumes(rootUID, rootGID)
668
+	volStore, err := d.configureVolumes(rootIDs)
669 669
 	if err != nil {
670 670
 		return nil, err
671 671
 	}
... ...
@@ -728,8 +726,7 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
728 728
 	d.EventsService = eventsService
729 729
 	d.volumes = volStore
730 730
 	d.root = config.Root
731
-	d.uidMaps = uidMaps
732
-	d.gidMaps = gidMaps
731
+	d.idMappings = idMappings
733 732
 	d.seccompEnabled = sysInfo.Seccomp
734 733
 	d.apparmorEnabled = sysInfo.AppArmor
735 734
 
... ...
@@ -970,25 +967,10 @@ func (daemon *Daemon) GraphDriverName() string {
970 970
 	return daemon.layerStore.DriverName()
971 971
 }
972 972
 
973
-// GetUIDGIDMaps returns the current daemon's user namespace settings
974
-// for the full uid and gid maps which will be applied to containers
975
-// started in this instance.
976
-func (daemon *Daemon) GetUIDGIDMaps() ([]idtools.IDMap, []idtools.IDMap) {
977
-	return daemon.uidMaps, daemon.gidMaps
978
-}
979
-
980
-// GetRemappedUIDGID returns the current daemon's uid and gid values
981
-// if user namespaces are in use for this daemon instance.  If not
982
-// this function will return "real" root values of 0, 0.
983
-func (daemon *Daemon) GetRemappedUIDGID() (int, int) {
984
-	uid, gid, _ := idtools.GetRootUIDGID(daemon.uidMaps, daemon.gidMaps)
985
-	return uid, gid
986
-}
987
-
988 973
 // prepareTempDir prepares and returns the default directory to use
989 974
 // for temporary files.
990 975
 // If it doesn't exist, it is created. If it exists, its content is removed.
991
-func prepareTempDir(rootDir string, rootUID, rootGID int) (string, error) {
976
+func prepareTempDir(rootDir string, rootIDs idtools.IDPair) (string, error) {
992 977
 	var tmpDir string
993 978
 	if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
994 979
 		tmpDir = filepath.Join(rootDir, "tmp")
... ...
@@ -1008,12 +990,12 @@ func prepareTempDir(rootDir string, rootUID, rootGID int) (string, error) {
1008 1008
 	}
1009 1009
 	// We don't remove the content of tmpdir if it's not the default,
1010 1010
 	// it may hold things that do not belong to us.
1011
-	return tmpDir, idtools.MkdirAllAs(tmpDir, 0700, rootUID, rootGID)
1011
+	return tmpDir, idtools.MkdirAllAndChown(tmpDir, 0700, rootIDs)
1012 1012
 }
1013 1013
 
1014 1014
 func (daemon *Daemon) setupInitLayer(initPath string) error {
1015
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
1016
-	return initlayer.Setup(initPath, rootUID, rootGID)
1015
+	rootIDs, _ := daemon.idMappings.RootPair()
1016
+	return initlayer.Setup(initPath, rootIDs)
1017 1017
 }
1018 1018
 
1019 1019
 func setDefaultMtu(conf *config.Config) {
... ...
@@ -1024,8 +1006,8 @@ func setDefaultMtu(conf *config.Config) {
1024 1024
 	conf.Mtu = config.DefaultNetworkMtu
1025 1025
 }
1026 1026
 
1027
-func (daemon *Daemon) configureVolumes(rootUID, rootGID int) (*store.VolumeStore, error) {
1028
-	volumesDriver, err := local.New(daemon.configStore.Root, rootUID, rootGID)
1027
+func (daemon *Daemon) configureVolumes(rootIDs idtools.IDPair) (*store.VolumeStore, error) {
1028
+	volumesDriver, err := local.New(daemon.configStore.Root, rootIDs)
1029 1029
 	if err != nil {
1030 1030
 		return nil, err
1031 1031
 	}
... ...
@@ -1171,16 +1153,16 @@ func CreateDaemonRoot(config *config.Config) error {
1171 1171
 		}
1172 1172
 	}
1173 1173
 
1174
-	uidMaps, gidMaps, err := setupRemappedRoot(config)
1174
+	idMappings, err := setupRemappedRoot(config)
1175 1175
 	if err != nil {
1176 1176
 		return err
1177 1177
 	}
1178
-	rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps)
1178
+	rootIDs, err := idMappings.RootPair()
1179 1179
 	if err != nil {
1180 1180
 		return err
1181 1181
 	}
1182 1182
 
1183
-	if err := setupDaemonRoot(config, realRoot, rootUID, rootGID); err != nil {
1183
+	if err := setupDaemonRoot(config, realRoot, rootIDs); err != nil {
1184 1184
 		return err
1185 1185
 	}
1186 1186
 
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	containertypes "github.com/docker/docker/api/types/container"
12 12
 	"github.com/docker/docker/container"
13 13
 	_ "github.com/docker/docker/pkg/discovery/memory"
14
+	"github.com/docker/docker/pkg/idtools"
14 15
 	"github.com/docker/docker/pkg/registrar"
15 16
 	"github.com/docker/docker/pkg/truncindex"
16 17
 	"github.com/docker/docker/volume"
... ...
@@ -127,7 +128,7 @@ func initDaemonWithVolumeStore(tmp string) (*Daemon, error) {
127 127
 		return nil, err
128 128
 	}
129 129
 
130
-	volumesDriver, err := local.New(tmp, 0, 0)
130
+	volumesDriver, err := local.New(tmp, idtools.IDPair{UID: 0, GID: 0})
131 131
 	if err != nil {
132 132
 		return nil, err
133 133
 	}
... ...
@@ -1026,40 +1026,38 @@ func parseRemappedRoot(usergrp string) (string, string, error) {
1026 1026
 	return username, groupname, nil
1027 1027
 }
1028 1028
 
1029
-func setupRemappedRoot(config *config.Config) ([]idtools.IDMap, []idtools.IDMap, error) {
1029
+func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
1030 1030
 	if runtime.GOOS != "linux" && config.RemappedRoot != "" {
1031
-		return nil, nil, fmt.Errorf("User namespaces are only supported on Linux")
1031
+		return nil, fmt.Errorf("User namespaces are only supported on Linux")
1032 1032
 	}
1033 1033
 
1034 1034
 	// if the daemon was started with remapped root option, parse
1035 1035
 	// the config option to the int uid,gid values
1036
-	var (
1037
-		uidMaps, gidMaps []idtools.IDMap
1038
-	)
1039 1036
 	if config.RemappedRoot != "" {
1040 1037
 		username, groupname, err := parseRemappedRoot(config.RemappedRoot)
1041 1038
 		if err != nil {
1042
-			return nil, nil, err
1039
+			return nil, err
1043 1040
 		}
1044 1041
 		if username == "root" {
1045 1042
 			// Cannot setup user namespaces with a 1-to-1 mapping; "--root=0:0" is a no-op
1046 1043
 			// effectively
1047 1044
 			logrus.Warn("User namespaces: root cannot be remapped with itself; user namespaces are OFF")
1048
-			return uidMaps, gidMaps, nil
1045
+			return &idtools.IDMappings{}, nil
1049 1046
 		}
1050 1047
 		logrus.Infof("User namespaces: ID ranges will be mapped to subuid/subgid ranges of: %s:%s", username, groupname)
1051 1048
 		// update remapped root setting now that we have resolved them to actual names
1052 1049
 		config.RemappedRoot = fmt.Sprintf("%s:%s", username, groupname)
1053 1050
 
1054
-		uidMaps, gidMaps, err = idtools.CreateIDMappings(username, groupname)
1051
+		mappings, err := idtools.NewIDMappings(username, groupname)
1055 1052
 		if err != nil {
1056
-			return nil, nil, fmt.Errorf("Can't create ID mappings: %v", err)
1053
+			return nil, errors.Wrapf(err, "Can't create ID mappings: %v")
1057 1054
 		}
1055
+		return mappings, nil
1058 1056
 	}
1059
-	return uidMaps, gidMaps, nil
1057
+	return &idtools.IDMappings{}, nil
1060 1058
 }
1061 1059
 
1062
-func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int) error {
1060
+func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
1063 1061
 	config.Root = rootDir
1064 1062
 	// the docker root metadata directory needs to have execute permissions for all users (g+x,o+x)
1065 1063
 	// so that syscalls executing as non-root, operating on subdirectories of the graph root
... ...
@@ -1084,10 +1082,10 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int
1084 1084
 	// a new subdirectory with ownership set to the remapped uid/gid (so as to allow
1085 1085
 	// `chdir()` to work for containers namespaced to that uid/gid)
1086 1086
 	if config.RemappedRoot != "" {
1087
-		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootUID, rootGID))
1087
+		config.Root = filepath.Join(rootDir, fmt.Sprintf("%d.%d", rootIDs.UID, rootIDs.GID))
1088 1088
 		logrus.Debugf("Creating user namespaced daemon root: %s", config.Root)
1089 1089
 		// Create the root directory if it doesn't exist
1090
-		if err := idtools.MkdirAllAs(config.Root, 0700, rootUID, rootGID); err != nil {
1090
+		if err := idtools.MkdirAllAndChown(config.Root, 0700, rootIDs); err != nil {
1091 1091
 			return fmt.Errorf("Cannot create daemon root: %s: %v", config.Root, err)
1092 1092
 		}
1093 1093
 		// we also need to verify that any pre-existing directories in the path to
... ...
@@ -1100,7 +1098,7 @@ func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int
1100 1100
 			if dirPath == "/" {
1101 1101
 				break
1102 1102
 			}
1103
-			if !idtools.CanAccess(dirPath, rootUID, rootGID) {
1103
+			if !idtools.CanAccess(dirPath, rootIDs) {
1104 1104
 				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)
1105 1105
 			}
1106 1106
 		}
... ...
@@ -11,6 +11,7 @@ import (
11 11
 	containertypes "github.com/docker/docker/api/types/container"
12 12
 	"github.com/docker/docker/container"
13 13
 	"github.com/docker/docker/daemon/config"
14
+	"github.com/docker/docker/pkg/idtools"
14 15
 	"github.com/docker/docker/volume"
15 16
 	"github.com/docker/docker/volume/drivers"
16 17
 	"github.com/docker/docker/volume/local"
... ...
@@ -277,7 +278,7 @@ func TestMigratePre17Volumes(t *testing.T) {
277 277
 	if err != nil {
278 278
 		t.Fatal(err)
279 279
 	}
280
-	drv, err := local.New(volumeRoot, 0, 0)
280
+	drv, err := local.New(volumeRoot, idtools.IDPair{UID: 0, GID: 0})
281 281
 	if err != nil {
282 282
 		t.Fatal(err)
283 283
 	}
... ...
@@ -454,11 +454,11 @@ func (daemon *Daemon) cleanupMounts() error {
454 454
 	return nil
455 455
 }
456 456
 
457
-func setupRemappedRoot(config *config.Config) ([]idtools.IDMap, []idtools.IDMap, error) {
458
-	return nil, nil, nil
457
+func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
458
+	return &idtools.IDMappings{}, nil
459 459
 }
460 460
 
461
-func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int) error {
461
+func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
462 462
 	config.Root = rootDir
463 463
 	// Create the root directory if it doesn't exists
464 464
 	if err := system.MkdirAllWithACL(config.Root, 0); err != nil && !os.IsExist(err) {
... ...
@@ -40,11 +40,10 @@ func (daemon *Daemon) containerExport(container *container.Container) (io.ReadCl
40 40
 		return nil, err
41 41
 	}
42 42
 
43
-	uidMaps, gidMaps := daemon.GetUIDGIDMaps()
44 43
 	archive, err := archive.TarWithOptions(container.BaseFS, &archive.TarOptions{
45 44
 		Compression: archive.Uncompressed,
46
-		UIDMaps:     uidMaps,
47
-		GIDMaps:     gidMaps,
45
+		UIDMaps:     daemon.idMappings.UIDs(),
46
+		GIDMaps:     daemon.idMappings.GIDs(),
48 47
 	})
49 48
 	if err != nil {
50 49
 		daemon.Unmount(container)
... ...
@@ -72,8 +72,8 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
72 72
 	if selinuxEnabled() {
73 73
 		securityOptions = append(securityOptions, "name=selinux")
74 74
 	}
75
-	uid, gid := daemon.GetRemappedUIDGID()
76
-	if uid != 0 || gid != 0 {
75
+	rootIDs, _ := daemon.idMappings.RootPair()
76
+	if rootIDs.UID != 0 || rootIDs.GID != 0 {
77 77
 		securityOptions = append(securityOptions, "name=userns")
78 78
 	}
79 79
 
... ...
@@ -16,7 +16,7 @@ import (
16 16
 //
17 17
 // This extra layer is used by all containers as the top-most ro layer. It protects
18 18
 // the container from unwanted side-effects on the rw layer.
19
-func Setup(initLayer string, rootUID, rootGID int) error {
19
+func Setup(initLayer string, rootIDs idtools.IDPair) error {
20 20
 	for pth, typ := range map[string]string{
21 21
 		"/dev/pts":         "dir",
22 22
 		"/dev/shm":         "dir",
... ...
@@ -38,12 +38,12 @@ func Setup(initLayer string, rootUID, rootGID int) error {
38 38
 
39 39
 		if _, err := os.Stat(filepath.Join(initLayer, pth)); err != nil {
40 40
 			if os.IsNotExist(err) {
41
-				if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootUID, rootGID); err != nil {
41
+				if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, filepath.Dir(pth)), 0755, rootIDs); err != nil {
42 42
 					return err
43 43
 				}
44 44
 				switch typ {
45 45
 				case "dir":
46
-					if err := idtools.MkdirAllNewAs(filepath.Join(initLayer, pth), 0755, rootUID, rootGID); err != nil {
46
+					if err := idtools.MkdirAllAndChownNew(filepath.Join(initLayer, pth), 0755, rootIDs); err != nil {
47 47
 						return err
48 48
 					}
49 49
 				case "file":
... ...
@@ -51,7 +51,7 @@ func Setup(initLayer string, rootUID, rootGID int) error {
51 51
 					if err != nil {
52 52
 						return err
53 53
 					}
54
-					f.Chown(rootUID, rootGID)
54
+					f.Chown(rootIDs.UID, rootIDs.GID)
55 55
 					f.Close()
56 56
 				default:
57 57
 					if err := os.Symlink(typ, filepath.Join(initLayer, pth)); err != nil {
... ...
@@ -2,12 +2,16 @@
2 2
 
3 3
 package initlayer
4 4
 
5
+import (
6
+	"github.com/docker/docker/pkg/idtools"
7
+)
8
+
5 9
 // Setup populates a directory with mountpoints suitable
6 10
 // for bind-mounting dockerinit into the container. The mountpoint is simply an
7 11
 // empty file at /.dockerinit
8 12
 //
9 13
 // This extra layer is used by all containers as the top-most ro layer. It protects
10 14
 // the container from unwanted side-effects on the rw layer.
11
-func Setup(initLayer string, rootUID, rootGID int) error {
15
+func Setup(initLayer string, rootIDs idtools.IDPair) error {
12 16
 	return nil
13 17
 }
... ...
@@ -271,13 +271,13 @@ func setNamespaces(daemon *Daemon, s *specs.Spec, c *container.Container) error
271 271
 	userNS := false
272 272
 	// user
273 273
 	if c.HostConfig.UsernsMode.IsPrivate() {
274
-		uidMap, gidMap := daemon.GetUIDGIDMaps()
274
+		uidMap := daemon.idMappings.UIDs()
275 275
 		if uidMap != nil {
276 276
 			userNS = true
277 277
 			ns := specs.LinuxNamespace{Type: "user"}
278 278
 			setNamespace(s, ns)
279 279
 			s.Linux.UIDMappings = specMapping(uidMap)
280
-			s.Linux.GIDMappings = specMapping(gidMap)
280
+			s.Linux.GIDMappings = specMapping(daemon.idMappings.GIDs())
281 281
 		}
282 282
 	}
283 283
 	// network
... ...
@@ -591,7 +591,7 @@ func setMounts(daemon *Daemon, s *specs.Spec, c *container.Container, mounts []c
591 591
 
592 592
 	// TODO: until a kernel/mount solution exists for handling remount in a user namespace,
593 593
 	// we must clear the readonly flag for the cgroups mount (@mrunalp concurs)
594
-	if uidMap, _ := daemon.GetUIDGIDMaps(); uidMap != nil || c.HostConfig.Privileged {
594
+	if uidMap := daemon.idMappings.UIDs(); uidMap != nil || c.HostConfig.Privileged {
595 595
 		for i, m := range s.Mounts {
596 596
 			if m.Type == "cgroup" {
597 597
 				clearReadOnly(&s.Mounts[i])
... ...
@@ -611,8 +611,8 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
611 611
 		Path:     c.BaseFS,
612 612
 		Readonly: c.HostConfig.ReadonlyRootfs,
613 613
 	}
614
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
615
-	if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil {
614
+	rootIDs, _ := daemon.idMappings.RootPair()
615
+	if err := c.SetupWorkingDirectory(rootIDs); err != nil {
616 616
 		return err
617 617
 	}
618 618
 	cwd := c.Config.WorkingDir
... ...
@@ -130,8 +130,8 @@ func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container)
130 130
 		Path:     filepath.Dir(c.BaseFS),
131 131
 		Readonly: c.HostConfig.ReadonlyRootfs,
132 132
 	}
133
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
134
-	if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil {
133
+	rootIDs, _ := daemon.idMappings.RootPair()
134
+	if err := c.SetupWorkingDirectory(rootIDs); err != nil {
135 135
 		return err
136 136
 	}
137 137
 	cwd := c.Config.WorkingDir
... ...
@@ -54,8 +54,8 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
54 54
 			return nil
55 55
 		}
56 56
 
57
-		rootUID, rootGID := daemon.GetRemappedUIDGID()
58
-		path, err := m.Setup(c.MountLabel, rootUID, rootGID, checkfunc)
57
+		rootIDs, _ := daemon.idMappings.RootPair()
58
+		path, err := m.Setup(c.MountLabel, rootIDs, checkfunc)
59 59
 		if err != nil {
60 60
 			return nil, err
61 61
 		}
... ...
@@ -85,9 +85,9 @@ func (daemon *Daemon) setupMounts(c *container.Container) ([]container.Mount, er
85 85
 	// if we are going to mount any of the network files from container
86 86
 	// metadata, the ownership must be set properly for potential container
87 87
 	// remapped root (user namespaces)
88
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
88
+	rootIDs, _ := daemon.idMappings.RootPair()
89 89
 	for _, mount := range netMounts {
90
-		if err := os.Chown(mount.Source, rootUID, rootGID); err != nil {
90
+		if err := os.Chown(mount.Source, rootIDs.UID, rootIDs.GID); err != nil {
91 91
 			return nil, err
92 92
 		}
93 93
 	}
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"sort"
7 7
 
8 8
 	"github.com/docker/docker/container"
9
+	"github.com/docker/docker/pkg/idtools"
9 10
 	"github.com/docker/docker/volume"
10 11
 )
11 12
 
... ...
@@ -24,7 +25,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, 0, 0, nil)
27
+		s, err := mount.Setup(c.MountLabel, idtools.IDPair{0, 0}, nil)
28 28
 		if err != nil {
29 29
 			return nil, err
30 30
 		}
... ...
@@ -16,6 +16,6 @@ func (daemon *Daemon) ContainerCreateWorkdir(cID string) error {
16 16
 		return err
17 17
 	}
18 18
 	defer daemon.Unmount(container)
19
-	rootUID, rootGID := daemon.GetRemappedUIDGID()
20
-	return container.SetupWorkingDirectory(rootUID, rootGID)
19
+	rootIDs, _ := daemon.idMappings.RootPair()
20
+	return container.SetupWorkingDirectory(rootIDs)
21 21
 }
... ...
@@ -44,8 +44,7 @@ type StoreOptions struct {
44 44
 	MetadataStorePathTemplate string
45 45
 	GraphDriver               string
46 46
 	GraphDriverOptions        []string
47
-	UIDMaps                   []idtools.IDMap
48
-	GIDMaps                   []idtools.IDMap
47
+	IDMappings                *idtools.IDMappings
49 48
 	PluginGetter              plugingetter.PluginGetter
50 49
 	ExperimentalEnabled       bool
51 50
 }
... ...
@@ -55,8 +54,8 @@ func NewStoreFromOptions(options StoreOptions) (Store, error) {
55 55
 	driver, err := graphdriver.New(options.GraphDriver, options.PluginGetter, graphdriver.Options{
56 56
 		Root:                options.StorePath,
57 57
 		DriverOptions:       options.GraphDriverOptions,
58
-		UIDMaps:             options.UIDMaps,
59
-		GIDMaps:             options.GIDMaps,
58
+		UIDMaps:             options.IDMappings.UIDs(),
59
+		GIDMaps:             options.IDMappings.GIDs(),
60 60
 		ExperimentalEnabled: options.ExperimentalEnabled,
61 61
 	})
62 62
 	if err != nil {
... ...
@@ -37,6 +37,7 @@ const (
37 37
 // MkdirAllAs 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
+// Deprecated: Use MkdirAllAndChown
40 41
 func MkdirAllAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
41 42
 	return mkdirAs(path, mode, ownerUID, ownerGID, true, true)
42 43
 }
... ...
@@ -44,16 +45,38 @@ func MkdirAllAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
44 44
 // MkdirAllNewAs creates a directory (include any along the path) and then modifies
45 45
 // ownership ONLY of newly created directories to the requested uid/gid. If the
46 46
 // directories along the path exist, no change of ownership will be performed
47
+// Deprecated: Use MkdirAllAndChownNew
47 48
 func MkdirAllNewAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
48 49
 	return mkdirAs(path, mode, ownerUID, ownerGID, true, false)
49 50
 }
50 51
 
51 52
 // MkdirAs creates a directory and then modifies ownership to the requested uid/gid.
52 53
 // If the directory already exists, this function still changes ownership
54
+// Deprecated: Use MkdirAndChown with a IDPair
53 55
 func MkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int) error {
54 56
 	return mkdirAs(path, mode, ownerUID, ownerGID, false, true)
55 57
 }
56 58
 
59
+// MkdirAllAndChown creates a directory (include any along the path) and then modifies
60
+// ownership to the requested uid/gid.  If the directory already exists, this
61
+// function will still change ownership to the requested uid/gid pair.
62
+func MkdirAllAndChown(path string, mode os.FileMode, ids IDPair) error {
63
+	return mkdirAs(path, mode, ids.UID, ids.GID, true, true)
64
+}
65
+
66
+// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
67
+// If the directory already exists, this function still changes ownership
68
+func MkdirAndChown(path string, mode os.FileMode, ids IDPair) error {
69
+	return mkdirAs(path, mode, ids.UID, ids.GID, false, true)
70
+}
71
+
72
+// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
73
+// ownership ONLY of newly created directories to the requested uid/gid. If the
74
+// directories along the path exist, no change of ownership will be performed
75
+func MkdirAllAndChownNew(path string, mode os.FileMode, ids IDPair) error {
76
+	return mkdirAs(path, mode, ids.UID, ids.GID, true, false)
77
+}
78
+
57 79
 // GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
58 80
 // If the maps are empty, then the root uid/gid will default to "real" 0/0
59 81
 func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) {
... ...
@@ -108,26 +131,59 @@ func ToHost(contID int, idMap []IDMap) (int, error) {
108 108
 	return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID)
109 109
 }
110 110
 
111
-// CreateIDMappings takes a requested user and group name and
111
+// IDPair is a UID and GID pair
112
+type IDPair struct {
113
+	UID int
114
+	GID int
115
+}
116
+
117
+// IDMappings contains a mappings of UIDs and GIDs
118
+type IDMappings struct {
119
+	uids []IDMap
120
+	gids []IDMap
121
+}
122
+
123
+// NewIDMappings takes a requested user and group name and
112 124
 // using the data from /etc/sub{uid,gid} ranges, creates the
113 125
 // proper uid and gid remapping ranges for that user/group pair
114
-func CreateIDMappings(username, groupname string) ([]IDMap, []IDMap, error) {
126
+func NewIDMappings(username, groupname string) (*IDMappings, error) {
115 127
 	subuidRanges, err := parseSubuid(username)
116 128
 	if err != nil {
117
-		return nil, nil, err
129
+		return nil, err
118 130
 	}
119 131
 	subgidRanges, err := parseSubgid(groupname)
120 132
 	if err != nil {
121
-		return nil, nil, err
133
+		return nil, err
122 134
 	}
123 135
 	if len(subuidRanges) == 0 {
124
-		return nil, nil, fmt.Errorf("No subuid ranges found for user %q", username)
136
+		return nil, fmt.Errorf("No subuid ranges found for user %q", username)
125 137
 	}
126 138
 	if len(subgidRanges) == 0 {
127
-		return nil, nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
139
+		return nil, fmt.Errorf("No subgid ranges found for group %q", groupname)
128 140
 	}
129 141
 
130
-	return createIDMap(subuidRanges), createIDMap(subgidRanges), nil
142
+	return &IDMappings{
143
+		uids: createIDMap(subuidRanges),
144
+		gids: createIDMap(subgidRanges),
145
+	}, nil
146
+}
147
+
148
+// RootPair returns a uid and gid pair for the root user
149
+func (i *IDMappings) RootPair() (IDPair, error) {
150
+	uid, gid, err := GetRootUIDGID(i.uids, i.gids)
151
+	return IDPair{UID: uid, GID: gid}, err
152
+}
153
+
154
+// UIDs return the UID mapping
155
+// TODO: remove this once everything has been refactored to use pairs
156
+func (i *IDMappings) UIDs() []IDMap {
157
+	return i.uids
158
+}
159
+
160
+// GIDs return the UID mapping
161
+// TODO: remove this once everything has been refactored to use pairs
162
+func (i *IDMappings) GIDs() []IDMap {
163
+	return i.gids
131 164
 }
132 165
 
133 166
 func createIDMap(subidRanges ranges) []IDMap {
... ...
@@ -69,15 +69,15 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
69 69
 
70 70
 // CanAccess takes a valid (existing) directory and a uid, gid pair and determines
71 71
 // if that uid, gid pair has access (execute bit) to the directory
72
-func CanAccess(path string, uid, gid int) bool {
72
+func CanAccess(path string, pair IDPair) bool {
73 73
 	statInfo, err := system.Stat(path)
74 74
 	if err != nil {
75 75
 		return false
76 76
 	}
77 77
 	fileMode := os.FileMode(statInfo.Mode())
78 78
 	permBits := fileMode.Perm()
79
-	return accessible(statInfo.UID() == uint32(uid),
80
-		statInfo.GID() == uint32(gid), permBits)
79
+	return accessible(statInfo.UID() == uint32(pair.UID),
80
+		statInfo.GID() == uint32(pair.GID), permBits)
81 81
 }
82 82
 
83 83
 func accessible(isOwner, isGroup bool, perms os.FileMode) bool {
... ...
@@ -20,6 +20,6 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
20 20
 // CanAccess takes a valid (existing) directory and a uid, gid pair and determines
21 21
 // if that uid, gid pair has access (execute bit) to the directory
22 22
 // Windows does not require/support this function, so always return true
23
-func CanAccess(path string, uid, gid int) bool {
23
+func CanAccess(path string, pair IDPair) bool {
24 24
 	return true
25 25
 }
... ...
@@ -15,6 +15,7 @@ import (
15 15
 	"github.com/docker/docker/api/types"
16 16
 	"github.com/docker/docker/daemon/initlayer"
17 17
 	"github.com/docker/docker/libcontainerd"
18
+	"github.com/docker/docker/pkg/idtools"
18 19
 	"github.com/docker/docker/pkg/mount"
19 20
 	"github.com/docker/docker/pkg/plugins"
20 21
 	"github.com/docker/docker/pkg/stringid"
... ...
@@ -58,7 +59,7 @@ func (pm *Manager) enable(p *v2.Plugin, c *controller, force bool) error {
58 58
 		}
59 59
 	}
60 60
 
61
-	if err := initlayer.Setup(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName), 0, 0); err != nil {
61
+	if err := initlayer.Setup(filepath.Join(pm.config.Root, p.PluginObj.ID, rootFSFileName), idtools.IDPair{0, 0}); err != nil {
62 62
 		return errors.WithStack(err)
63 63
 	}
64 64
 
... ...
@@ -55,10 +55,10 @@ type activeMount struct {
55 55
 // New instantiates a new Root instance with the provided scope. Scope
56 56
 // is the base path that the Root instance uses to store its
57 57
 // volumes. The base path is created here if it does not exist.
58
-func New(scope string, rootUID, rootGID int) (*Root, error) {
58
+func New(scope string, rootIDs idtools.IDPair) (*Root, error) {
59 59
 	rootDirectory := filepath.Join(scope, volumesPathName)
60 60
 
61
-	if err := idtools.MkdirAllAs(rootDirectory, 0700, rootUID, rootGID); err != nil {
61
+	if err := idtools.MkdirAllAndChown(rootDirectory, 0700, rootIDs); err != nil {
62 62
 		return nil, err
63 63
 	}
64 64
 
... ...
@@ -66,8 +66,7 @@ func New(scope string, rootUID, rootGID int) (*Root, error) {
66 66
 		scope:   scope,
67 67
 		path:    rootDirectory,
68 68
 		volumes: make(map[string]*localVolume),
69
-		rootUID: rootUID,
70
-		rootGID: rootGID,
69
+		rootIDs: rootIDs,
71 70
 	}
72 71
 
73 72
 	dirs, err := ioutil.ReadDir(rootDirectory)
... ...
@@ -125,8 +124,7 @@ type Root struct {
125 125
 	scope   string
126 126
 	path    string
127 127
 	volumes map[string]*localVolume
128
-	rootUID int
129
-	rootGID int
128
+	rootIDs idtools.IDPair
130 129
 }
131 130
 
132 131
 // List lists all the volumes
... ...
@@ -167,7 +165,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error
167 167
 	}
168 168
 
169 169
 	path := r.DataPath(name)
170
-	if err := idtools.MkdirAllAs(path, 0755, r.rootUID, r.rootGID); err != nil {
170
+	if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil {
171 171
 		if os.IsExist(err) {
172 172
 			return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path))
173 173
 		}
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"strings"
10 10
 	"testing"
11 11
 
12
+	"github.com/docker/docker/pkg/idtools"
12 13
 	"github.com/docker/docker/pkg/mount"
13 14
 )
14 15
 
... ...
@@ -40,7 +41,7 @@ func TestRemove(t *testing.T) {
40 40
 	}
41 41
 	defer os.RemoveAll(rootDir)
42 42
 
43
-	r, err := New(rootDir, 0, 0)
43
+	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
44 44
 	if err != nil {
45 45
 		t.Fatal(err)
46 46
 	}
... ...
@@ -82,7 +83,7 @@ func TestInitializeWithVolumes(t *testing.T) {
82 82
 	}
83 83
 	defer os.RemoveAll(rootDir)
84 84
 
85
-	r, err := New(rootDir, 0, 0)
85
+	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
86 86
 	if err != nil {
87 87
 		t.Fatal(err)
88 88
 	}
... ...
@@ -92,7 +93,7 @@ func TestInitializeWithVolumes(t *testing.T) {
92 92
 		t.Fatal(err)
93 93
 	}
94 94
 
95
-	r, err = New(rootDir, 0, 0)
95
+	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
96 96
 	if err != nil {
97 97
 		t.Fatal(err)
98 98
 	}
... ...
@@ -114,7 +115,7 @@ func TestCreate(t *testing.T) {
114 114
 	}
115 115
 	defer os.RemoveAll(rootDir)
116 116
 
117
-	r, err := New(rootDir, 0, 0)
117
+	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
118 118
 	if err != nil {
119 119
 		t.Fatal(err)
120 120
 	}
... ...
@@ -151,7 +152,7 @@ func TestCreate(t *testing.T) {
151 151
 		}
152 152
 	}
153 153
 
154
-	r, err = New(rootDir, 0, 0)
154
+	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
155 155
 	if err != nil {
156 156
 		t.Fatal(err)
157 157
 	}
... ...
@@ -189,7 +190,7 @@ func TestCreateWithOpts(t *testing.T) {
189 189
 	}
190 190
 	defer os.RemoveAll(rootDir)
191 191
 
192
-	r, err := New(rootDir, 0, 0)
192
+	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
193 193
 	if err != nil {
194 194
 		t.Fatal(err)
195 195
 	}
... ...
@@ -270,7 +271,7 @@ func TestCreateWithOpts(t *testing.T) {
270 270
 		t.Fatal("expected mount to still be active")
271 271
 	}
272 272
 
273
-	r, err = New(rootDir, 0, 0)
273
+	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
274 274
 	if err != nil {
275 275
 		t.Fatal(err)
276 276
 	}
... ...
@@ -292,7 +293,7 @@ func TestRealodNoOpts(t *testing.T) {
292 292
 	}
293 293
 	defer os.RemoveAll(rootDir)
294 294
 
295
-	r, err := New(rootDir, 0, 0)
295
+	r, err := New(rootDir, idtools.IDPair{UID: 0, GID: 0})
296 296
 	if err != nil {
297 297
 		t.Fatal(err)
298 298
 	}
... ...
@@ -320,7 +321,7 @@ func TestRealodNoOpts(t *testing.T) {
320 320
 		t.Fatal(err)
321 321
 	}
322 322
 
323
-	r, err = New(rootDir, 0, 0)
323
+	r, err = New(rootDir, idtools.IDPair{UID: 0, GID: 0})
324 324
 	if err != nil {
325 325
 		t.Fatal(err)
326 326
 	}
... ...
@@ -151,7 +151,7 @@ func (m *MountPoint) Cleanup() error {
151 151
 // configured, or creating the source directory if supplied.
152 152
 // The, optional, checkFun parameter allows doing additional checking
153 153
 // before creating the source directory on the host.
154
-func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int, checkFun func(m *MountPoint) error) (path string, err error) {
154
+func (m *MountPoint) Setup(mountLabel string, rootIDs idtools.IDPair, checkFun func(m *MountPoint) error) (path string, err error) {
155 155
 	defer func() {
156 156
 		if err == nil {
157 157
 			if label.RelabelNeeded(m.Mode) {
... ...
@@ -196,7 +196,7 @@ func (m *MountPoint) Setup(mountLabel string, rootUID, rootGID int, checkFun fun
196 196
 		}
197 197
 		// idtools.MkdirAllNewAs() produces an error if m.Source exists and is a file (not a directory)
198 198
 		// also, makes sure that if the directory is created, the correct remapped rootUID/rootGID will own it
199
-		if err := idtools.MkdirAllNewAs(m.Source, 0755, rootUID, rootGID); err != nil {
199
+		if err := idtools.MkdirAllAndChownNew(m.Source, 0755, rootIDs); err != nil {
200 200
 			if perr, ok := err.(*os.PathError); ok {
201 201
 				if perr.Err != syscall.ENOTDIR {
202 202
 					return "", errors.Wrapf(err, "error while creating mount source path '%s'", m.Source)