diff --git a/lib/file/mkdir_windows.go b/lib/file/mkdir_windows.go index 36ccadd9c..73a82ac62 100644 --- a/lib/file/mkdir_windows.go +++ b/lib/file/mkdir_windows.go @@ -11,8 +11,9 @@ import ( // MkdirAll creates a directory named path, along with any necessary parents. // -// Improves os.MkdirAll by avoiding trying to create a folder \\? when the -// volume of a given extended length path does not exist. +// Improves os.MkdirAll by avoiding trying to create a folder `\\?` when the +// volume of a given extended length path does not exist, and `\\?\UNC` when +// a network host name does not exist. // // Based on source code from golang's os.MkdirAll // (https://github.com/golang/go/blob/master/src/os/path.go) @@ -37,7 +38,6 @@ func MkdirAll(path string, perm os.FileMode) error { } if i > 0 { path = path[:i] - if path == filepath.VolumeName(path) { // Make reference to a drive's root directory include the trailing slash. // In extended-length form without trailing slash ("\\?\C:"), os.Stat @@ -53,10 +53,12 @@ func MkdirAll(path string, perm os.FileMode) error { j-- } if j > 1 { - // Create parent. - err = MkdirAll(path[:j-1], perm) - if err != nil { - return err + if path[:j-1] != `\\?\UNC` { + // Create parent. + err = MkdirAll(path[:j-1], perm) + if err != nil { + return err + } } } } diff --git a/lib/file/mkdir_windows_test.go b/lib/file/mkdir_windows_test.go index e6daf1d49..6b574b792 100644 --- a/lib/file/mkdir_windows_test.go +++ b/lib/file/mkdir_windows_test.go @@ -128,3 +128,21 @@ func TestMkdirAllOnUnusedDrive(t *testing.T) { errormsg = fmt.Sprintf("mkdir \\\\?\\%s\\: The system cannot find the path specified.", path) checkMkdirAllSubdirs(t, `\\?\`+path, false, errormsg) } + +// 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` + errormsg = `mkdir \\?\UNC\0.0.0.0: The specified path is invalid.` + checkMkdirAllSubdirs(t, path, false, errormsg) +}