diff options
Diffstat (limited to 'lib/System/Win32/Program.inc')
-rw-r--r-- | lib/System/Win32/Program.inc | 409 |
1 files changed, 0 insertions, 409 deletions
diff --git a/lib/System/Win32/Program.inc b/lib/System/Win32/Program.inc deleted file mode 100644 index 16bb28e..0000000 --- a/lib/System/Win32/Program.inc +++ /dev/null @@ -1,409 +0,0 @@ -//===- Win32/Program.cpp - Win32 Program Implementation ------- -*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file provides the Win32 specific implementation of the Program class. -// -//===----------------------------------------------------------------------===// - -#include "Win32.h" -#include <cstdio> -#include <malloc.h> -#include <io.h> -#include <fcntl.h> - -//===----------------------------------------------------------------------===// -//=== WARNING: Implementation here must contain only Win32 specific code -//=== and must not be UNIX code -//===----------------------------------------------------------------------===// - -namespace { - struct Win32ProcessInfo { - HANDLE hProcess; - DWORD dwProcessId; - }; -} - -namespace llvm { -using namespace sys; - -Program::Program() : Data_(0) {} - -Program::~Program() { - if (Data_) { - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - CloseHandle(wpi->hProcess); - delete wpi; - Data_ = 0; - } -} - -unsigned Program::GetPid() const { - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - return wpi->dwProcessId; -} - -// This function just uses the PATH environment variable to find the program. -Path -Program::FindProgramByName(const std::string& progName) { - - // Check some degenerate cases - if (progName.length() == 0) // no program - return Path(); - Path temp; - if (!temp.set(progName)) // invalid name - return Path(); - if (temp.canExecute()) // already executable as is - return temp; - - // At this point, the file name is valid and its not executable. - // Let Windows search for it. - char buffer[MAX_PATH]; - char *dummy = NULL; - DWORD len = SearchPath(NULL, progName.c_str(), ".exe", MAX_PATH, - buffer, &dummy); - - // See if it wasn't found. - if (len == 0) - return Path(); - - // See if we got the entire path. - if (len < MAX_PATH) - return Path(buffer); - - // Buffer was too small; grow and retry. - while (true) { - char *b = reinterpret_cast<char *>(_alloca(len+1)); - DWORD len2 = SearchPath(NULL, progName.c_str(), ".exe", len+1, b, &dummy); - - // It is unlikely the search failed, but it's always possible some file - // was added or removed since the last search, so be paranoid... - if (len2 == 0) - return Path(); - else if (len2 <= len) - return Path(b); - - len = len2; - } -} - -static HANDLE RedirectIO(const Path *path, int fd, std::string* ErrMsg) { - HANDLE h; - if (path == 0) { - DuplicateHandle(GetCurrentProcess(), (HANDLE)_get_osfhandle(fd), - GetCurrentProcess(), &h, - 0, TRUE, DUPLICATE_SAME_ACCESS); - return h; - } - - const char *fname; - if (path->isEmpty()) - fname = "NUL"; - else - fname = path->c_str(); - - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = 0; - sa.bInheritHandle = TRUE; - - h = CreateFile(fname, fd ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, - &sa, fd == 0 ? OPEN_EXISTING : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, std::string(fname) + ": Can't open file for " + - (fd ? "input: " : "output: ")); - } - - return h; -} - -#ifdef __MINGW32__ - // Due to unknown reason, mingw32's w32api doesn't have this declaration. - extern "C" - BOOL WINAPI SetInformationJobObject(HANDLE hJob, - JOBOBJECTINFOCLASS JobObjectInfoClass, - LPVOID lpJobObjectInfo, - DWORD cbJobObjectInfoLength); -#endif - -/// ArgNeedsQuotes - Check whether argument needs to be quoted when calling -/// CreateProcess. -static bool ArgNeedsQuotes(const char *Str) { - return Str[0] == '\0' || strchr(Str, ' ') != 0; -} - - -/// ArgLenWithQuotes - Check whether argument needs to be quoted when calling -/// CreateProcess and returns length of quoted arg with escaped quotes -static unsigned int ArgLenWithQuotes(const char *Str) { - unsigned int len = ArgNeedsQuotes(Str) ? 2 : 0; - - while (*Str != '\0') { - if (*Str == '\"') - ++len; - - ++len; - ++Str; - } - - return len; -} - - -bool -Program::Execute(const Path& path, - const char** args, - const char** envp, - const Path** redirects, - unsigned memoryLimit, - std::string* ErrMsg) { - if (Data_) { - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - CloseHandle(wpi->hProcess); - delete wpi; - Data_ = 0; - } - - if (!path.canExecute()) { - if (ErrMsg) - *ErrMsg = "program not executable"; - return false; - } - - // Windows wants a command line, not an array of args, to pass to the new - // process. We have to concatenate them all, while quoting the args that - // have embedded spaces (or are empty). - - // First, determine the length of the command line. - unsigned len = 0; - for (unsigned i = 0; args[i]; i++) { - len += ArgLenWithQuotes(args[i]) + 1; - } - - // Now build the command line. - char *command = reinterpret_cast<char *>(_alloca(len+1)); - char *p = command; - - for (unsigned i = 0; args[i]; i++) { - const char *arg = args[i]; - - bool needsQuoting = ArgNeedsQuotes(arg); - if (needsQuoting) - *p++ = '"'; - - while (*arg != '\0') { - if (*arg == '\"') - *p++ = '\\'; - - *p++ = *arg++; - } - - if (needsQuoting) - *p++ = '"'; - *p++ = ' '; - } - - *p = 0; - - // The pointer to the environment block for the new process. - char *envblock = 0; - - if (envp) { - // An environment block consists of a null-terminated block of - // null-terminated strings. Convert the array of environment variables to - // an environment block by concatenating them. - - // First, determine the length of the environment block. - len = 0; - for (unsigned i = 0; envp[i]; i++) - len += strlen(envp[i]) + 1; - - // Now build the environment block. - envblock = reinterpret_cast<char *>(_alloca(len+1)); - p = envblock; - - for (unsigned i = 0; envp[i]; i++) { - const char *ev = envp[i]; - size_t len = strlen(ev) + 1; - memcpy(p, ev, len); - p += len; - } - - *p = 0; - } - - // Create a child process. - STARTUPINFO si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.hStdInput = INVALID_HANDLE_VALUE; - si.hStdOutput = INVALID_HANDLE_VALUE; - si.hStdError = INVALID_HANDLE_VALUE; - - if (redirects) { - si.dwFlags = STARTF_USESTDHANDLES; - - si.hStdInput = RedirectIO(redirects[0], 0, ErrMsg); - if (si.hStdInput == INVALID_HANDLE_VALUE) { - MakeErrMsg(ErrMsg, "can't redirect stdin"); - return false; - } - si.hStdOutput = RedirectIO(redirects[1], 1, ErrMsg); - if (si.hStdOutput == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - MakeErrMsg(ErrMsg, "can't redirect stdout"); - return false; - } - if (redirects[1] && redirects[2] && *(redirects[1]) == *(redirects[2])) { - // If stdout and stderr should go to the same place, redirect stderr - // to the handle already open for stdout. - DuplicateHandle(GetCurrentProcess(), si.hStdOutput, - GetCurrentProcess(), &si.hStdError, - 0, TRUE, DUPLICATE_SAME_ACCESS); - } else { - // Just redirect stderr - si.hStdError = RedirectIO(redirects[2], 2, ErrMsg); - if (si.hStdError == INVALID_HANDLE_VALUE) { - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - MakeErrMsg(ErrMsg, "can't redirect stderr"); - return false; - } - } - } - - PROCESS_INFORMATION pi; - memset(&pi, 0, sizeof(pi)); - - fflush(stdout); - fflush(stderr); - BOOL rc = CreateProcess(path.c_str(), command, NULL, NULL, TRUE, 0, - envblock, NULL, &si, &pi); - DWORD err = GetLastError(); - - // Regardless of whether the process got created or not, we are done with - // the handles we created for it to inherit. - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - - // Now return an error if the process didn't get created. - if (!rc) { - SetLastError(err); - MakeErrMsg(ErrMsg, std::string("Couldn't execute program '") + - path.str() + "'"); - return false; - } - Win32ProcessInfo* wpi = new Win32ProcessInfo; - wpi->hProcess = pi.hProcess; - wpi->dwProcessId = pi.dwProcessId; - Data_ = wpi; - - // Make sure these get closed no matter what. - AutoHandle hThread(pi.hThread); - - // Assign the process to a job if a memory limit is defined. - AutoHandle hJob(0); - if (memoryLimit != 0) { - hJob = CreateJobObject(0, 0); - bool success = false; - if (hJob != 0) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli; - memset(&jeli, 0, sizeof(jeli)); - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_PROCESS_MEMORY; - jeli.ProcessMemoryLimit = uintptr_t(memoryLimit) * 1048576; - if (SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, - &jeli, sizeof(jeli))) { - if (AssignProcessToJobObject(hJob, pi.hProcess)) - success = true; - } - } - if (!success) { - SetLastError(GetLastError()); - MakeErrMsg(ErrMsg, std::string("Unable to set memory limit")); - TerminateProcess(pi.hProcess, 1); - WaitForSingleObject(pi.hProcess, INFINITE); - return false; - } - } - - return true; -} - -int -Program::Wait(unsigned secondsToWait, - std::string* ErrMsg) { - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return -1; - } - - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - HANDLE hProcess = wpi->hProcess; - - // Wait for the process to terminate. - DWORD millisecondsToWait = INFINITE; - if (secondsToWait > 0) - millisecondsToWait = secondsToWait * 1000; - - if (WaitForSingleObject(hProcess, millisecondsToWait) == WAIT_TIMEOUT) { - if (!TerminateProcess(hProcess, 1)) { - MakeErrMsg(ErrMsg, "Failed to terminate timed-out program."); - return -1; - } - WaitForSingleObject(hProcess, INFINITE); - } - - // Get its exit status. - DWORD status; - BOOL rc = GetExitCodeProcess(hProcess, &status); - DWORD err = GetLastError(); - - if (!rc) { - SetLastError(err); - MakeErrMsg(ErrMsg, "Failed getting status for program."); - return -1; - } - - return status; -} - -bool -Program::Kill(std::string* ErrMsg) { - if (Data_ == 0) { - MakeErrMsg(ErrMsg, "Process not started!"); - return true; - } - - Win32ProcessInfo* wpi = reinterpret_cast<Win32ProcessInfo*>(Data_); - HANDLE hProcess = wpi->hProcess; - if (TerminateProcess(hProcess, 1) == 0) { - MakeErrMsg(ErrMsg, "The process couldn't be killed!"); - return true; - } - - return false; -} - -bool Program::ChangeStdinToBinary(){ - int result = _setmode( _fileno(stdin), _O_BINARY ); - return result == -1; -} - -bool Program::ChangeStdoutToBinary(){ - int result = _setmode( _fileno(stdout), _O_BINARY ); - return result == -1; -} - -bool Program::ChangeStderrToBinary(){ - int result = _setmode( _fileno(stderr), _O_BINARY ); - return result == -1; -} - -} |