rev 11339 : 8072611: (process) ProcessBuilder redirecting output to file should work with long file names (win) Reviewed-by: rriggs, simonis Contributed-by: johannes.scheerer@sap.com, stuefe
1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <assert.h> 27 #include "java_lang_ProcessImpl.h" 28 29 #include "jni.h" 30 #include "jvm.h" 31 #include "jni_util.h" 32 #include "io_util.h" 33 #include <windows.h> 34 #include <io.h> 35 36 /* We try to make sure that we can read and write 4095 bytes (the 37 * fixed limit on Linux) to the pipe on all operating systems without 38 * deadlock. Windows 2000 inexplicably appears to need an extra 24 39 * bytes of slop to avoid deadlock. 40 */ 41 #define PIPE_SIZE (4096+24) 42 43 /* We have THREE locales in action: 44 * 1. Thread default locale - dictates UNICODE-to-8bit conversion 45 * 2. System locale that defines the message localization 46 * 3. The file name locale 47 * Each locale could be an extended locale, that means that text cannot be 48 * mapped to 8bit sequence without multibyte encoding. 49 * VM is ready for that, if text is UTF-8. 50 * Here we make the work right from the beginning. 51 */ 52 size_t os_error_message(int errnum, WCHAR* utf16_OSErrorMsg, size_t maxMsgLength) { 53 size_t n = (size_t)FormatMessageW( 54 FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 55 NULL, 56 (DWORD)errnum, 57 0, 58 utf16_OSErrorMsg, 59 (DWORD)maxMsgLength, 60 NULL); 61 if (n > 3) { 62 // Drop final '.', CR, LF 63 if (utf16_OSErrorMsg[n - 1] == L'\n') --n; 64 if (utf16_OSErrorMsg[n - 1] == L'\r') --n; 65 if (utf16_OSErrorMsg[n - 1] == L'.') --n; 66 utf16_OSErrorMsg[n] = L'\0'; 67 } 68 return n; 69 } 70 71 #define MESSAGE_LENGTH (256 + 100) 72 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x)) 73 74 static void 75 win32Error(JNIEnv *env, const WCHAR *functionName) 76 { 77 WCHAR utf16_OSErrorMsg[MESSAGE_LENGTH - 100]; 78 WCHAR utf16_javaMessage[MESSAGE_LENGTH]; 79 /*Good suggestion about 2-bytes-per-symbol in localized error reports*/ 80 char utf8_javaMessage[MESSAGE_LENGTH*2]; 81 const int errnum = (int)GetLastError(); 82 size_t n = os_error_message(errnum, utf16_OSErrorMsg, ARRAY_SIZE(utf16_OSErrorMsg)); 83 n = (n > 0) 84 ? swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s error=%d, %s", functionName, errnum, utf16_OSErrorMsg) 85 : swprintf(utf16_javaMessage, MESSAGE_LENGTH, L"%s failed, error=%d", functionName, errnum); 86 87 if (n > 0) /*terminate '\0' is not a part of conversion procedure*/ 88 n = WideCharToMultiByte( 89 CP_UTF8, 90 0, 91 utf16_javaMessage, 92 n, /*by creation n <= MESSAGE_LENGTH*/ 93 utf8_javaMessage, 94 MESSAGE_LENGTH*2, 95 NULL, 96 NULL); 97 98 /*no way to die*/ 99 { 100 const char *errorMessage = "Secondary error while OS message extraction"; 101 if (n > 0) { 102 utf8_javaMessage[min(MESSAGE_LENGTH*2 - 1, n)] = '\0'; 103 errorMessage = utf8_javaMessage; 104 } 105 JNU_ThrowIOException(env, errorMessage); 106 } 107 } 108 109 static void 110 closeSafely(HANDLE handle) 111 { 112 if (handle != INVALID_HANDLE_VALUE) 113 CloseHandle(handle); 114 } 115 116 static BOOL hasInheritFlag(HANDLE handle) 117 { 118 DWORD mask; 119 if (GetHandleInformation(handle, &mask)) { 120 return mask & HANDLE_FLAG_INHERIT; 121 } 122 return FALSE; 123 } 124 125 #define HANDLE_STORAGE_SIZE 6 126 #define OFFSET_READ 0 127 #define OFFSET_WRITE 1 128 //long signed version of INVALID_HANDLE_VALUE 129 #define JAVA_INVALID_HANDLE_VALUE ((jlong) -1) 130 #define OPPOSITE_END(offset) (offset==OFFSET_READ ? OFFSET_WRITE : OFFSET_READ) 131 132 /* Pipe holder structure */ 133 typedef struct _STDHOLDER { 134 HANDLE pipe[2]; 135 int offset; 136 } STDHOLDER; 137 138 /* Responsible for correct initialization of the [pHolder] structure 139 (that is used for handles recycling) if needs, 140 and appropriate setup of IOE handle [phStd] for child process based 141 on created pipe or Java handle. */ 142 static BOOL initHolder( 143 JNIEnv *env, 144 jlong *pjhandles, /* IN OUT - the handle form Java, 145 that can be a file, console or undefined */ 146 STDHOLDER *pHolder, /* OUT - initialized structure that holds pipe 147 handles */ 148 HANDLE *phStd /* OUT - initialized handle for child process */ 149 ) { 150 /* Here we test the value from Java against invalid 151 handle value. We are not using INVALID_HANDLE_VALUE macro 152 due to double signed/unsigned and 32/64bit ambiguity. 153 Otherwise it will be easy to get the wrong 154 value 0x00000000FFFFFFFF 155 instead 0xFFFFFFFFFFFFFFFF. */ 156 if (*pjhandles != JAVA_INVALID_HANDLE_VALUE) { 157 /* Java file or console redirection */ 158 *phStd = (HANDLE) *pjhandles; 159 /* Here we set the related Java stream (Process.getXXXXStream()) 160 to [ProcessBuilder.NullXXXXStream.INSTANCE] value. 161 The initial Java handle [*pjhandles] will be closed in 162 ANY case. It is not a handle leak. */ 163 *pjhandles = JAVA_INVALID_HANDLE_VALUE; 164 } else { 165 /* Creation of parent-child pipe */ 166 if (!CreatePipe( 167 &pHolder->pipe[OFFSET_READ], 168 &pHolder->pipe[OFFSET_WRITE], 169 NULL, /* we would like to inherit 170 default process access, 171 instead of 'Everybody' access */ 172 PIPE_SIZE)) 173 { 174 win32Error(env, L"CreatePipe"); 175 return FALSE; 176 } else { 177 /* [thisProcessEnd] has no the inherit flag because 178 the [lpPipeAttributes] param of [CreatePipe] 179 had the NULL value. */ 180 HANDLE thisProcessEnd = pHolder->pipe[OPPOSITE_END(pHolder->offset)]; 181 *phStd = pHolder->pipe[pHolder->offset]; 182 *pjhandles = (jlong) thisProcessEnd; 183 } 184 } 185 /* Pipe handle will be closed in the [releaseHolder] call, 186 file handle will be closed in Java. 187 The long-live handle need to restore the inherit flag, 188 we do it later in the [prepareIOEHandleState] call. */ 189 SetHandleInformation( 190 *phStd, 191 HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); 192 return TRUE; 193 } 194 195 /* Smart recycling of pipe handles in [pHolder]. For the failed 196 create process attempts, both ends of pipe need to be released. 197 The [complete] has the [TRUE] value in the failed attempt. */ 198 static void releaseHolder(BOOL complete, STDHOLDER *pHolder) { 199 closeSafely(pHolder->pipe[pHolder->offset]); 200 if (complete) { 201 /* Error occur, close this process pipe end */ 202 closeSafely(pHolder->pipe[OPPOSITE_END(pHolder->offset)]); 203 } 204 } 205 206 /* Stores and drops the inherit flag of handles that should not 207 be shared with the child process by default, but can hold the 208 inherit flag due to MS process birth specific. */ 209 static void prepareIOEHandleState( 210 HANDLE *stdIOE, 211 BOOL *inherit) 212 { 213 int i; 214 for (i = 0; i < HANDLE_STORAGE_SIZE; ++i) { 215 HANDLE hstd = stdIOE[i]; 216 if (INVALID_HANDLE_VALUE != hstd && hasInheritFlag(hstd)) { 217 /* FALSE by default */ 218 inherit[i] = TRUE; 219 /* Java does not need implicit inheritance for IOE handles, 220 so we drop inherit flag that probably was installed by 221 previous CreateProcess call that launched current process. 222 We will return the handle state back after CreateProcess call. 223 By clearing inherit flag we prevent "greedy grandchild" birth. 224 The explicit inheritance for child process IOE handles is 225 implemented in the [initHolder] call. */ 226 SetHandleInformation(hstd, HANDLE_FLAG_INHERIT, 0); 227 } 228 } 229 } 230 231 /* Restores the inheritance flag of handles from stored values. */ 232 static void restoreIOEHandleState( 233 const HANDLE *stdIOE, 234 const BOOL *inherit) 235 { 236 /* The set of current process standard IOE handles and 237 the set of child process IOE handles can intersect. 238 To restore the inherit flag right, we use backward 239 array iteration. */ 240 int i; 241 for (i = HANDLE_STORAGE_SIZE - 1; i >= 0; --i) 242 if (INVALID_HANDLE_VALUE != stdIOE[i]) { 243 /* Restore inherit flag for any case. 244 The handle can be changed by explicit inheritance.*/ 245 SetHandleInformation(stdIOE[i], 246 HANDLE_FLAG_INHERIT, 247 inherit[i] ? HANDLE_FLAG_INHERIT : 0); 248 } 249 } 250 251 /* 252 * Class: java_lang_ProcessImpl 253 * Method: getProcessId0 254 * Signature: (J)I 255 */ 256 JNIEXPORT jint JNICALL Java_java_lang_ProcessImpl_getProcessId0 257 (JNIEnv *env, jclass clazz, jlong handle) { 258 DWORD pid = GetProcessId((HANDLE) jlong_to_ptr(handle)); 259 return (jint)pid; 260 } 261 262 /* Please, read about the MS inheritance problem 263 http://support.microsoft.com/kb/315939 264 and critical section/synchronized block solution. */ 265 static jlong processCreate( 266 JNIEnv *env, 267 const jchar *pcmd, 268 const jchar *penvBlock, 269 const jchar *pdir, 270 jlong *handles, 271 jboolean redirectErrorStream) 272 { 273 jlong ret = 0L; 274 STARTUPINFOW si = {sizeof(si)}; 275 276 /* Handles for which the inheritance flag must be restored. */ 277 HANDLE stdIOE[HANDLE_STORAGE_SIZE] = { 278 /* Current process standard IOE handles: JDK-7147084 */ 279 INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 280 /* Child process IOE handles: JDK-6921885 */ 281 (HANDLE)handles[0], (HANDLE)handles[1], (HANDLE)handles[2]}; 282 BOOL inherit[HANDLE_STORAGE_SIZE] = { 283 FALSE, FALSE, FALSE, 284 FALSE, FALSE, FALSE}; 285 286 /* These three should not be closed by CloseHandle! */ 287 stdIOE[0] = GetStdHandle(STD_INPUT_HANDLE); 288 stdIOE[1] = GetStdHandle(STD_OUTPUT_HANDLE); 289 stdIOE[2] = GetStdHandle(STD_ERROR_HANDLE); 290 291 prepareIOEHandleState(stdIOE, inherit); 292 { 293 /* Input */ 294 STDHOLDER holderIn = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_READ}; 295 if (initHolder(env, &handles[0], &holderIn, &si.hStdInput)) { 296 297 /* Output */ 298 STDHOLDER holderOut = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; 299 if (initHolder(env, &handles[1], &holderOut, &si.hStdOutput)) { 300 301 /* Error */ 302 STDHOLDER holderErr = {{INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}, OFFSET_WRITE}; 303 BOOL success; 304 if (redirectErrorStream) { 305 si.hStdError = si.hStdOutput; 306 /* Here we set the error stream to [ProcessBuilder.NullInputStream.INSTANCE] 307 value. That is in accordance with Java Doc for the redirection case. 308 The Java file for the [ handles[2] ] will be closed in ANY case. It is not 309 a handle leak. */ 310 handles[2] = JAVA_INVALID_HANDLE_VALUE; 311 success = TRUE; 312 } else { 313 success = initHolder(env, &handles[2], &holderErr, &si.hStdError); 314 } 315 316 if (success) { 317 PROCESS_INFORMATION pi; 318 DWORD processFlag = CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; 319 320 /* If the standard I/O is inherited, CREATE_NO_WINDOW must not be used. */ 321 if (GetConsoleWindow() != NULL && 322 (si.hStdInput == stdIOE[0] || 323 si.hStdOutput == stdIOE[1] || 324 si.hStdError == (redirectErrorStream ? stdIOE[1] : stdIOE[2]))) 325 { 326 processFlag &= ~CREATE_NO_WINDOW; 327 } 328 329 si.dwFlags = STARTF_USESTDHANDLES; 330 if (!CreateProcessW( 331 NULL, /* executable name */ 332 (LPWSTR)pcmd, /* command line */ 333 NULL, /* process security attribute */ 334 NULL, /* thread security attribute */ 335 TRUE, /* inherits system handles */ 336 processFlag, /* selected based on exe type */ 337 (LPVOID)penvBlock,/* environment block */ 338 (LPCWSTR)pdir, /* change to the new current directory */ 339 &si, /* (in) startup information */ 340 &pi)) /* (out) process information */ 341 { 342 win32Error(env, L"CreateProcess"); 343 } else { 344 closeSafely(pi.hThread); 345 ret = (jlong)pi.hProcess; 346 } 347 } 348 releaseHolder(ret == 0, &holderErr); 349 releaseHolder(ret == 0, &holderOut); 350 } 351 releaseHolder(ret == 0, &holderIn); 352 } 353 } 354 restoreIOEHandleState(stdIOE, inherit); 355 356 return ret; 357 } 358 359 JNIEXPORT jlong JNICALL 360 Java_java_lang_ProcessImpl_create(JNIEnv *env, jclass ignored, 361 jstring cmd, 362 jstring envBlock, 363 jstring dir, 364 jlongArray stdHandles, 365 jboolean redirectErrorStream) 366 { 367 jlong ret = 0; 368 if (cmd != NULL && stdHandles != NULL) { 369 const jchar *pcmd = (*env)->GetStringChars(env, cmd, NULL); 370 if (pcmd != NULL) { 371 const jchar *penvBlock = (envBlock != NULL) 372 ? (*env)->GetStringChars(env, envBlock, NULL) 373 : NULL; 374 if (!(*env)->ExceptionCheck(env)) { 375 const jchar *pdir = (dir != NULL) 376 ? (*env)->GetStringChars(env, dir, NULL) 377 : NULL; 378 if (!(*env)->ExceptionCheck(env)) { 379 jlong *handles = (*env)->GetLongArrayElements(env, stdHandles, NULL); 380 if (handles != NULL) { 381 ret = processCreate( 382 env, 383 pcmd, 384 penvBlock, 385 pdir, 386 handles, 387 redirectErrorStream); 388 (*env)->ReleaseLongArrayElements(env, stdHandles, handles, 0); 389 } 390 if (pdir != NULL) 391 (*env)->ReleaseStringChars(env, dir, pdir); 392 } 393 if (penvBlock != NULL) 394 (*env)->ReleaseStringChars(env, envBlock, penvBlock); 395 } 396 (*env)->ReleaseStringChars(env, cmd, pcmd); 397 } 398 } 399 return ret; 400 } 401 402 JNIEXPORT jint JNICALL 403 Java_java_lang_ProcessImpl_getExitCodeProcess(JNIEnv *env, jclass ignored, jlong handle) 404 { 405 DWORD exit_code; 406 if (GetExitCodeProcess((HANDLE) handle, &exit_code) == 0) 407 win32Error(env, L"GetExitCodeProcess"); 408 return exit_code; 409 } 410 411 JNIEXPORT jint JNICALL 412 Java_java_lang_ProcessImpl_getStillActive(JNIEnv *env, jclass ignored) 413 { 414 return STILL_ACTIVE; 415 } 416 417 JNIEXPORT void JNICALL 418 Java_java_lang_ProcessImpl_waitForInterruptibly(JNIEnv *env, jclass ignored, jlong handle) 419 { 420 HANDLE events[2]; 421 events[0] = (HANDLE) handle; 422 events[1] = JVM_GetThreadInterruptEvent(); 423 424 if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 425 FALSE, /* Wait for ANY event */ 426 INFINITE) /* Wait forever */ 427 == WAIT_FAILED) 428 win32Error(env, L"WaitForMultipleObjects"); 429 } 430 431 JNIEXPORT void JNICALL 432 Java_java_lang_ProcessImpl_waitForTimeoutInterruptibly(JNIEnv *env, 433 jclass ignored, 434 jlong handle, 435 jlong timeout) 436 { 437 HANDLE events[2]; 438 DWORD dwTimeout = (DWORD)timeout; 439 DWORD result; 440 events[0] = (HANDLE) handle; 441 events[1] = JVM_GetThreadInterruptEvent(); 442 result = WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events, 443 FALSE, /* Wait for ANY event */ 444 dwTimeout); /* Wait for dwTimeout */ 445 446 if (result == WAIT_FAILED) 447 win32Error(env, L"WaitForMultipleObjects"); 448 } 449 450 JNIEXPORT void JNICALL 451 Java_java_lang_ProcessImpl_terminateProcess(JNIEnv *env, jclass ignored, jlong handle) 452 { 453 TerminateProcess((HANDLE) handle, 1); 454 } 455 456 JNIEXPORT jboolean JNICALL 457 Java_java_lang_ProcessImpl_isProcessAlive(JNIEnv *env, jclass ignored, jlong handle) 458 { 459 DWORD dwExitStatus; 460 GetExitCodeProcess((HANDLE) handle, &dwExitStatus); 461 return dwExitStatus == STILL_ACTIVE; 462 } 463 464 JNIEXPORT jboolean JNICALL 465 Java_java_lang_ProcessImpl_closeHandle(JNIEnv *env, jclass ignored, jlong handle) 466 { 467 return (jboolean) CloseHandle((HANDLE) handle); 468 } 469 470 /** 471 * Returns a copy of the Unicode characters of a string. Fow now this 472 * function doesn't handle long path names and other issues. 473 */ 474 static WCHAR* getPath(JNIEnv *env, jstring ps) { 475 WCHAR *pathbuf = NULL; 476 const jchar *chars = (*(env))->GetStringChars(env, ps, NULL); 477 if (chars != NULL) { 478 size_t pathlen = wcslen(chars); 479 pathbuf = (WCHAR*)malloc((pathlen + 6) * sizeof(WCHAR)); 480 if (pathbuf == NULL) { 481 JNU_ThrowOutOfMemoryError(env, NULL); 482 } else { 483 wcscpy(pathbuf, chars); 484 } 485 (*env)->ReleaseStringChars(env, ps, chars); 486 } 487 return pathbuf; 488 } 489 490 JNIEXPORT jlong JNICALL 491 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path) 492 { 493 const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA); 494 const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; 495 const DWORD disposition = OPEN_ALWAYS; 496 const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL; 497 HANDLE h; 498 WCHAR *pathbuf = getPath(env, path); 499 if (pathbuf == NULL) { 500 /* Exception already pending */ 501 return -1; 502 } 503 h = CreateFileW( 504 pathbuf, /* Wide char path name */ 505 access, /* Read and/or write permission */ 506 sharing, /* File sharing flags */ 507 NULL, /* Security attributes */ 508 disposition, /* creation disposition */ 509 flagsAndAttributes, /* flags and attributes */ 510 NULL); 511 free(pathbuf); 512 if (h == INVALID_HANDLE_VALUE) { 513 JNU_ThrowIOExceptionWithLastError(env, "CreateFileW"); 514 } 515 return ptr_to_jlong(h); 516 } --- EOF ---