Mercurial > yakumo_izuru > aya
comparison vendor/golang.org/x/sys/windows/exec_windows.go @ 66:787b5ee0289d draft
Use vendored modules
Signed-off-by: Izuru Yakumo <yakumo.izuru@chaotic.ninja>
author | yakumo.izuru |
---|---|
date | Sun, 23 Jul 2023 13:18:53 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
65:6d985efa0f7a | 66:787b5ee0289d |
---|---|
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 | |
7 package windows | |
8 | |
9 import ( | |
10 errorspkg "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. | |
23 func EscapeArg(s string) string { | |
24 if len(s) == 0 { | |
25 return "\"\"" | |
26 } | |
27 n := len(s) | |
28 hasSpace := false | |
29 for i := 0; i < len(s); i++ { | |
30 switch s[i] { | |
31 case '"', '\\': | |
32 n++ | |
33 case ' ', '\t': | |
34 hasSpace = true | |
35 } | |
36 } | |
37 if hasSpace { | |
38 n += 2 | |
39 } | |
40 if n == len(s) { | |
41 return s | |
42 } | |
43 | |
44 qs := make([]byte, n) | |
45 j := 0 | |
46 if hasSpace { | |
47 qs[j] = '"' | |
48 j++ | |
49 } | |
50 slashes := 0 | |
51 for i := 0; i < len(s); i++ { | |
52 switch s[i] { | |
53 default: | |
54 slashes = 0 | |
55 qs[j] = s[i] | |
56 case '\\': | |
57 slashes++ | |
58 qs[j] = s[i] | |
59 case '"': | |
60 for ; slashes > 0; slashes-- { | |
61 qs[j] = '\\' | |
62 j++ | |
63 } | |
64 qs[j] = '\\' | |
65 j++ | |
66 qs[j] = s[i] | |
67 } | |
68 j++ | |
69 } | |
70 if hasSpace { | |
71 for ; slashes > 0; slashes-- { | |
72 qs[j] = '\\' | |
73 j++ | |
74 } | |
75 qs[j] = '"' | |
76 j++ | |
77 } | |
78 return 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. | |
84 func ComposeCommandLine(args []string) string { | |
85 var commandLine string | |
86 for i := range args { | |
87 if i > 0 { | |
88 commandLine += " " | |
89 } | |
90 commandLine += EscapeArg(args[i]) | |
91 } | |
92 return commandLine | |
93 } | |
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. | |
98 func DecomposeCommandLine(commandLine string) ([]string, error) { | |
99 if len(commandLine) == 0 { | |
100 return []string{}, nil | |
101 } | |
102 var argc int32 | |
103 argv, err := CommandLineToArgv(StringToUTF16Ptr(commandLine), &argc) | |
104 if err != nil { | |
105 return nil, err | |
106 } | |
107 defer LocalFree(Handle(unsafe.Pointer(argv))) | |
108 var args []string | |
109 for _, v := range (*argv)[:argc] { | |
110 args = append(args, UTF16ToString((*v)[:])) | |
111 } | |
112 return args, nil | |
113 } | |
114 | |
115 func CloseOnExec(fd Handle) { | |
116 SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0) | |
117 } | |
118 | |
119 // FullPath retrieves the full path of the specified file. | |
120 func FullPath(name string) (path string, err error) { | |
121 p, err := UTF16PtrFromString(name) | |
122 if err != nil { | |
123 return "", err | |
124 } | |
125 n := uint32(100) | |
126 for { | |
127 buf := make([]uint16, n) | |
128 n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil) | |
129 if err != nil { | |
130 return "", err | |
131 } | |
132 if n <= uint32(len(buf)) { | |
133 return UTF16ToString(buf[:n]), nil | |
134 } | |
135 } | |
136 } | |
137 | |
138 // NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes. | |
139 func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) { | |
140 var size uintptr | |
141 err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size) | |
142 if err != ERROR_INSUFFICIENT_BUFFER { | |
143 if err == nil { | |
144 return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList") | |
145 } | |
146 return nil, err | |
147 } | |
148 alloc, err := LocalAlloc(LMEM_FIXED, uint32(size)) | |
149 if err != nil { | |
150 return nil, err | |
151 } | |
152 // size is guaranteed to be ≥1 by InitializeProcThreadAttributeList. | |
153 al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))} | |
154 err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size) | |
155 if err != nil { | |
156 return nil, err | |
157 } | |
158 return al, err | |
159 } | |
160 | |
161 // Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute. | |
162 func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error { | |
163 al.pointers = append(al.pointers, value) | |
164 return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil) | |
165 } | |
166 | |
167 // Delete frees ProcThreadAttributeList's resources. | |
168 func (al *ProcThreadAttributeListContainer) Delete() { | |
169 deleteProcThreadAttributeList(al.data) | |
170 LocalFree(Handle(unsafe.Pointer(al.data))) | |
171 al.data = nil | |
172 al.pointers = nil | |
173 } | |
174 | |
175 // List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx. | |
176 func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList { | |
177 return al.data | |
178 } |