#if defined(__MINGW32__) #include #include #include /* * 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__ */