diff options
Diffstat (limited to 'src/path/filepath/path_windows.go')
| -rw-r--r-- | src/path/filepath/path_windows.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go index c754301bf4..b26658a937 100644 --- a/src/path/filepath/path_windows.go +++ b/src/path/filepath/path_windows.go @@ -20,6 +20,73 @@ func toUpper(c byte) byte { return c } +// isReservedName reports if name is a Windows reserved device name. +// It does not detect names with an extension, which are also reserved on some Windows versions. +// +// For details, search for PRN in +// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. +func isReservedName(name string) bool { + if 3 <= len(name) && len(name) <= 4 { + switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { + case "CON", "PRN", "AUX", "NUL": + return len(name) == 3 + case "COM", "LPT": + return len(name) == 4 && '1' <= name[3] && name[3] <= '9' + } + } + return false +} + +func isLocal(path string) bool { + if path == "" { + return false + } + if isSlash(path[0]) { + // Path rooted in the current drive. + return false + } + if strings.IndexByte(path, ':') >= 0 { + // Colons are only valid when marking a drive letter ("C:foo"). + // Rejecting any path with a colon is conservative but safe. + return false + } + hasDots := false // contains . or .. path elements + for p := path; p != ""; { + var part string + part, p, _ = cutPath(p) + if part == "." || part == ".." { + hasDots = true + } + // Trim the extension and look for a reserved name. + base, _, hasExt := strings.Cut(part, ".") + if isReservedName(base) { + if !hasExt { + return false + } + // The path element is a reserved name with an extension. Some Windows + // versions consider this a reserved name, while others do not. Use + // FullPath to see if the name is reserved. + // + // FullPath will convert references to reserved device names to their + // canonical form: \\.\${DEVICE_NAME} + // + // FullPath does not perform this conversion for paths which contain + // a reserved device name anywhere other than in the last element, + // so check the part rather than the full path. + if p, _ := syscall.FullPath(part); len(p) >= 4 && p[:4] == `\\.\` { + return false + } + } + } + if hasDots { + path = Clean(path) + } + if path == ".." || strings.HasPrefix(path, `..\`) { + return false + } + return true +} + // IsAbs reports whether the path is absolute. func IsAbs(path string) (b bool) { l := volumeNameLen(path) |
