Explorar o código

lib/fs: Fix root path handling for Windows (fixes #8778)

Co-authored-by: Jakob Borg <[email protected]>
Ross Smith II %!s(int64=2) %!d(string=hai) anos
pai
achega
3adfe2f91f
Modificáronse 2 ficheiros con 30 adicións e 11 borrados
  1. 7 5
      lib/fs/basicfs.go
  2. 23 6
      lib/fs/basicfs_windows_test.go

+ 7 - 5
lib/fs/basicfs.go

@@ -51,8 +51,10 @@ type BasicFilesystem struct {
 	groupCache      *groupCache
 }
 
-type userCache = valueCache[string, *user.User]
-type groupCache = valueCache[string, *user.Group]
+type (
+	userCache  = valueCache[string, *user.User]
+	groupCache = valueCache[string, *user.Group]
+)
 
 func newBasicFilesystem(root string, opts ...Option) *BasicFilesystem {
 	if root == "" {
@@ -62,11 +64,11 @@ func newBasicFilesystem(root string, opts ...Option) *BasicFilesystem {
 	// The reason it's done like this:
 	// C:          ->  C:\            ->  C:\        (issue that this is trying to fix)
 	// C:\somedir  ->  C:\somedir\    ->  C:\somedir
-	// C:\somedir\ ->  C:\somedir\\   ->  C:\somedir
+	// C:\somedir\ ->  C:\somedir\    ->  C:\somedir
 	// This way in the tests, we get away without OS specific separators
 	// in the test configs.
 	sep := string(filepath.Separator)
-	root = filepath.Dir(root + sep)
+	root = filepath.Clean(filepath.Dir(root + sep))
 
 	// Attempt tilde expansion; leave unchanged in case of error
 	if path, err := ExpandTilde(root); err == nil {
@@ -215,7 +217,7 @@ func (f *BasicFilesystem) DirNames(name string) ([]string, error) {
 	if err != nil {
 		return nil, err
 	}
-	fd, err := os.OpenFile(name, OptReadOnly, 0777)
+	fd, err := os.OpenFile(name, OptReadOnly, 0o777)
 	if err != nil {
 		return nil, err
 	}

+ 23 - 6
lib/fs/basicfs_windows_test.go

@@ -12,29 +12,46 @@ package fs
 import (
 	"os"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"syscall"
 	"testing"
 )
 
 func TestWindowsPaths(t *testing.T) {
-	testCases := []struct {
+	type testCase struct {
 		input        string
 		expectedRoot string
 		expectedURI  string
-	}{
+	}
+	testCases := []testCase{
+		{`e:`, `\\?\e:\`, `e:\`},
 		{`e:\`, `\\?\e:\`, `e:\`},
+		{`e:\\`, `\\?\e:\`, `e:\`},
+		{`\\?\e:`, `\\?\e:\`, `e:\`},
 		{`\\?\e:\`, `\\?\e:\`, `e:\`},
+		{`\\?\e:\\`, `\\?\e:\`, `e:\`},
+		{`e:\x`, `\\?\e:\x`, `e:\x`},
+		{`e:\x\`, `\\?\e:\x`, `e:\x`},
+		{`e:\x\\`, `\\?\e:\x`, `e:\x`},
 		{`\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`, `\\192.0.2.22\network\share`},
 	}
 
-	for _, testCase := range testCases {
+	if runtime.Version() >= "go1.20" {
+		testCases = append(testCases,
+			testCase{`\\.\e:`, `\\.\e:\`, `e:\`},
+			testCase{`\\.\e:\`, `\\.\e:\`, `e:\`},
+			testCase{`\\.\e:\\`, `\\.\e:\`, `e:\`},
+		)
+	}
+
+	for i, testCase := range testCases {
 		fs := newBasicFilesystem(testCase.input)
 		if fs.root != testCase.expectedRoot {
-			t.Errorf("root %q != %q", fs.root, testCase.expectedRoot)
+			t.Errorf("test %d: root: expected `%s`, got `%s`", i, testCase.expectedRoot, fs.root)
 		}
 		if fs.URI() != testCase.expectedURI {
-			t.Errorf("uri %q != %q", fs.URI(), testCase.expectedURI)
+			t.Errorf("test %d: uri: expected `%s`, got `%s`", i, testCase.expectedURI, fs.URI())
 		}
 	}
 
@@ -195,7 +212,7 @@ func TestGetFinalPath(t *testing.T) {
 }
 
 func TestRemoveWindowsDirIcon(t *testing.T) {
-	//Try to delete a folder with a custom icon with os.Remove (simulated by the readonly file attribute)
+	// Try to delete a folder with a custom icon with os.Remove (simulated by the readonly file attribute)
 
 	fs, dir := setup(t)
 	relativePath := "folder_with_icon"