123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- /*
- * Copyright (c) 2023 Lain Bailey <[email protected]>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include "platform.h"
- #include "bmem.h"
- #include "pipe.h"
- struct os_process_pipe {
- bool read_pipe;
- HANDLE handle;
- HANDLE handle_err;
- HANDLE process;
- };
- static bool create_pipe(HANDLE *input, HANDLE *output)
- {
- SECURITY_ATTRIBUTES sa = {0};
- sa.nLength = sizeof(sa);
- sa.bInheritHandle = true;
- if (!CreatePipe(input, output, &sa, 0)) {
- return false;
- }
- return true;
- }
- static inline bool create_process(const char *cmd_line, HANDLE stdin_handle,
- HANDLE stdout_handle, HANDLE stderr_handle,
- HANDLE *process)
- {
- PROCESS_INFORMATION pi = {0};
- wchar_t *cmd_line_w = NULL;
- STARTUPINFOW si = {0};
- bool success = false;
- si.cb = sizeof(si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_FORCEOFFFEEDBACK;
- si.hStdInput = stdin_handle;
- si.hStdOutput = stdout_handle;
- si.hStdError = stderr_handle;
- DWORD flags = 0;
- #ifndef SHOW_SUBPROCESSES
- flags = CREATE_NO_WINDOW;
- #endif
- os_utf8_to_wcs_ptr(cmd_line, 0, &cmd_line_w);
- if (cmd_line_w) {
- success = !!CreateProcessW(NULL, cmd_line_w, NULL, NULL, true,
- flags, NULL, NULL, &si, &pi);
- if (success) {
- *process = pi.hProcess;
- CloseHandle(pi.hThread);
- } else {
- // Not logging the full command line is intentional
- // as it may contain stream keys etc.
- blog(LOG_ERROR, "CreateProcessW failed: %lu",
- GetLastError());
- }
- bfree(cmd_line_w);
- }
- return success;
- }
- os_process_pipe_t *os_process_pipe_create(const char *cmd_line,
- const char *type)
- {
- os_process_pipe_t *pp = NULL;
- bool read_pipe;
- HANDLE process;
- HANDLE output;
- HANDLE err_input, err_output;
- HANDLE input;
- bool success;
- if (!cmd_line || !type) {
- return NULL;
- }
- if (*type != 'r' && *type != 'w') {
- return NULL;
- }
- if (!create_pipe(&input, &output)) {
- return NULL;
- }
- if (!create_pipe(&err_input, &err_output)) {
- return NULL;
- }
- read_pipe = *type == 'r';
- success = !!SetHandleInformation(read_pipe ? input : output,
- HANDLE_FLAG_INHERIT, false);
- if (!success) {
- goto error;
- }
- success = !!SetHandleInformation(err_input, HANDLE_FLAG_INHERIT, false);
- if (!success) {
- goto error;
- }
- success = create_process(cmd_line, read_pipe ? NULL : input,
- read_pipe ? output : NULL, err_output,
- &process);
- if (!success) {
- goto error;
- }
- pp = bmalloc(sizeof(*pp));
- pp->handle = read_pipe ? input : output;
- pp->read_pipe = read_pipe;
- pp->process = process;
- pp->handle_err = err_input;
- CloseHandle(read_pipe ? output : input);
- CloseHandle(err_output);
- return pp;
- error:
- CloseHandle(output);
- CloseHandle(input);
- return NULL;
- }
- int os_process_pipe_destroy(os_process_pipe_t *pp)
- {
- int ret = 0;
- if (pp) {
- DWORD code;
- CloseHandle(pp->handle);
- CloseHandle(pp->handle_err);
- WaitForSingleObject(pp->process, INFINITE);
- if (GetExitCodeProcess(pp->process, &code))
- ret = (int)code;
- CloseHandle(pp->process);
- bfree(pp);
- }
- return ret;
- }
- size_t os_process_pipe_read(os_process_pipe_t *pp, uint8_t *data, size_t len)
- {
- DWORD bytes_read;
- bool success;
- if (!pp) {
- return 0;
- }
- if (!pp->read_pipe) {
- return 0;
- }
- success = !!ReadFile(pp->handle, data, (DWORD)len, &bytes_read, NULL);
- if (success && bytes_read) {
- return bytes_read;
- }
- return 0;
- }
- size_t os_process_pipe_read_err(os_process_pipe_t *pp, uint8_t *data,
- size_t len)
- {
- DWORD bytes_read;
- bool success;
- if (!pp || !pp->handle_err) {
- return 0;
- }
- success =
- !!ReadFile(pp->handle_err, data, (DWORD)len, &bytes_read, NULL);
- if (success && bytes_read) {
- return bytes_read;
- } else
- bytes_read = GetLastError();
- return 0;
- }
- size_t os_process_pipe_write(os_process_pipe_t *pp, const uint8_t *data,
- size_t len)
- {
- DWORD bytes_written;
- bool success;
- if (!pp) {
- return 0;
- }
- if (pp->read_pipe) {
- return 0;
- }
- success =
- !!WriteFile(pp->handle, data, (DWORD)len, &bytes_written, NULL);
- if (success && bytes_written) {
- return bytes_written;
- }
- return 0;
- }
|