Fixes for libcontainer changes

Libcontainer no longer provides placeholders for
unsupported platforms, which cause the Windows
builds to fail.

This patch moves features that are not supported
to platform-specific files.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit d1c34831e930c1f6b3de28cab3f4a358845a79d5)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
diff --git a/builder/dockerfile/internals.go b/builder/dockerfile/internals.go
index c38f48a..117d4e7 100644
--- a/builder/dockerfile/internals.go
+++ b/builder/dockerfile/internals.go
@@ -11,7 +11,6 @@
 	"os"
 	"path"
 	"path/filepath"
-	"strconv"
 	"strings"
 
 	"github.com/docker/docker/api/types"
@@ -23,10 +22,8 @@
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/pkg/stringid"
-	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/go-connections/nat"
-	lcUser "github.com/opencontainers/runc/libcontainer/user"
 	"github.com/pkg/errors"
 )
 
@@ -216,82 +213,6 @@
 	return b.exportImage(state, imageMount, runConfigWithCommentCmd)
 }
 
-func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
-	var userStr, grpStr string
-	parts := strings.Split(chown, ":")
-	if len(parts) > 2 {
-		return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
-	}
-	if len(parts) == 1 {
-		// if no group specified, use the user spec as group as well
-		userStr, grpStr = parts[0], parts[0]
-	} else {
-		userStr, grpStr = parts[0], parts[1]
-	}
-
-	passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
-	if err != nil {
-		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
-	}
-	groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
-	if err != nil {
-		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
-	}
-	uid, err := lookupUser(userStr, passwdPath)
-	if err != nil {
-		return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
-	}
-	gid, err := lookupGroup(grpStr, groupPath)
-	if err != nil {
-		return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
-	}
-
-	// convert as necessary because of user namespaces
-	chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
-	if err != nil {
-		return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
-	}
-	return chownPair, nil
-}
-
-func lookupUser(userStr, filepath string) (int, error) {
-	// if the string is actually a uid integer, parse to int and return
-	// as we don't need to translate with the help of files
-	uid, err := strconv.Atoi(userStr)
-	if err == nil {
-		return uid, nil
-	}
-	users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
-		return u.Name == userStr
-	})
-	if err != nil {
-		return 0, err
-	}
-	if len(users) == 0 {
-		return 0, errors.New("no such user: " + userStr)
-	}
-	return users[0].Uid, nil
-}
-
-func lookupGroup(groupStr, filepath string) (int, error) {
-	// if the string is actually a gid integer, parse to int and return
-	// as we don't need to translate with the help of files
-	gid, err := strconv.Atoi(groupStr)
-	if err == nil {
-		return gid, nil
-	}
-	groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
-		return g.Name == groupStr
-	})
-	if err != nil {
-		return 0, err
-	}
-	if len(groups) == 0 {
-		return 0, errors.New("no such group: " + groupStr)
-	}
-	return groups[0].Gid, nil
-}
-
 func createDestInfo(workingDir string, inst copyInstruction, imageMount *imageMount, platform string) (copyInfo, error) {
 	// Twiddle the destination when it's a relative path - meaning, make it
 	// relative to the WORKINGDIR
diff --git a/builder/dockerfile/internals_linux.go b/builder/dockerfile/internals_linux.go
new file mode 100644
index 0000000..1314779
--- /dev/null
+++ b/builder/dockerfile/internals_linux.go
@@ -0,0 +1,88 @@
+package dockerfile
+
+import (
+	"path/filepath"
+	"strconv"
+	"strings"
+
+	"github.com/docker/docker/pkg/idtools"
+	"github.com/docker/docker/pkg/symlink"
+	lcUser "github.com/opencontainers/runc/libcontainer/user"
+	"github.com/pkg/errors"
+)
+
+func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
+	var userStr, grpStr string
+	parts := strings.Split(chown, ":")
+	if len(parts) > 2 {
+		return idtools.IDPair{}, errors.New("invalid chown string format: " + chown)
+	}
+	if len(parts) == 1 {
+		// if no group specified, use the user spec as group as well
+		userStr, grpStr = parts[0], parts[0]
+	} else {
+		userStr, grpStr = parts[0], parts[1]
+	}
+
+	passwdPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "passwd"), ctrRootPath)
+	if err != nil {
+		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/passwd path in container rootfs")
+	}
+	groupPath, err := symlink.FollowSymlinkInScope(filepath.Join(ctrRootPath, "etc", "group"), ctrRootPath)
+	if err != nil {
+		return idtools.IDPair{}, errors.Wrapf(err, "can't resolve /etc/group path in container rootfs")
+	}
+	uid, err := lookupUser(userStr, passwdPath)
+	if err != nil {
+		return idtools.IDPair{}, errors.Wrapf(err, "can't find uid for user "+userStr)
+	}
+	gid, err := lookupGroup(grpStr, groupPath)
+	if err != nil {
+		return idtools.IDPair{}, errors.Wrapf(err, "can't find gid for group "+grpStr)
+	}
+
+	// convert as necessary because of user namespaces
+	chownPair, err := idMappings.ToHost(idtools.IDPair{UID: uid, GID: gid})
+	if err != nil {
+		return idtools.IDPair{}, errors.Wrapf(err, "unable to convert uid/gid to host mapping")
+	}
+	return chownPair, nil
+}
+
+func lookupUser(userStr, filepath string) (int, error) {
+	// if the string is actually a uid integer, parse to int and return
+	// as we don't need to translate with the help of files
+	uid, err := strconv.Atoi(userStr)
+	if err == nil {
+		return uid, nil
+	}
+	users, err := lcUser.ParsePasswdFileFilter(filepath, func(u lcUser.User) bool {
+		return u.Name == userStr
+	})
+	if err != nil {
+		return 0, err
+	}
+	if len(users) == 0 {
+		return 0, errors.New("no such user: " + userStr)
+	}
+	return users[0].Uid, nil
+}
+
+func lookupGroup(groupStr, filepath string) (int, error) {
+	// if the string is actually a gid integer, parse to int and return
+	// as we don't need to translate with the help of files
+	gid, err := strconv.Atoi(groupStr)
+	if err == nil {
+		return gid, nil
+	}
+	groups, err := lcUser.ParseGroupFileFilter(filepath, func(g lcUser.Group) bool {
+		return g.Name == groupStr
+	})
+	if err != nil {
+		return 0, err
+	}
+	if len(groups) == 0 {
+		return 0, errors.New("no such group: " + groupStr)
+	}
+	return groups[0].Gid, nil
+}
diff --git a/builder/dockerfile/internals_linux_test.go b/builder/dockerfile/internals_linux_test.go
new file mode 100644
index 0000000..dd23a33
--- /dev/null
+++ b/builder/dockerfile/internals_linux_test.go
@@ -0,0 +1,138 @@
+package dockerfile
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"github.com/docker/docker/pkg/idtools"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestChownFlagParsing(t *testing.T) {
+	testFiles := map[string]string{
+		"passwd": `root:x:0:0::/bin:/bin/false
+bin:x:1:1::/bin:/bin/false
+wwwwww:x:21:33::/bin:/bin/false
+unicorn:x:1001:1002::/bin:/bin/false
+		`,
+		"group": `root:x:0:
+bin:x:1:
+wwwwww:x:33:
+unicorn:x:1002:
+somegrp:x:5555:
+othergrp:x:6666:
+		`,
+	}
+	// test mappings for validating use of maps
+	idMaps := []idtools.IDMap{
+		{
+			ContainerID: 0,
+			HostID:      100000,
+			Size:        65536,
+		},
+	}
+	remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
+	unmapped := &idtools.IDMappings{}
+
+	contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
+	defer cleanup()
+
+	if err := os.Mkdir(filepath.Join(contextDir, "etc"), 0755); err != nil {
+		t.Fatalf("error creating test directory: %v", err)
+	}
+
+	for filename, content := range testFiles {
+		createTestTempFile(t, filepath.Join(contextDir, "etc"), filename, content, 0644)
+	}
+
+	// positive tests
+	for _, testcase := range []struct {
+		name      string
+		chownStr  string
+		idMapping *idtools.IDMappings
+		expected  idtools.IDPair
+	}{
+		{
+			name:      "UIDNoMap",
+			chownStr:  "1",
+			idMapping: unmapped,
+			expected:  idtools.IDPair{UID: 1, GID: 1},
+		},
+		{
+			name:      "UIDGIDNoMap",
+			chownStr:  "0:1",
+			idMapping: unmapped,
+			expected:  idtools.IDPair{UID: 0, GID: 1},
+		},
+		{
+			name:      "UIDWithMap",
+			chownStr:  "0",
+			idMapping: remapped,
+			expected:  idtools.IDPair{UID: 100000, GID: 100000},
+		},
+		{
+			name:      "UIDGIDWithMap",
+			chownStr:  "1:33",
+			idMapping: remapped,
+			expected:  idtools.IDPair{UID: 100001, GID: 100033},
+		},
+		{
+			name:      "UserNoMap",
+			chownStr:  "bin:5555",
+			idMapping: unmapped,
+			expected:  idtools.IDPair{UID: 1, GID: 5555},
+		},
+		{
+			name:      "GroupWithMap",
+			chownStr:  "0:unicorn",
+			idMapping: remapped,
+			expected:  idtools.IDPair{UID: 100000, GID: 101002},
+		},
+		{
+			name:      "UserOnlyWithMap",
+			chownStr:  "unicorn",
+			idMapping: remapped,
+			expected:  idtools.IDPair{UID: 101001, GID: 101002},
+		},
+	} {
+		t.Run(testcase.name, func(t *testing.T) {
+			idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
+			require.NoError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
+			assert.Equal(t, testcase.expected, idPair, "chown flag mapping failure")
+		})
+	}
+
+	// error tests
+	for _, testcase := range []struct {
+		name      string
+		chownStr  string
+		idMapping *idtools.IDMappings
+		descr     string
+	}{
+		{
+			name:      "BadChownFlagFormat",
+			chownStr:  "bob:1:555",
+			idMapping: unmapped,
+			descr:     "invalid chown string format: bob:1:555",
+		},
+		{
+			name:      "UserNoExist",
+			chownStr:  "bob",
+			idMapping: unmapped,
+			descr:     "can't find uid for user bob: no such user: bob",
+		},
+		{
+			name:      "GroupNoExist",
+			chownStr:  "root:bob",
+			idMapping: unmapped,
+			descr:     "can't find gid for group bob: no such group: bob",
+		},
+	} {
+		t.Run(testcase.name, func(t *testing.T) {
+			_, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
+			assert.EqualError(t, err, testcase.descr, "Expected error string doesn't match")
+		})
+	}
+}
diff --git a/builder/dockerfile/internals_test.go b/builder/dockerfile/internals_test.go
index 83a207c..04c8c4b 100644
--- a/builder/dockerfile/internals_test.go
+++ b/builder/dockerfile/internals_test.go
@@ -2,8 +2,6 @@
 
 import (
 	"fmt"
-	"os"
-	"path/filepath"
 	"runtime"
 	"testing"
 
@@ -13,7 +11,6 @@
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/builder/remotecontext"
 	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/go-connections/nat"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
@@ -171,130 +168,3 @@
 	copy.Shell[0] = "sh"
 	assert.Equal(t, fullMutableRunConfig(), runConfig)
 }
-
-func TestChownFlagParsing(t *testing.T) {
-	testFiles := map[string]string{
-		"passwd": `root:x:0:0::/bin:/bin/false
-bin:x:1:1::/bin:/bin/false
-wwwwww:x:21:33::/bin:/bin/false
-unicorn:x:1001:1002::/bin:/bin/false
-		`,
-		"group": `root:x:0:
-bin:x:1:
-wwwwww:x:33:
-unicorn:x:1002:
-somegrp:x:5555:
-othergrp:x:6666:
-		`,
-	}
-	// test mappings for validating use of maps
-	idMaps := []idtools.IDMap{
-		{
-			ContainerID: 0,
-			HostID:      100000,
-			Size:        65536,
-		},
-	}
-	remapped := idtools.NewIDMappingsFromMaps(idMaps, idMaps)
-	unmapped := &idtools.IDMappings{}
-
-	contextDir, cleanup := createTestTempDir(t, "", "builder-chown-parse-test")
-	defer cleanup()
-
-	if err := os.Mkdir(filepath.Join(contextDir, "etc"), 0755); err != nil {
-		t.Fatalf("error creating test directory: %v", err)
-	}
-
-	for filename, content := range testFiles {
-		createTestTempFile(t, filepath.Join(contextDir, "etc"), filename, content, 0644)
-	}
-
-	// positive tests
-	for _, testcase := range []struct {
-		name      string
-		chownStr  string
-		idMapping *idtools.IDMappings
-		expected  idtools.IDPair
-	}{
-		{
-			name:      "UIDNoMap",
-			chownStr:  "1",
-			idMapping: unmapped,
-			expected:  idtools.IDPair{UID: 1, GID: 1},
-		},
-		{
-			name:      "UIDGIDNoMap",
-			chownStr:  "0:1",
-			idMapping: unmapped,
-			expected:  idtools.IDPair{UID: 0, GID: 1},
-		},
-		{
-			name:      "UIDWithMap",
-			chownStr:  "0",
-			idMapping: remapped,
-			expected:  idtools.IDPair{UID: 100000, GID: 100000},
-		},
-		{
-			name:      "UIDGIDWithMap",
-			chownStr:  "1:33",
-			idMapping: remapped,
-			expected:  idtools.IDPair{UID: 100001, GID: 100033},
-		},
-		{
-			name:      "UserNoMap",
-			chownStr:  "bin:5555",
-			idMapping: unmapped,
-			expected:  idtools.IDPair{UID: 1, GID: 5555},
-		},
-		{
-			name:      "GroupWithMap",
-			chownStr:  "0:unicorn",
-			idMapping: remapped,
-			expected:  idtools.IDPair{UID: 100000, GID: 101002},
-		},
-		{
-			name:      "UserOnlyWithMap",
-			chownStr:  "unicorn",
-			idMapping: remapped,
-			expected:  idtools.IDPair{UID: 101001, GID: 101002},
-		},
-	} {
-		t.Run(testcase.name, func(t *testing.T) {
-			idPair, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
-			require.NoError(t, err, "Failed to parse chown flag: %q", testcase.chownStr)
-			assert.Equal(t, testcase.expected, idPair, "chown flag mapping failure")
-		})
-	}
-
-	// error tests
-	for _, testcase := range []struct {
-		name      string
-		chownStr  string
-		idMapping *idtools.IDMappings
-		descr     string
-	}{
-		{
-			name:      "BadChownFlagFormat",
-			chownStr:  "bob:1:555",
-			idMapping: unmapped,
-			descr:     "invalid chown string format: bob:1:555",
-		},
-		{
-			name:      "UserNoExist",
-			chownStr:  "bob",
-			idMapping: unmapped,
-			descr:     "can't find uid for user bob: no such user: bob",
-		},
-		{
-			name:      "GroupNoExist",
-			chownStr:  "root:bob",
-			idMapping: unmapped,
-			descr:     "can't find gid for group bob: no such group: bob",
-		},
-	} {
-		t.Run(testcase.name, func(t *testing.T) {
-			_, err := parseChownFlag(testcase.chownStr, contextDir, testcase.idMapping)
-			assert.EqualError(t, err, testcase.descr, "Expected error string doesn't match")
-		})
-	}
-}
diff --git a/builder/dockerfile/internals_windows.go b/builder/dockerfile/internals_windows.go
new file mode 100644
index 0000000..931df2f
--- /dev/null
+++ b/builder/dockerfile/internals_windows.go
@@ -0,0 +1,7 @@
+package dockerfile
+
+import "github.com/docker/docker/pkg/idtools"
+
+func parseChownFlag(chown, ctrRootPath string, idMappings *idtools.IDMappings) (idtools.IDPair, error) {
+	return idMappings.RootPair(), nil
+}
diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go
index e6c1d91..9231595 100644
--- a/integration-cli/docker_cli_run_test.go
+++ b/integration-cli/docker_cli_run_test.go
@@ -36,7 +36,6 @@
 	"github.com/docker/libnetwork/types"
 	"github.com/go-check/check"
 	"github.com/gotestyourself/gotestyourself/icmd"
-	libcontainerUser "github.com/opencontainers/runc/libcontainer/user"
 	"golang.org/x/net/context"
 )
 
@@ -751,7 +750,7 @@
 	if err == nil {
 		c.Fatal("No error, but must be.", out)
 	}
-	if !strings.Contains(strings.ToUpper(out), strings.ToUpper(libcontainerUser.ErrRange.Error())) {
+	if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
 		c.Fatalf("expected error about uids range, got %s", out)
 	}
 }
@@ -764,7 +763,7 @@
 	if err == nil {
 		c.Fatal("No error, but must be.", out)
 	}
-	if !strings.Contains(strings.ToUpper(out), strings.ToUpper(libcontainerUser.ErrRange.Error())) {
+	if !strings.Contains(strings.ToLower(out), "uids and gids must be in range") {
 		c.Fatalf("expected error about uids range, got %s", out)
 	}
 }