1
0
mirror of https://github.com/rclone/rclone.git synced 2025-01-19 04:47:54 +02:00

Fix windows build - fixes

Try to make clearer the distinction between OS paths and rclone paths
(remotes) so it is harder to muddle them up.
This commit is contained in:
Nick Craig-Wood 2016-08-18 23:16:47 +01:00
parent 84eb7031bb
commit 6089f443b9
4 changed files with 41 additions and 57 deletions

@ -15,6 +15,8 @@ import (
"time"
"unicode/utf8"
"golang.org/x/text/unicode/norm"
"github.com/ncw/rclone/fs"
"github.com/pkg/errors"
)
@ -41,7 +43,7 @@ func init() {
// Fs represents a local filesystem rooted at root
type Fs struct {
name string // the name of the remote
root string // The root directory
root string // The root directory (OS path)
precisionOk sync.Once // Whether we need to read the precision
precision time.Duration // precision of local filesystem
wmu sync.Mutex // used for locking access to 'warned'.
@ -70,7 +72,7 @@ func NewFs(name, root string) (fs.Fs, error) {
warned: make(map[string]struct{}),
nounc: nounc == "true",
}
f.root = f.filterPath(root)
f.root = f.cleanPath(root)
// Check to see if this points to a file
fi, err := os.Lstat(f.root)
@ -100,9 +102,8 @@ func (f *Fs) String() string {
// newObject makes a half completed Object
func (f *Fs) newObject(remote string) *Object {
remote = normString(remote)
dstPath := f.filterPath(filepath.Join(f.root, remote))
remote = filepath.ToSlash(f.cleanUtf8(remote))
dstPath := f.cleanPath(filepath.Join(f.root, remote))
remote = f.cleanRemote(remote)
return &Object{
fs: f,
remote: remote,
@ -175,7 +176,7 @@ func (f *Fs) list(out fs.ListOpts, remote string, dirpath string, level int) (su
if fi.IsDir() {
if out.IncludeDirectory(newRemote) {
dir := &fs.Dir{
Name: normString(f.cleanUtf8(newRemote)),
Name: f.cleanRemote(newRemote),
When: fi.ModTime(),
Bytes: 0,
Count: 0,
@ -207,8 +208,8 @@ func (f *Fs) list(out fs.ListOpts, remote string, dirpath string, level int) (su
// Ignores everything which isn't Storable, eg links etc
func (f *Fs) List(out fs.ListOpts, dir string) {
defer out.Finished()
dir = filterFragment(f.cleanUtf8(dir))
root := filepath.Join(f.root, dir)
root := f.cleanPath(filepath.Join(f.root, dir))
dir = f.cleanRemote(dir)
_, err := os.Stat(root)
if err != nil {
out.SetError(fs.ErrorDirNotFound)
@ -252,10 +253,11 @@ func (f *Fs) List(out fs.ListOpts, dir string) {
wg.Wait()
}
// CleanUtf8 makes string a valid UTF-8 string
// cleanRemote makes string a valid UTF-8 string for remote strings.
//
// Any invalid UTF-8 characters will be replaced with utf8.RuneError
func (f *Fs) cleanUtf8(name string) string {
// It also normalises the UTF-8 and converts the slashes if necessary.
func (f *Fs) cleanRemote(name string) string {
if !utf8.ValidString(name) {
f.wmu.Lock()
if _, ok := f.warned[name]; !ok {
@ -265,9 +267,8 @@ func (f *Fs) cleanUtf8(name string) string {
f.wmu.Unlock()
name = string([]rune(name))
}
if runtime.GOOS == "windows" {
name = cleanWindowsName(f, name)
}
name = norm.NFC.String(name)
name = filepath.ToSlash(name)
return name
}
@ -647,8 +648,8 @@ func (o *Object) Remove() error {
return os.Remove(o.path)
}
// Return the current directory and file from a path
// Assumes os.PathSeparator is used.
// Return the directory and file from an OS path. Assumes
// os.PathSeparator is used.
func getDirFile(s string) (string, string) {
i := strings.LastIndex(s, string(os.PathSeparator))
dir, file := s[:i], s[i+1:]
@ -658,9 +659,9 @@ func getDirFile(s string) (string, string) {
return dir, file
}
// filterFragment cleans a path fragment which is part of a bigger
// path and not necessarily absolute
func filterFragment(s string) string {
// cleanPathFragment cleans an OS path fragment which is part of a
// bigger path and not necessarily absolute
func cleanPathFragment(s string) string {
if s == "" {
return s
}
@ -671,11 +672,16 @@ func filterFragment(s string) string {
return s
}
// filterPath cleans and makes absolute the path passed in.
// cleanPath cleans and makes absolute the path passed in and returns
// an OS path.
//
// On windows it makes the path UNC also.
func (f *Fs) filterPath(s string) string {
s = filterFragment(s)
// The input might be in OS form or rclone form or a mixture, but the
// output is in OS form.
//
// On windows it makes the path UNC also and replaces any characters
// Windows can't deal with with their replacements.
func (f *Fs) cleanPath(s string) string {
s = cleanPathFragment(s)
if runtime.GOOS == "windows" {
if !filepath.IsAbs(s) && !strings.HasPrefix(s, "\\") {
s2, err := filepath.Abs(s)
@ -683,21 +689,19 @@ func (f *Fs) filterPath(s string) string {
s = s2
}
}
if f.nounc {
return s
if !f.nounc {
// Convert to UNC
s = uncPath(s)
}
// Convert to UNC
return uncPath(s)
}
if !filepath.IsAbs(s) {
s2, err := filepath.Abs(s)
if err == nil {
s = s2
s = cleanWindowsName(f, s)
} else {
if !filepath.IsAbs(s) {
s2, err := filepath.Abs(s)
if err == nil {
s = s2
}
}
}
return s
}
@ -726,7 +730,7 @@ func uncPath(s string) string {
return s
}
// cleanWindowsName will clean invalid Windows characters
// cleanWindowsName will clean invalid Windows characters replacing them with _
func cleanWindowsName(f *Fs, name string) string {
original := name
var name2 string

@ -1,12 +0,0 @@
// +build darwin
package local
import (
"golang.org/x/text/unicode/norm"
)
// normString normalises the remote name as some OS X denormalises UTF-8 when storing it to disk
func normString(remote string) string {
return norm.NFC.String(remote)
}

@ -1,8 +0,0 @@
// +build !darwin
package local
// normString normalises the remote name if necessary
func normString(remote string) string {
return remote
}

@ -57,11 +57,11 @@ var utf8Tests = [][2]string{
{string([]byte{'a', 0x80, 'b'}), "a�b"},
}
func TestCleanUtf8(t *testing.T) {
func TestCleanRemote(t *testing.T) {
f := &Fs{}
f.warned = make(map[string]struct{})
for _, test := range utf8Tests {
got := f.cleanUtf8(test[0])
got := f.cleanRemote(test[0])
expect := test[1]
if got != expect {
t.Fatalf("got %q, expected %q", got, expect)