URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [syscall/] [exec_windows.go] - Rev 747
Compare with Previous | Blame | View Log
// 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 syscallimport ("sync""unicode/utf16""unsafe")var ForkLock sync.RWMutex// 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 := falsefor 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 := 0if hasSpace {qs[j] = '"'j++}slashes := 0for i := 0; i < len(s); i++ {switch s[i] {default:slashes = 0qs[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])}// makeCmdLine builds a command line out of args by escaping "special"// characters and joining the arguments with spaces.func makeCmdLine(args []string) string {var s stringfor _, v := range args {if s != "" {s += " "}s += EscapeArg(v)}return s}// createEnvBlock converts an array of environment strings into// the representation required by CreateProcess: a sequence of NUL// terminated strings followed by a nil.// Last bytes are two UCS-2 NULs, or four NUL bytes.func createEnvBlock(envv []string) *uint16 {if len(envv) == 0 {return &utf16.Encode([]rune("\x00\x00"))[0]}length := 0for _, s := range envv {length += len(s) + 1}length += 1b := make([]byte, length)i := 0for _, s := range envv {l := len(s)copy(b[i:i+l], []byte(s))copy(b[i+l:i+l+1], []byte{0})i = i + l + 1}copy(b[i:i+1], []byte{0})return &utf16.Encode([]rune(string(b)))[0]}func CloseOnExec(fd Handle) {SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)}func SetNonblock(fd Handle, nonblocking bool) (err error) {return nil}// getFullPath retrieves the full path of the specified file.// Just a wrapper for Windows GetFullPathName api.func getFullPath(name string) (path string, err error) {p := StringToUTF16Ptr(name)buf := make([]uint16, 100)n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)if err != nil {return "", err}if n > uint32(len(buf)) {// Windows is asking for bigger buffer.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 "", EINVAL}}return UTF16ToString(buf[:n]), nil}func isSlash(c uint8) bool {return c == '\\' || c == '/'}func normalizeDir(dir string) (name string, err error) {ndir, err := getFullPath(dir)if err != nil {return "", err}if len(ndir) > 2 && isSlash(ndir[0]) && isSlash(ndir[1]) {// dir cannot have \\server\share\path formreturn "", EINVAL}return ndir, nil}func volToUpper(ch int) int {if 'a' <= ch && ch <= 'z' {ch += 'A' - 'a'}return ch}func joinExeDirAndFName(dir, p string) (name string, err error) {if len(p) == 0 {return "", EINVAL}if len(p) > 2 && isSlash(p[0]) && isSlash(p[1]) {// \\server\share\path formreturn p, nil}if len(p) > 1 && p[1] == ':' {// has drive letterif len(p) == 2 {return "", EINVAL}if isSlash(p[2]) {return p, nil} else {d, err := normalizeDir(dir)if err != nil {return "", err}if volToUpper(int(p[0])) == volToUpper(int(d[0])) {return getFullPath(d + "\\" + p[2:])} else {return getFullPath(p)}}} else {// no drive letterd, err := normalizeDir(dir)if err != nil {return "", err}if isSlash(p[0]) {return getFullPath(d[:2] + p)} else {return getFullPath(d + "\\" + p)}}// we shouldn't be herereturn "", EINVAL}type ProcAttr struct {Dir stringEnv []stringFiles []HandleSys *SysProcAttr}type SysProcAttr struct {HideWindow boolCmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess}var zeroProcAttr ProcAttrvar zeroSysProcAttr SysProcAttrfunc StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {if len(argv0) == 0 {return 0, 0, EWINDOWS}if attr == nil {attr = &zeroProcAttr}sys := attr.Sysif sys == nil {sys = &zeroSysProcAttr}if len(attr.Files) > 3 {return 0, 0, EWINDOWS}if len(attr.Dir) != 0 {// StartProcess assumes that argv0 is relative to attr.Dir,// because it implies Chdir(attr.Dir) before executing argv0.// Windows CreateProcess assumes the opposite: it looks for// argv0 relative to the current directory, and, only once the new// process is started, it does Chdir(attr.Dir). We are adjusting// for that difference here by making argv0 absolute.var err errorargv0, err = joinExeDirAndFName(attr.Dir, argv0)if err != nil {return 0, 0, err}}argv0p := StringToUTF16Ptr(argv0)var cmdline string// Windows CreateProcess takes the command line as a single string:// use attr.CmdLine if set, else build the command line by escaping// and joining each argument with spacesif sys.CmdLine != "" {cmdline = sys.CmdLine} else {cmdline = makeCmdLine(argv)}var argvp *uint16if len(cmdline) != 0 {argvp = StringToUTF16Ptr(cmdline)}var dirp *uint16if len(attr.Dir) != 0 {dirp = StringToUTF16Ptr(attr.Dir)}// Acquire the fork lock so that no other threads// create new fds that are not yet close-on-exec// before we fork.ForkLock.Lock()defer ForkLock.Unlock()p, _ := GetCurrentProcess()fd := make([]Handle, len(attr.Files))for i := range attr.Files {if attr.Files[i] > 0 {err := DuplicateHandle(p, Handle(attr.Files[i]), p, &fd[i], 0, true, DUPLICATE_SAME_ACCESS)if err != nil {return 0, 0, err}defer CloseHandle(Handle(fd[i]))}}si := new(StartupInfo)si.Cb = uint32(unsafe.Sizeof(*si))si.Flags = STARTF_USESTDHANDLESif sys.HideWindow {si.Flags |= STARTF_USESHOWWINDOWsi.ShowWindow = SW_HIDE}si.StdInput = fd[0]si.StdOutput = fd[1]si.StdErr = fd[2]pi := new(ProcessInformation)err = CreateProcess(argv0p, argvp, nil, nil, true, CREATE_UNICODE_ENVIRONMENT, createEnvBlock(attr.Env), dirp, si, pi)if err != nil {return 0, 0, err}defer CloseHandle(Handle(pi.Thread))return int(pi.ProcessId), uintptr(pi.Process), nil}func Exec(argv0 string, argv []string, envv []string) (err error) {return EWINDOWS}
