Skip to content

Commit b8ee3d2

Browse files
committed
Replace evalSymlink() with powershell command for subPath_windows.go
In golang, evalSymlink() does not work if windows disk driver letter is not assigned. Replace this function with a powershell command to work around this issue.
1 parent 49c5072 commit b8ee3d2

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

pkg/volume/util/subpath/subpath_windows.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package subpath
2121
import (
2222
"fmt"
2323
"os"
24+
"os/exec"
2425
"path/filepath"
2526
"strings"
2627
"syscall"
@@ -43,18 +44,45 @@ func NewNSEnter(mounter mount.Interface, ne *nsenter.Nsenter, rootDir string) In
4344
return nil
4445
}
4546

47+
// evalPath returns the path name after the evaluation of any symbolic links.
48+
// If the path after evaluation starts with Volume or \??\Volume, it means that it was a symlink from
49+
// volume (represented by volumeID) to the given path. In this case, the given path is returned.
50+
func evalPath(path string) (linkedPath string, err error) {
51+
cmd := fmt.Sprintf("Get-Item -Path %s | Select-Object -ExpandProperty Target", path)
52+
output, err := exec.Command("powershell", "/c", cmd).CombinedOutput()
53+
klog.V(4).Infof("evaluate symlink from %s: %s %v", path, string(output), err)
54+
if err != nil {
55+
return "", err
56+
}
57+
linkedPath = strings.TrimSpace(string(output))
58+
if isVolumePrefix(linkedPath) {
59+
return path, err
60+
}
61+
return linkedPath, err
62+
}
63+
64+
// isVolumePrefix returns true if the given path name starts with "Volume" or volume prefix including
65+
// "\\.\" or "\\?\". Otherwise, it returns false.
66+
func isVolumePrefix(path string) bool {
67+
if strings.HasPrefix(path, "Volume") || strings.HasPrefix(path, "\\\\?\\") || strings.HasPrefix(path, "\\\\.\\") {
68+
return true
69+
}
70+
return false
71+
}
72+
4673
// check whether hostPath is within volume path
4774
// this func will lock all intermediate subpath directories, need to close handle outside of this func after container started
4875
func lockAndCheckSubPath(volumePath, hostPath string) ([]uintptr, error) {
4976
if len(volumePath) == 0 || len(hostPath) == 0 {
5077
return []uintptr{}, nil
5178
}
5279

53-
finalSubPath, err := filepath.EvalSymlinks(hostPath)
80+
finalSubPath, err := evalPath(hostPath)
5481
if err != nil {
55-
return []uintptr{}, fmt.Errorf("cannot read link %s: %s", hostPath, err)
82+
return []uintptr{}, fmt.Errorf("cannot evaluate link %s: %s", hostPath, err)
5683
}
57-
finalVolumePath, err := filepath.EvalSymlinks(volumePath)
84+
85+
finalVolumePath, err := evalPath(volumePath)
5886
if err != nil {
5987
return []uintptr{}, fmt.Errorf("cannot read link %s: %s", volumePath, err)
6088
}
@@ -162,7 +190,7 @@ func (sp *subpath) CleanSubPaths(podDir string, volumeName string) error {
162190

163191
// SafeMakeDir makes sure that the created directory does not escape given base directory mis-using symlinks.
164192
func (sp *subpath) SafeMakeDir(subdir string, base string, perm os.FileMode) error {
165-
realBase, err := filepath.EvalSymlinks(base)
193+
realBase, err := evalPath(base)
166194
if err != nil {
167195
return fmt.Errorf("error resolving symlinks in %s: %s", base, err)
168196
}
@@ -201,11 +229,11 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
201229
}
202230

203231
// Ensure the existing directory is inside allowed base
204-
fullExistingPath, err := filepath.EvalSymlinks(existingPath)
232+
fullExistingPath, err := evalPath(existingPath)
205233
if err != nil {
206234
return fmt.Errorf("error opening existing directory %s: %s", existingPath, err)
207235
}
208-
fullBasePath, err := filepath.EvalSymlinks(base)
236+
fullBasePath, err := evalPath(base)
209237
if err != nil {
210238
return fmt.Errorf("cannot read link %s: %s", base, err)
211239
}

0 commit comments

Comments
 (0)