From dd610f595b320ffbd04ff1d288aa0252ea9997aa Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Thu, 16 Oct 2008 11:31:13 +0000 Subject: [PATCH] ebl Fix #1110 about RunScript that can't execute a script with Unicode caracters in the path. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@7817 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/win32/compat/compat.cpp | 156 ++++++++++++++++++++--------- bacula/src/win32/compat/winapi.c | 9 ++ bacula/src/win32/winapi.h | 26 +++++ bacula/technotes-2.5 | 3 + 4 files changed, 149 insertions(+), 45 deletions(-) diff --git a/bacula/src/win32/compat/compat.cpp b/bacula/src/win32/compat/compat.cpp index aeeb8fbc61..43334a83c9 100644 --- a/bacula/src/win32/compat/compat.cpp +++ b/bacula/src/win32/compat/compat.cpp @@ -1846,6 +1846,97 @@ GetApplicationName(const char *cmdline, char **pexe, const char **pargs) return true; } +/** + * Create the process with UTF8 API + */ +static BOOL +CreateChildProcessW(const char *comspec, const char *cmdLine, + PROCESS_INFORMATION *hProcInfo, + HANDLE in, HANDLE out, HANDLE err) +{ + STARTUPINFOW siStartInfo; + BOOL bFuncRetn = FALSE; + + // Set up members of the STARTUPINFO structure. + ZeroMemory( &siStartInfo, sizeof(siStartInfo) ); + siStartInfo.cb = sizeof(siStartInfo); + // setup new process to use supplied handles for stdin,stdout,stderr + + siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; + + siStartInfo.hStdInput = in; + siStartInfo.hStdOutput = out; + siStartInfo.hStdError = err; + + // Convert argument to WCHAR + POOLMEM *cmdLine_wchar = get_pool_memory(PM_FNAME); + POOLMEM *comspec_wchar = get_pool_memory(PM_FNAME); + + make_win32_path_UTF8_2_wchar(&cmdLine_wchar, cmdLine); + make_win32_path_UTF8_2_wchar(&comspec_wchar, comspec); + + // Create the child process. + Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine); + + // try to execute program + bFuncRetn = p_CreateProcessW((WCHAR*)comspec_wchar, + (WCHAR*)cmdLine_wchar,// command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + hProcInfo); // receives PROCESS_INFORMATION + + free_pool_memory(cmdLine_wchar); + free_pool_memory(comspec_wchar); + + return bFuncRetn; +} + + +/** + * Create the process with ANSI API + */ +static BOOL +CreateChildProcessA(const char *comspec, char *cmdLine, + PROCESS_INFORMATION *hProcInfo, + HANDLE in, HANDLE out, HANDLE err) +{ + STARTUPINFOA siStartInfo; + BOOL bFuncRetn = FALSE; + + // Set up members of the STARTUPINFO structure. + ZeroMemory( &siStartInfo, sizeof(siStartInfo) ); + siStartInfo.cb = sizeof(siStartInfo); + // setup new process to use supplied handles for stdin,stdout,stderr + siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; + + siStartInfo.hStdInput = in; + siStartInfo.hStdOutput = out; + siStartInfo.hStdError = err; + + // Create the child process. + Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine); + + // try to execute program + bFuncRetn = p_CreateProcessA(comspec, + cmdLine, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo,// STARTUPINFO pointer + hProcInfo);// receives PROCESS_INFORMATION + return bFuncRetn; +} + /** * OK, so it would seem CreateProcess only handles true executables: * .com or .exe files. So grab $COMSPEC value and pass command line to it. @@ -1855,43 +1946,29 @@ CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err) { static const char *comspec = NULL; PROCESS_INFORMATION piProcInfo; - STARTUPINFOA siStartInfo; BOOL bFuncRetn = FALSE; - if (comspec == NULL) { + if (!p_CreateProcessA || !p_CreateProcessW) + return INVALID_HANDLE_VALUE; + + if (comspec == NULL) comspec = getenv("COMSPEC"); - } if (comspec == NULL) // should never happen return INVALID_HANDLE_VALUE; // Set up members of the PROCESS_INFORMATION structure. ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); - // Set up members of the STARTUPINFO structure. - - ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); - siStartInfo.cb = sizeof(STARTUPINFO); - // setup new process to use supplied handles for stdin,stdout,stderr // if supplied handles are not used the send a copy of our STD_HANDLE // as appropriate - siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - siStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; - - if (in != INVALID_HANDLE_VALUE) - siStartInfo.hStdInput = in; - else - siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + if (in == INVALID_HANDLE_VALUE) + in = GetStdHandle(STD_INPUT_HANDLE); - if (out != INVALID_HANDLE_VALUE) - siStartInfo.hStdOutput = out; - else - siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - if (err != INVALID_HANDLE_VALUE) - siStartInfo.hStdError = err; - else - siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (out == INVALID_HANDLE_VALUE) + out = GetStdHandle(STD_OUTPUT_HANDLE); - // Create the child process. + if (err == INVALID_HANDLE_VALUE) + err = GetStdHandle(STD_ERROR_HANDLE); char *exeFile; const char *argStart; @@ -1900,43 +1977,32 @@ CreateChildProcess(const char *cmdline, HANDLE in, HANDLE out, HANDLE err) return INVALID_HANDLE_VALUE; } - int cmdLen = strlen(comspec) + 4 + strlen(exeFile) + strlen(argStart) + 1; - - char *cmdLine = (char *)alloca(cmdLen); - - snprintf(cmdLine, cmdLen, "%s /c %s%s", comspec, exeFile, argStart); + POOL_MEM cmdLine(PM_FNAME); + Mmsg(cmdLine, "%s /c %s%s", comspec, exeFile, argStart); free(exeFile); - Dmsg2(150, "Calling CreateProcess(%s, %s, ...)\n", comspec, cmdLine); - - // try to execute program - bFuncRetn = CreateProcessA(comspec, - cmdLine, // command line - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - 0, // creation flags - NULL, // use parent's environment - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &piProcInfo); // receives PROCESS_INFORMATION + if (p_CreateProcessW && p_MultiByteToWideChar) { + bFuncRetn = CreateChildProcessW(comspec, cmdLine.c_str(), &piProcInfo, + in, out, err); + } else { + bFuncRetn = CreateChildProcessA(comspec, cmdLine.c_str(), &piProcInfo, + in, out, err); + } if (bFuncRetn == 0) { ErrorExit("CreateProcess failed\n"); const char *err = errorString(); - Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n", comspec, cmdLine, err); + Dmsg3(99, "CreateProcess(%s, %s, ...)=%s\n",comspec,cmdLine.c_str(),err); LocalFree((void *)err); return INVALID_HANDLE_VALUE; } // we don't need a handle on the process primary thread so we close // this now. CloseHandle(piProcInfo.hThread); - return piProcInfo.hProcess; } - void ErrorExit (LPCSTR lpszMessage) { diff --git a/bacula/src/win32/compat/winapi.c b/bacula/src/win32/compat/winapi.c index b94922fa52..b6aef82d9f 100644 --- a/bacula/src/win32/compat/winapi.c +++ b/bacula/src/win32/compat/winapi.c @@ -88,6 +88,9 @@ t_GetVolumeNameForVolumeMountPointW p_GetVolumeNameForVolumeMountPointW = NULL; t_SHGetFolderPath p_SHGetFolderPath = NULL; +t_CreateProcessA p_CreateProcessA = NULL; +t_CreateProcessW p_CreateProcessW = NULL; + void InitWinAPIWrapper() { @@ -104,6 +107,12 @@ InitWinAPIWrapper() HMODULE hLib = LoadLibraryA("KERNEL32.DLL"); if (hLib) { + /* create process calls */ + p_CreateProcessA = (t_CreateProcessA) + GetProcAddress(hLib, "CreateProcessA"); + p_CreateProcessW = (t_CreateProcessW) + GetProcAddress(hLib, "CreateProcessW"); + /* create file calls */ p_CreateFileA = (t_CreateFileA)GetProcAddress(hLib, "CreateFileA"); p_CreateDirectoryA = (t_CreateDirectoryA)GetProcAddress(hLib, "CreateDirectoryA"); diff --git a/bacula/src/win32/winapi.h b/bacula/src/win32/winapi.h index 471e0365d9..ed77b6ec46 100644 --- a/bacula/src/win32/winapi.h +++ b/bacula/src/win32/winapi.h @@ -138,6 +138,32 @@ typedef BOOL (WINAPI * t_GetVolumeNameForVolumeMountPointW) (LPCWSTR, LPWSTR, DW typedef BOOL (WINAPI * t_AttachConsole) (DWORD); +typedef BOOL (WINAPI *t_CreateProcessA) ( + LPCSTR, + LPSTR, + LPSECURITY_ATTRIBUTES, + LPSECURITY_ATTRIBUTES, + BOOL, + DWORD, + PVOID, + LPCSTR, + LPSTARTUPINFOA, + LPPROCESS_INFORMATION); +typedef BOOL (WINAPI *t_CreateProcessW) ( + LPCWSTR, + LPWSTR, + LPSECURITY_ATTRIBUTES, + LPSECURITY_ATTRIBUTES, + BOOL, + DWORD, + PVOID, + LPCWSTR, + LPSTARTUPINFOW, + LPPROCESS_INFORMATION); + +extern t_CreateProcessA DLL_IMP_EXP p_CreateProcessA; +extern t_CreateProcessW DLL_IMP_EXP p_CreateProcessW; + extern t_GetFileAttributesA DLL_IMP_EXP p_GetFileAttributesA; extern t_GetFileAttributesW DLL_IMP_EXP p_GetFileAttributesW; diff --git a/bacula/technotes-2.5 b/bacula/technotes-2.5 index 96bdcde97b..7bcb0a2289 100644 --- a/bacula/technotes-2.5 +++ b/bacula/technotes-2.5 @@ -17,6 +17,9 @@ dbdriver remove reader/writer in FOPTS???? General: +16Oct08 +ebl Fix #1110 about RunScript that can't execute a script with + Unicode caracters in the path. 15Oct08 kes Apply tray-monitor patch from Bastian Friedrich to make it work with the new FD. -- 2.39.5