mirror of
https://github.com/golang/sys.git
synced 2026-02-08 11:46:04 +03:00
go.sys/windows: delete StartProcess and Exec
These are being deleted from go.sys because in general they can only be implemented in close coordination with the runtime. LGTM=alex.brainman R=alex.brainman CC=golang-codereviews https://golang.org/cl/132010043
This commit is contained in:
@@ -6,14 +6,7 @@
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var ForkLock sync.RWMutex
|
||||
import "syscall"
|
||||
|
||||
// EscapeArg rewrites command line argument s as prescribed
|
||||
// in http://msdn.microsoft.com/en-us/library/ms880421.
|
||||
@@ -82,54 +75,10 @@ func EscapeArg(s string) string {
|
||||
return string(qs[:j])
|
||||
}
|
||||
|
||||
// makeCmdLine builds a command line out of args by escaping "special"
|
||||
// characters and joining the arguments with spaces.
|
||||
func makeCmdLine(args []string) string {
|
||||
var s string
|
||||
for _, v := range args {
|
||||
if s != "" {
|
||||
s += " "
|
||||
}
|
||||
s += EscapeArg(v)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// createEnvBlock converts an array of environment strings into
|
||||
// the representation required by CreateProcess: a sequence of NUL
|
||||
// terminated strings followed by a nil.
|
||||
// Last bytes are two UCS-2 NULs, or four NUL bytes.
|
||||
func createEnvBlock(envv []string) *uint16 {
|
||||
if len(envv) == 0 {
|
||||
return &utf16.Encode([]rune("\x00\x00"))[0]
|
||||
}
|
||||
length := 0
|
||||
for _, s := range envv {
|
||||
length += len(s) + 1
|
||||
}
|
||||
length += 1
|
||||
|
||||
b := make([]byte, length)
|
||||
i := 0
|
||||
for _, s := range envv {
|
||||
l := len(s)
|
||||
copy(b[i:i+l], []byte(s))
|
||||
copy(b[i+l:i+l+1], []byte{0})
|
||||
i = i + l + 1
|
||||
}
|
||||
copy(b[i:i+1], []byte{0})
|
||||
|
||||
return &utf16.Encode([]rune(string(b)))[0]
|
||||
}
|
||||
|
||||
func CloseOnExec(fd Handle) {
|
||||
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||
}
|
||||
|
||||
func SetNonblock(fd Handle, nonblocking bool) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FullPath retrieves the full path of the specified file.
|
||||
func FullPath(name string) (path string, err error) {
|
||||
p, err := UTF16PtrFromString(name)
|
||||
@@ -154,188 +103,3 @@ func FullPath(name string) (path string, err error) {
|
||||
}
|
||||
return UTF16ToString(buf[:n]), nil
|
||||
}
|
||||
|
||||
func isSlash(c uint8) bool {
|
||||
return c == '\\' || c == '/'
|
||||
}
|
||||
|
||||
func normalizeDir(dir string) (name string, err error) {
|
||||
ndir, err := FullPath(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
|
||||
// dir cannot have \\server\share\path form
|
||||
return "", syscall.EINVAL
|
||||
}
|
||||
return ndir, nil
|
||||
}
|
||||
|
||||
func volToUpper(ch int) int {
|
||||
if 'a' <= ch && ch <= 'z' {
|
||||
ch += 'A' - 'a'
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
func joinExeDirAndFName(dir, p string) (name string, err error) {
|
||||
if len(p) == 0 {
|
||||
return "", syscall.EINVAL
|
||||
}
|
||||
if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
|
||||
// \\server\share\path form
|
||||
return p, nil
|
||||
}
|
||||
if len(p) > 1 && p[1] == ':' {
|
||||
// has drive letter
|
||||
if len(p) == 2 {
|
||||
return "", syscall.EINVAL
|
||||
}
|
||||
if isSlash(p[2]) {
|
||||
return p, nil
|
||||
} else {
|
||||
d, err := normalizeDir(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
|
||||
return FullPath(d + "\\" + p[2:])
|
||||
} else {
|
||||
return FullPath(p)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no drive letter
|
||||
d, err := normalizeDir(dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if isSlash(p[0]) {
|
||||
return FullPath(d[:2] + p)
|
||||
} else {
|
||||
return FullPath(d + "\\" + p)
|
||||
}
|
||||
}
|
||||
// we shouldn't be here
|
||||
return "", syscall.EINVAL
|
||||
}
|
||||
|
||||
type ProcAttr struct {
|
||||
Dir string
|
||||
Env []string
|
||||
Files []uintptr
|
||||
Sys *SysProcAttr
|
||||
}
|
||||
|
||||
type SysProcAttr struct {
|
||||
HideWindow bool
|
||||
CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
|
||||
CreationFlags uint32
|
||||
}
|
||||
|
||||
var zeroProcAttr ProcAttr
|
||||
var zeroSysProcAttr SysProcAttr
|
||||
|
||||
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
||||
if len(argv0) == 0 {
|
||||
return 0, 0, syscall.EWINDOWS
|
||||
}
|
||||
if attr == nil {
|
||||
attr = &zeroProcAttr
|
||||
}
|
||||
sys := attr.Sys
|
||||
if sys == nil {
|
||||
sys = &zeroSysProcAttr
|
||||
}
|
||||
|
||||
if len(attr.Files) > 3 {
|
||||
return 0, 0, syscall.EWINDOWS
|
||||
}
|
||||
|
||||
if len(attr.Dir) != 0 {
|
||||
// StartProcess assumes that argv0 is relative to attr.Dir,
|
||||
// because it implies Chdir(attr.Dir) before executing argv0.
|
||||
// Windows CreateProcess assumes the opposite: it looks for
|
||||
// argv0 relative to the current directory, and, only once the new
|
||||
// process is started, it does Chdir(attr.Dir). We are adjusting
|
||||
// for that difference here by making argv0 absolute.
|
||||
var err error
|
||||
argv0, err = joinExeDirAndFName(attr.Dir, argv0)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
}
|
||||
argv0p, err := UTF16PtrFromString(argv0)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
var cmdline string
|
||||
// Windows CreateProcess takes the command line as a single string:
|
||||
// use attr.CmdLine if set, else build the command line by escaping
|
||||
// and joining each argument with spaces
|
||||
if sys.CmdLine != "" {
|
||||
cmdline = sys.CmdLine
|
||||
} else {
|
||||
cmdline = makeCmdLine(argv)
|
||||
}
|
||||
|
||||
var argvp *uint16
|
||||
if len(cmdline) != 0 {
|
||||
argvp, err = UTF16PtrFromString(cmdline)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
var dirp *uint16
|
||||
if len(attr.Dir) != 0 {
|
||||
dirp, err = UTF16PtrFromString(attr.Dir)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
// Acquire the fork lock so that no other threads
|
||||
// create new fds that are not yet close-on-exec
|
||||
// before we fork.
|
||||
ForkLock.Lock()
|
||||
defer ForkLock.Unlock()
|
||||
|
||||
p, _ := GetCurrentProcess()
|
||||
fd := make([]Handle, len(attr.Files))
|
||||
for i := range attr.Files {
|
||||
if attr.Files[i] > 0 {
|
||||
err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
defer CloseHandle(Handle(fd[i]))
|
||||
}
|
||||
}
|
||||
si := new(StartupInfo)
|
||||
si.Cb = uint32(unsafe.Sizeof(*si))
|
||||
si.Flags = STARTF_USESTDHANDLES
|
||||
if sys.HideWindow {
|
||||
si.Flags |= STARTF_USESHOWWINDOW
|
||||
si.ShowWindow = SW_HIDE
|
||||
}
|
||||
si.StdInput = fd[0]
|
||||
si.StdOutput = fd[1]
|
||||
si.StdErr = fd[2]
|
||||
|
||||
pi := new(ProcessInformation)
|
||||
|
||||
flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT
|
||||
err = CreateProcess(argv0p, argvp, nil, nil, true, flags, createEnvBlock(attr.Env), dirp, si, pi)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
defer CloseHandle(Handle(pi.Thread))
|
||||
|
||||
return int(pi.ProcessId), uintptr(pi.Process), nil
|
||||
}
|
||||
|
||||
func Exec(argv0 string, argv []string, envv []string) (err error) {
|
||||
return syscall.EWINDOWS
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user