mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-22 10:58:57 +00:00
With this change, error messages include the offending characters or name parts. Examples: nul.txt: name is invalid, contains Windows reserved name: "nul" foo>bar.txt: name is invalid, contains Windows reserved character: ">" foo \bar.txt: name is invalid, must not end in space or period on Windows
This commit is contained in:
parent
6ff5ed6d23
commit
c44de2cd58
@ -22,8 +22,8 @@ import (
|
||||
var (
|
||||
errInvalidFilenameEmpty = errors.New("name is invalid, must not be empty")
|
||||
errInvalidFilenameWindowsSpacePeriod = errors.New("name is invalid, must not end in space or period on Windows")
|
||||
errInvalidFilenameWindowsReservedName = errors.New("name is invalid, contains Windows reserved name (NUL, COM1, etc.)")
|
||||
errInvalidFilenameWindowsReservedChar = errors.New("name is invalid, contains Windows reserved character (?, *, etc.)")
|
||||
errInvalidFilenameWindowsReservedName = errors.New("name is invalid, contains Windows reserved name")
|
||||
errInvalidFilenameWindowsReservedChar = errors.New("name is invalid, contains Windows reserved character")
|
||||
)
|
||||
|
||||
type OptionJunctionsAsDirs struct{}
|
||||
|
@ -54,8 +54,8 @@ const windowsDisallowedCharacters = (`<>:"|?*` +
|
||||
|
||||
func WindowsInvalidFilename(name string) error {
|
||||
// The path must not contain any disallowed characters.
|
||||
if strings.ContainsAny(name, windowsDisallowedCharacters) {
|
||||
return errInvalidFilenameWindowsReservedChar
|
||||
if idx := strings.IndexAny(name, windowsDisallowedCharacters); idx != -1 {
|
||||
return fmt.Errorf("%w: %q", errInvalidFilenameWindowsReservedChar, name[idx:idx+1])
|
||||
}
|
||||
|
||||
// None of the path components should end in space or period, or be a
|
||||
@ -72,8 +72,8 @@ func WindowsInvalidFilename(name string) error {
|
||||
// Names ending in space or period are not valid.
|
||||
return errInvalidFilenameWindowsSpacePeriod
|
||||
}
|
||||
if windowsIsReserved(part) {
|
||||
return errInvalidFilenameWindowsReservedName
|
||||
if reserved := windowsReservedNamePart(part); reserved != "" {
|
||||
return fmt.Errorf("%w: %q", errInvalidFilenameWindowsReservedName, reserved)
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,13 +117,13 @@ func SanitizePath(path string) string {
|
||||
}
|
||||
|
||||
path = strings.TrimSpace(b.String())
|
||||
if windowsIsReserved(path) {
|
||||
if reserved := windowsReservedNamePart(path); reserved != "" {
|
||||
path = "-" + path
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func windowsIsReserved(part string) bool {
|
||||
func windowsReservedNamePart(part string) string {
|
||||
// nul.txt.jpg is also disallowed.
|
||||
dot := strings.IndexByte(part, '.')
|
||||
if dot != -1 {
|
||||
@ -132,7 +132,7 @@ func windowsIsReserved(part string) bool {
|
||||
|
||||
// Check length to skip allocating ToUpper.
|
||||
if len(part) != 3 && len(part) != 4 {
|
||||
return false
|
||||
return ""
|
||||
}
|
||||
|
||||
// COM0 and LPT0 are missing from the Microsoft docs,
|
||||
@ -144,9 +144,9 @@ func windowsIsReserved(part string) bool {
|
||||
"COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT0", "LPT1", "LPT2", "LPT3", "LPT4",
|
||||
"LPT5", "LPT6", "LPT7", "LPT8", "LPT9":
|
||||
return true
|
||||
return part
|
||||
}
|
||||
return false
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsParent compares paths purely lexicographically, meaning it returns false
|
||||
|
@ -7,6 +7,7 @@
|
||||
package fs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"unicode"
|
||||
@ -69,9 +70,10 @@ func TestWindowsInvalidFilename(t *testing.T) {
|
||||
|
||||
for _, tc := range cases {
|
||||
err := WindowsInvalidFilename(tc.name)
|
||||
if err != tc.err {
|
||||
if !errors.Is(err, tc.err) {
|
||||
t.Errorf("For %q, got %v, expected %v", tc.name, err, tc.err)
|
||||
}
|
||||
t.Logf("%s: %v", tc.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,9 +126,11 @@ func benchmarkWindowsInvalidFilename(b *testing.B, name string) {
|
||||
WindowsInvalidFilename(name)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWindowsInvalidFilenameValid(b *testing.B) {
|
||||
benchmarkWindowsInvalidFilename(b, "License.txt.gz")
|
||||
}
|
||||
|
||||
func BenchmarkWindowsInvalidFilenameNUL(b *testing.B) {
|
||||
benchmarkWindowsInvalidFilename(b, "nul.txt.gz")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user