github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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 func HasPrefix(p, prefix string) bool { 69 if strings.HasPrefix(p, prefix) { 70 return true 71 } 72 return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) 73 } 74 75 func splitList(path string) []string { 76 // The same implementation is used in LookPath in os/exec; 77 // consider changing os/exec when changing this. 78 79 if path == "" { 80 return []string{} 81 } 82 83 // Split path, respecting but preserving quotes. 84 list := []string{} 85 start := 0 86 quo := false 87 for i := 0; i < len(path); i++ { 88 switch c := path[i]; { 89 case c == '"': 90 quo = !quo 91 case c == ListSeparator && !quo: 92 list = append(list, path[start:i]) 93 start = i + 1 94 } 95 } 96 list = append(list, path[start:]) 97 98 // Remove quotes. 99 for i, s := range list { 100 if strings.Contains(s, `"`) { 101 list[i] = strings.Replace(s, `"`, ``, -1) 102 } 103 } 104 105 return list 106 } 107 108 func abs(path string) (string, error) { 109 fullPath, err := syscall.FullPath(path) 110 if err != nil { 111 return "", err 112 } 113 return Clean(fullPath), nil 114 } 115 116 func join(elem []string) string { 117 for i, e := range elem { 118 if e != "" { 119 return joinNonEmpty(elem[i:]) 120 } 121 } 122 return "" 123 } 124 125 // joinNonEmpty is like join, but it assumes that the first element is non-empty. 126 func joinNonEmpty(elem []string) string { 127 if len(elem[0]) == 2 && elem[0][1] == ':' { 128 // First element is drive letter without terminating slash. 129 // Keep path relative to current directory on that drive. 130 return Clean(elem[0] + strings.Join(elem[1:], string(Separator))) 131 } 132 // The following logic prevents Join from inadvertently creating a 133 // UNC path on Windows. Unless the first element is a UNC path, Join 134 // shouldn't create a UNC path. See golang.org/issue/9167. 135 p := Clean(strings.Join(elem, string(Separator))) 136 if !isUNC(p) { 137 return p 138 } 139 // p == UNC only allowed when the first element is a UNC path. 140 head := Clean(elem[0]) 141 if isUNC(head) { 142 return p 143 } 144 // head + tail == UNC, but joining two non-UNC paths should not result 145 // in a UNC path. Undo creation of UNC path. 146 tail := Clean(strings.Join(elem[1:], string(Separator))) 147 if head[len(head)-1] == Separator { 148 return head + tail 149 } 150 return head + string(Separator) + tail 151 } 152 153 // isUNC reports whether path is a UNC path. 154 func isUNC(path string) bool { 155 return volumeNameLen(path) > 2 156 } 157 158 func sameWord(a, b string) bool { 159 return strings.EqualFold(a, b) 160 }