path: use OS-specific function in MkdirAll, don't always keep trailing slash

CL 86295 changed MkdirAll to always pass a trailing path separator to
support extended-length paths on Windows.

However, when Stat is called on an existing file followed by trailing
slash, it will return a "not a directory" error, skipping the fast
path at the beginning of MkdirAll.

This change fixes MkdirAll to only pass the trailing path separator
where required on Windows, by using an OS-specific function fixRootDirectory.

Updates #23918

Change-Id: I23f84a20e65ccce556efa743d026d352b4812c34
Reviewed-on: https://go-review.googlesource.com/95255
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David du Colombier <0intro@gmail.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
diff --git a/src/os/path.go b/src/os/path.go
index ec6a793..5c53506 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -40,9 +40,7 @@
 
 	if j > 1 {
 		// Create parent.
-		// Pass trailing path separator to MkdirAll, so our
-		// algorithm works for paths, like \\?\c:\
-		err = MkdirAll(path[0:j], perm)
+		err = MkdirAll(fixRootDirectory(path[:j-1]), perm)
 		if err != nil {
 			return err
 		}
diff --git a/src/os/path_plan9.go b/src/os/path_plan9.go
index b09b53a..a54b4b9 100644
--- a/src/os/path_plan9.go
+++ b/src/os/path_plan9.go
@@ -13,3 +13,7 @@
 func IsPathSeparator(c uint8) bool {
 	return PathSeparator == c
 }
+
+func fixRootDirectory(p string) string {
+	return p
+}
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index ecf098c..9117ad0 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -33,3 +33,7 @@
 
 	return name
 }
+
+func fixRootDirectory(p string) string {
+	return p
+}
diff --git a/src/os/path_windows.go b/src/os/path_windows.go
index 101b026..87b1cac 100644
--- a/src/os/path_windows.go
+++ b/src/os/path_windows.go
@@ -207,3 +207,14 @@
 	}
 	return string(pathbuf[:w])
 }
+
+// fixRootDirectory fixes a reference to a drive's root directory to
+// have the required trailing slash.
+func fixRootDirectory(p string) string {
+	if len(p) == len(`\\?\c:`) {
+		if IsPathSeparator(p[0]) && IsPathSeparator(p[1]) && p[2] == '?' && IsPathSeparator(p[3]) && p[5] == ':' {
+			return p + `\`
+		}
+	}
+	return p
+}