Source file src/syscall/exec_windows.go
1
2
3
4
5
6
7 package syscall
8
9 import (
10 "sync"
11 "unicode/utf16"
12 "unsafe"
13 )
14
15 var ForkLock sync.RWMutex
16
17
18
19
20
21
22
23
24
25
26 func EscapeArg(s string) string {
27 if len(s) == 0 {
28 return "\"\""
29 }
30 n := len(s)
31 hasSpace := false
32 for i := 0; i < len(s); i++ {
33 switch s[i] {
34 case '"', '\\':
35 n++
36 case ' ', '\t':
37 hasSpace = true
38 }
39 }
40 if hasSpace {
41 n += 2
42 }
43 if n == len(s) {
44 return s
45 }
46
47 qs := make([]byte, n)
48 j := 0
49 if hasSpace {
50 qs[j] = '"'
51 j++
52 }
53 slashes := 0
54 for i := 0; i < len(s); i++ {
55 switch s[i] {
56 default:
57 slashes = 0
58 qs[j] = s[i]
59 case '\\':
60 slashes++
61 qs[j] = s[i]
62 case '"':
63 for ; slashes > 0; slashes-- {
64 qs[j] = '\\'
65 j++
66 }
67 qs[j] = '\\'
68 j++
69 qs[j] = s[i]
70 }
71 j++
72 }
73 if hasSpace {
74 for ; slashes > 0; slashes-- {
75 qs[j] = '\\'
76 j++
77 }
78 qs[j] = '"'
79 j++
80 }
81 return string(qs[:j])
82 }
83
84
85
86 func makeCmdLine(args []string) string {
87 var s string
88 for _, v := range args {
89 if s != "" {
90 s += " "
91 }
92 s += EscapeArg(v)
93 }
94 return s
95 }
96
97
98
99
100
101 func createEnvBlock(envv []string) *uint16 {
102 if len(envv) == 0 {
103 return &utf16.Encode([]rune("\x00\x00"))[0]
104 }
105 length := 0
106 for _, s := range envv {
107 length += len(s) + 1
108 }
109 length += 1
110
111 b := make([]byte, length)
112 i := 0
113 for _, s := range envv {
114 l := len(s)
115 copy(b[i:i+l], []byte(s))
116 copy(b[i+l:i+l+1], []byte{0})
117 i = i + l + 1
118 }
119 copy(b[i:i+1], []byte{0})
120
121 return &utf16.Encode([]rune(string(b)))[0]
122 }
123
124 func CloseOnExec(fd Handle) {
125 SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
126 }
127
128 func SetNonblock(fd Handle, nonblocking bool) (err error) {
129 return nil
130 }
131
132
133 func FullPath(name string) (path string, err error) {
134 p, err := UTF16PtrFromString(name)
135 if err != nil {
136 return "", err
137 }
138 n := uint32(100)
139 for {
140 buf := make([]uint16, n)
141 n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
142 if err != nil {
143 return "", err
144 }
145 if n <= uint32(len(buf)) {
146 return UTF16ToString(buf[:n]), nil
147 }
148 }
149 }
150
151 func isSlash(c uint8) bool {
152 return c == '\\' || c == '/'
153 }
154
155 func normalizeDir(dir string) (name string, err error) {
156 ndir, err := FullPath(dir)
157 if err != nil {
158 return "", err
159 }
160 if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
161
162 return "", EINVAL
163 }
164 return ndir, nil
165 }
166
167 func volToUpper(ch int) int {
168 if 'a' <= ch && ch <= 'z' {
169 ch += 'A' - 'a'
170 }
171 return ch
172 }
173
174 func joinExeDirAndFName(dir, p string) (name string, err error) {
175 if len(p) == 0 {
176 return "", EINVAL
177 }
178 if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
179
180 return p, nil
181 }
182 if len(p) > 1 && p[1] == ':' {
183
184 if len(p) == 2 {
185 return "", EINVAL
186 }
187 if isSlash(p[2]) {
188 return p, nil
189 } else {
190 d, err := normalizeDir(dir)
191 if err != nil {
192 return "", err
193 }
194 if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
195 return FullPath(d + "\\" + p[2:])
196 } else {
197 return FullPath(p)
198 }
199 }
200 } else {
201
202 d, err := normalizeDir(dir)
203 if err != nil {
204 return "", err
205 }
206 if isSlash(p[0]) {
207 return FullPath(d[:2] + p)
208 } else {
209 return FullPath(d + "\\" + p)
210 }
211 }
212 }
213
214 type ProcAttr struct {
215 Dir string
216 Env []string
217 Files []uintptr
218 Sys *SysProcAttr
219 }
220
221 type SysProcAttr struct {
222 HideWindow bool
223 CmdLine string
224 CreationFlags uint32
225 Token Token
226 ProcessAttributes *SecurityAttributes
227 ThreadAttributes *SecurityAttributes
228 }
229
230 var zeroProcAttr ProcAttr
231 var zeroSysProcAttr SysProcAttr
232
233 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
234 if len(argv0) == 0 {
235 return 0, 0, EWINDOWS
236 }
237 if attr == nil {
238 attr = &zeroProcAttr
239 }
240 sys := attr.Sys
241 if sys == nil {
242 sys = &zeroSysProcAttr
243 }
244
245 if len(attr.Files) > 3 {
246 return 0, 0, EWINDOWS
247 }
248 if len(attr.Files) < 3 {
249 return 0, 0, EINVAL
250 }
251
252 if len(attr.Dir) != 0 {
253
254
255
256
257
258
259 var err error
260 argv0, err = joinExeDirAndFName(attr.Dir, argv0)
261 if err != nil {
262 return 0, 0, err
263 }
264 }
265 argv0p, err := UTF16PtrFromString(argv0)
266 if err != nil {
267 return 0, 0, err
268 }
269
270 var cmdline string
271
272
273
274 if sys.CmdLine != "" {
275 cmdline = sys.CmdLine
276 } else {
277 cmdline = makeCmdLine(argv)
278 }
279
280 var argvp *uint16
281 if len(cmdline) != 0 {
282 argvp, err = UTF16PtrFromString(cmdline)
283 if err != nil {
284 return 0, 0, err
285 }
286 }
287
288 var dirp *uint16
289 if len(attr.Dir) != 0 {
290 dirp, err = UTF16PtrFromString(attr.Dir)
291 if err != nil {
292 return 0, 0, err
293 }
294 }
295
296
297
298
299 ForkLock.Lock()
300 defer ForkLock.Unlock()
301
302 p, _ := GetCurrentProcess()
303 fd := make([]Handle, len(attr.Files))
304 for i := range attr.Files {
305 if attr.Files[i] > 0 {
306 err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
307 if err != nil {
308 return 0, 0, err
309 }
310 defer CloseHandle(Handle(fd[i]))
311 }
312 }
313 si := new(StartupInfo)
314 si.Cb = uint32(unsafe.Sizeof(*si))
315 si.Flags = STARTF_USESTDHANDLES
316 if sys.HideWindow {
317 si.Flags |= STARTF_USESHOWWINDOW
318 si.ShowWindow = SW_HIDE
319 }
320 si.StdInput = fd[0]
321 si.StdOutput = fd[1]
322 si.StdErr = fd[2]
323
324 pi := new(ProcessInformation)
325
326 flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT
327 if sys.Token != 0 {
328 err = CreateProcessAsUser(sys.Token, argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, true, flags, createEnvBlock(attr.Env), dirp, si, pi)
329 } else {
330 err = CreateProcess(argv0p, argvp, sys.ProcessAttributes, sys.ThreadAttributes, true, flags, createEnvBlock(attr.Env), dirp, si, pi)
331 }
332 if err != nil {
333 return 0, 0, err
334 }
335 defer CloseHandle(Handle(pi.Thread))
336
337 return int(pi.ProcessId), uintptr(pi.Process), nil
338 }
339
340 func Exec(argv0 string, argv []string, envv []string) (err error) {
341 return EWINDOWS
342 }
343
View as plain text