-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25151 from l0rd/fix-evalsymlink-windows-option3
Safer use of `filepath.EvalSymlinks()` on Windows
- Loading branch information
Showing
2 changed files
with
139 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
//go:build windows | ||
|
||
package machine | ||
|
||
import ( | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
// CreateNewItemWithPowerShell creates a new item using PowerShell. | ||
// It's an helper to easily create junctions on Windows (as well as other file types). | ||
// It constructs a PowerShell command to create a new item at the specified path with the given item type. | ||
// If a target is provided, it includes it in the command. | ||
// | ||
// Parameters: | ||
// - t: The testing.T instance. | ||
// - path: The path where the new item will be created. | ||
// - itemType: The type of the item to be created (e.g., "File", "SymbolicLink", "Junction"). | ||
// - target: The target for the new item, if applicable. | ||
func CreateNewItemWithPowerShell(t *testing.T, path string, itemType string, target string) { | ||
var pwshCmd string | ||
pwshCmd = "New-Item -Path " + path + " -ItemType " + itemType | ||
if target != "" { | ||
pwshCmd += " -Target " + target | ||
} | ||
cmd := exec.Command("pwsh", "-Command", pwshCmd) | ||
cmd.Stdout = os.Stdout | ||
cmd.Stderr = os.Stderr | ||
err := cmd.Run() | ||
require.NoError(t, err) | ||
} | ||
|
||
// TestEvalSymlinksOrClean tests the EvalSymlinksOrClean function. | ||
// In particular it verifies that EvalSymlinksOrClean behaves as | ||
// filepath.EvalSymlink before Go 1.23 - with the exception of | ||
// files under a mount point (juntion) that aren't resolved | ||
// anymore. | ||
// The old behavior of filepath.EvalSymlinks can be tested with | ||
// the directive "//go:debug winsymlink=0" and replacing EvalSymlinksOrClean() | ||
// with filepath.EvalSymlink(). | ||
func TestEvalSymlinksOrClean(t *testing.T) { | ||
// Create a temporary directory to store the normal file | ||
normalFileDir := t.TempDir() | ||
|
||
// Create a temporary directory to store the (hard/sym)link files | ||
linkFilesDir := t.TempDir() | ||
|
||
// Create a temporary directory where the mount point will be created | ||
mountPointDir := t.TempDir() | ||
|
||
// Create a normal file | ||
normalFile := filepath.Join(normalFileDir, "testFile") | ||
CreateNewItemWithPowerShell(t, normalFile, "File", "") | ||
|
||
// Create a symlink file | ||
symlinkFile := filepath.Join(linkFilesDir, "testSymbolicLink") | ||
CreateNewItemWithPowerShell(t, symlinkFile, "SymbolicLink", normalFile) | ||
|
||
// Create a hardlink file | ||
hardlinkFile := filepath.Join(linkFilesDir, "testHardLink") | ||
CreateNewItemWithPowerShell(t, hardlinkFile, "HardLink", normalFile) | ||
|
||
// Create a mount point file | ||
mountPoint := filepath.Join(mountPointDir, "testJunction") | ||
mountPointFile := filepath.Join(mountPoint, "testFile") | ||
CreateNewItemWithPowerShell(t, mountPoint, "Junction", normalFileDir) | ||
|
||
// Replaces the backslashes with forward slashes in the normal file path | ||
normalFileWithBadSeparators := filepath.ToSlash(normalFile) | ||
|
||
tests := []struct { | ||
name string | ||
filePath string | ||
want string | ||
}{ | ||
{ | ||
name: "Normal file", | ||
filePath: normalFile, | ||
want: normalFile, | ||
}, | ||
{ | ||
name: "File under a mount point (juntion)", | ||
filePath: mountPointFile, | ||
want: mountPointFile, | ||
}, | ||
{ | ||
name: "Symbolic link", | ||
filePath: symlinkFile, | ||
want: normalFile, | ||
}, | ||
{ | ||
name: "Hard link", | ||
filePath: hardlinkFile, | ||
want: hardlinkFile, | ||
}, | ||
{ | ||
name: "Bad separators in path", | ||
filePath: normalFileWithBadSeparators, | ||
want: normalFile, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
assert := assert.New(t) | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, err := EvalSymlinksOrClean(tt.filePath) | ||
require.NoError(t, err) | ||
assert.Equal(tt.want, got) | ||
}) | ||
} | ||
} |