golang exec_windows 代码
文件路径:/src/cmd/vendor/golang.org/x/sys/windows/exec_windows.go
/ Copyright 2009 The Go Authors. All rights reserved.
/ Use of this source code is governed by a BSD-style
/ license that can be found in the LICENSE file.
/ Fork, exec, wait, etc.
package windows
import (
errorspkg "errors"
"unsafe"
)
/ EscapeArg rewrites command line argument s as prescribed
/ in http://msdn.microsoft.com/en-us/library/ms880421.
/ This function returns "" (2 double quotes) if s is empty.
/ Alternatively, these transformations are done:
/ - every back slash (\) is doubled, but only if immediately
/ followed by double quote (");
/ - every double quote (") is escaped by back slash (\);
/ - finally, s is wrapped with double quotes (arg -> "arg"),
/ but only if there is space or tab inside s.
func EscapeArg(s string) string {
if len(s) == 0 {
return "\"\""
}
n := len(s)
hasSpace := false
for i := 0; i < len(s); i++ {
switch s[i] {
case '"', '\\':
n++
case ' ', '\t':
hasSpace = true
}
}
if hasSpace {
n += 2
}
if n == len(s) {
return s
}
qs := make([]byte, n)
j := 0
if hasSpace {
qs[j] = '"'
j++
}
slashes := 0
for i := 0; i < len(s); i++ {
switch s[i] {
default:
slashes = 0
qs[j] = s[i]
case '\\':
slashes++
qs[j] = s[i]
case '"':
for ; slashes > 0; slashes-- {
qs[j] = '\\'
j++
}
qs[j] = '\\'
j++
qs[j] = s[i]
}
j++
}
if hasSpace {
for ; slashes > 0; slashes-- {
qs[j] = '\\'
j++
}
qs[j] = '"'
j++
}
return string(qs[:j])
}
/ ComposeCommandLine escapes and joins the given arguments suitable for use as a Windows command line,
/ in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
/ or any program that uses CommandLineToArgv.
func ComposeCommandLine(args []string) string {
var commandLine string
for i := range args {
if i > 0 {
commandLine += " "
}
commandLine += EscapeArg(args[i])
}
return commandLine
}
/ DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
/ as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
/ command lines are passed around.
func DecomposeCommandLine(commandLine string) ([]string, error) {
if len(commandLine) == 0 {
return []string{}, nil
}
var argc int32
argv, err := CommandLineToArgv(StringToUTF16Ptr(commandLine), &argc)
if err != nil {
return nil, err
}
defer LocalFree(Handle(unsafe.Pointer(argv)))
var args []string
for _, v := range (*argv)[:argc] {
args = append(args, UTF16ToString((*v)[:]))
}
return args, nil
}
func CloseOnExec(fd Handle) {
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
}
/ FullPath retrieves the full path of the specified file.
func FullPath(name string) (path string, err error) {
p, err := UTF16PtrFromString(name)
if err != nil {
return "", err
}
n := uint32(100)
for {
buf := make([]uint16, n)
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
if err != nil {
return "", err
}
if n <= uint32(len(buf)) {
return UTF16ToString(buf[:n]), nil
}
}
}
/ NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes.
func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) {
var size uintptr
err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size)
if err != ERROR_INSUFFICIENT_BUFFER {
if err == nil {
return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList")
}
return nil, err
}
alloc, err := LocalAlloc(LMEM_FIXED, uint32(size))
if err != nil {
return nil, err
}
/ size is guaranteed to be ≥1 by InitializeProcThreadAttributeList.
al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))}
err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size)
if err != nil {
return nil, err
}
return al, err
}
/ Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute.
func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error {
al.pointers = append(al.pointers, value)
return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil)
}
/ Delete frees ProcThreadAttributeList's resources.
func (al *ProcThreadAttributeListContainer) Delete() {
deleteProcThreadAttributeList(al.data)
LocalFree(Handle(unsafe.Pointer(al.data)))
al.data = nil
al.pointers = nil
}
/ List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx.
func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList {
return al.data
}