1 // Copyright 2022 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
12 func fromFS(path string) (string, error) {
13 if !utf8.ValidString(path) {
14 return "", errInvalidPath
16 for len(path) > 1 && path[0] == '/' && path[1] == '/' {
19 containsSlash := false
20 for p := path; p != ""; {
21 // Find the next path element.
24 for i < len(p) && p[i] != '/' {
27 return "", errInvalidPath
42 // Trim the extension and look for a reserved name.
47 if isReservedName(base) {
49 return "", errInvalidPath
51 // The path element is a reserved name with an extension.
52 // Some Windows versions consider this a reserved name,
53 // while others do not. Use FullPath to see if the name is
55 if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` {
56 return "", errInvalidPath
61 // We can't depend on strings, so substitute \ for / manually.
63 for i, b := range buf {
73 // isReservedName reports if name is a Windows reserved device name.
74 // It does not detect names with an extension, which are also reserved on some Windows versions.
76 // For details, search for PRN in
77 // https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file.
78 func isReservedName(name string) bool {
79 if 3 <= len(name) && len(name) <= 4 {
80 switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) {
81 case "CON", "PRN", "AUX", "NUL":
84 return len(name) == 4 && '1' <= name[3] && name[3] <= '9'
90 func toUpper(c byte) byte {
91 if 'a' <= c && c <= 'z' {
92 return c - ('a' - 'A')