pkg.re/essentialkaos/ek.10@v12.41.0+incompatible/path/path.go (about) 1 //go:build !windows 2 // +build !windows 3 4 // Package path provides methods for working with paths (fully compatible with base path package) 5 package path 6 7 // ////////////////////////////////////////////////////////////////////////////////// // 8 // // 9 // Copyright (c) 2022 ESSENTIAL KAOS // 10 // Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0> // 11 // // 12 // ////////////////////////////////////////////////////////////////////////////////// // 13 14 import ( 15 "errors" 16 "os" 17 PATH "path" 18 "path/filepath" 19 "strings" 20 ) 21 22 // ////////////////////////////////////////////////////////////////////////////////// // 23 24 // ErrBadPattern indicates a globbing pattern was malformed 25 var ErrBadPattern = errors.New("Syntax error in pattern") 26 27 // unsafePaths is slice with unsafe paths 28 var unsafePaths = []string{ 29 "/lost+found", 30 "/bin", 31 "/boot", 32 "/etc", 33 "/dev", 34 "/lib", 35 "/lib64", 36 "/proc", 37 "/root", 38 "/sbin", 39 "/selinux", 40 "/sys", 41 "/usr/bin", 42 "/usr/lib", 43 "/usr/lib64", 44 "/usr/libexec", 45 "/usr/sbin", 46 "/usr/include", 47 "/var/cache", 48 "/var/db", 49 "/var/lib", 50 } 51 52 // ////////////////////////////////////////////////////////////////////////////////// // 53 54 // Base returns the last element of path 55 func Base(path string) string { 56 return PATH.Base(path) 57 } 58 59 // Clean returns the shortest path name equivalent to path by purely lexical processing 60 func Clean(path string) string { 61 path = evalHome(path) 62 return PATH.Clean(path) 63 } 64 65 // Dir returns all but the last element of path, typically the path's directory 66 func Dir(path string) string { 67 return PATH.Dir(path) 68 } 69 70 // DirN returns first N elements of path 71 func DirN(path string, n int) string { 72 if len(path) <= 1 || n < 1 { 73 return path 74 } 75 76 if path[0] == '/' { 77 n++ 78 } 79 80 var k int 81 82 for i, r := range path { 83 if r == '/' { 84 k++ 85 } 86 87 if k == n { 88 return path[:i] 89 } 90 } 91 92 return path 93 } 94 95 // Ext returns the file name extension used by path 96 func Ext(path string) string { 97 return PATH.Ext(path) 98 } 99 100 // IsAbs reports whether the path is absolute 101 func IsAbs(path string) bool { 102 return PATH.IsAbs(path) 103 } 104 105 // Join joins any number of path elements into a single path, adding a separating slash if necessary 106 func Join(elem ...string) string { 107 return PATH.Join(elem...) 108 } 109 110 // Match reports whether name matches the shell file name pattern 111 func Match(pattern, name string) (matched bool, err error) { 112 return PATH.Match(pattern, name) 113 } 114 115 // Split splits path immediately following the final slash, separating it into a directory and file name component 116 func Split(path string) (dir, file string) { 117 return PATH.Split(path) 118 } 119 120 // IsSafe returns true is given path is safe to use (not points to system dirs) 121 func IsSafe(path string) bool { 122 if path == "" { 123 return false 124 } 125 126 absPath, err := filepath.Abs(Clean(path)) 127 128 if err != nil || absPath == "/" { 129 return false 130 } 131 132 for _, up := range unsafePaths { 133 if contains(absPath, up) { 134 return false 135 } 136 } 137 138 return true 139 } 140 141 // IsDotfile returns true if file name begins with a full stop 142 func IsDotfile(path string) bool { 143 if path == "" { 144 return false 145 } 146 147 if !strings.Contains(path, "/") { 148 return path[0:1] == "." 149 } 150 151 pathBase := Base(path) 152 153 return pathBase[0:1] == "." 154 } 155 156 // IsGlob returns true if given pattern is Unix-like glob 157 func IsGlob(pattern string) bool { 158 if pattern == "" { 159 return false 160 } 161 162 var rs bool 163 164 for _, r := range pattern { 165 switch r { 166 case '?', '*': 167 return true 168 case '[': 169 rs = true 170 case ']': 171 if rs { 172 return true 173 } 174 } 175 } 176 177 return false 178 } 179 180 // ////////////////////////////////////////////////////////////////////////////////// // 181 182 func evalHome(path string) string { 183 if path == "" || path[0:1] != "~" { 184 return path 185 } 186 187 return os.Getenv("HOME") + path[1:] 188 } 189 190 func contains(path, subpath string) bool { 191 spl := len(subpath) 192 193 if len(path) < spl { 194 return false 195 } 196 197 return path[:spl] == subpath 198 }