mariadb/mysys/my_win_popen.cc
anson1014 966d22b715
Ensure that source files contain only valid UTF8 encodings (#2188)
Modern software (including text editors, static analysis software,
and web-based code review interfaces) often requires source code files
to be interpretable via a consistent character encoding, with UTF-8 or
ASCII (a strict subset of UTF-8) as the default. Several of the MariaDB
source files contain bytes that are not valid in either the UTF-8 or
ASCII encodings, but instead represent strings encoded in the
ISO-8859-1/Latin-1 or ISO-8859-2/Latin-2 encodings.

These inconsistent encodings may prevent software from correctly
presenting or processing such files. Converting all source files to
valid UTF8 characters will ensure correct handling.

Comments written in Czech were replaced with lightly-corrected
translations from Google Translate. Additionally, comments describing
the proper handling of special characters were changed so that the
comments are now purely UTF8.

All new code of the whole pull request, including one or several files
that are either new files or modified ones, are contributed under the
BSD-new license. I am contributing on behalf of my employer
Amazon Web Services, Inc.

Co-authored-by: Andrew Hutchings <andrew@linuxjedi.co.uk>
2022-08-30 09:21:40 +01:00

170 lines
4 KiB
C++

/* 2019, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
Replacement of the buggy implementations of popen in Windows CRT
*/
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <mutex>
#include <stdlib.h>
#include <unordered_map>
enum
{
REDIRECT_STDIN= 'w',
REDIRECT_STDOUT= 'r'
};
/** Map from FILE* returned by popen() to corresponding process handle.*/
static std::unordered_map<FILE *, HANDLE> popen_map;
/* Mutex to protect the map.*/
static std::mutex popen_mtx;
/**
Creates a FILE* from HANDLE.
*/
static FILE *make_fp(HANDLE *handle, const char *mode)
{
int flags = 0;
if (mode[0] == REDIRECT_STDOUT)
flags |= O_RDONLY;
switch (mode[1])
{
case 't':
flags |= _O_TEXT;
break;
case 'b':
flags |= _O_BINARY;
break;
}
int fd= _open_osfhandle((intptr_t) *handle, flags);
if (fd < 0)
return NULL;
FILE *fp= fdopen(fd, mode);
if (!fp)
{
/* Closing file descriptor also closes underlying handle.*/
close(fd);
*handle= 0;
}
return fp;
}
/** A home-backed version of popen(). */
extern "C" FILE *my_win_popen(const char *cmd, const char *mode)
{
FILE *fp(0);
char type= mode[0];
HANDLE parent_pipe_end(0);
HANDLE child_pipe_end(0);
PROCESS_INFORMATION pi{};
STARTUPINFO si{};
std::string command_line;
/* Create a pipe between this and child process.*/
SECURITY_ATTRIBUTES sa_attr{};
sa_attr.nLength= sizeof(SECURITY_ATTRIBUTES);
sa_attr.bInheritHandle= TRUE;
switch (type)
{
case REDIRECT_STDIN:
if (!CreatePipe(&child_pipe_end, &parent_pipe_end, &sa_attr, 0))
goto error;
break;
case REDIRECT_STDOUT:
if (!CreatePipe(&parent_pipe_end, &child_pipe_end, &sa_attr, 0))
goto error;
break;
default:
/* Unknown mode, expected "r", "rt", "w", "wt" */
abort();
}
if (!SetHandleInformation(parent_pipe_end, HANDLE_FLAG_INHERIT, 0))
goto error;
/* Start child process with redirected output.*/
si.cb= sizeof(STARTUPINFO);
si.hStdError= GetStdHandle(STD_ERROR_HANDLE);
si.hStdOutput= (type == REDIRECT_STDOUT) ? child_pipe_end
: GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdInput= (type == REDIRECT_STDIN) ? child_pipe_end
: GetStdHandle(STD_INPUT_HANDLE);
si.dwFlags|= STARTF_USESTDHANDLES;
command_line.append("cmd.exe /c ").append(cmd);
if (!CreateProcess(0, (LPSTR) command_line.c_str(), 0, 0, TRUE, 0, 0, 0, &si,
&pi))
goto error;
CloseHandle(pi.hThread);
CloseHandle(child_pipe_end);
child_pipe_end= 0;
fp= make_fp(&parent_pipe_end, mode);
if (fp)
{
std::unique_lock<std::mutex> lk(popen_mtx);
popen_map[fp]= pi.hProcess;
return fp;
}
error:
for (auto handle : { parent_pipe_end, child_pipe_end })
{
if (handle)
CloseHandle(handle);
}
if (pi.hProcess)
{
TerminateProcess(pi.hProcess, 1);
CloseHandle(pi.hProcess);
}
return NULL;
}
/** A home-backed version of pclose(). */
extern "C" int my_win_pclose(FILE *fp)
{
/* Find process entry for given file pointer.*/
std::unique_lock<std::mutex> lk(popen_mtx);
HANDLE proc= popen_map[fp];
if (!proc)
{
errno= EINVAL;
return -1;
}
popen_map.erase(fp);
lk.unlock();
fclose(fp);
/* Wait for process to complete, return its exit code.*/
DWORD ret;
if (WaitForSingleObject(proc, INFINITE) || !GetExitCodeProcess(proc, &ret))
{
ret= -1;
errno= EINVAL;
}
CloseHandle(proc);
return ret;
}