95 && buffer[0] == 'M' && buffer[1] == 'Z'
96 && _lseek(fd, 60L, SEEK_SET) == 60L
97 && _read(fd, buffer, 2) == 2)
98 {
99 long headerLoc = (long)buffer[1] << 8 | (long)buffer[0];
100 if (_lseek(fd, headerLoc, SEEK_SET) == headerLoc
101 && _read(fd, buffer, 2) == 2
102 && buffer[0] == 'P' && buffer[1] == 'E')
103 {
104 newFlag = DETACHED_PROCESS;
105 }
106 }
107 _close(fd);
108 }
109 }
110 JNU_ReleaseStringPlatformChars(env, cmd0, exe);
111 }
112 return newFlag;
113 }
114
115 static void
116 win32Error(JNIEnv *env, const char *functionName)
117 {
118 static const char * const format = "%s error=%d, %s";
119 static const char * const fallbackFormat = "%s failed, error=%d";
120 char buf[256];
121 char errmsg[sizeof(buf) + 100];
122 const int errnum = GetLastError();
123 const int n = JVM_GetLastErrorString(buf, sizeof(buf));
124 if (n > 0)
125 sprintf(errmsg, format, functionName, errnum, buf);
126 else
127 sprintf(errmsg, fallbackFormat, functionName, errnum);
128 JNU_ThrowIOException(env, errmsg);
129 }
130
131 static void
132 closeSafely(HANDLE handle)
133 {
134 if (handle != INVALID_HANDLE_VALUE)
135 CloseHandle(handle);
136 }
137
138 static BOOL hasInheritFlag(HANDLE handle)
139 {
140 DWORD mask;
141 if (GetHandleInformation(handle, &mask)) {
142 return mask & HANDLE_FLAG_INHERIT;
143 }
144 return FALSE;
145 }
146
147 #define HANDLE_STORAGE_SIZE 6
148 #define OFFSET_READ 0
176 value 0x00000000FFFFFFFF
177 instead 0xFFFFFFFFFFFFFFFF. */
178 if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
179 /* Java file or console redirection */
180 *phStd = (HANDLE) *pjhandles;
181 /* Here we set the related Java stream (Process.getXXXXStream())
182 to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
183 The initial Java handle [*pjhandles] will be closed in
184 ANY case. It is not a handle leak. */
185 *pjhandles = JAVA_INVALID_HANDLE_VALUE;
186 } else {
187 /* Creation of parent-child pipe */
188 if (!CreatePipe(
189 &pHolder->pipe[OFFSET_READ],
190 &pHolder->pipe[OFFSET_WRITE],
191 NULL, /* we would like to inherit
192 default process access,
193 instead of 'Everybody' access */
194 PIPE_SIZE))
195 {
196 win32Error(env, "CreatePipe");
197 return FALSE;
198 } else {
199 /* [thisProcessEnd] has no the inherit flag because
200 the [lpPipeAttributes] param of [CreatePipe]
201 had the NULL value. */
202 HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
203 *phStd = pHolder->pipe[pHolder->offset];
204 *pjhandles = (jlong) thisProcessEnd;
205 }
206 }
207 /* Pipe handle will be closed in the [releaseHolder] call,
208 file handle will be closed in Java.
209 The long-live handle need to restore the inherit flag,
210 we do it later in the [prepareIOEHandleState] call. */
211 SetHandleInformation(
212 *phStd,
213 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
214 return TRUE;
215 }
216
332 PROCESS_INFORMATION pi;
333 DWORD processFlag = CREATE_UNICODE_ENVIRONMENT;
334
335 /* Suppress popping-up of a console window for non-console applications */
336 if (GetConsoleWindow() == NULL)
337 processFlag |= CREATE_NO_WINDOW;
338
339 si.dwFlags = STARTF_USESTDHANDLES;
340 if (!CreateProcessW(
341 NULL, /* executable name */
342 (LPWSTR)pcmd, /* command line */
343 NULL, /* process security attribute */
344 NULL, /* thread security attribute */
345 TRUE, /* inherits system handles */
346 processFlag, /* selected based on exe type */
347 (LPVOID)penvBlock,/* environment block */
348 (LPCWSTR)pdir, /* change to the new current directory */
349 &si, /* (in) startup information */
350 &pi)) /* (out) process information */
351 {
352 win32Error(env, "CreateProcess");
353 } else {
354 closeSafely(pi.hThread);
355 ret = (jlong)pi.hProcess;
356 }
357 }
358 releaseHolder(ret == 0, &holderErr);
359 releaseHolder(ret == 0, &holderOut);
360 }
361 releaseHolder(ret == 0, &holderIn);
362 }
363 }
364 restoreIOEHandleState(stdIOE, inherit);
365
366 return ret;
367 }
368
369 JNIEXPORT jlong JNICALL
370 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
371 jstring cmd,
372 jstring envBlock,
393 pdir,
394 handles,
395 redirectErrorStream);
396 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
397 }
398 if (pdir != NULL)
399 (*env)->ReleaseStringChars(env, dir, pdir);
400 if (penvBlock != NULL)
401 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
402 (*env)->ReleaseStringChars(env, cmd, pcmd);
403 }
404 }
405 return ret;
406 }
407
408 JNIEXPORT jint JNICALL
409 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
410 {
411 DWORD exit_code;
412 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
413 win32Error(env, "GetExitCodeProcess");
414 return exit_code;
415 }
416
417 JNIEXPORT jint JNICALL
418 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
419 {
420 return STILL_ACTIVE;
421 }
422
423 JNIEXPORT void JNICALL
424 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
425 {
426 HANDLE events[2];
427 events[0] = (HANDLE) handle;
428 events[1] = JVM_GetThreadInterruptEvent();
429
430 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
431 FALSE, /* Wait for ANY event */
432 INFINITE) /* Wait forever */
433 == WAIT_FAILED)
434 win32Error(env, "WaitForMultipleObjects");
435 }
436
437 JNIEXPORT void JNICALL
438 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
439 {
440 TerminateProcess((HANDLE) handle, 1);
441 }
442
443 JNIEXPORT jboolean JNICALL
444 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
445 {
446 return CloseHandle((HANDLE) handle);
447 }
448
449 /**
450 * Returns a copy of the Unicode characters of a string. Fow now this
451 * function doesn't handle long path names and other issues.
452 */
453 static WCHAR* getPath(JNIEnv *env, jstring ps) {
454 WCHAR *pathbuf = NULL;
|
95 && buffer[0] == 'M' && buffer[1] == 'Z'
96 && _lseek(fd, 60L, SEEK_SET) == 60L
97 && _read(fd, buffer, 2) == 2)
98 {
99 long headerLoc = (long)buffer[1] << 8 | (long)buffer[0];
100 if (_lseek(fd, headerLoc, SEEK_SET) == headerLoc
101 && _read(fd, buffer, 2) == 2
102 && buffer[0] == 'P' && buffer[1] == 'E')
103 {
104 newFlag = DETACHED_PROCESS;
105 }
106 }
107 _close(fd);
108 }
109 }
110 JNU_ReleaseStringPlatformChars(env, cmd0, exe);
111 }
112 return newFlag;
113 }
114
115 /* We have THREE locales in action:
116 * 1. Thread default locale - dictates UNICODE-to-8bit conversion
117 * 2. System locale that defines the message localization
118 * 3. The file name locale
119 * Each locale could be an extended locale, that means that text cannot be
120 * mapped to 8bit sequence without multibyte encoding.
121 * VM is ready for that, if text is UTF-8.
122 * Here we make the work right from the beginning.
123 */
124 size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) {
125 size_t n = (size_t)FormatMessageW(
126 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
127 NULL,
128 (DWORD)errnum,
129 0,
130 utf16_OSErrorMsg,
131 (DWORD)maxMsgLength,
132 NULL);
133 if (n > 3) {
134 // Drop final '.', CR, LF
135 if (utf16_OSErrorMsg[n - 1] == L'\n') --n;
136 if (utf16_OSErrorMsg[n - 1] == L'\r') --n;
137 if (utf16_OSErrorMsg[n - 1] == L'.') --n;
138 utf16_OSErrorMsg[n] = L'\0';
139 }
140 return n;
141 }
142
143 #define MESSAGE_LENGTH (256 + 100)
144 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
145
146 static void
147 win32Error(JNIEnv *env, const WCHAR *functionName)
148 {
149 WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100];
150 WCHAR utf16_javaMessage[MESSAGE_LENGTH];
151 /*Good suggestion about 2-bytes-per-symbol in localized error reports*/
152 char utf8_javaMessage[MESSAGE_LENGTH*2];
153 const int errnum = (int)GetLastError();
154 int n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg));
155 n = (n > 0)
156 ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg)
157 : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum);
158
159 if (n > 0) /*terminate '\0' is not a part of conversion procedure*/
160 n = WideCharToMultiByte(
161 CP_UTF8,
162 0,
163 utf16_javaMessage,
164 n, /*by creation n <= MESSAGE_LENGTH*/
165 utf8_javaMessage,
166 MESSAGE_LENGTH*2,
167 NULL,
168 NULL);
169
170 /*no way to die*/
171 {
172 const char *errorMessage = "Secondary error while OS message extraction";
173 if (n > 0) {
174 utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0';
175 errorMessage = utf8_javaMessage;
176 }
177 JNU_ThrowIOException(env, errorMessage);
178 }
179 }
180
181 static void
182 closeSafely(HANDLE handle)
183 {
184 if (handle != INVALID_HANDLE_VALUE)
185 CloseHandle(handle);
186 }
187
188 static BOOL hasInheritFlag(HANDLE handle)
189 {
190 DWORD mask;
191 if (GetHandleInformation(handle, &mask)) {
192 return mask & HANDLE_FLAG_INHERIT;
193 }
194 return FALSE;
195 }
196
197 #define HANDLE_STORAGE_SIZE 6
198 #define OFFSET_READ 0
226 value 0x00000000FFFFFFFF
227 instead 0xFFFFFFFFFFFFFFFF. */
228 if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) {
229 /* Java file or console redirection */
230 *phStd = (HANDLE) *pjhandles;
231 /* Here we set the related Java stream (Process.getXXXXStream())
232 to [ProcessBuilder.NullXXXXStream.INSTANCE] value.
233 The initial Java handle [*pjhandles] will be closed in
234 ANY case. It is not a handle leak. */
235 *pjhandles = JAVA_INVALID_HANDLE_VALUE;
236 } else {
237 /* Creation of parent-child pipe */
238 if (!CreatePipe(
239 &pHolder->pipe[OFFSET_READ],
240 &pHolder->pipe[OFFSET_WRITE],
241 NULL, /* we would like to inherit
242 default process access,
243 instead of 'Everybody' access */
244 PIPE_SIZE))
245 {
246 win32Error(env, L"CreatePipe");
247 return FALSE;
248 } else {
249 /* [thisProcessEnd] has no the inherit flag because
250 the [lpPipeAttributes] param of [CreatePipe]
251 had the NULL value. */
252 HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)];
253 *phStd = pHolder->pipe[pHolder->offset];
254 *pjhandles = (jlong) thisProcessEnd;
255 }
256 }
257 /* Pipe handle will be closed in the [releaseHolder] call,
258 file handle will be closed in Java.
259 The long-live handle need to restore the inherit flag,
260 we do it later in the [prepareIOEHandleState] call. */
261 SetHandleInformation(
262 *phStd,
263 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
264 return TRUE;
265 }
266
382 PROCESS_INFORMATION pi;
383 DWORD processFlag = CREATE_UNICODE_ENVIRONMENT;
384
385 /* Suppress popping-up of a console window for non-console applications */
386 if (GetConsoleWindow() == NULL)
387 processFlag |= CREATE_NO_WINDOW;
388
389 si.dwFlags = STARTF_USESTDHANDLES;
390 if (!CreateProcessW(
391 NULL, /* executable name */
392 (LPWSTR)pcmd, /* command line */
393 NULL, /* process security attribute */
394 NULL, /* thread security attribute */
395 TRUE, /* inherits system handles */
396 processFlag, /* selected based on exe type */
397 (LPVOID)penvBlock,/* environment block */
398 (LPCWSTR)pdir, /* change to the new current directory */
399 &si, /* (in) startup information */
400 &pi)) /* (out) process information */
401 {
402 win32Error(env, L"CreateProcess");
403 } else {
404 closeSafely(pi.hThread);
405 ret = (jlong)pi.hProcess;
406 }
407 }
408 releaseHolder(ret == 0, &holderErr);
409 releaseHolder(ret == 0, &holderOut);
410 }
411 releaseHolder(ret == 0, &holderIn);
412 }
413 }
414 restoreIOEHandleState(stdIOE, inherit);
415
416 return ret;
417 }
418
419 JNIEXPORT jlong JNICALL
420 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored,
421 jstring cmd,
422 jstring envBlock,
443 pdir,
444 handles,
445 redirectErrorStream);
446 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0);
447 }
448 if (pdir != NULL)
449 (*env)->ReleaseStringChars(env, dir, pdir);
450 if (penvBlock != NULL)
451 (*env)->ReleaseStringChars(env, envBlock, penvBlock);
452 (*env)->ReleaseStringChars(env, cmd, pcmd);
453 }
454 }
455 return ret;
456 }
457
458 JNIEXPORT jint JNICALL
459 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle)
460 {
461 DWORD exit_code;
462 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0)
463 win32Error(env, L"GetExitCodeProcess");
464 return exit_code;
465 }
466
467 JNIEXPORT jint JNICALL
468 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored)
469 {
470 return STILL_ACTIVE;
471 }
472
473 JNIEXPORT void JNICALL
474 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle)
475 {
476 HANDLE events[2];
477 events[0] = (HANDLE) handle;
478 events[1] = JVM_GetThreadInterruptEvent();
479
480 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
481 FALSE, /* Wait for ANY event */
482 INFINITE) /* Wait forever */
483 == WAIT_FAILED)
484 win32Error(env, L"WaitForMultipleObjects");
485 }
486
487 JNIEXPORT void JNICALL
488 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle)
489 {
490 TerminateProcess((HANDLE) handle, 1);
491 }
492
493 JNIEXPORT jboolean JNICALL
494 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle)
495 {
496 return CloseHandle((HANDLE) handle);
497 }
498
499 /**
500 * Returns a copy of the Unicode characters of a string. Fow now this
501 * function doesn't handle long path names and other issues.
502 */
503 static WCHAR* getPath(JNIEnv *env, jstring ps) {
504 WCHAR *pathbuf = NULL;
|