Attachment "my_popen.h" to
ticket [11622724]
added by
anonymous
2010-08-26 09:04:55.
#if defined(__MINGW32__)
#include <sys/fcntl.h>
#include <tchar.h>
#include <windows.h>
/*
* Display the error message of Windows system call
*/
void ErrorExit(LPTSTR lpszFunction)
{
/* Retrieve the system error message for the last-error code */
TCHAR buff[1024] = {};
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
&buff,
sizeof(buff)/sizeof(buff[0]),
NULL );
/* Display the error message and exit the process */
_ftprintf(stderr, "%s\n%s\n", buff, lpszFunction);
ExitProcess(dw);
}
/*
* Convert a Windows file handle to crt type FILE*
*/
FILE* fhopen(HANDLE hFile, const char *zMode){
int fd = _open_osfhandle((intptr_t)hFile, _O_BINARY);
if( fd != -1)
return _fdopen(fd, zMode);
else
return NULL;
}
/*
* Spawn child process and redirect its io to our handles
*/
static DWORD SpawnChild(LPTSTR lpCmdLine, HANDLE hIn, HANDLE hOut, HANDLE hErr)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
BOOL success;
memset((void *)&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof (STARTUPINFO);
/*
* Indicate the hStdInput, hStdOutput, and hStdError members are valid.
*/
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hIn;
si.hStdOutput = hOut;
si.hStdError = hErr;
/*
* Ensure stdio inheritable.
*/
success = SetHandleInformation(si.hStdInput, HANDLE_FLAG_INHERIT, TRUE);
if(!success) {
ErrorExit("SetHandleInformation failed");
}
success = SetHandleInformation(si.hStdOutput, HANDLE_FLAG_INHERIT, TRUE);
if(!success) {
ErrorExit("SetHandleInformation failed");
}
success = SetHandleInformation(si.hStdError, HANDLE_FLAG_INHERIT, TRUE);
if(!success) {
ErrorExit("SetHandleInformation failed");
}
/*
* Create child process
*/
success = CreateProcess(NULL, /* LPCSTR address of module name */
lpCmdLine, /* LPCSTR address of command line */
NULL, /* Process security attributes */
NULL, /* Thread security attributes */
TRUE, /* Inheritable Handes inherited. */
0, /* DWORD creation flags */
NULL, /* Use parent environment block */
NULL, /* Address of current directory name */
&si, /* Address of STARTUPINFO */
&pi); /* Address of PROCESS_INFORMATION */
if(!success){
ErrorExit("CreateProcess failed");
}
/* Close process and thread handles. */
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return pi.dwProcessId;
}
static DWORD win32_create_child(const char *zCmd, HANDLE *hIn, HANDLE *hOut)
{
HANDLE hChildStdinRd, hChildStdinWr,
hChildStdoutRd, hChildStdoutWr;
HANDLE hStderr;
SECURITY_ATTRIBUTES saAttr;
BOOL fSuccess;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; /* Set the bInheritHandle flag so pipe handles are inherited. */
saAttr.lpSecurityDescriptor = NULL;
#if defined(FOSSIL_CHILD_DEBUG)
char zDebugFName[200] = {0};
const char *zTempPrefix = "sever_child_debug_output";
static volatile long i = 0;
InterlockedIncrement(&i);
snprintf(zDebugFName, sizeof(zDebugFName), "%s_%05ld.txt", zTempPrefix, i);
hStderr = CreateFile(zDebugFName, // file to open
GENERIC_WRITE, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
CREATE_ALWAYS, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
SetHandleInformation( hStderr, HANDLE_FLAG_INHERIT, TRUE);
#else
/* Get the handle to the current STDERR. */
hStderr = GetStdHandle(STD_ERROR_HANDLE);
#endif
/* Create a pipe for the child process's STDOUT. */
if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 4096))
ErrorExit("Stdout pipe creation failed\n");
/* Ensure the read handle to the pipe for STDOUT is not inherited. */
SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
/* Create a pipe for the child process's STDIN. */
if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 4096))
ErrorExit("Stdin pipe creation failed\n");
/* Ensure the write handle to the pipe for STDIN is not inherited. */
SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, FALSE);
/* Spawn child and redirect its io */
DWORD processId = SpawnChild(zCmd, hChildStdinRd, hChildStdoutWr, hStderr);
/* Close pipe handles that used by child to read and write */
CloseHandle(hChildStdinRd);
CloseHandle(hChildStdoutWr);
#if defined(FOSSIL_CHILD_DEBUG)
CloseHandle(hStderr);
#endif
*hIn = hChildStdoutRd;
*hOut = hChildStdinWr;
return processId;
}
int popen2(const char *zCmd, FILE **ppIn, FILE **ppOut, int *pChildPid){
HANDLE in, out;
DWORD childProcessId = win32_create_child(zCmd, &in, &out);
if(childProcessId == 0){
fossil_fatal("create child process failed");
}
*ppIn = fhopen(in, "rb");
*ppOut = fhopen(out, "wb");
if( (*ppIn) == NULL || (*ppOut) == NULL){
fossil_fatal("fhopen failed!");
}
*pChildPid = childProcessId;
}
#endif /* __MINGW32__ */