stash/pkg/fsutil/fs.go
WithoutPants f69bd8a94f
Restructure go project (#2356)
* Move main to cmd
* Move api to internal
* Move logger and manager to internal
* Move shell hiding code to separate package
* Decouple job from desktop and utils
* Decouple session from config
* Move static into internal
* Decouple config from dlna
* Move desktop to internal
* Move dlna to internal
* Decouple remaining packages from config
* Move config into internal
* Move jsonschema and paths to models
* Make ffmpeg functions private
* Move file utility methods into fsutil package
* Move symwalk into fsutil
* Move single-use util functions into client package
* Move slice functions to separate packages
* Add env var to suppress windowsgui arg
* Move hash functions into separate package
* Move identify to internal
* Move autotag to internal
* Touch UI when generating backend
2022-03-17 11:33:59 +11:00

67 lines
2 KiB
Go

package fsutil
import (
"fmt"
"os"
"path/filepath"
"strings"
"unicode"
)
// IsFsPathCaseSensitive checks the fs of the given path to see if it is case sensitive
// if the case sensitivity can not be determined false and an error != nil are returned
func IsFsPathCaseSensitive(path string) (bool, error) {
// The case sensitivity of the fs of "path" is determined by case flipping
// the first letter rune from the base string of the path
// If the resulting flipped path exists then the fs should not be case sensitive
// ( we check the file mod time to avoid matching an existing path )
fi, err := os.Stat(path)
if err != nil { // path cannot be stat'd
return false, err
}
base := filepath.Base(path)
fBase, err := flipCaseSingle(base)
if err != nil { // cannot be case flipped
return false, err
}
i := strings.LastIndex(path, base)
if i < 0 { // shouldn't happen
return false, fmt.Errorf("could not case flip path %s", path)
}
flipped := []byte(path)
for _, c := range []byte(fBase) { // replace base of path with the flipped one ( we need to flip the base or last dir part )
flipped[i] = c
i++
}
fiCase, err := os.Stat(string(flipped))
if err != nil { // cannot stat the case flipped path
return true, nil // fs of path should be case sensitive
}
if fiCase.ModTime() == fi.ModTime() { // file path exists and is the same
return false, nil // fs of path is not case sensitive
}
return false, fmt.Errorf("can not determine case sensitivity of path %s", path)
}
// flipCaseSingle flips the case ( lower<->upper ) of a single char from the string s
// If the string cannot be flipped, the original string value and an error are returned
func flipCaseSingle(s string) (string, error) {
rr := []rune(s)
for i, r := range rr {
if unicode.IsLetter(r) { // look for a letter to flip
if unicode.IsUpper(r) {
rr[i] = unicode.ToLower(r)
return string(rr), nil
}
rr[i] = unicode.ToUpper(r)
return string(rr), nil
}
}
return s, fmt.Errorf("could not case flip string %s", s)
}