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