forked from rclone/rclone
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mkdir_windows_test.go
161 lines (141 loc) · 5.17 KB
/
mkdir_windows_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
//go:build windows
package file
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Basic test from golang's os/path_test.go
func TestMkdirAll(t *testing.T) {
tmpDir := t.TempDir()
path := tmpDir + "/dir/./dir2"
err := MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
// Already exists, should succeed.
err = MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q (second time): %s", path, err)
}
// Make file.
fpath := path + "/file"
f, err := Create(fpath)
if err != nil {
t.Fatalf("create %q: %s", fpath, err)
}
defer func() {
if err := f.Close(); err != nil {
t.Fatalf("Close %q: %s", fpath, err)
}
}()
// Can't make directory named after file.
err = MkdirAll(fpath, 0777)
if err == nil {
t.Fatalf("MkdirAll %q: no error", fpath)
}
perr, ok := err.(*os.PathError)
if !ok {
t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err)
}
if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
}
// Can't make subdirectory of file.
ffpath := fpath + "/subdir"
err = MkdirAll(ffpath, 0777)
if err == nil {
t.Fatalf("MkdirAll %q: no error", ffpath)
}
perr, ok = err.(*os.PathError)
if !ok {
t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err)
}
if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
}
path = tmpDir + `\dir\.\dir2\`
err = MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
}
func unusedDrive(t *testing.T) string {
letter := FindUnusedDriveLetter()
require.NotEqual(t, letter, 0)
return string(letter) + ":"
}
func checkMkdirAll(t *testing.T, path string, valid bool, errormsgs ...string) {
if valid {
assert.NoError(t, MkdirAll(path, 0777))
} else {
err := MkdirAll(path, 0777)
assert.Error(t, err)
ok := false
for _, msg := range errormsgs {
if err.Error() == msg {
ok = true
}
}
assert.True(t, ok, fmt.Sprintf("Error message '%v' didn't match any of %v", err, errormsgs))
}
}
func checkMkdirAllSubdirs(t *testing.T, path string, valid bool, errormsgs ...string) {
checkMkdirAll(t, path, valid, errormsgs...)
checkMkdirAll(t, path+`\`, valid, errormsgs...)
checkMkdirAll(t, path+`\parent`, valid, errormsgs...)
checkMkdirAll(t, path+`\parent\`, valid, errormsgs...)
checkMkdirAll(t, path+`\parent\child`, valid, errormsgs...)
checkMkdirAll(t, path+`\parent\child\`, valid, errormsgs...)
}
// Testing paths on existing drive
func TestMkdirAllOnDrive(t *testing.T) {
path := t.TempDir()
dir, err := os.Stat(path)
require.NoError(t, err)
require.True(t, dir.IsDir())
drive := filepath.VolumeName(path)
checkMkdirAll(t, drive, true, "")
checkMkdirAll(t, drive+`\`, true, "")
// checkMkdirAll(t, `\\?\`+drive, true, "") - this isn't actually a Valid Windows path - this test used to work under go1.21.3 but fails under go1.21.4
checkMkdirAll(t, `\\?\`+drive+`\`, true, "")
checkMkdirAllSubdirs(t, path, true, "")
checkMkdirAllSubdirs(t, `\\?\`+path, true, "")
}
// Testing paths on unused drive
// This is where there is a difference from golang's os.MkdirAll. It would
// recurse extended-length paths down to the "\\?" prefix and return the
// noninformative error:
// "mkdir \\?: The filename, directory name, or volume label syntax is incorrect."
// Our version stops the recursion at drive's root directory, and reports:
// "mkdir \\?\A:\: The system cannot find the path specified."
func TestMkdirAllOnUnusedDrive(t *testing.T) {
path := unusedDrive(t)
errormsg := fmt.Sprintf(`mkdir %s\: The system cannot find the path specified.`, path)
checkMkdirAllSubdirs(t, path, false, errormsg)
errormsg1 := fmt.Sprintf(`mkdir \\?\%s\: The system cannot find the path specified.`, path) // pre go1.21.4
errormsg2 := fmt.Sprintf(`mkdir \\?\%s: The system cannot find the file specified.`, path) // go1.21.4 and after
checkMkdirAllSubdirs(t, `\\?\`+path, false, errormsg1, errormsg2)
}
// Testing paths on unknown network host
// This is an additional difference from golang's os.MkdirAll. With our
// first fix, stopping it from recursing extended-length paths down to
// the "\\?" prefix, it would now stop at `\\?\UNC`, because that is what
// filepath.VolumeName returns (which is wrong, that is not a volume name!),
// and still return a nonifnromative error:
// "mkdir \\?\UNC\\: The filename, directory name, or volume label syntax is incorrect."
// Our version stops the recursion at level before this, and reports:
// "mkdir \\?\UNC\0.0.0.0: The specified path is invalid."
func TestMkdirAllOnUnusedNetworkHost(t *testing.T) {
path := `\\0.0.0.0\share`
errormsg := fmt.Sprintf("mkdir %s\\: The format of the specified network name is invalid.", path)
checkMkdirAllSubdirs(t, path, false, errormsg)
path = `\\?\UNC\0.0.0.0\share`
checkMkdirAllSubdirs(t, path, false,
`mkdir \\?\UNC\0.0.0.0: The specified path is invalid.`, // pre go1.20
`mkdir \\?\UNC\0.0.0.0\share\: The format of the specified network name is invalid.`,
)
}