1package filepath 2 3import ( 4 "os" 5 "strings" 6 "syscall" 7) 8 9// HasPrefix exists for historical compatibility and should not be used. 10// 11// Deprecated: HasPrefix does not respect path boundaries and 12// does not ignore case when required. 13func HasPrefix(p, prefix string) bool { 14 if strings.HasPrefix(p, prefix) { 15 return true 16 } 17 return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) 18} 19 20func splitList(path string) []string { 21 // The same implementation is used in LookPath in os/exec; 22 // consider changing os/exec when changing this. 23 24 if path == "" { 25 return []string{} 26 } 27 28 // Split path, respecting but preserving quotes. 29 list := []string{} 30 start := 0 31 quo := false 32 for i := 0; i < len(path); i++ { 33 switch c := path[i]; { 34 case c == '"': 35 quo = !quo 36 case c == ListSeparator && !quo: 37 list = append(list, path[start:i]) 38 start = i + 1 39 } 40 } 41 list = append(list, path[start:]) 42 43 // Remove quotes. 44 for i, s := range list { 45 list[i] = strings.ReplaceAll(s, `"`, ``) 46 } 47 48 return list 49} 50 51func abs(path string) (string, error) { 52 if path == "" { 53 // syscall.FullPath returns an error on empty path, because it's not a valid path. 54 // To implement Abs behavior of returning working directory on empty string input, 55 // special-case empty path by changing it to "." path. See golang.org/issue/24441. 56 path = "." 57 } 58 fullPath, err := syscall.FullPath(path) 59 if err != nil { 60 return "", err 61 } 62 return Clean(fullPath), nil 63} 64 65func join(elem []string) string { 66 var b strings.Builder 67 var lastChar byte 68 for _, e := range elem { 69 switch { 70 case b.Len() == 0: 71 // Add the first non-empty path element unchanged. 72 case os.IsPathSeparator(lastChar): 73 // If the path ends in a slash, strip any leading slashes from the next 74 // path element to avoid creating a UNC path (any path starting with "\\") 75 // from non-UNC elements. 76 // 77 // The correct behavior for Join when the first element is an incomplete UNC 78 // path (for example, "\\") is underspecified. We currently join subsequent 79 // elements so Join("\\", "host", "share") produces "\\host\share". 80 for len(e) > 0 && os.IsPathSeparator(e[0]) { 81 e = e[1:] 82 } 83 // If the path is \ and the next path element is ??, 84 // add an extra .\ to create \.\?? rather than \??\ 85 // (a Root Local Device path). 86 if b.Len() == 1 && strings.HasPrefix(e, "??") && (len(e) == len("??") || os.IsPathSeparator(e[2])) { 87 b.WriteString(`.\`) 88 } 89 case lastChar == ':': 90 // If the path ends in a colon, keep the path relative to the current directory 91 // on a drive and don't add a separator. Preserve leading slashes in the next 92 // path element, which may make the path absolute. 93 // 94 // Join(`C:`, `f`) = `C:f` 95 // Join(`C:`, `\f`) = `C:\f` 96 default: 97 // In all other cases, add a separator between elements. 98 b.WriteByte('\\') 99 lastChar = '\\' 100 } 101 if len(e) > 0 { 102 b.WriteString(e) 103 lastChar = e[len(e)-1] 104 } 105 } 106 if b.Len() == 0 { 107 return "" 108 } 109 return Clean(b.String()) 110} 111 112func sameWord(a, b string) bool { 113 return strings.EqualFold(a, b) 114} 115