Skip to content

Commit e57d358

Browse files
authored
Merge pull request #399 from laozc/wmi-library-filesystem-api
feat: Use Win32 API to implement Filesystem API to reduce PowerShell overhead (library version)
2 parents b6f7ad7 + e2b10c4 commit e57d358

File tree

5 files changed

+567
-65
lines changed

5 files changed

+567
-65
lines changed

pkg/filesystem/hostapi/hostapi.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"fmt"
55
"os"
66
"path/filepath"
7-
"strings"
87

98
"github.com/kubernetes-csi/csi-proxy/v2/pkg/utils"
109
)
@@ -49,17 +48,6 @@ func (filesystemAPI) PathExists(path string) (bool, error) {
4948
return pathExists(path)
5049
}
5150

52-
func pathValid(path string) (bool, error) {
53-
cmd := `Test-Path $Env:remotepath`
54-
cmdEnv := fmt.Sprintf("remotepath=%s", path)
55-
output, err := utils.RunPowershellCmd(cmd, cmdEnv)
56-
if err != nil {
57-
return false, fmt.Errorf("returned output: %s, error: %v", string(output), err)
58-
}
59-
60-
return strings.HasPrefix(strings.ToLower(string(output)), "true"), nil
61-
}
62-
6351
// PathValid determines whether all elements of a path exist
6452
//
6553
// https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/test-path?view=powershell-7
@@ -68,7 +56,7 @@ func pathValid(path string) (bool, error) {
6856
//
6957
// e.g. in a SMB server connection, if password is changed, connection will be lost, this func will return false
7058
func (filesystemAPI) PathValid(path string) (bool, error) {
71-
return pathValid(path)
59+
return utils.IsPathValid(path)
7260
}
7361

7462
// Mkdir makes a dir with `os.MkdirAll`.
@@ -124,18 +112,23 @@ func (filesystemAPI) IsSymlink(tgt string) (bool, error) {
124112
// This code is similar to k8s.io/kubernetes/pkg/util/mount except the pathExists usage.
125113
// Also in a remote call environment the os error cannot be passed directly back, hence the callers
126114
// are expected to perform the isExists check before calling this call in CSI proxy.
127-
stat, err := os.Lstat(tgt)
115+
isSymlink, err := utils.IsPathSymlink(tgt)
116+
if err != nil {
117+
return false, err
118+
}
119+
120+
// mounted folder created by SetVolumeMountPoint may still report ModeSymlink == 0
121+
mountedFolder, err := utils.IsMountedFolder(tgt)
128122
if err != nil {
129123
return false, err
130124
}
131125

132-
// If its a link and it points to an existing file then its a mount point.
133-
if stat.Mode()&os.ModeSymlink != 0 {
126+
if isSymlink || mountedFolder {
134127
target, err := os.Readlink(tgt)
135128
if err != nil {
136129
return false, fmt.Errorf("readlink error: %v", err)
137130
}
138-
exists, err := pathExists(target)
131+
exists, err := utils.PathExists(target)
139132
if err != nil {
140133
return false, err
141134
}

pkg/filesystem/hostapi/hostapi_test.go

Lines changed: 0 additions & 37 deletions
This file was deleted.

pkg/system/hostapi/hostapi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const (
3535
var (
3636
serviceStateCheckInternal = 200 * time.Millisecond
3737
serviceStateCheckTimeout = 30 * time.Second
38-
errTimedOut = errors.New("Timed out")
38+
errTimedOut = errors.New("timed out")
3939
)
4040

4141
type ServiceManager interface {

pkg/utils/utils.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package utils
33
import (
44
"fmt"
55
"os"
6-
"os/exec"
76
"strings"
87

98
"github.com/pkg/errors"
@@ -18,22 +17,33 @@ const (
1817
LongPathPrefix = `\\?\`
1918
)
2019

21-
func RunPowershellCmd(command string, envs ...string) ([]byte, error) {
22-
command = fmt.Sprintf("$global:ProgressPreference = 'SilentlyContinue'; %s", command)
23-
cmd := exec.Command("powershell", "-Mta", "-NoProfile", "-Command", command)
24-
cmd.Env = append(os.Environ(), envs...)
25-
klog.V(8).Infof("Executing command: %q", cmd.String())
26-
out, err := cmd.CombinedOutput()
27-
return out, err
28-
}
29-
3020
func EnsureLongPath(path string) string {
3121
if !strings.HasPrefix(path, LongPathPrefix) {
3222
path = LongPathPrefix + path
3323
}
3424
return path
3525
}
3626

27+
func IsPathValid(path string) (bool, error) {
28+
pathString, err := windows.UTF16PtrFromString(path)
29+
if err != nil {
30+
return false, fmt.Errorf("invalid path: %w", err)
31+
}
32+
33+
attrs, err := windows.GetFileAttributes(pathString)
34+
if err != nil {
35+
if errors.Is(err, windows.ERROR_PATH_NOT_FOUND) || errors.Is(err, windows.ERROR_FILE_NOT_FOUND) || errors.Is(err, windows.ERROR_INVALID_NAME) {
36+
return false, nil
37+
}
38+
39+
// GetFileAttribute returns user or password incorrect for a disconnected SMB connection after the password is changed
40+
return false, fmt.Errorf("failed to get path %s attribute: %w", path, err)
41+
}
42+
43+
klog.V(6).Infof("Path %s attribute: %O", path, attrs)
44+
return attrs != windows.INVALID_FILE_ATTRIBUTES, nil
45+
}
46+
3747
// IsMountedFolder checks whether the `path` is a mounted folder.
3848
func IsMountedFolder(path string) (bool, error) {
3949
// https://learn.microsoft.com/en-us/windows/win32/fileio/determining-whether-a-directory-is-a-volume-mount-point

0 commit comments

Comments
 (0)