parent
8b15624f7d
commit
ee6516aa31
@ -12,12 +12,12 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setup(t *testing.T) (Filesystem, string) {
|
func setup(t *testing.T) (*BasicFilesystem, string) {
|
||||||
|
t.Helper()
|
||||||
dir, err := ioutil.TempDir("", "")
|
dir, err := ioutil.TempDir("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -304,38 +304,6 @@ func TestUsage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWindowsPaths(t *testing.T) {
|
|
||||||
if runtime.GOOS != "windows" {
|
|
||||||
t.Skip("Not useful on non-Windows")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
input string
|
|
||||||
expectedRoot string
|
|
||||||
expectedURI string
|
|
||||||
}{
|
|
||||||
{`e:\`, `\\?\e:\`, `e:\`},
|
|
||||||
{`\\?\e:\`, `\\?\e:\`, `e:\`},
|
|
||||||
{`\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
|
||||||
fs := newBasicFilesystem(testCase.input)
|
|
||||||
if fs.root != testCase.expectedRoot {
|
|
||||||
t.Errorf("root %q != %q", fs.root, testCase.expectedRoot)
|
|
||||||
}
|
|
||||||
if fs.URI() != testCase.expectedURI {
|
|
||||||
t.Errorf("uri %q != %q", fs.URI(), testCase.expectedURI)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fs := newBasicFilesystem(`relative\path`)
|
|
||||||
if fs.root == `relative\path` || !strings.HasPrefix(fs.root, "\\\\?\\") {
|
|
||||||
t.Errorf("%q == %q, expected absolutification", fs.root, `relative\path`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRooted(t *testing.T) {
|
func TestRooted(t *testing.T) {
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
root string
|
root string
|
||||||
|
|||||||
@ -51,3 +51,7 @@ func (f *BasicFilesystem) Hide(name string) error {
|
|||||||
func (f *BasicFilesystem) Roots() ([]string, error) {
|
func (f *BasicFilesystem) Roots() ([]string, error) {
|
||||||
return []string{"/"}, nil
|
return []string{"/"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *BasicFilesystem) resolveWin83(absPath string) string {
|
||||||
|
return absPath
|
||||||
|
}
|
||||||
|
|||||||
@ -117,5 +117,5 @@ func (f *BasicFilesystem) unrootedChecked(absPath string) string {
|
|||||||
if !strings.HasPrefix(absPath, f.rootSymlinkEvaluated) {
|
if !strings.HasPrefix(absPath, f.rootSymlinkEvaluated) {
|
||||||
panic(fmt.Sprintf("bug: Notify backend is processing a change outside of the filesystem root: root==%v, rootSymEval==%v, path==%v", f.root, f.rootSymlinkEvaluated, absPath))
|
panic(fmt.Sprintf("bug: Notify backend is processing a change outside of the filesystem root: root==%v, rootSymEval==%v, path==%v", f.root, f.rootSymlinkEvaluated, absPath))
|
||||||
}
|
}
|
||||||
return f.unrootedSymlinkEvaluated(absPath)
|
return f.unrootedSymlinkEvaluated(f.resolveWin83(absPath))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -150,3 +151,39 @@ func (f *BasicFilesystem) Roots() ([]string, error) {
|
|||||||
|
|
||||||
return drives, nil
|
return drives, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *BasicFilesystem) resolveWin83(absPath string) string {
|
||||||
|
if !isMaybeWin83(absPath) {
|
||||||
|
return absPath
|
||||||
|
}
|
||||||
|
if in, err := syscall.UTF16FromString(absPath); err == nil {
|
||||||
|
out := make([]uint16, 4*len(absPath)) // *2 for UTF16 and *2 to double path length
|
||||||
|
if n, err := syscall.GetLongPathName(&in[0], &out[0], uint32(len(out))); err == nil {
|
||||||
|
if n <= uint32(len(out)) {
|
||||||
|
return syscall.UTF16ToString(out[:n])
|
||||||
|
}
|
||||||
|
out = make([]uint16, n)
|
||||||
|
if _, err = syscall.GetLongPathName(&in[0], &out[0], n); err == nil {
|
||||||
|
return syscall.UTF16ToString(out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Failed getting the long path. Return the part of the path which is
|
||||||
|
// already a long path.
|
||||||
|
for absPath = filepath.Dir(absPath); strings.HasPrefix(absPath, f.rootSymlinkEvaluated); absPath = filepath.Dir(absPath) {
|
||||||
|
if !isMaybeWin83(absPath) {
|
||||||
|
return absPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return f.rootSymlinkEvaluated
|
||||||
|
}
|
||||||
|
|
||||||
|
func isMaybeWin83(absPath string) bool {
|
||||||
|
if !strings.Contains(absPath, "~") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if strings.Contains(filepath.Dir(absPath), "~") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return strings.Contains(strings.TrimPrefix(filepath.Base(absPath), WindowsTempPrefix), "~")
|
||||||
|
}
|
||||||
|
|||||||
92
lib/fs/basicfs_windows_test.go
Normal file
92
lib/fs/basicfs_windows_test.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
// Copyright (C) 2018 The Syncthing Authors.
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||||
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package fs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWindowsPaths(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
input string
|
||||||
|
expectedRoot string
|
||||||
|
expectedURI string
|
||||||
|
}{
|
||||||
|
{`e:\`, `\\?\e:\`, `e:\`},
|
||||||
|
{`\\?\e:\`, `\\?\e:\`, `e:\`},
|
||||||
|
{`\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
fs := newBasicFilesystem(testCase.input)
|
||||||
|
if fs.root != testCase.expectedRoot {
|
||||||
|
t.Errorf("root %q != %q", fs.root, testCase.expectedRoot)
|
||||||
|
}
|
||||||
|
if fs.URI() != testCase.expectedURI {
|
||||||
|
t.Errorf("uri %q != %q", fs.URI(), testCase.expectedURI)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs := newBasicFilesystem(`relative\path`)
|
||||||
|
if fs.root == `relative\path` || !strings.HasPrefix(fs.root, "\\\\?\\") {
|
||||||
|
t.Errorf("%q == %q, expected absolutification", fs.root, `relative\path`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveWindows83(t *testing.T) {
|
||||||
|
fs, dir := setup(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
shortAbs, _ := fs.rooted("LFDATA~1")
|
||||||
|
long := "LFDataTool"
|
||||||
|
longAbs, _ := fs.rooted(long)
|
||||||
|
deleted, _ := fs.rooted(filepath.Join("foo", "LFDATA~1"))
|
||||||
|
notShort, _ := fs.rooted(filepath.Join("foo", "bar", "baz"))
|
||||||
|
|
||||||
|
fd, err := fs.Create(long)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fd.Close()
|
||||||
|
|
||||||
|
if res := fs.resolveWin83(shortAbs); res != longAbs {
|
||||||
|
t.Errorf(`Resolving for 8.3 names of "%v" resulted in "%v", expected "%v"`, shortAbs, res, longAbs)
|
||||||
|
}
|
||||||
|
if res := fs.resolveWin83(deleted); res != filepath.Dir(deleted) {
|
||||||
|
t.Errorf(`Resolving for 8.3 names of "%v" resulted in "%v", expected "%v"`, deleted, res, filepath.Dir(deleted))
|
||||||
|
}
|
||||||
|
if res := fs.resolveWin83(notShort); res != notShort {
|
||||||
|
t.Errorf(`Resolving for 8.3 names of "%v" resulted in "%v", expected "%v"`, notShort, res, notShort)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsWindows83(t *testing.T) {
|
||||||
|
fs, dir := setup(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
tempTop, _ := fs.rooted(TempName("baz"))
|
||||||
|
tempBelow, _ := fs.rooted(filepath.Join("foo", "bar", TempName("baz")))
|
||||||
|
short, _ := fs.rooted(filepath.Join("LFDATA~1", TempName("baz")))
|
||||||
|
tempAndShort, _ := fs.rooted(filepath.Join("LFDATA~1", TempName("baz")))
|
||||||
|
|
||||||
|
for _, f := range []string{tempTop, tempBelow} {
|
||||||
|
if isMaybeWin83(f) {
|
||||||
|
t.Errorf(`"%v" is not a windows 8.3 path"`, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range []string{short, tempAndShort} {
|
||||||
|
if !isMaybeWin83(f) {
|
||||||
|
t.Errorf(`"%v" is not a windows 8.3 path"`, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user