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  }