summaryrefslogtreecommitdiffstats
path: root/src/path/filepath/path_windows.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:14:23 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:14:23 +0000
commit73df946d56c74384511a194dd01dbe099584fd1a (patch)
treefd0bcea490dd81327ddfbb31e215439672c9a068 /src/path/filepath/path_windows.go
parentInitial commit. (diff)
downloadgolang-1.16-upstream.tar.xz
golang-1.16-upstream.zip
Adding upstream version 1.16.10.upstream/1.16.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/path/filepath/path_windows.go')
-rw-r--r--src/path/filepath/path_windows.go200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
new file mode 100644
index 0000000..445c868
--- /dev/null
+++ b/src/path/filepath/path_windows.go
@@ -0,0 +1,200 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package filepath
+
+import (
+ "strings"
+ "syscall"
+)
+
+func isSlash(c uint8) bool {
+ return c == '\\' || c == '/'
+}
+
+// reservedNames lists reserved Windows names. Search for PRN in
+// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
+// for details.
+var reservedNames = []string{
+ "CON", "PRN", "AUX", "NUL",
+ "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
+ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
+}
+
+// isReservedName returns true, if path is Windows reserved name.
+// See reservedNames for the full list.
+func isReservedName(path string) bool {
+ if len(path) == 0 {
+ return false
+ }
+ for _, reserved := range reservedNames {
+ if strings.EqualFold(path, reserved) {
+ return true
+ }
+ }
+ return false
+}
+
+// IsAbs reports whether the path is absolute.
+func IsAbs(path string) (b bool) {
+ if isReservedName(path) {
+ return true
+ }
+ l := volumeNameLen(path)
+ if l == 0 {
+ return false
+ }
+ path = path[l:]
+ if path == "" {
+ return false
+ }
+ return isSlash(path[0])
+}
+
+// volumeNameLen returns length of the leading volume name on Windows.
+// It returns 0 elsewhere.
+func volumeNameLen(path string) int {
+ if len(path) < 2 {
+ return 0
+ }
+ // with drive letter
+ c := path[0]
+ if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
+ return 2
+ }
+ // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+ if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
+ !isSlash(path[2]) && path[2] != '.' {
+ // first, leading `\\` and next shouldn't be `\`. its server name.
+ for n := 3; n < l-1; n++ {
+ // second, next '\' shouldn't be repeated.
+ if isSlash(path[n]) {
+ n++
+ // third, following something characters. its share name.
+ if !isSlash(path[n]) {
+ if path[n] == '.' {
+ break
+ }
+ for ; n < l; n++ {
+ if isSlash(path[n]) {
+ break
+ }
+ }
+ return n
+ }
+ break
+ }
+ }
+ }
+ return 0
+}
+
+// HasPrefix exists for historical compatibility and should not be used.
+//
+// Deprecated: HasPrefix does not respect path boundaries and
+// does not ignore case when required.
+func HasPrefix(p, prefix string) bool {
+ if strings.HasPrefix(p, prefix) {
+ return true
+ }
+ return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix))
+}
+
+func splitList(path string) []string {
+ // The same implementation is used in LookPath in os/exec;
+ // consider changing os/exec when changing this.
+
+ if path == "" {
+ return []string{}
+ }
+
+ // Split path, respecting but preserving quotes.
+ list := []string{}
+ start := 0
+ quo := false
+ for i := 0; i < len(path); i++ {
+ switch c := path[i]; {
+ case c == '"':
+ quo = !quo
+ case c == ListSeparator && !quo:
+ list = append(list, path[start:i])
+ start = i + 1
+ }
+ }
+ list = append(list, path[start:])
+
+ // Remove quotes.
+ for i, s := range list {
+ list[i] = strings.ReplaceAll(s, `"`, ``)
+ }
+
+ return list
+}
+
+func abs(path string) (string, error) {
+ if path == "" {
+ // syscall.FullPath returns an error on empty path, because it's not a valid path.
+ // To implement Abs behavior of returning working directory on empty string input,
+ // special-case empty path by changing it to "." path. See golang.org/issue/24441.
+ path = "."
+ }
+ fullPath, err := syscall.FullPath(path)
+ if err != nil {
+ return "", err
+ }
+ return Clean(fullPath), nil
+}
+
+func join(elem []string) string {
+ for i, e := range elem {
+ if e != "" {
+ return joinNonEmpty(elem[i:])
+ }
+ }
+ return ""
+}
+
+// joinNonEmpty is like join, but it assumes that the first element is non-empty.
+func joinNonEmpty(elem []string) string {
+ if len(elem[0]) == 2 && elem[0][1] == ':' {
+ // First element is drive letter without terminating slash.
+ // Keep path relative to current directory on that drive.
+ // Skip empty elements.
+ i := 1
+ for ; i < len(elem); i++ {
+ if elem[i] != "" {
+ break
+ }
+ }
+ return Clean(elem[0] + strings.Join(elem[i:], string(Separator)))
+ }
+ // The following logic prevents Join from inadvertently creating a
+ // UNC path on Windows. Unless the first element is a UNC path, Join
+ // shouldn't create a UNC path. See golang.org/issue/9167.
+ p := Clean(strings.Join(elem, string(Separator)))
+ if !isUNC(p) {
+ return p
+ }
+ // p == UNC only allowed when the first element is a UNC path.
+ head := Clean(elem[0])
+ if isUNC(head) {
+ return p
+ }
+ // head + tail == UNC, but joining two non-UNC paths should not result
+ // in a UNC path. Undo creation of UNC path.
+ tail := Clean(strings.Join(elem[1:], string(Separator)))
+ if head[len(head)-1] == Separator {
+ return head + tail
+ }
+ return head + string(Separator) + tail
+}
+
+// isUNC reports whether path is a UNC path.
+func isUNC(path string) bool {
+ return volumeNameLen(path) > 2
+}
+
+func sameWord(a, b string) bool {
+ return strings.EqualFold(a, b)
+}