aboutsummaryrefslogtreecommitdiff
path: root/src/os
diff options
context:
space:
mode:
Diffstat (limited to 'src/os')
-rw-r--r--src/os/path.go24
-rw-r--r--src/os/path_plan9.go4
-rw-r--r--src/os/path_unix.go4
-rw-r--r--src/os/path_windows.go11
-rw-r--r--src/os/path_windows_test.go49
5 files changed, 68 insertions, 24 deletions
diff --git a/src/os/path.go b/src/os/path.go
index df87887b9b..6ac4cbe20f 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -26,19 +26,25 @@ func MkdirAll(path string, perm FileMode) error {
}
// Slow path: make sure parent exists and then call Mkdir for path.
- i := len(path)
- for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
+
+ // Extract the parent folder from path by first removing any trailing
+ // path separator and then scanning backward until finding a path
+ // separator or reaching the beginning of the string.
+ i := len(path) - 1
+ for i >= 0 && IsPathSeparator(path[i]) {
i--
}
-
- j := i
- for j > 0 && !IsPathSeparator(path[j-1]) { // Scan backward over element.
- j--
+ for i >= 0 && !IsPathSeparator(path[i]) {
+ i--
+ }
+ if i < 0 {
+ i = 0
}
- if j > 1 {
- // Create parent.
- err = MkdirAll(fixRootDirectory(path[:j-1]), perm)
+ // If there is a parent directory, and it is not the volume name,
+ // recurse to ensure parent directory exists.
+ if parent := path[:i]; len(parent) > len(volumeName(path)) {
+ err = MkdirAll(parent, perm)
if err != nil {
return err
}
diff --git a/src/os/path_plan9.go b/src/os/path_plan9.go
index a54b4b98f1..f1c9dbc048 100644
--- a/src/os/path_plan9.go
+++ b/src/os/path_plan9.go
@@ -14,6 +14,6 @@ func IsPathSeparator(c uint8) bool {
return PathSeparator == c
}
-func fixRootDirectory(p string) string {
- return p
+func volumeName(p string) string {
+ return ""
}
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index c975cdb11e..1c80fa91f8 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -70,6 +70,6 @@ func splitPath(path string) (string, string) {
return dirname, basename
}
-func fixRootDirectory(p string) string {
- return p
+func volumeName(p string) string {
+ return ""
}
diff --git a/src/os/path_windows.go b/src/os/path_windows.go
index 3356908a36..ec9a87274d 100644
--- a/src/os/path_windows.go
+++ b/src/os/path_windows.go
@@ -214,14 +214,3 @@ func fixLongPath(path string) string {
}
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
-}
diff --git a/src/os/path_windows_test.go b/src/os/path_windows_test.go
index 2506b4f0d8..4e5e501d1f 100644
--- a/src/os/path_windows_test.go
+++ b/src/os/path_windows_test.go
@@ -5,7 +5,11 @@
package os_test
import (
+ "fmt"
+ "internal/syscall/windows"
+ "internal/testenv"
"os"
+ "path/filepath"
"strings"
"syscall"
"testing"
@@ -106,3 +110,48 @@ func TestOpenRootSlash(t *testing.T) {
dir.Close()
}
}
+
+func testMkdirAllAtRoot(t *testing.T, root string) {
+ // Create a unique-enough directory name in root.
+ base := fmt.Sprintf("%s-%d", t.Name(), os.Getpid())
+ path := filepath.Join(root, base)
+ if err := os.MkdirAll(path, 0777); err != nil {
+ t.Fatalf("MkdirAll(%q) failed: %v", path, err)
+ }
+ // Clean up
+ if err := os.RemoveAll(path); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestMkdirAllExtendedLengthAtRoot(t *testing.T) {
+ if testenv.Builder() == "" {
+ t.Skipf("skipping non-hermetic test outside of Go builders")
+ }
+
+ const prefix = `\\?\`
+ vol := filepath.VolumeName(t.TempDir()) + `\`
+ if len(vol) < 4 || vol[:4] != prefix {
+ vol = prefix + vol
+ }
+ testMkdirAllAtRoot(t, vol)
+}
+
+func TestMkdirAllVolumeNameAtRoot(t *testing.T) {
+ if testenv.Builder() == "" {
+ t.Skipf("skipping non-hermetic test outside of Go builders")
+ }
+
+ vol, err := syscall.UTF16PtrFromString(filepath.VolumeName(t.TempDir()) + `\`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ const maxVolNameLen = 50
+ var buf [maxVolNameLen]uint16
+ err = windows.GetVolumeNameForVolumeMountPoint(vol, &buf[0], maxVolNameLen)
+ if err != nil {
+ t.Fatal(err)
+ }
+ volName := syscall.UTF16ToString(buf[:])
+ testMkdirAllAtRoot(t, volName)
+}