OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [syscall/] [exec_windows.go] - Blame information for rev 867

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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 syscall
8
 
9
import (
10
        "sync"
11
        "unicode/utf16"
12
        "unsafe"
13
)
14
 
15
var ForkLock sync.RWMutex
16
 
17
// EscapeArg rewrites command line argument s as prescribed
18
// in http://msdn.microsoft.com/en-us/library/ms880421.
19
// This function returns "" (2 double quotes) if s is empty.
20
// Alternatively, these transformations are done:
21
// - every back slash (\) is doubled, but only if immediately
22
//   followed by double quote (");
23
// - every double quote (") is escaped by back slash (\);
24
// - finally, s is wrapped with double quotes (arg -> "arg"),
25
//   but only if there is space or tab inside s.
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
// makeCmdLine builds a command line out of args by escaping "special"
85
// characters and joining the arguments with spaces.
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
// createEnvBlock converts an array of environment strings into
98
// the representation required by CreateProcess: a sequence of NUL
99
// terminated strings followed by a nil.
100
// Last bytes are two UCS-2 NULs, or four NUL bytes.
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
// getFullPath retrieves the full path of the specified file.
133
// Just a wrapper for Windows GetFullPathName api.
134
func getFullPath(name string) (path string, err error) {
135
        p := StringToUTF16Ptr(name)
136
        buf := make([]uint16, 100)
137
        n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
138
        if err != nil {
139
                return "", err
140
        }
141
        if n > uint32(len(buf)) {
142
                // Windows is asking for bigger buffer.
143
                buf = make([]uint16, n)
144
                n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
145
                if err != nil {
146
                        return "", err
147
                }
148
                if n > uint32(len(buf)) {
149
                        return "", EINVAL
150
                }
151
        }
152
        return UTF16ToString(buf[:n]), nil
153
}
154
 
155
func isSlash(c uint8) bool {
156
        return c == '\\' || c == '/'
157
}
158
 
159
func normalizeDir(dir string) (name string, err error) {
160
        ndir, err := getFullPath(dir)
161
        if err != nil {
162
                return "", err
163
        }
164
        if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {
165
                // dir cannot have \\server\share\path form
166
                return "", EINVAL
167
        }
168
        return ndir, nil
169
}
170
 
171
func volToUpper(ch int) int {
172
        if 'a' <= ch && ch <= 'z' {
173
                ch += 'A' - 'a'
174
        }
175
        return ch
176
}
177
 
178
func joinExeDirAndFName(dir, p string) (name string, err error) {
179
        if len(p) == 0 {
180
                return "", EINVAL
181
        }
182
        if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {
183
                // \\server\share\path form
184
                return p, nil
185
        }
186
        if len(p) > 1 && p[1] == ':' {
187
                // has drive letter
188
                if len(p) == 2 {
189
                        return "", EINVAL
190
                }
191
                if isSlash(p[2]) {
192
                        return p, nil
193
                } else {
194
                        d, err := normalizeDir(dir)
195
                        if err != nil {
196
                                return "", err
197
                        }
198
                        if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
199
                                return getFullPath(d + "\\" + p[2:])
200
                        } else {
201
                                return getFullPath(p)
202
                        }
203
                }
204
        } else {
205
                // no drive letter
206
                d, err := normalizeDir(dir)
207
                if err != nil {
208
                        return "", err
209
                }
210
                if isSlash(p[0]) {
211
                        return getFullPath(d[:2] + p)
212
                } else {
213
                        return getFullPath(d + "\\" + p)
214
                }
215
        }
216
        // we shouldn't be here
217
        return "", EINVAL
218
}
219
 
220
type ProcAttr struct {
221
        Dir   string
222
        Env   []string
223
        Files []Handle
224
        Sys   *SysProcAttr
225
}
226
 
227
type SysProcAttr struct {
228
        HideWindow bool
229
        CmdLine    string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess
230
}
231
 
232
var zeroProcAttr ProcAttr
233
var zeroSysProcAttr SysProcAttr
234
 
235
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
236
        if len(argv0) == 0 {
237
                return 0, 0, EWINDOWS
238
        }
239
        if attr == nil {
240
                attr = &zeroProcAttr
241
        }
242
        sys := attr.Sys
243
        if sys == nil {
244
                sys = &zeroSysProcAttr
245
        }
246
 
247
        if len(attr.Files) > 3 {
248
                return 0, 0, EWINDOWS
249
        }
250
 
251
        if len(attr.Dir) != 0 {
252
                // StartProcess assumes that argv0 is relative to attr.Dir,
253
                // because it implies Chdir(attr.Dir) before executing argv0.
254
                // Windows CreateProcess assumes the opposite: it looks for
255
                // argv0 relative to the current directory, and, only once the new
256
                // process is started, it does Chdir(attr.Dir). We are adjusting
257
                // for that difference here by making argv0 absolute.
258
                var err error
259
                argv0, err = joinExeDirAndFName(attr.Dir, argv0)
260
                if err != nil {
261
                        return 0, 0, err
262
                }
263
        }
264
        argv0p := StringToUTF16Ptr(argv0)
265
 
266
        var cmdline string
267
        // Windows CreateProcess takes the command line as a single string:
268
        // use attr.CmdLine if set, else build the command line by escaping
269
        // and joining each argument with spaces
270
        if sys.CmdLine != "" {
271
                cmdline = sys.CmdLine
272
        } else {
273
                cmdline = makeCmdLine(argv)
274
        }
275
 
276
        var argvp *uint16
277
        if len(cmdline) != 0 {
278
                argvp = StringToUTF16Ptr(cmdline)
279
        }
280
 
281
        var dirp *uint16
282
        if len(attr.Dir) != 0 {
283
                dirp = StringToUTF16Ptr(attr.Dir)
284
        }
285
 
286
        // Acquire the fork lock so that no other threads
287
        // create new fds that are not yet close-on-exec
288
        // before we fork.
289
        ForkLock.Lock()
290
        defer ForkLock.Unlock()
291
 
292
        p, _ := GetCurrentProcess()
293
        fd := make([]Handle, len(attr.Files))
294
        for i := range attr.Files {
295
                if attr.Files[i] > 0 {
296
                        err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)
297
                        if err != nil {
298
                                return 0, 0, err
299
                        }
300
                        defer CloseHandle(Handle(fd[i]))
301
                }
302
        }
303
        si := new(StartupInfo)
304
        si.Cb = uint32(unsafe.Sizeof(*si))
305
        si.Flags = STARTF_USESTDHANDLES
306
        if sys.HideWindow {
307
                si.Flags |= STARTF_USESHOWWINDOW
308
                si.ShowWindow = SW_HIDE
309
        }
310
        si.StdInput = fd[0]
311
        si.StdOutput = fd[1]
312
        si.StdErr = fd[2]
313
 
314
        pi := new(ProcessInformation)
315
 
316
        err = CreateProcess(argv0p, argvp, nil, nil, true, CREATE_UNICODE_ENVIRONMENT, createEnvBlock(attr.Env), dirp, si, pi)
317
        if err != nil {
318
                return 0, 0, err
319
        }
320
        defer CloseHandle(Handle(pi.Thread))
321
 
322
        return int(pi.ProcessId), uintptr(pi.Process), nil
323
}
324
 
325
func Exec(argv0 string, argv []string, envv []string) (err error) {
326
        return EWINDOWS
327
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.