Skip to content

Commit

Permalink
Merge pull request #525 from essentialkaos/develop
Browse files Browse the repository at this point in the history
Version 13.14.1
  • Loading branch information
andyone authored Dec 3, 2024
2 parents 3cf3361 + cd5e2ea commit 25b8507
Show file tree
Hide file tree
Showing 11 changed files with 428 additions and 336 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Changelog

### [13.14.1](https://kaos.sh/ek/13.14.1)

- `[usage]` Fixed bug with rendering examples (_introduced in `13.14.0`_)
- `[path]` Added Windows support

### [13.14.0](https://kaos.sh/ek/13.14.0)

- `[fmtutil/filetree]` Added experimental package for printing file tree
Expand Down
3 changes: 3 additions & 0 deletions path/example_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build !windows
// +build !windows

package path

// ////////////////////////////////////////////////////////////////////////////////// //
Expand Down
125 changes: 36 additions & 89 deletions path/path.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
//go:build !windows
// +build !windows

// Package path provides methods for working with paths (fully compatible with base path package)
package path

Expand All @@ -15,86 +12,50 @@ import (
"errors"
"fmt"
"os"
PATH "path"
"path/filepath"
"strings"
"syscall"
)

// ////////////////////////////////////////////////////////////////////////////////// //

// ErrBadPattern indicates a globbing pattern was malformed
var ErrBadPattern = errors.New("Syntax error in pattern")

// unsafePaths is slice with unsafe paths
var unsafePaths = []string{
"/lost+found",
"/bin",
"/boot",
"/etc",
"/dev",
"/lib",
"/lib64",
"/proc",
"/root",
"/sbin",
"/selinux",
"/sys",
"/usr/bin",
"/usr/lib",
"/usr/lib64",
"/usr/libexec",
"/usr/sbin",
"/usr/include",
"/var/cache",
"/var/db",
"/var/lib",
}
// ////////////////////////////////////////////////////////////////////////////////// //

var pathSeparator = string(filepath.Separator)

// ////////////////////////////////////////////////////////////////////////////////// //

// Base returns the last element of path
func Base(path string) string {
return PATH.Base(path)
return filepath.Base(path)
}

// Clean returns the shortest path name equivalent to path by purely lexical processing
func Clean(path string) string {
path = evalHome(path)
return PATH.Clean(path)
return filepath.Clean(path)
}

// Dir returns all but the last element of path, typically the path's directory
func Dir(path string) string {
return PATH.Dir(path)
}

// DirN returns first N elements of path
func DirN(path string, n int) string {
if len(path) <= 1 || n == 0 {
return path
}

if n > 0 {
return dirNRight(path, n)
}

return dirNLeft(path, n*-1)
return filepath.Dir(path)
}

// Ext returns the file name extension used by path
func Ext(path string) string {
return PATH.Ext(path)
return filepath.Ext(path)
}

// IsAbs reports whether the path is absolute
func IsAbs(path string) bool {
return PATH.IsAbs(path)
return filepath.IsAbs(path)
}

// Join joins any number of path elements into a single path, adding a separating slash if necessary
func Join(elem ...string) string {
return PATH.Join(elem...)
return filepath.Join(elem...)
}

// JoinSecure joins all elements of path, makes lexical processing, and evaluating all symlinks.
Expand All @@ -109,15 +70,18 @@ func JoinSecure(root string, elem ...string) (string, error) {
}

for _, e := range elem {
result = Clean(result + "/" + e)

if isLink(result) {
result, err = filepath.EvalSymlinks(result)
result = Clean(result + pathSeparator + e)
resultSym, err := filepath.EvalSymlinks(result)

if err != nil {
if err != nil {
if errors.Is(err, os.ErrNotExist) {
resultSym = result
} else {
return "", fmt.Errorf("Can't eval symlinks: %w", err)
}
}

result = resultSym
}

if !strings.HasPrefix(result, root) {
Expand All @@ -129,29 +93,29 @@ func JoinSecure(root string, elem ...string) (string, error) {

// Match reports whether name matches the shell file name pattern
func Match(pattern, name string) (matched bool, err error) {
return PATH.Match(pattern, name)
return filepath.Match(pattern, name)
}

// Split splits path immediately following the final slash, separating it into a directory and file name component
func Split(path string) (dir, file string) {
return PATH.Split(path)
return filepath.Split(path)
}

// Compact converts path to compact representation (e.g /some/random/directory/file.txt → /s/r/d/file.txt)
func Compact(path string) string {
if !strings.Contains(path, "/") {
if !strings.ContainsRune(path, filepath.Separator) {
return path
}

pathSlice := strings.Split(path, "/")
pathSlice := strings.Split(path, pathSeparator)

for i := 0; i < len(pathSlice)-1; i++ {
if len(pathSlice[i]) > 1 {
if len(pathSlice[i]) > 1 && !strings.HasSuffix(pathSlice[i], ":") {
pathSlice[i] = pathSlice[i][0:1]
}
}

return strings.Join(pathSlice, "/")
return strings.Join(pathSlice, pathSeparator)
}

// IsSafe returns true is given path is safe to use (not points to system dirs)
Expand All @@ -162,17 +126,11 @@ func IsSafe(path string) bool {

absPath, err := filepath.Abs(Clean(path))

if err != nil || absPath == "/" {
if err != nil || absPath == pathSeparator {
return false
}

for _, up := range unsafePaths {
if contains(absPath, up) {
return false
}
}

return true
return isSafePath(absPath)
}

// IsDotfile returns true if file name begins with a full stop
Expand All @@ -181,13 +139,13 @@ func IsDotfile(path string) bool {
return false
}

if !strings.Contains(path, "/") {
return path[0:1] == "."
if !strings.ContainsRune(path, filepath.Separator) {
return strings.HasPrefix(path, ".")
}

pathBase := Base(path)

return pathBase[0:1] == "."
return strings.HasPrefix(pathBase, ".")
}

// IsGlob returns true if given pattern is Unix-like glob
Expand Down Expand Up @@ -217,14 +175,14 @@ func IsGlob(pattern string) bool {
// ////////////////////////////////////////////////////////////////////////////////// //

func dirNRight(path string, n int) string {
if path[0] == '/' {
if path[0] == filepath.Separator {
n++
}

var k int

for i, r := range path {
if r == '/' {
if r == filepath.Separator {
k++
}

Expand All @@ -237,14 +195,14 @@ func dirNRight(path string, n int) string {
}

func dirNLeft(path string, n int) string {
if path[len(path)-1] == '/' {
if path[len(path)-1] == filepath.Separator {
n++
}

var k int

for i := len(path) - 1; i > 0; i-- {
if path[i] == '/' {
if path[i] == filepath.Separator {
k++
}

Expand All @@ -256,27 +214,16 @@ func dirNLeft(path string, n int) string {
return path
}

func isLink(path string) bool {
var buf = make([]byte, 1)
_, err := syscall.Readlink(path, buf)

return err == nil
}

func evalHome(path string) string {
if path == "" || path[0:1] != "~" {
return path
}

return os.Getenv("HOME") + path[1:]
}

func contains(path, subpath string) bool {
spl := len(subpath)
homeDir, err := os.UserHomeDir()

if len(path) < spl {
return false
if err != nil {
return path
}

return path[:spl] == subpath
return homeDir + path[1:]
}
69 changes: 69 additions & 0 deletions path/path_posix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//go:build !windows
// +build !windows

package path

// ////////////////////////////////////////////////////////////////////////////////// //
// //
// Copyright (c) 2024 ESSENTIAL KAOS //
// Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0> //
// //
// ////////////////////////////////////////////////////////////////////////////////// //

import "strings"

// ////////////////////////////////////////////////////////////////////////////////// //

// unsafePaths is slice with unsafe paths
var unsafePaths = []string{
"/lost+found",
"/bin",
"/boot",
"/etc",
"/dev",
"/lib",
"/lib64",
"/proc",
"/root",
"/sbin",
"/selinux",
"/sys",
"/usr/bin",
"/usr/lib",
"/usr/lib64",
"/usr/libexec",
"/usr/sbin",
"/usr/include",
"/var/cache",
"/var/db",
"/var/lib",
}

// ////////////////////////////////////////////////////////////////////////////////// //

// DirN returns first N elements of path
func DirN(path string, n int) string {
if strings.Count(path, pathSeparator) < 2 || n == 0 {
return path
}

if n > 0 {
return dirNRight(path, n)
}

return dirNLeft(path, n*-1)
}

// ////////////////////////////////////////////////////////////////////////////////// //

func isSafePath(path string) bool {
for _, p := range unsafePaths {
if strings.HasPrefix(path, p) {
return false
}
}

return true
}

// ////////////////////////////////////////////////////////////////////////////////// //
Loading

0 comments on commit 25b8507

Please sign in to comment.