cubefs
1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Fork, exec, wait, etc.
6
7package windows8
9import (10errorspkg "errors"11"unsafe"12)
13
14// EscapeArg rewrites command line argument s as prescribed
15// in http://msdn.microsoft.com/en-us/library/ms880421.
16// This function returns "" (2 double quotes) if s is empty.
17// Alternatively, these transformations are done:
18// - every back slash (\) is doubled, but only if immediately
19// followed by double quote (");
20// - every double quote (") is escaped by back slash (\);
21// - finally, s is wrapped with double quotes (arg -> "arg"),
22// but only if there is space or tab inside s.
23func EscapeArg(s string) string {24if len(s) == 0 {25return "\"\""26}27n := len(s)28hasSpace := false29for i := 0; i < len(s); i++ {30switch s[i] {31case '"', '\\':32n++33case ' ', '\t':34hasSpace = true35}36}37if hasSpace {38n += 239}40if n == len(s) {41return s42}43
44qs := make([]byte, n)45j := 046if hasSpace {47qs[j] = '"'48j++49}50slashes := 051for i := 0; i < len(s); i++ {52switch s[i] {53default:54slashes = 055qs[j] = s[i]56case '\\':57slashes++58qs[j] = s[i]59case '"':60for ; slashes > 0; slashes-- {61qs[j] = '\\'62j++63}64qs[j] = '\\'65j++66qs[j] = s[i]67}68j++69}70if hasSpace {71for ; slashes > 0; slashes-- {72qs[j] = '\\'73j++74}75qs[j] = '"'76j++77}78return string(qs[:j])79}
80
81// ComposeCommandLine escapes and joins the given arguments suitable for use as a Windows command line,
82// in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
83// or any program that uses CommandLineToArgv.
84func ComposeCommandLine(args []string) string {85var commandLine string86for i := range args {87if i > 0 {88commandLine += " "89}90commandLine += EscapeArg(args[i])91}92return commandLine93}
94
95// DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
96// as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
97// command lines are passed around.
98func DecomposeCommandLine(commandLine string) ([]string, error) {99if len(commandLine) == 0 {100return []string{}, nil101}102var argc int32103argv, err := CommandLineToArgv(StringToUTF16Ptr(commandLine), &argc)104if err != nil {105return nil, err106}107defer LocalFree(Handle(unsafe.Pointer(argv)))108var args []string109for _, v := range (*argv)[:argc] {110args = append(args, UTF16ToString((*v)[:]))111}112return args, nil113}
114
115func CloseOnExec(fd Handle) {116SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)117}
118
119// FullPath retrieves the full path of the specified file.
120func FullPath(name string) (path string, err error) {121p, err := UTF16PtrFromString(name)122if err != nil {123return "", err124}125n := uint32(100)126for {127buf := make([]uint16, n)128n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)129if err != nil {130return "", err131}132if n <= uint32(len(buf)) {133return UTF16ToString(buf[:n]), nil134}135}136}
137
138// NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes.
139func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) {140var size uintptr141err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size)142if err != ERROR_INSUFFICIENT_BUFFER {143if err == nil {144return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList")145}146return nil, err147}148alloc, err := LocalAlloc(LMEM_FIXED, uint32(size))149if err != nil {150return nil, err151}152// size is guaranteed to be ≥1 by InitializeProcThreadAttributeList.153al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))}154err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size)155if err != nil {156return nil, err157}158return al, err159}
160
161// Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute.
162func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error {163al.pointers = append(al.pointers, value)164return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil)165}
166
167// Delete frees ProcThreadAttributeList's resources.
168func (al *ProcThreadAttributeListContainer) Delete() {169deleteProcThreadAttributeList(al.data)170LocalFree(Handle(unsafe.Pointer(al.data)))171al.data = nil172al.pointers = nil173}
174
175// List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx.
176func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList {177return al.data178}
179