Add local file system option to disable UNC on Windows.

This will add an option to disable UNC conversion on Windows to deal with buggy file system implementations like EncFS.

Fixes #261
This commit is contained in:
klauspost 2016-01-04 12:28:47 +01:00 committed by Nick Craig-Wood
parent 3f5d8390ba
commit 3c31d711b3
2 changed files with 56 additions and 6 deletions

View File

@ -36,3 +36,37 @@ will emit a debug message in this case (use `-v` to see), eg
```
Local file system at .: Replacing invalid UTF-8 characters in "gro\xdf"
```
### Long paths on Windows ###
Rclone handles long paths automatically, by converting all paths to long
[UNC paths](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath)
which allows paths up to 32,767 characters.
This is why you will see that your paths, for instance `c:\files` is
converted to the UNC path `\\?\c:\files` in the output,
and `\\server\share` is converted to `\\?\UNC\server\share`.
However, in rare cases this may cause problems with buggy file
system drivers like [EncFS](https://github.com/ncw/rclone/issues/261).
To disable UNC conversion globally, add this to your `.rclone.conf` file:
```
[local]
nounc = true
```
If you want to selectively disable UNC, you can add it to a separate entry like this:
```
[nounc]
type = local
nounc = true
```
And use rclone like this:
`rclone copy c:\src nounc:z:\dst`
This will use UNC paths on `c:\src` but not on `z:\dst`.
Of course this will cause problems if the absolute path length of a
file exceeds 258 characters on z, so only use this option if you have to.

View File

@ -22,10 +22,20 @@ import (
// Register with Fs
func init() {
fs.Register(&fs.Info{
fsi := &fs.Info{
Name: "local",
NewFs: NewFs,
})
Options: []fs.Option{fs.Option{
Name: "nounc",
Help: "Disable UNC (long path names) conversion on Windows",
Optional: true,
Examples: []fs.OptionExample{{
Value: "true",
Help: "Disables long file names",
}},
}},
}
fs.Register(fsi)
}
// Fs represents a local filesystem rooted at root
@ -35,6 +45,7 @@ type Fs struct {
precisionOk sync.Once // Whether we need to read the precision
precision time.Duration // precision of local filesystem
warned map[string]struct{} // whether we have warned about this string
nounc bool // Skip UNC conversion on Windows
}
// Object represents a local filesystem object
@ -52,11 +63,13 @@ type Object struct {
func NewFs(name, root string) (fs.Fs, error) {
var err error
nounc, _ := fs.ConfigFile.GetValue(name, "nounc")
f := &Fs{
name: name,
warned: make(map[string]struct{}),
nounc: nounc == "true",
}
f.root = filterPath(f.cleanUtf8(root))
f.root = f.filterPath(f.cleanUtf8(root))
// Check to see if this points to a file
fi, err := os.Lstat(f.root)
@ -89,7 +102,7 @@ func (f *Fs) String() string {
// newFsObject makes a half completed Object
func (f *Fs) newFsObject(remote string) *Object {
remote = filepath.ToSlash(remote)
dstPath := filterPath(filepath.Join(f.root, f.cleanUtf8(remote)))
dstPath := f.filterPath(filepath.Join(f.root, f.cleanUtf8(remote)))
return &Object{
fs: f,
remote: remote,
@ -195,7 +208,7 @@ func (f *Fs) ListDir() fs.DirChan {
Count: 0,
}
// Go down the tree to count the files and directories
dirpath := filterPath(filepath.Join(f.root, item.Name()))
dirpath := f.filterPath(filepath.Join(f.root, item.Name()))
err := filepath.Walk(dirpath, func(path string, fi os.FileInfo, err error) error {
if err != nil {
fs.Stats.Error()
@ -594,7 +607,7 @@ func getDirFile(s string) (string, string) {
return s[:i], s[i+1:]
}
func filterPath(s string) string {
func (f *Fs) filterPath(s string) string {
s = filepath.Clean(s)
if runtime.GOOS == "windows" {
s = strings.Replace(s, `/`, `\`, -1)
@ -606,6 +619,9 @@ func filterPath(s string) string {
}
}
if f.nounc {
return s
}
// Convert to UNC
return uncPath(s)
}