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




















 471 JNIEXPORT jlong JNICALL
 472 Java_java_lang_ProcessImpl_openForAtomicAppend(JNIEnv *env, jclass ignored, jstring path)
 473 {
 474     const DWORD access = (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA);
 475     const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
 476     const DWORD disposition = OPEN_ALWAYS;
 477     const DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
 478     HANDLE h;
 479     WCHAR *pathbuf = pathToNTPath(env, path, JNI_FALSE);
 480     if (pathbuf == NULL) {
 481         /* Exception already pending */
 482         return -1;
 483     }
 484     h = CreateFileW(
 485         pathbuf,            /* Wide char path name */
 486         access,             /* Read and/or write permission */
 487         sharing,            /* File sharing flags */
 488         NULL,               /* Security attributes */
 489         disposition,        /* creation disposition */
 490         flagsAndAttributes, /* flags and attributes */
 491         NULL);
 492     free(pathbuf);
 493     if (h == INVALID_HANDLE_VALUE) {
 494         JNU_ThrowIOExceptionWithLastError(env, "CreateFileW");
 495     }
 496     return ptr_to_jlong(h);
 497 }
--- EOF ---