xref: /AOO41X/main/sal/osl/w32/procimpl.cxx (revision 87d2adbc9cadf14644c3679b041b9226f7630199)
1*87d2adbcSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*87d2adbcSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*87d2adbcSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*87d2adbcSAndrew Rist  * distributed with this work for additional information
6*87d2adbcSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*87d2adbcSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*87d2adbcSAndrew Rist  * "License"); you may not use this file except in compliance
9*87d2adbcSAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*87d2adbcSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*87d2adbcSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*87d2adbcSAndrew Rist  * software distributed under the License is distributed on an
15*87d2adbcSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*87d2adbcSAndrew Rist  * KIND, either express or implied.  See the License for the
17*87d2adbcSAndrew Rist  * specific language governing permissions and limitations
18*87d2adbcSAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*87d2adbcSAndrew Rist  *************************************************************/
21*87d2adbcSAndrew Rist 
22*87d2adbcSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sal.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #define UNICODE
28cdf0e10cSrcweir #define _UNICODE
29cdf0e10cSrcweir 
30cdf0e10cSrcweir #ifndef WIN32_LEAN_AND_MEAN
31cdf0e10cSrcweir #   define WIN32_LEAN_AND_MEAN
32cdf0e10cSrcweir # ifdef _MSC_VER
33cdf0e10cSrcweir #   pragma warning(push,1) /* disable warnings within system headers */
34cdf0e10cSrcweir # endif
35cdf0e10cSrcweir #   include <windows.h>
36cdf0e10cSrcweir # ifdef _MSC_VER
37cdf0e10cSrcweir #   pragma warning(pop)
38cdf0e10cSrcweir # endif
39cdf0e10cSrcweir #   include <tchar.h>
40cdf0e10cSrcweir #   undef WIN32_LEAN_AND_MEAN
41cdf0e10cSrcweir #endif
42cdf0e10cSrcweir #include "procimpl.h"
43cdf0e10cSrcweir #include <rtl/ustring.hxx>
44cdf0e10cSrcweir #include <rtl/ustrbuf.hxx>
45cdf0e10cSrcweir #include "secimpl.h"
46cdf0e10cSrcweir #include "rtl/allocator.hxx"
47cdf0e10cSrcweir #include <osl/file.hxx>
48cdf0e10cSrcweir 
49cdf0e10cSrcweir #include <list>
50cdf0e10cSrcweir #include <vector>
51cdf0e10cSrcweir #include <algorithm>
52cdf0e10cSrcweir #include <string>
53cdf0e10cSrcweir 
54cdf0e10cSrcweir //#################################################
55cdf0e10cSrcweir extern "C" oslFileHandle SAL_CALL osl_createFileHandleFromOSHandle( HANDLE hFile, sal_uInt32 uFlags );
56cdf0e10cSrcweir 
57cdf0e10cSrcweir //#################################################
58cdf0e10cSrcweir const sal_Unicode NAME_VALUE_SEPARATOR = TEXT('=');
59cdf0e10cSrcweir const sal_Char* SPACE = " ";
60cdf0e10cSrcweir const rtl::OUString ENV_COMSPEC = rtl::OUString::createFromAscii("COMSPEC");
61cdf0e10cSrcweir const rtl::OUString QUOTE = rtl::OUString::createFromAscii("\"");
62cdf0e10cSrcweir 
63cdf0e10cSrcweir namespace /* private */
64cdf0e10cSrcweir {
65cdf0e10cSrcweir     //#################################################
66cdf0e10cSrcweir     typedef std::list<rtl::OUString, rtl::Allocator<rtl::OUString> > string_container_t;
67cdf0e10cSrcweir     typedef string_container_t::iterator string_container_iterator_t;
68cdf0e10cSrcweir     typedef string_container_t::const_iterator string_container_const_iterator_t;
69cdf0e10cSrcweir     typedef std::pair<string_container_iterator_t, string_container_iterator_t> iterator_pair_t;
70cdf0e10cSrcweir     typedef std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > environment_container_t;
71cdf0e10cSrcweir 
72cdf0e10cSrcweir     //#################################################
73cdf0e10cSrcweir     /* Function object that compares two strings that are
74cdf0e10cSrcweir        expected to be environment variables in the form
75cdf0e10cSrcweir        "name=value". Only the 'name' part will be compared.
76cdf0e10cSrcweir        The comparison is in upper case and returns true
77cdf0e10cSrcweir        if the first of both strings is less than the
78cdf0e10cSrcweir        second one. */
79cdf0e10cSrcweir     struct less_environment_variable :
80cdf0e10cSrcweir         public std::binary_function<rtl::OUString, rtl::OUString, bool>
81cdf0e10cSrcweir     {
82cdf0e10cSrcweir         bool operator() (const rtl::OUString& lhs, const rtl::OUString& rhs) const
83cdf0e10cSrcweir         {
84cdf0e10cSrcweir             OSL_ENSURE((lhs.indexOf(NAME_VALUE_SEPARATOR) > -1) && \
85cdf0e10cSrcweir                         (rhs.indexOf(NAME_VALUE_SEPARATOR) > -1), \
86cdf0e10cSrcweir                         "Malformed environment variable");
87cdf0e10cSrcweir 
88cdf0e10cSrcweir             // Windows compares environment variables uppercase
89cdf0e10cSrcweir             // so we do it, too
90cdf0e10cSrcweir             return (rtl_ustr_compare_WithLength(
91cdf0e10cSrcweir                 lhs.toAsciiUpperCase().pData->buffer,
92cdf0e10cSrcweir                 lhs.indexOf(NAME_VALUE_SEPARATOR),
93cdf0e10cSrcweir                 rhs.toAsciiUpperCase().pData->buffer,
94cdf0e10cSrcweir                 rhs.indexOf(NAME_VALUE_SEPARATOR)) < 0);
95cdf0e10cSrcweir         }
96cdf0e10cSrcweir     };
97cdf0e10cSrcweir 
98cdf0e10cSrcweir     //#################################################
99cdf0e10cSrcweir     /* Function object used by for_each algorithm to
100cdf0e10cSrcweir        calculate the sum of the length of all strings
101cdf0e10cSrcweir        in a string container. */
102cdf0e10cSrcweir     class sum_of_string_lengths
103cdf0e10cSrcweir     {
104cdf0e10cSrcweir     public:
105cdf0e10cSrcweir         //--------------------------------
106cdf0e10cSrcweir         sum_of_string_lengths() : sum_(0) {}
107cdf0e10cSrcweir 
108cdf0e10cSrcweir         //--------------------------------
109cdf0e10cSrcweir         void operator() (const rtl::OUString& string)
110cdf0e10cSrcweir         {
111cdf0e10cSrcweir             OSL_ASSERT(string.getLength());
112cdf0e10cSrcweir 
113cdf0e10cSrcweir             // always include the terminating '\0'
114cdf0e10cSrcweir             if (string.getLength())
115cdf0e10cSrcweir                 sum_ += string.getLength() + 1;
116cdf0e10cSrcweir         }
117cdf0e10cSrcweir 
118cdf0e10cSrcweir         //--------------------------------
119cdf0e10cSrcweir         operator size_t () const
120cdf0e10cSrcweir         {
121cdf0e10cSrcweir             return sum_;
122cdf0e10cSrcweir         }
123cdf0e10cSrcweir     private:
124cdf0e10cSrcweir         size_t sum_;
125cdf0e10cSrcweir     };
126cdf0e10cSrcweir 
127cdf0e10cSrcweir     //#################################################
128cdf0e10cSrcweir     inline size_t calc_sum_of_string_lengths(const string_container_t& string_cont)
129cdf0e10cSrcweir     {
130cdf0e10cSrcweir         return std::for_each(
131cdf0e10cSrcweir             string_cont.begin(), string_cont.end(), sum_of_string_lengths());
132cdf0e10cSrcweir     }
133cdf0e10cSrcweir 
134cdf0e10cSrcweir     //#################################################
135cdf0e10cSrcweir     void read_environment(/*out*/ string_container_t* environment)
136cdf0e10cSrcweir     {
137cdf0e10cSrcweir         // GetEnvironmentStrings returns a sorted list, Windows
138cdf0e10cSrcweir         // sorts environment variables upper case
139cdf0e10cSrcweir         LPTSTR env = reinterpret_cast<LPTSTR>(GetEnvironmentStrings());
140cdf0e10cSrcweir         LPTSTR p   = env;
141cdf0e10cSrcweir 
142cdf0e10cSrcweir         while (size_t l = _tcslen(p))
143cdf0e10cSrcweir         {
144cdf0e10cSrcweir             environment->push_back(reinterpret_cast<const sal_Unicode*>(p));
145cdf0e10cSrcweir             p += l + 1;
146cdf0e10cSrcweir         }
147cdf0e10cSrcweir         FreeEnvironmentStrings(env);
148cdf0e10cSrcweir     }
149cdf0e10cSrcweir 
150cdf0e10cSrcweir     //#################################################
151cdf0e10cSrcweir     /* the environment list must be sorted, new values
152cdf0e10cSrcweir     should either replace existing ones or should be
153cdf0e10cSrcweir     added to the list, environment variables will
154cdf0e10cSrcweir     be handled case-insensitive */
155cdf0e10cSrcweir     bool create_merged_environment(
156cdf0e10cSrcweir         rtl_uString* env_vars[],
157cdf0e10cSrcweir         sal_uInt32 env_vars_count,
158cdf0e10cSrcweir         /*in|out*/ string_container_t* merged_env)
159cdf0e10cSrcweir     {
160cdf0e10cSrcweir         OSL_ASSERT(env_vars && env_vars_count > 0 && merged_env);
161cdf0e10cSrcweir 
162cdf0e10cSrcweir         read_environment(merged_env);
163cdf0e10cSrcweir 
164cdf0e10cSrcweir         for (sal_uInt32 i = 0; i < env_vars_count; i++)
165cdf0e10cSrcweir         {
166cdf0e10cSrcweir             rtl::OUString env_var = rtl::OUString(env_vars[i]);
167cdf0e10cSrcweir 
168cdf0e10cSrcweir             if (env_var.getLength() == 0)
169cdf0e10cSrcweir                 return false;
170cdf0e10cSrcweir 
171cdf0e10cSrcweir             iterator_pair_t iter_pair = std::equal_range(
172cdf0e10cSrcweir                 merged_env->begin(),
173cdf0e10cSrcweir                 merged_env->end(),
174cdf0e10cSrcweir                 env_var,
175cdf0e10cSrcweir                 less_environment_variable());
176cdf0e10cSrcweir 
177cdf0e10cSrcweir             if (env_var.indexOf(NAME_VALUE_SEPARATOR) == -1)
178cdf0e10cSrcweir             {
179cdf0e10cSrcweir                 merged_env->erase(iter_pair.first, iter_pair.second);
180cdf0e10cSrcweir             }
181cdf0e10cSrcweir             else
182cdf0e10cSrcweir             {
183cdf0e10cSrcweir                 if (iter_pair.first != iter_pair.second) // found
184cdf0e10cSrcweir                     *iter_pair.first = env_var;
185cdf0e10cSrcweir                 else // not found
186cdf0e10cSrcweir                     merged_env->insert(iter_pair.first, env_var);
187cdf0e10cSrcweir             }
188cdf0e10cSrcweir         }
189cdf0e10cSrcweir         return true;
190cdf0e10cSrcweir     }
191cdf0e10cSrcweir 
192cdf0e10cSrcweir     //#################################################
193cdf0e10cSrcweir     /* Create a merged environment */
194cdf0e10cSrcweir     bool setup_process_environment(
195cdf0e10cSrcweir         rtl_uString* environment_vars[],
196cdf0e10cSrcweir         sal_uInt32 n_environment_vars,
197cdf0e10cSrcweir         /*in|out*/ environment_container_t& environment)
198cdf0e10cSrcweir     {
199cdf0e10cSrcweir         string_container_t merged_env;
200cdf0e10cSrcweir 	    if (!create_merged_environment(environment_vars, n_environment_vars, &merged_env))
201cdf0e10cSrcweir 	        return false;
202cdf0e10cSrcweir 
203cdf0e10cSrcweir         // allocate enough space for the '\0'-separated environment strings and
204cdf0e10cSrcweir         // a final '\0'
205cdf0e10cSrcweir         environment.resize(calc_sum_of_string_lengths(merged_env) + 1);
206cdf0e10cSrcweir 
207cdf0e10cSrcweir         string_container_const_iterator_t iter = merged_env.begin();
208cdf0e10cSrcweir         string_container_const_iterator_t iter_end = merged_env.end();
209cdf0e10cSrcweir 
210cdf0e10cSrcweir         sal_uInt32 pos = 0;
211cdf0e10cSrcweir         for (/**/; iter != iter_end; ++iter)
212cdf0e10cSrcweir         {
213cdf0e10cSrcweir             rtl::OUString envv = *iter;
214cdf0e10cSrcweir 
215cdf0e10cSrcweir             OSL_ASSERT(envv.getLength());
216cdf0e10cSrcweir 
217cdf0e10cSrcweir             sal_uInt32 n = envv.getLength() + 1; // copy the final '\0', too
218cdf0e10cSrcweir             rtl_copyMemory(
219cdf0e10cSrcweir                 reinterpret_cast<void*>(&environment[pos]),
220cdf0e10cSrcweir                 reinterpret_cast<const void*>(envv.getStr()),
221cdf0e10cSrcweir                 n * sizeof(sal_Unicode));
222cdf0e10cSrcweir             pos += n;
223cdf0e10cSrcweir         }
224cdf0e10cSrcweir         environment[pos] = 0; // append a final '\0'
225cdf0e10cSrcweir 
226cdf0e10cSrcweir         return true;
227cdf0e10cSrcweir     }
228cdf0e10cSrcweir 
229cdf0e10cSrcweir     //##########################################################
230cdf0e10cSrcweir     /*  In contrast to the Win32 API function CreatePipe with
231cdf0e10cSrcweir         this function the caller is able to determine separately
232cdf0e10cSrcweir         which handle of the pipe is inheritable. */
233cdf0e10cSrcweir     bool create_pipe(
234cdf0e10cSrcweir         PHANDLE p_read_pipe,
235cdf0e10cSrcweir         bool    b_read_pipe_inheritable,
236cdf0e10cSrcweir         PHANDLE p_write_pipe,
237cdf0e10cSrcweir         bool    b_write_pipe_inheritable,
238cdf0e10cSrcweir         LPVOID  p_security_descriptor = NULL,
239cdf0e10cSrcweir         DWORD   pipe_size = 0)
240cdf0e10cSrcweir     {
241cdf0e10cSrcweir         SECURITY_ATTRIBUTES	sa;
242cdf0e10cSrcweir 	    sa.nLength              = sizeof(SECURITY_ATTRIBUTES);
243cdf0e10cSrcweir 	    sa.lpSecurityDescriptor = p_security_descriptor;
244cdf0e10cSrcweir 	    sa.bInheritHandle       = b_read_pipe_inheritable || b_write_pipe_inheritable;
245cdf0e10cSrcweir 
246cdf0e10cSrcweir 	    BOOL   bRet  = FALSE;
247cdf0e10cSrcweir 	    HANDLE hTemp = NULL;
248cdf0e10cSrcweir 
249cdf0e10cSrcweir 	    if (!b_read_pipe_inheritable && b_write_pipe_inheritable)
250cdf0e10cSrcweir 	    {
251cdf0e10cSrcweir 	        bRet = CreatePipe(&hTemp, p_write_pipe, &sa, pipe_size);
252cdf0e10cSrcweir 
253cdf0e10cSrcweir 	        if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp,
254cdf0e10cSrcweir 	                        GetCurrentProcess(), p_read_pipe, 0, FALSE,
255cdf0e10cSrcweir 	                        DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
256cdf0e10cSrcweir 	        {
257cdf0e10cSrcweir 	            CloseHandle(hTemp);
258cdf0e10cSrcweir 	            CloseHandle(*p_read_pipe);
259cdf0e10cSrcweir 	            return false;
260cdf0e10cSrcweir 	        }
261cdf0e10cSrcweir 	    }
262cdf0e10cSrcweir 	    else if (b_read_pipe_inheritable && !b_write_pipe_inheritable)
263cdf0e10cSrcweir 	    {
264cdf0e10cSrcweir 	        bRet = CreatePipe(p_read_pipe, &hTemp, &sa, pipe_size);
265cdf0e10cSrcweir 
266cdf0e10cSrcweir 	        if (bRet && !DuplicateHandle(GetCurrentProcess(), hTemp,
267cdf0e10cSrcweir 	                        GetCurrentProcess(), p_write_pipe, 0, FALSE,
268cdf0e10cSrcweir 	                        DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
269cdf0e10cSrcweir 	        {
270cdf0e10cSrcweir 	            CloseHandle(hTemp);
271cdf0e10cSrcweir 	            CloseHandle(*p_write_pipe);
272cdf0e10cSrcweir 	            return false;
273cdf0e10cSrcweir 	        }
274cdf0e10cSrcweir 	    }
275cdf0e10cSrcweir 	    else
276cdf0e10cSrcweir 	    {
277cdf0e10cSrcweir 	        bRet = CreatePipe(p_read_pipe, p_write_pipe, &sa, pipe_size);
278cdf0e10cSrcweir 	    }
279cdf0e10cSrcweir 	    return bRet;
280cdf0e10cSrcweir     }
281cdf0e10cSrcweir 
282cdf0e10cSrcweir     //#########################################################
283cdf0e10cSrcweir     // Add a quote sign to the start and the end of a string
284cdf0e10cSrcweir     // if not already present
285cdf0e10cSrcweir     rtl::OUString quote_string(const rtl::OUString& string)
286cdf0e10cSrcweir     {
287cdf0e10cSrcweir         rtl::OUStringBuffer quoted;
288cdf0e10cSrcweir         if (string.indexOf(QUOTE) != 0)
289cdf0e10cSrcweir             quoted.append(QUOTE);
290cdf0e10cSrcweir 
291cdf0e10cSrcweir         quoted.append(string);
292cdf0e10cSrcweir 
293cdf0e10cSrcweir         if (string.lastIndexOf(QUOTE) != (string.getLength() - 1))
294cdf0e10cSrcweir             quoted.append(QUOTE);
295cdf0e10cSrcweir 
296cdf0e10cSrcweir         return quoted.makeStringAndClear();
297cdf0e10cSrcweir     }
298cdf0e10cSrcweir 
299cdf0e10cSrcweir     //The parameter path must be a system path. If it is longer than 260 characters
300cdf0e10cSrcweir     //then it is shortened using the GetShortPathName function. This function only
301cdf0e10cSrcweir     //works if the path exists. Because "path" can be the path to an executable, it
302cdf0e10cSrcweir     //may not have the file extension ".exe". However, if the file on disk has the
303cdf0e10cSrcweir     //".exe" extension, then the function will fail. In this case a second attempt
304cdf0e10cSrcweir     //is started by adding the parameter "extension" to "path".
305cdf0e10cSrcweir     rtl::OUString getShortPath(rtl::OUString const & path, rtl::OUString const & extension)
306cdf0e10cSrcweir     {
307cdf0e10cSrcweir         rtl::OUString ret(path);
308cdf0e10cSrcweir         if (path.getLength() > 260)
309cdf0e10cSrcweir         {
310cdf0e10cSrcweir             std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > vec(path.getLength() + 1);
311cdf0e10cSrcweir             //GetShortPathNameW only works if the file can be found!
312cdf0e10cSrcweir             const DWORD len = GetShortPathNameW(
313cdf0e10cSrcweir                 reinterpret_cast<LPCWSTR>(path.getStr()), reinterpret_cast<LPWSTR>(&vec[0]), path.getLength() + 1);
314cdf0e10cSrcweir 
315cdf0e10cSrcweir             if (!len && GetLastError() == ERROR_FILE_NOT_FOUND
316cdf0e10cSrcweir                 && extension.getLength())
317cdf0e10cSrcweir             {
318cdf0e10cSrcweir                 const rtl::OUString extPath(path + extension);
319cdf0e10cSrcweir                 std::vector<sal_Unicode, rtl::Allocator<sal_Unicode> > vec2(
320cdf0e10cSrcweir                     extPath.getLength() + 1);
321cdf0e10cSrcweir                 const DWORD len2 = GetShortPathNameW(
322cdf0e10cSrcweir                     reinterpret_cast<LPCWSTR>(extPath.getStr()), reinterpret_cast<LPWSTR>(&vec2[0]), extPath.getLength() + 1);
323cdf0e10cSrcweir                 ret = rtl::OUString(&vec2[0], len2);
324cdf0e10cSrcweir             }
325cdf0e10cSrcweir             else
326cdf0e10cSrcweir             {
327cdf0e10cSrcweir                 ret = rtl::OUString(&vec[0], len);
328cdf0e10cSrcweir             }
329cdf0e10cSrcweir         }
330cdf0e10cSrcweir         return ret;
331cdf0e10cSrcweir     }
332cdf0e10cSrcweir     //##########################################################
333cdf0e10cSrcweir     // Returns the system path of the executable which can either
334cdf0e10cSrcweir     // be provided via the strImageName parameter or as first
335cdf0e10cSrcweir     // element of the strArguments list.
336cdf0e10cSrcweir     // The returned path will be quoted if it contains spaces.
337cdf0e10cSrcweir     rtl::OUString get_executable_path(
338cdf0e10cSrcweir         rtl_uString* image_name,
339cdf0e10cSrcweir         rtl_uString* cmdline_args[],
340cdf0e10cSrcweir         sal_uInt32 n_cmdline_args,
341cdf0e10cSrcweir         bool search_path)
342cdf0e10cSrcweir     {
343cdf0e10cSrcweir         rtl::OUString exe_name;
344cdf0e10cSrcweir 
345cdf0e10cSrcweir         if (image_name)
346cdf0e10cSrcweir             exe_name = image_name;
347cdf0e10cSrcweir         else if (n_cmdline_args)
348cdf0e10cSrcweir             exe_name = rtl::OUString(cmdline_args[0]);
349cdf0e10cSrcweir 
350cdf0e10cSrcweir         rtl::OUString exe_url = exe_name;
351cdf0e10cSrcweir         if (search_path)
352cdf0e10cSrcweir             osl_searchFileURL(exe_name.pData, NULL, &exe_url.pData);
353cdf0e10cSrcweir 
354cdf0e10cSrcweir         rtl::OUString exe_path;
355cdf0e10cSrcweir         if (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(exe_url, exe_path))
356cdf0e10cSrcweir             return rtl::OUString();
357cdf0e10cSrcweir 
358cdf0e10cSrcweir         exe_path = getShortPath(exe_path, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".exe")));
359cdf0e10cSrcweir 
360cdf0e10cSrcweir         if (exe_path.indexOf(' ') != -1)
361cdf0e10cSrcweir             exe_path = quote_string(exe_path);
362cdf0e10cSrcweir 
363cdf0e10cSrcweir         return exe_path;
364cdf0e10cSrcweir     }
365cdf0e10cSrcweir 
366cdf0e10cSrcweir     //##########################################################
367cdf0e10cSrcweir     rtl::OUString get_file_extension(const rtl::OUString& file_name)
368cdf0e10cSrcweir     {
369cdf0e10cSrcweir         sal_Int32 index = file_name.lastIndexOf('.');
370cdf0e10cSrcweir         if ((index != -1) && ((index + 1) < file_name.getLength()))
371cdf0e10cSrcweir             return file_name.copy(index + 1);
372cdf0e10cSrcweir 
373cdf0e10cSrcweir         return rtl::OUString();
374cdf0e10cSrcweir     }
375cdf0e10cSrcweir 
376cdf0e10cSrcweir     //##########################################################
377cdf0e10cSrcweir     bool is_batch_file(const rtl::OUString& file_name)
378cdf0e10cSrcweir     {
379cdf0e10cSrcweir         rtl::OUString ext = get_file_extension(file_name);
380cdf0e10cSrcweir         return (ext.equalsIgnoreAsciiCaseAscii("bat") ||
381cdf0e10cSrcweir                 ext.equalsIgnoreAsciiCaseAscii("cmd") ||
382cdf0e10cSrcweir                 ext.equalsIgnoreAsciiCaseAscii("btm"));
383cdf0e10cSrcweir     }
384cdf0e10cSrcweir 
385cdf0e10cSrcweir     //##########################################################
386cdf0e10cSrcweir     rtl::OUString get_batch_processor()
387cdf0e10cSrcweir     {
388cdf0e10cSrcweir         rtl::OUString comspec;
389cdf0e10cSrcweir         osl_getEnvironment(ENV_COMSPEC.pData, &comspec.pData);
390cdf0e10cSrcweir 
391cdf0e10cSrcweir         OSL_ASSERT(comspec.getLength());
392cdf0e10cSrcweir 
393cdf0e10cSrcweir         /* check if comspec path contains blanks and quote it if any */
394cdf0e10cSrcweir         if (comspec.indexOf(' ') != -1)
395cdf0e10cSrcweir             comspec = quote_string(comspec);
396cdf0e10cSrcweir 
397cdf0e10cSrcweir         return comspec;
398cdf0e10cSrcweir     }
399cdf0e10cSrcweir 
400cdf0e10cSrcweir } // namespace private
401cdf0e10cSrcweir 
402cdf0e10cSrcweir 
403cdf0e10cSrcweir //#################################################
404cdf0e10cSrcweir oslProcessError SAL_CALL osl_executeProcess(
405cdf0e10cSrcweir 	rtl_uString *strImageName,
406cdf0e10cSrcweir 	rtl_uString *strArguments[],
407cdf0e10cSrcweir 	sal_uInt32   nArguments,
408cdf0e10cSrcweir 	oslProcessOption Options,
409cdf0e10cSrcweir 	oslSecurity Security,
410cdf0e10cSrcweir 	rtl_uString *strDirectory,
411cdf0e10cSrcweir 	rtl_uString *strEnvironmentVars[],
412cdf0e10cSrcweir 	sal_uInt32   nEnvironmentVars,
413cdf0e10cSrcweir 	oslProcess *pProcess
414cdf0e10cSrcweir )
415cdf0e10cSrcweir {
416cdf0e10cSrcweir 	return osl_executeProcess_WithRedirectedIO(
417cdf0e10cSrcweir 		strImageName,
418cdf0e10cSrcweir 		strArguments,
419cdf0e10cSrcweir 		nArguments,
420cdf0e10cSrcweir 		Options,
421cdf0e10cSrcweir 		Security,
422cdf0e10cSrcweir 		strDirectory,
423cdf0e10cSrcweir 		strEnvironmentVars,
424cdf0e10cSrcweir 		nEnvironmentVars,
425cdf0e10cSrcweir 		pProcess,
426cdf0e10cSrcweir 		NULL, NULL, NULL );
427cdf0e10cSrcweir }
428cdf0e10cSrcweir 
429cdf0e10cSrcweir //#################################################
430cdf0e10cSrcweir oslProcessError SAL_CALL osl_executeProcess_WithRedirectedIO(
431cdf0e10cSrcweir 	rtl_uString *ustrImageName,
432cdf0e10cSrcweir 	rtl_uString *ustrArguments[],
433cdf0e10cSrcweir 	sal_uInt32   nArguments,
434cdf0e10cSrcweir 	oslProcessOption Options,
435cdf0e10cSrcweir 	oslSecurity Security,
436cdf0e10cSrcweir 	rtl_uString *ustrDirectory,
437cdf0e10cSrcweir 	rtl_uString *ustrEnvironmentVars[],
438cdf0e10cSrcweir 	sal_uInt32 nEnvironmentVars,
439cdf0e10cSrcweir 	oslProcess *pProcess,
440cdf0e10cSrcweir 	oslFileHandle *pProcessInputWrite,
441cdf0e10cSrcweir 	oslFileHandle *pProcessOutputRead,
442cdf0e10cSrcweir 	oslFileHandle *pProcessErrorRead)
443cdf0e10cSrcweir {
444cdf0e10cSrcweir     rtl::OUString exe_path = get_executable_path(
445cdf0e10cSrcweir         ustrImageName, ustrArguments, nArguments, (Options & osl_Process_SEARCHPATH));
446cdf0e10cSrcweir 
447cdf0e10cSrcweir     if (0 == exe_path.getLength())
448cdf0e10cSrcweir         return osl_Process_E_NotFound;
449cdf0e10cSrcweir 
450cdf0e10cSrcweir     if (pProcess == NULL)
451cdf0e10cSrcweir         return osl_Process_E_InvalidError;
452cdf0e10cSrcweir 
453cdf0e10cSrcweir     DWORD flags = NORMAL_PRIORITY_CLASS;
454cdf0e10cSrcweir     rtl::OUStringBuffer command_line;
455cdf0e10cSrcweir 
456cdf0e10cSrcweir     if (is_batch_file(exe_path))
457cdf0e10cSrcweir     {
458cdf0e10cSrcweir         rtl::OUString batch_processor = get_batch_processor();
459cdf0e10cSrcweir 
460cdf0e10cSrcweir         if (batch_processor.getLength())
461cdf0e10cSrcweir         {
462cdf0e10cSrcweir             /* cmd.exe does not work without a console window */
463cdf0e10cSrcweir             if (!(Options & osl_Process_WAIT) || (Options & osl_Process_DETACHED))
464cdf0e10cSrcweir                 flags |= CREATE_NEW_CONSOLE;
465cdf0e10cSrcweir 
466cdf0e10cSrcweir             command_line.append(batch_processor);
467cdf0e10cSrcweir             command_line.appendAscii(" /c ");
468cdf0e10cSrcweir         }
469cdf0e10cSrcweir         else
470cdf0e10cSrcweir             // should we return here in case of error?
471cdf0e10cSrcweir             return osl_Process_E_Unknown;
472cdf0e10cSrcweir     }
473cdf0e10cSrcweir 
474cdf0e10cSrcweir     command_line.append(exe_path);
475cdf0e10cSrcweir 
476cdf0e10cSrcweir     /* Add remaining arguments to command line. If ustrImageName is NULL
477cdf0e10cSrcweir        the first parameter is the name of the executable so we have to
478cdf0e10cSrcweir        start at 1 instead of 0 */
479cdf0e10cSrcweir     for (sal_uInt32 n = (NULL != ustrImageName) ? 0 : 1; n < nArguments; n++)
480cdf0e10cSrcweir     {
481cdf0e10cSrcweir         command_line.appendAscii(SPACE);
482cdf0e10cSrcweir 
483cdf0e10cSrcweir         /* Quote arguments containing blanks */
484cdf0e10cSrcweir         if (rtl::OUString(ustrArguments[n]).indexOf(' ') != -1)
485cdf0e10cSrcweir             command_line.append(quote_string(ustrArguments[n]));
486cdf0e10cSrcweir         else
487cdf0e10cSrcweir             command_line.append(ustrArguments[n]);
488cdf0e10cSrcweir     }
489cdf0e10cSrcweir 
490cdf0e10cSrcweir     environment_container_t environment;
491cdf0e10cSrcweir     LPVOID p_environment = NULL;
492cdf0e10cSrcweir 
493cdf0e10cSrcweir     if (nEnvironmentVars && ustrEnvironmentVars)
494cdf0e10cSrcweir     {
495cdf0e10cSrcweir         if (!setup_process_environment(
496cdf0e10cSrcweir                 ustrEnvironmentVars, nEnvironmentVars, environment))
497cdf0e10cSrcweir             return osl_Process_E_InvalidError;
498cdf0e10cSrcweir 
499cdf0e10cSrcweir         flags |= CREATE_UNICODE_ENVIRONMENT;
500cdf0e10cSrcweir         p_environment = &environment[0];
501cdf0e10cSrcweir     }
502cdf0e10cSrcweir 
503cdf0e10cSrcweir     rtl::OUString cwd;
504cdf0e10cSrcweir     if (ustrDirectory && ustrDirectory->length && (osl_File_E_None != osl::FileBase::getSystemPathFromFileURL(ustrDirectory, cwd)))
505cdf0e10cSrcweir    	    return osl_Process_E_InvalidError;
506cdf0e10cSrcweir 
507cdf0e10cSrcweir     LPCWSTR	p_cwd = (cwd.getLength()) ? reinterpret_cast<LPCWSTR>(cwd.getStr()) : NULL;
508cdf0e10cSrcweir 
509cdf0e10cSrcweir 	if ((Options & osl_Process_DETACHED) && !(flags & CREATE_NEW_CONSOLE))
510cdf0e10cSrcweir 		flags |= DETACHED_PROCESS;
511cdf0e10cSrcweir 
512cdf0e10cSrcweir     STARTUPINFO startup_info;
513cdf0e10cSrcweir 	memset(&startup_info, 0, sizeof(STARTUPINFO));
514cdf0e10cSrcweir 
515cdf0e10cSrcweir 	startup_info.cb        = sizeof(STARTUPINFO);
516cdf0e10cSrcweir 	startup_info.dwFlags   = STARTF_USESHOWWINDOW;
517cdf0e10cSrcweir 	startup_info.lpDesktop = L"";
518cdf0e10cSrcweir 
519cdf0e10cSrcweir 	/* Create pipes for redirected IO */
520cdf0e10cSrcweir     HANDLE hInputRead  = NULL;
521cdf0e10cSrcweir     HANDLE hInputWrite = NULL;
522cdf0e10cSrcweir 	if (pProcessInputWrite && create_pipe(&hInputRead, true, &hInputWrite, false))
523cdf0e10cSrcweir 	    startup_info.hStdInput = hInputRead;
524cdf0e10cSrcweir 
525cdf0e10cSrcweir 	HANDLE hOutputRead  = NULL;
526cdf0e10cSrcweir     HANDLE hOutputWrite = NULL;
527cdf0e10cSrcweir 	if (pProcessOutputRead && create_pipe(&hOutputRead, false, &hOutputWrite, true))
528cdf0e10cSrcweir 	    startup_info.hStdOutput = hOutputWrite;
529cdf0e10cSrcweir 
530cdf0e10cSrcweir 	HANDLE hErrorRead  = NULL;
531cdf0e10cSrcweir     HANDLE hErrorWrite = NULL;
532cdf0e10cSrcweir 	if (pProcessErrorRead && create_pipe(&hErrorRead, false, &hErrorWrite, true))
533cdf0e10cSrcweir 	    startup_info.hStdError = hErrorWrite;
534cdf0e10cSrcweir 
535cdf0e10cSrcweir 	bool b_inherit_handles = false;
536cdf0e10cSrcweir 	if (pProcessInputWrite || pProcessOutputRead || pProcessErrorRead)
537cdf0e10cSrcweir 	{
538cdf0e10cSrcweir 	    startup_info.dwFlags |= STARTF_USESTDHANDLES;
539cdf0e10cSrcweir 		b_inherit_handles      = true;
540cdf0e10cSrcweir 	}
541cdf0e10cSrcweir 
542cdf0e10cSrcweir 	switch(Options & (osl_Process_NORMAL | osl_Process_HIDDEN | osl_Process_MINIMIZED | osl_Process_MAXIMIZED | osl_Process_FULLSCREEN))
543cdf0e10cSrcweir 	{
544cdf0e10cSrcweir 		case osl_Process_HIDDEN:
545cdf0e10cSrcweir 			startup_info.wShowWindow = SW_HIDE;
546cdf0e10cSrcweir             flags |= CREATE_NO_WINDOW; // ignored for non-console
547cdf0e10cSrcweir                                        // applications; ignored on
548cdf0e10cSrcweir                                        // Win9x
549cdf0e10cSrcweir 			break;
550cdf0e10cSrcweir 
551cdf0e10cSrcweir 		case osl_Process_MINIMIZED:
552cdf0e10cSrcweir 			startup_info.wShowWindow = SW_MINIMIZE;
553cdf0e10cSrcweir 			break;
554cdf0e10cSrcweir 
555cdf0e10cSrcweir 		case osl_Process_MAXIMIZED:
556cdf0e10cSrcweir 		case osl_Process_FULLSCREEN:
557cdf0e10cSrcweir 			startup_info.wShowWindow = SW_MAXIMIZE;
558cdf0e10cSrcweir 			break;
559cdf0e10cSrcweir 
560cdf0e10cSrcweir 		default:
561cdf0e10cSrcweir 			startup_info.wShowWindow = SW_NORMAL;
562cdf0e10cSrcweir 	}
563cdf0e10cSrcweir 
564cdf0e10cSrcweir     rtl::OUString cmdline = command_line.makeStringAndClear();
565cdf0e10cSrcweir     PROCESS_INFORMATION process_info;
566cdf0e10cSrcweir     BOOL bRet = FALSE;
567cdf0e10cSrcweir 
568cdf0e10cSrcweir 	if ((Security != NULL) && (((oslSecurityImpl*)Security)->m_hToken != NULL))
569cdf0e10cSrcweir 	{
570cdf0e10cSrcweir 		bRet = CreateProcessAsUser(
571cdf0e10cSrcweir             ((oslSecurityImpl*)Security)->m_hToken,
572cdf0e10cSrcweir 			NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL,  NULL,
573cdf0e10cSrcweir 		    b_inherit_handles, flags, p_environment, p_cwd,
574cdf0e10cSrcweir 			&startup_info, &process_info);
575cdf0e10cSrcweir 	}
576cdf0e10cSrcweir 	else
577cdf0e10cSrcweir 	{
578cdf0e10cSrcweir 		bRet = CreateProcess(
579cdf0e10cSrcweir             NULL, const_cast<LPTSTR>(reinterpret_cast<LPCTSTR>(cmdline.getStr())), NULL,  NULL,
580cdf0e10cSrcweir 			b_inherit_handles, flags, p_environment, p_cwd,
581cdf0e10cSrcweir 			&startup_info, &process_info);
582cdf0e10cSrcweir 	}
583cdf0e10cSrcweir 
584cdf0e10cSrcweir 	/* Now we can close the pipe ends that are used by the child process */
585cdf0e10cSrcweir 
586cdf0e10cSrcweir 	if (hInputRead)
587cdf0e10cSrcweir 		CloseHandle(hInputRead);
588cdf0e10cSrcweir 
589cdf0e10cSrcweir 	if (hOutputWrite)
590cdf0e10cSrcweir 		CloseHandle(hOutputWrite);
591cdf0e10cSrcweir 
592cdf0e10cSrcweir 	if (hErrorWrite)
593cdf0e10cSrcweir 		CloseHandle(hErrorWrite);
594cdf0e10cSrcweir 
595cdf0e10cSrcweir 	if (bRet)
596cdf0e10cSrcweir 	{
597cdf0e10cSrcweir 		CloseHandle(process_info.hThread);
598cdf0e10cSrcweir 
599cdf0e10cSrcweir 		oslProcessImpl* pProcImpl = reinterpret_cast<oslProcessImpl*>(
600cdf0e10cSrcweir 		    rtl_allocateMemory(sizeof(oslProcessImpl)));
601cdf0e10cSrcweir 
602cdf0e10cSrcweir 		if (pProcImpl != NULL)
603cdf0e10cSrcweir 		{
604cdf0e10cSrcweir 		    pProcImpl->m_hProcess  = process_info.hProcess;
605cdf0e10cSrcweir 		    pProcImpl->m_IdProcess = process_info.dwProcessId;
606cdf0e10cSrcweir 
607cdf0e10cSrcweir 		    *pProcess = (oslProcess)pProcImpl;
608cdf0e10cSrcweir 
609cdf0e10cSrcweir 		    if (Options & osl_Process_WAIT)
610cdf0e10cSrcweir 			    WaitForSingleObject(pProcImpl->m_hProcess, INFINITE);
611cdf0e10cSrcweir 
612cdf0e10cSrcweir 		    if (pProcessInputWrite)
613cdf0e10cSrcweir 			    *pProcessInputWrite = osl_createFileHandleFromOSHandle(hInputWrite, osl_File_OpenFlag_Write);
614cdf0e10cSrcweir 
615cdf0e10cSrcweir 		    if (pProcessOutputRead)
616cdf0e10cSrcweir 			    *pProcessOutputRead = osl_createFileHandleFromOSHandle(hOutputRead, osl_File_OpenFlag_Read);
617cdf0e10cSrcweir 
618cdf0e10cSrcweir 		    if (pProcessErrorRead)
619cdf0e10cSrcweir 			    *pProcessErrorRead = osl_createFileHandleFromOSHandle(hErrorRead, osl_File_OpenFlag_Read);
620cdf0e10cSrcweir 
621cdf0e10cSrcweir 		    return osl_Process_E_None;
622cdf0e10cSrcweir 	    }
623cdf0e10cSrcweir     }
624cdf0e10cSrcweir 
625cdf0e10cSrcweir 	/* if an error occured we have to close the server side pipe ends too */
626cdf0e10cSrcweir 
627cdf0e10cSrcweir 	if (hInputWrite)
628cdf0e10cSrcweir 		CloseHandle(hInputWrite);
629cdf0e10cSrcweir 
630cdf0e10cSrcweir 	if (hOutputRead)
631cdf0e10cSrcweir 		CloseHandle(hOutputRead);
632cdf0e10cSrcweir 
633cdf0e10cSrcweir 	if (hErrorRead)
634cdf0e10cSrcweir 		CloseHandle(hErrorRead);
635cdf0e10cSrcweir 
636cdf0e10cSrcweir 	return osl_Process_E_Unknown;
637cdf0e10cSrcweir }
638