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