diff options
Diffstat (limited to 'src/Exec.cpp')
-rw-r--r-- | src/Exec.cpp | 98 |
1 files changed, 67 insertions, 31 deletions
diff --git a/src/Exec.cpp b/src/Exec.cpp index 2eac8bc..6c1a72e 100644 --- a/src/Exec.cpp +++ b/src/Exec.cpp @@ -3,24 +3,28 @@ using namespace std; +const int BUFSIZE = 1024; + +// TODO: Redirect stderr to namespace sibs { #if OS_FAMILY == OS_FAMILY_POSIX Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print) { - char buffer[128]; - std::string result; + char buffer[BUFSIZE]; + std::string execStdout; FILE *pipe = popen(cmd, "r"); if(!pipe) return Result<ExecResult>::Err("popen() failed"); while(!feof(pipe)) { - if(fgets(buffer, 128, pipe)) + int bytesRead = fgets(buffer, BUFSIZE, pipe); + if(bytesRead > 0) { - result += buffer; + execStdout.append(buffer, bytesRead); if(print) - printf("%s", buffer); + printf("%.*s", bytesRead, buffer); } } @@ -29,7 +33,7 @@ namespace sibs { int returned = WEXITSTATUS(processCloseResult); ExecResult execResult; - execResult.execStdout = result; + execResult.execStdout = move(execStdout); execResult.exitCode = returned; return Result<ExecResult>::Ok(execResult); } @@ -55,48 +59,80 @@ namespace sibs } } #else - // TODO(Windows): Redirect stdout (and stderr) to string + // Currently stdout is read in text mode so \n is replaced with \r\n, should we read in binary mode instead? Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print) { - char buffer[128]; - std::string result; + FileString cmdNonConst = cmd; + std::string execStdout; - STARTUPINFO startupInfo; - ZeroMemory(&startupInfo, sizeof(startupInfo)); - startupInfo.cb = sizeof(startupInfo); + SECURITY_ATTRIBUTES saAttr; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = nullptr; - PROCESS_INFORMATION processInfo; - ZeroMemory(&processInfo, sizeof(processInfo)); + HANDLE childReadHandle = nullptr; + HANDLE childStdoutHandle = nullptr; - DWORD exitCode; - - if (!CreateProcess(NULL, (LPWSTR)cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo)) + if (!CreatePipe(&childReadHandle, &childStdoutHandle, &saAttr, 0)) { string errMsg = "exec unexpected error: "; errMsg += toUtf8(getLastErrorAsString()); return Result<ExecResult>::Err(errMsg); } - WaitForSingleObject(processInfo.hProcess, INFINITE); - GetExitCodeProcess(processInfo.hProcess, &exitCode); - CloseHandle(processInfo.hProcess); - CloseHandle(processInfo.hThread); + if (!SetHandleInformation(childReadHandle, HANDLE_FLAG_INHERIT, 0)) + goto cleanupAndExit; + + PROCESS_INFORMATION piProcInfo; + ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); + + STARTUPINFO siStartInfo; + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = nullptr; + siStartInfo.hStdOutput = childStdoutHandle; + siStartInfo.hStdInput = nullptr; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + DWORD exitCode; + + if (!CreateProcessW(nullptr, (LPWSTR)cmdNonConst.data(), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &siStartInfo, &piProcInfo)) + goto cleanupAndExit; + + WaitForSingleObject(piProcInfo.hProcess, INFINITE); + GetExitCodeProcess(piProcInfo.hProcess, &exitCode); + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + CloseHandle(childStdoutHandle); + childStdoutHandle = nullptr; + + DWORD bytesRead; + CHAR buffer[BUFSIZE]; + while (true) + { + BOOL bSuccess = ReadFile(childReadHandle, buffer, BUFSIZE, &bytesRead, nullptr); + if (!bSuccess || bytesRead == 0) + break; + + execStdout.append(buffer, bytesRead); + if (print) + printf("%.*s", bytesRead, buffer); + } - if (exitCode == 0) { ExecResult execResult; - execResult.execStdout = result; + execResult.execStdout = move(execStdout); execResult.exitCode = exitCode; + CloseHandle(childReadHandle); return Result<ExecResult>::Ok(execResult); } - else - { - string errMsg = "Exited with non-zero exit code ("; - errMsg += to_string(exitCode); - errMsg += "): "; - errMsg += toUtf8(getLastErrorAsString()); - return Result<ExecResult>::Err(errMsg); - } + + cleanupAndExit: + string errMsg = "exec unexpected error: "; + errMsg += toUtf8(getLastErrorAsString()); + CloseHandle(childReadHandle); + CloseHandle(childStdoutHandle); + return Result<ExecResult>::Err(errMsg); } #endif } |