feat: Add support for Cwd() on Windows

pull/1163/head
Max Altgelt 4 years ago
parent fb65e185a9
commit a4679b798b
No known key found for this signature in database
GPG Key ID: 52C16AF8F6B69C5A

@ -720,6 +720,22 @@ func Test_IsRunning(t *testing.T) {
} }
} }
func Test_Process_Cwd(t *testing.T) {
myPid := os.Getpid()
currentWorkingDirectory, _ := os.Getwd()
process, _ := NewProcess(int32(myPid))
pidCwd, err := process.Cwd()
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting cwd error %v", err)
}
pidCwd = strings.TrimSuffix(pidCwd, string(os.PathSeparator))
assert.Equal(t, currentWorkingDirectory, pidCwd)
t.Log(pidCwd)
}
func Test_Process_Environ(t *testing.T) { func Test_Process_Environ(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "") tmpdir, err := ioutil.TempDir("", "")
if err != nil { if err != nil {
@ -811,6 +827,23 @@ func Test_AllProcesses_environ(t *testing.T) {
} }
} }
func Test_AllProcesses_Cwd(t *testing.T) {
procs, err := Processes()
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting processes error %v", err)
}
for _, proc := range procs {
exeName, _ := proc.Exe()
cwd, err := proc.Cwd()
if err != nil {
cwd = "Error: " + err.Error()
}
t.Logf("Process #%v: Name: %v / Current Working Directory: %s\n", proc.Pid, exeName, cwd)
}
}
func BenchmarkNewProcess(b *testing.B) { func BenchmarkNewProcess(b *testing.B) {
checkPid := os.Getpid() checkPid := os.Getpid()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

@ -137,30 +137,54 @@ type processEnvironmentBlock64 struct {
} }
type rtlUserProcessParameters32 struct { type rtlUserProcessParameters32 struct {
Reserved1 [16]uint8 Reserved1 [16]uint8
Reserved2 [10]uint32 ConsoleHandle uint32
ConsoleFlags uint32
StdInputHandle uint32
StdOutputHandle uint32
StdErrorHandle uint32
CurrentDirectoryPathNameLength uint16
_ uint16 // Max Length
CurrentDirectoryPathAddress uint32
CurrentDirectoryHandle uint32
DllPathNameLength uint16
_ uint16 // Max Length
DllPathAddress uint32
ImagePathNameLength uint16 ImagePathNameLength uint16
_ uint16 _ uint16 // Max Length
ImagePathAddress uint32 ImagePathAddress uint32
CommandLineLength uint16 CommandLineLength uint16
_ uint16 _ uint16 // Max Length
CommandLineAddress uint32 CommandLineAddress uint32
EnvironmentAddress uint32 EnvironmentAddress uint32
// More fields which we don't use so far // More fields which we don't use so far
} }
type rtlUserProcessParameters64 struct { type rtlUserProcessParameters64 struct {
Reserved1 [16]uint8 Reserved1 [16]uint8
Reserved2 [10]uint64 ConsoleHandle uint64
ConsoleFlags uint64
StdInputHandle uint64
StdOutputHandle uint64
StdErrorHandle uint64
CurrentDirectoryPathNameLength uint16
_ uint16 // Max Length
_ uint32 // Padding
CurrentDirectoryPathAddress uint64
CurrentDirectoryHandle uint64
DllPathNameLength uint16
_ uint16 // Max Length
_ uint32 // Padding
DllPathAddress uint64
ImagePathNameLength uint16 ImagePathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
_ uint32 // Padding _ uint32 // Padding
ImagePathAddress uint64 ImagePathAddress uint64
CommandLineLength uint16 CommandLineLength uint16
_ uint16 // Max Length _ uint16 // Max Length
_ uint32 // Padding _ uint32 // Padding
CommandLineAddress uint64 CommandLineAddress uint64
EnvironmentAddress uint64 EnvironmentAddress uint64
// More fields which we don't use so far // More fields which we don't use so far
} }
@ -377,8 +401,48 @@ func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
return ru.CreationTime.Nanoseconds() / 1000000, nil return ru.CreationTime.Nanoseconds() / 1000000, nil
} }
func (p *Process) CwdWithContext(ctx context.Context) (string, error) { func (p *Process) CwdWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
return "", nil
}
if err != nil {
return "", err
}
defer syscall.CloseHandle(syscall.Handle(h))
procIs32Bits := is32BitProcess(h)
if procIs32Bits {
userProcParams, err := getUserProcessParams32(h)
if err != nil {
return "", err
}
if userProcParams.CurrentDirectoryPathNameLength > 0 {
cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength))
if len(cwd) != int(userProcParams.CurrentDirectoryPathAddress) {
return "", errors.New("cannot read current working directory")
}
return convertUTF16ToString(cwd), nil
}
} else {
userProcParams, err := getUserProcessParams64(h)
if err != nil {
return "", err
}
if userProcParams.CurrentDirectoryPathNameLength > 0 {
cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength))
if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
return "", errors.New("cannot read current working directory")
}
return convertUTF16ToString(cwd), nil
}
}
//if we reach here, we have no cwd
return "", nil
} }
func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {

@ -776,6 +776,22 @@ func Test_Process_Environ(t *testing.T) {
} }
} }
func Test_Process_Cwd(t *testing.T) {
myPid := os.Getpid()
currentWorkingDirectory, _ := os.Getwd()
process, _ := NewProcess(int32(myPid))
pidCwd, err := process.Cwd()
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting cwd error %v", err)
}
pidCwd = strings.TrimSuffix(pidCwd, string(os.PathSeparator))
assert.Equal(t, currentWorkingDirectory, pidCwd)
t.Log(pidCwd)
}
func Test_AllProcesses_cmdLine(t *testing.T) { func Test_AllProcesses_cmdLine(t *testing.T) {
procs, err := Processes() procs, err := Processes()
skipIfNotImplementedErr(t, err) skipIfNotImplementedErr(t, err)
@ -813,6 +829,23 @@ func Test_AllProcesses_environ(t *testing.T) {
} }
} }
func Test_AllProcesses_Cwd(t *testing.T) {
procs, err := Processes()
skipIfNotImplementedErr(t, err)
if err != nil {
t.Fatalf("getting processes error %v", err)
}
for _, proc := range procs {
exeName, _ := proc.Exe()
cwd, err := proc.Cwd()
if err != nil {
cwd = "Error: " + err.Error()
}
t.Logf("Process #%v: Name: %v / Current Working Directory: %s\n", proc.Pid, exeName, cwd)
}
}
func BenchmarkNewProcess(b *testing.B) { func BenchmarkNewProcess(b *testing.B) {
checkPid := os.Getpid() checkPid := os.Getpid()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {

@ -125,12 +125,23 @@ type processEnvironmentBlock64 struct {
type rtlUserProcessParameters32 struct { type rtlUserProcessParameters32 struct {
Reserved1 [16]uint8 Reserved1 [16]uint8
Reserved2 [10]uint32 ConsoleHandle uint32
ConsoleFlags uint32
StdInputHandle uint32
StdOutputHandle uint32
StdErrorHandle uint32
CurrentDirectoryPathNameLength uint16
_ uint16 // Max Length
CurrentDirectoryPathAddress uint32
CurrentDirectoryHandle uint32
DllPathNameLength uint16
_ uint16 // Max Length
DllPathAddress uint32
ImagePathNameLength uint16 ImagePathNameLength uint16
_ uint16 _ uint16 // Max Length
ImagePathAddress uint32 ImagePathAddress uint32
CommandLineLength uint16 CommandLineLength uint16
_ uint16 _ uint16 // Max Length
CommandLineAddress uint32 CommandLineAddress uint32
EnvironmentAddress uint32 EnvironmentAddress uint32
// More fields which we don't use so far // More fields which we don't use so far
@ -138,7 +149,20 @@ type rtlUserProcessParameters32 struct {
type rtlUserProcessParameters64 struct { type rtlUserProcessParameters64 struct {
Reserved1 [16]uint8 Reserved1 [16]uint8
Reserved2 [10]uint64 ConsoleHandle uint64
ConsoleFlags uint64
StdInputHandle uint64
StdOutputHandle uint64
StdErrorHandle uint64
CurrentDirectoryPathNameLength uint16
_ uint16 // Max Length
_ uint32 // Padding
CurrentDirectoryPathAddress uint64
CurrentDirectoryHandle uint64
DllPathNameLength uint16
_ uint16 // Max Length
_ uint32 // Padding
DllPathAddress uint64
ImagePathNameLength uint16 ImagePathNameLength uint16
_ uint16 // Max Length _ uint16 // Max Length
_ uint32 // Padding _ uint32 // Padding
@ -364,8 +388,48 @@ func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) {
return ru.CreationTime.Nanoseconds() / 1000000, nil return ru.CreationTime.Nanoseconds() / 1000000, nil
} }
func (p *Process) CwdWithContext(ctx context.Context) (string, error) { func (p *Process) CwdWithContext(_ context.Context) (string, error) {
return "", common.ErrNotImplementedError h, err := windows.OpenProcess(processQueryInformation|windows.PROCESS_VM_READ, false, uint32(p.Pid))
if err == windows.ERROR_ACCESS_DENIED || err == windows.ERROR_INVALID_PARAMETER {
return "", nil
}
if err != nil {
return "", err
}
defer syscall.CloseHandle(syscall.Handle(h))
procIs32Bits := is32BitProcess(h)
if procIs32Bits {
userProcParams, err := getUserProcessParams32(h)
if err != nil {
return "", err
}
if userProcParams.CurrentDirectoryPathNameLength > 0 {
cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, uint64(userProcParams.CurrentDirectoryPathAddress), uint(userProcParams.CurrentDirectoryPathNameLength))
if len(cwd) != int(userProcParams.CurrentDirectoryPathAddress) {
return "", errors.New("cannot read current working directory")
}
return convertUTF16ToString(cwd), nil
}
} else {
userProcParams, err := getUserProcessParams64(h)
if err != nil {
return "", err
}
if userProcParams.CurrentDirectoryPathNameLength > 0 {
cwd := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams.CurrentDirectoryPathAddress, uint(userProcParams.CurrentDirectoryPathNameLength))
if len(cwd) != int(userProcParams.CurrentDirectoryPathNameLength) {
return "", errors.New("cannot read current working directory")
}
return convertUTF16ToString(cwd), nil
}
}
//if we reach here, we have no cwd
return "", nil
} }
func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) {

Loading…
Cancel
Save