diff options
Diffstat (limited to 'src/pkg/syscall/exec_windows.go')
-rw-r--r-- | src/pkg/syscall/exec_windows.go | 341 |
1 files changed, 0 insertions, 341 deletions
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go deleted file mode 100644 index 82abc0715..000000000 --- a/src/pkg/syscall/exec_windows.go +++ /dev/null @@ -1,341 +0,0 @@ -// 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 syscall - -import ( - "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 := false - for 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 := 0 - if hasSpace { - qs[j] = '"' - j++ - } - slashes := 0 - for i := 0; i < len(s); i++ { - switch s[i] { - default: - slashes = 0 - qs[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 string - for _, 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 := 0 - for _, s := range envv { - length += len(s) + 1 - } - length += 1 - - b := make([]byte, length) - i := 0 - for _, 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, err := UTF16PtrFromString(name) - if err != nil { - return "", err - } - 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 form - return "", 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 form - return p, nil - } - if len(p) > 1 && p[1] == ':' { - // has drive letter - if 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 letter - d, 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 here - return "", EINVAL -} - -type ProcAttr struct { - Dir string - Env []string - Files []uintptr - Sys *SysProcAttr -} - -type SysProcAttr struct { - HideWindow bool - CmdLine string // used if non-empty, else the windows command line is built by escaping the arguments passed to StartProcess - CreationFlags uint32 -} - -var zeroProcAttr ProcAttr -var zeroSysProcAttr SysProcAttr - -func 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.Sys - if 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 error - argv0, err = joinExeDirAndFName(attr.Dir, argv0) - if err != nil { - return 0, 0, err - } - } - argv0p, err := UTF16PtrFromString(argv0) - if err != nil { - return 0, 0, err - } - - 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 spaces - if sys.CmdLine != "" { - cmdline = sys.CmdLine - } else { - cmdline = makeCmdLine(argv) - } - - var argvp *uint16 - if len(cmdline) != 0 { - argvp, err = UTF16PtrFromString(cmdline) - if err != nil { - return 0, 0, err - } - } - - var dirp *uint16 - if len(attr.Dir) != 0 { - dirp, err = UTF16PtrFromString(attr.Dir) - if err != nil { - return 0, 0, err - } - } - - // 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_USESTDHANDLES - if sys.HideWindow { - si.Flags |= STARTF_USESHOWWINDOW - si.ShowWindow = SW_HIDE - } - si.StdInput = fd[0] - si.StdOutput = fd[1] - si.StdErr = fd[2] - - pi := new(ProcessInformation) - - flags := sys.CreationFlags | CREATE_UNICODE_ENVIRONMENT - err = CreateProcess(argv0p, argvp, nil, nil, true, flags, 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 -} |