1 /*-
2 * Copyright (c) 2009-2012 Michihiro NAKAJIMA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "archive_platform.h"
27
28 #if defined(_WIN32) && !defined(__CYGWIN__)
29 #include "archive_cmdline_private.h"
30 #include "archive_string.h"
31
32 #include "filter_fork.h"
33
34 #if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
35 /* There are some editions of Windows ("nano server," for example) that
36 * do not host user32.dll. If we want to keep running on those editions,
37 * we need to delay-load WaitForInputIdle. */
38 static void *
la_GetFunctionUser32(const char * name)39 la_GetFunctionUser32(const char *name)
40 {
41 static HINSTANCE lib;
42 static int set;
43 if (!set) {
44 set = 1;
45 lib = LoadLibrary(TEXT("user32.dll"));
46 }
47 if (lib == NULL) {
48 return NULL;
49 }
50 return (void *)GetProcAddress(lib, name);
51 }
52
53 static int
la_WaitForInputIdle(HANDLE hProcess,DWORD dwMilliseconds)54 la_WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds)
55 {
56 static DWORD (WINAPI *f)(HANDLE, DWORD);
57 static int set;
58
59 if (!set) {
60 set = 1;
61 f = la_GetFunctionUser32("WaitForInputIdle");
62 }
63
64 if (!f) {
65 /* An inability to wait for input idle is
66 * not _good_, but it is not catastrophic. */
67 return WAIT_FAILED;
68 }
69 return (*f)(hProcess, dwMilliseconds);
70 }
71
72 int
__archive_create_child(const char * cmd,int * child_stdin,int * child_stdout,HANDLE * out_child)73 __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout,
74 HANDLE *out_child)
75 {
76 HANDLE childStdout[2], childStdin[2],childStderr;
77 SECURITY_ATTRIBUTES secAtts;
78 STARTUPINFOA staInfo;
79 PROCESS_INFORMATION childInfo;
80 struct archive_string cmdline;
81 struct archive_string fullpath;
82 struct archive_cmdline *acmd;
83 char *arg0, *ext;
84 int i, l;
85 DWORD fl, fl_old;
86 HANDLE child;
87
88 childStdout[0] = childStdout[1] = INVALID_HANDLE_VALUE;
89 childStdin[0] = childStdin[1] = INVALID_HANDLE_VALUE;
90 childStderr = INVALID_HANDLE_VALUE;
91 archive_string_init(&cmdline);
92 archive_string_init(&fullpath);
93
94 acmd = __archive_cmdline_allocate();
95 if (acmd == NULL)
96 goto fail;
97 if (__archive_cmdline_parse(acmd, cmd) != ARCHIVE_OK)
98 goto fail;
99
100 /*
101 * Search the full path of 'path'.
102 * NOTE: This does not need if we give CreateProcessA 'path' as
103 * a part of the cmdline and give CreateProcessA NULL as first
104 * parameter, but I do not like that way.
105 */
106 ext = strrchr(acmd->path, '.');
107 if (ext == NULL || strlen(ext) > 4)
108 /* 'path' does not have a proper extension, so we have to
109 * give SearchPath() ".exe" as the extension. */
110 ext = ".exe";
111 else
112 ext = NULL;/* 'path' has an extension. */
113
114 fl = MAX_PATH;
115 do {
116 if (archive_string_ensure(&fullpath, fl) == NULL)
117 goto fail;
118 fl_old = fl;
119 fl = SearchPathA(NULL, acmd->path, ext, fl, fullpath.s,
120 &arg0);
121 } while (fl != 0 && fl > fl_old);
122 if (fl == 0)
123 goto fail;
124
125 /*
126 * Make a command line.
127 */
128 for (l = 0, i = 0; acmd->argv[i] != NULL; i++) {
129 if (i == 0)
130 continue;
131 l += (int)strlen(acmd->argv[i]) + 1;
132 }
133 if (archive_string_ensure(&cmdline, l + 1) == NULL)
134 goto fail;
135 for (i = 0; acmd->argv[i] != NULL; i++) {
136 if (i == 0) {
137 const char *p, *sp;
138
139 if ((p = strchr(acmd->argv[i], '/')) != NULL ||
140 (p = strchr(acmd->argv[i], '\\')) != NULL)
141 p++;
142 else
143 p = acmd->argv[i];
144 if ((sp = strchr(p, ' ')) != NULL)
145 archive_strappend_char(&cmdline, '"');
146 archive_strcat(&cmdline, p);
147 if (sp != NULL)
148 archive_strappend_char(&cmdline, '"');
149 } else {
150 archive_strappend_char(&cmdline, ' ');
151 archive_strcat(&cmdline, acmd->argv[i]);
152 }
153 }
154 if (i <= 1) {
155 const char *sp;
156
157 if ((sp = strchr(arg0, ' ')) != NULL)
158 archive_strappend_char(&cmdline, '"');
159 archive_strcat(&cmdline, arg0);
160 if (sp != NULL)
161 archive_strappend_char(&cmdline, '"');
162 }
163
164 secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
165 secAtts.bInheritHandle = TRUE;
166 secAtts.lpSecurityDescriptor = NULL;
167 if (CreatePipe(&childStdout[0], &childStdout[1], &secAtts, 0) == 0)
168 goto fail;
169 if (!SetHandleInformation(childStdout[0], HANDLE_FLAG_INHERIT, 0))
170 goto fail;
171 if (CreatePipe(&childStdin[0], &childStdin[1], &secAtts, 0) == 0)
172 goto fail;
173 if (!SetHandleInformation(childStdin[1], HANDLE_FLAG_INHERIT, 0))
174 goto fail;
175 if (DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
176 GetCurrentProcess(), &childStderr, 0, TRUE,
177 DUPLICATE_SAME_ACCESS) == 0)
178 goto fail;
179
180 memset(&staInfo, 0, sizeof(staInfo));
181 staInfo.cb = sizeof(staInfo);
182 staInfo.hStdError = childStderr;
183 staInfo.hStdOutput = childStdout[1];
184 staInfo.hStdInput = childStdin[0];
185 staInfo.wShowWindow = SW_HIDE;
186 staInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
187 if (CreateProcessA(fullpath.s, cmdline.s, NULL, NULL, TRUE, 0,
188 NULL, NULL, &staInfo, &childInfo) == 0)
189 goto fail;
190 la_WaitForInputIdle(childInfo.hProcess, INFINITE);
191 CloseHandle(childInfo.hProcess);
192 CloseHandle(childInfo.hThread);
193
194 *child_stdout = _open_osfhandle((intptr_t)childStdout[0], _O_RDONLY);
195 *child_stdin = _open_osfhandle((intptr_t)childStdin[1], _O_WRONLY);
196
197 child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
198 childInfo.dwProcessId);
199 if (child == NULL) // INVALID_HANDLE_VALUE ?
200 goto fail;
201
202 *out_child = child;
203
204 CloseHandle(childStdout[1]);
205 CloseHandle(childStdin[0]);
206
207 archive_string_free(&cmdline);
208 archive_string_free(&fullpath);
209 __archive_cmdline_free(acmd);
210 return ARCHIVE_OK;
211
212 fail:
213 if (childStdout[0] != INVALID_HANDLE_VALUE)
214 CloseHandle(childStdout[0]);
215 if (childStdout[1] != INVALID_HANDLE_VALUE)
216 CloseHandle(childStdout[1]);
217 if (childStdin[0] != INVALID_HANDLE_VALUE)
218 CloseHandle(childStdin[0]);
219 if (childStdin[1] != INVALID_HANDLE_VALUE)
220 CloseHandle(childStdin[1]);
221 if (childStderr != INVALID_HANDLE_VALUE)
222 CloseHandle(childStderr);
223 archive_string_free(&cmdline);
224 archive_string_free(&fullpath);
225 __archive_cmdline_free(acmd);
226 return ARCHIVE_FAILED;
227 }
228 #else /* !WINAPI_PARTITION_DESKTOP */
229 int
__archive_create_child(const char * cmd,int * child_stdin,int * child_stdout,HANDLE * out_child)230 __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout, HANDLE *out_child)
231 {
232 (void)cmd; (void)child_stdin; (void) child_stdout; (void) out_child;
233 return ARCHIVE_FAILED;
234 }
235 #endif /* !WINAPI_PARTITION_DESKTOP */
236
237 void
__archive_check_child(int in,int out)238 __archive_check_child(int in, int out)
239 {
240 (void)in; /* UNUSED */
241 (void)out; /* UNUSED */
242 Sleep(100);
243 }
244
245 #endif /* _WIN32 && !__CYGWIN__ */
246