local: fix encoding of root path

fix #7824
Statements like rclone copy <somewhere> . will spontaneously miss
if . expands to a path with a Full Width replacement character.
This is due to the incorrect order in which
relative paths and decoding were handled in the original implementation.
This commit is contained in:
URenko 2024-05-09 18:50:08 +00:00 committed by Nick Craig-Wood
parent 2a615f4681
commit e1b7bf7701

View File

@ -1568,34 +1568,49 @@ func (o *Object) SetMetadata(ctx context.Context, metadata fs.Metadata) error {
} }
func cleanRootPath(s string, noUNC bool, enc encoder.MultiEncoder) string { func cleanRootPath(s string, noUNC bool, enc encoder.MultiEncoder) string {
if runtime.GOOS != "windows" || !strings.HasPrefix(s, "\\") { var vol string
if !filepath.IsAbs(s) {
s2, err := filepath.Abs(s)
if err == nil {
s = s2
}
} else {
s = filepath.Clean(s)
}
}
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
s = filepath.ToSlash(s) vol = filepath.VolumeName(s)
vol := filepath.VolumeName(s)
if vol == `\\?` && len(s) >= 6 { if vol == `\\?` && len(s) >= 6 {
// `\\?\C:` // `\\?\C:`
vol = s[:6] vol = s[:6]
} }
s = vol + enc.FromStandardPath(s[len(vol):]) s = s[len(vol):]
}
// Don't use FromStandardPath. Make sure Dot (`.`, `..`) as name will not be reencoded
// Take care of the case Standard: .// (the first dot means current directory)
if enc != encoder.Standard {
s = filepath.ToSlash(s)
parts := strings.Split(s, "/")
encoded := make([]string, len(parts))
changed := false
for i, p := range parts {
if (p == ".") || (p == "..") {
encoded[i] = p
continue
}
part := enc.FromStandardName(p)
changed = changed || part != p
encoded[i] = part
}
if changed {
s = strings.Join(encoded, "/")
}
s = filepath.FromSlash(s) s = filepath.FromSlash(s)
}
if runtime.GOOS == "windows" {
s = vol + s
}
s2, err := filepath.Abs(s)
if err == nil {
s = s2
}
if !noUNC { if !noUNC {
// Convert to UNC // Convert to UNC. It does nothing on non windows platforms.
s = file.UNCPath(s) s = file.UNCPath(s)
} }
return s return s
} }
s = enc.FromStandardPath(s)
return s
}
// Items returns the count of items in this directory or this // Items returns the count of items in this directory or this
// directory and subdirectories if known, -1 for unknown // directory and subdirectories if known, -1 for unknown