homebox/backend/pkgs/pathlib/pathlib.go

66 lines
1.4 KiB
Go
Raw Permalink Normal View History

// Package pathlib provides a way to safely create a file path without overwriting any existing files.
package pathlib
import (
"fmt"
"os"
"path/filepath"
"strings"
)
type dirReaderFunc func(name string) []string
var dirReader dirReaderFunc = func(directory string) []string {
f, err := os.Open(directory)
if err != nil {
return nil
}
defer func() { _ = f.Close() }()
names, err := f.Readdirnames(-1)
if err != nil {
return nil
}
return names
}
func hasConflict(path string, neighbors []string) bool {
filename := strings.ToLower(filepath.Base(path))
for _, n := range neighbors {
if strings.ToLower(n) == filename {
return true
}
}
return false
}
// Safe will take a destination path and return a validated path that is safe to use.
// without overwriting any existing files. If a conflict exists, it will append a number
// to the end of the file name. If the parent directory does not exist this function will
// return the original path.
func Safe(path string) string {
parent := filepath.Dir(path)
neighbors := dirReader(parent)
if neighbors == nil {
return path
}
if hasConflict(path, neighbors) {
ext := filepath.Ext(path)
name := strings.TrimSuffix(filepath.Base(path), ext)
for i := 1; i < 1000; i++ {
newName := fmt.Sprintf("%s (%d)%s", name, i, ext)
newPath := filepath.Join(parent, newName)
if !hasConflict(newPath, neighbors) {
return newPath
}
}
}
return path
}