github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/path/filepath/path_windows.go (about) 1 // Copyright 2010 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. 4 5 package filepath 6 7 import ( 8 "strings" 9 "syscall" 10 ) 11 12 func isSlash(c uint8) bool { 13 return c == '\\' || c == '/' 14 } 15 16 // IsAbs reports whether the path is absolute. 17 func IsAbs(path string) (b bool) { 18 l := volumeNameLen(path) 19 if l == 0 { 20 return false 21 } 22 path = path[l:] 23 if path == "" { 24 return false 25 } 26 return isSlash(path[0]) 27 } 28 29 // volumeNameLen returns length of the leading volume name on Windows. 30 // It returns 0 elsewhere. 31 func volumeNameLen(path string) int { 32 if len(path) < 2 { 33 return 0 34 } 35 // with drive letter 36 c := path[0] 37 if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { 38 return 2 39 } 40 // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx 41 if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) && 42 !isSlash(path[2]) && path[2] != '.' { 43 // first, leading `\\` and next shouldn't be `\`. its server name. 44 for n := 3; n < l-1; n++ { 45 // second, next '\' shouldn't be repeated. 46 if isSlash(path[n]) { 47 n++ 48 // third, following something characters. its share name. 49 if !isSlash(path[n]) { 50 if path[n] == '.' { 51 break 52 } 53 for ; n < l; n++ { 54 if isSlash(path[n]) { 55 break 56 } 57 } 58 return n 59 } 60 break 61 } 62 } 63 } 64 return 0 65 } 66 67 // HasPrefix exists for historical compatibility and should not be used. 68 // 69 // Deprecated: HasPrefix does not respect path boundaries and 70 // does not ignore case when required. 71 func HasPrefix(p, prefix string) bool { 72 if strings.HasPrefix(p, prefix) { 73 return true 74 } 75 return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) 76 } 77 78 func splitList(path string) []string { 79 // The same implementation is used in LookPath in os/exec; 80 // consider changing os/exec when changing this. 81 82 if path == "" { 83 return []string{} 84 } 85 86 // Split path, respecting but preserving quotes. 87 list := []string{} 88 start := 0 89 quo := false 90 for i := 0; i < len(path); i++ { 91 switch c := path[i]; { 92 case c == '"': 93 quo = !quo 94 case c == ListSeparator && !quo: 95 list = append(list, path[start:i]) 96 start = i + 1 97 } 98 } 99 list = append(list, path[start:]) 100 101 // Remove quotes. 102 for i, s := range list { 103 if strings.Contains(s, `"`) { 104 list[i] = strings.Replace(s, `"`, ``, -1) 105 } 106 } 107 108 return list 109 } 110 111 func abs(path string) (string, error) { 112 fullPath, err := syscall.FullPath(path) 113 if err != nil { 114 return "", err 115 } 116 return Clean(fullPath), nil 117 } 118 119 func join(elem []string) string { 120 for i, e := range elem { 121 if e != "" { 122 return joinNonEmpty(elem[i:]) 123 } 124 } 125 return "" 126 } 127 128 // joinNonEmpty is like join, but it assumes that the first element is non-empty. 129 func joinNonEmpty(elem []string) string { 130 if len(elem[0]) == 2 && elem[0][1] == ':' { 131 // First element is drive letter without terminating slash. 132 // Keep path relative to current directory on that drive. 133 return Clean(elem[0] + strings.Join(elem[1:], string(Separator))) 134 } 135 // The following logic prevents Join from inadvertently creating a 136 // UNC path on Windows. Unless the first element is a UNC path, Join 137 // shouldn't create a UNC path. See golang.org/issue/9167. 138 p := Clean(strings.Join(elem, string(Separator))) 139 if !isUNC(p) { 140 return p 141 } 142 // p == UNC only allowed when the first element is a UNC path. 143 head := Clean(elem[0]) 144 if isUNC(head) { 145 return p 146 } 147 // head + tail == UNC, but joining two non-UNC paths should not result 148 // in a UNC path. Undo creation of UNC path. 149 tail := Clean(strings.Join(elem[1:], string(Separator))) 150 if head[len(head)-1] == Separator { 151 return head + tail 152 } 153 return head + string(Separator) + tail 154 } 155 156 // isUNC reports whether path is a UNC path. 157 func isUNC(path string) bool { 158 return volumeNameLen(path) > 2 159 } 160 161 func sameWord(a, b string) bool { 162 return strings.EqualFold(a, b) 163 }