jdk/src/windows/classes/java/lang/ProcessImpl.java
changeset 16901 d98c53659845
parent 16490 43315ae7fa96
parent 16885 d54b22d3b306
child 17467 374c1cceefff
equal deleted inserted replaced
16851:3bbdae468b05 16901:d98c53659845
   143             }
   143             }
   144         }
   144         }
   145 
   145 
   146     }
   146     }
   147 
   147 
       
   148     // We guarantee the only command file execution for implicit [cmd.exe] run.
       
   149     //    http://technet.microsoft.com/en-us/library/bb490954.aspx
       
   150     private static final char CMD_BAT_ESCAPE[] = {' ', '\t', '<', '>', '&', '|', '^'};
       
   151     private static final char WIN32_EXECUTABLE_ESCAPE[] = {' ', '\t', '<', '>'};
       
   152 
       
   153     private static boolean isQuoted(boolean noQuotesInside, String arg,
       
   154             String errorMessage) {
       
   155         int lastPos = arg.length() - 1;
       
   156         if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') {
       
   157             // The argument has already been quoted.
       
   158             if (noQuotesInside) {
       
   159                 if (arg.indexOf('"', 1) != lastPos) {
       
   160                     // There is ["] inside.
       
   161                     throw new IllegalArgumentException(errorMessage);
       
   162                 }
       
   163             }
       
   164             return true;
       
   165         }
       
   166         if (noQuotesInside) {
       
   167             if (arg.indexOf('"') >= 0) {
       
   168                 // There is ["] inside.
       
   169                 throw new IllegalArgumentException(errorMessage);
       
   170             }
       
   171         }
       
   172         return false;
       
   173     }
       
   174 
       
   175     private static boolean needsEscaping(boolean isCmdFile, String arg) {
       
   176         // Switch off MS heuristic for internal ["].
       
   177         // Please, use the explicit [cmd.exe] call
       
   178         // if you need the internal ["].
       
   179         //    Example: "cmd.exe", "/C", "Extended_MS_Syntax"
       
   180 
       
   181         // For [.exe] or [.com] file the unpaired/internal ["]
       
   182         // in the argument is not a problem.
       
   183         boolean argIsQuoted = isQuoted(isCmdFile, arg,
       
   184             "Argument has embedded quote, use the explicit CMD.EXE call.");
       
   185 
       
   186         if (!argIsQuoted) {
       
   187             char testEscape[] = isCmdFile
       
   188                     ? CMD_BAT_ESCAPE
       
   189                     : WIN32_EXECUTABLE_ESCAPE;
       
   190             for (int i = 0; i < testEscape.length; ++i) {
       
   191                 if (arg.indexOf(testEscape[i]) >= 0) {
       
   192                     return true;
       
   193                 }
       
   194             }
       
   195         }
       
   196         return false;
       
   197     }
       
   198 
       
   199     private static String getExecutablePath(String path)
       
   200         throws IOException
       
   201     {
       
   202         boolean pathIsQuoted = isQuoted(true, path,
       
   203                 "Executable name has embedded quote, split the arguments");
       
   204 
       
   205         // Win32 CreateProcess requires path to be normalized
       
   206         File fileToRun = new File(pathIsQuoted
       
   207             ? path.substring(1, path.length() - 1)
       
   208             : path);
       
   209 
       
   210         // From the [CreateProcess] function documentation:
       
   211         //
       
   212         // "If the file name does not contain an extension, .exe is appended.
       
   213         // Therefore, if the file name extension is .com, this parameter
       
   214         // must include the .com extension. If the file name ends in
       
   215         // a period (.) with no extension, or if the file name contains a path,
       
   216         // .exe is not appended."
       
   217         //
       
   218         // "If the file name !does not contain a directory path!,
       
   219         // the system searches for the executable file in the following
       
   220         // sequence:..."
       
   221         //
       
   222         // In practice ANY non-existent path is extended by [.exe] extension
       
   223         // in the [CreateProcess] funcion with the only exception:
       
   224         // the path ends by (.)
       
   225 
       
   226         return fileToRun.getPath();
       
   227     }
       
   228 
       
   229 
   148     private long handle = 0;
   230     private long handle = 0;
   149     private OutputStream stdin_stream;
   231     private OutputStream stdin_stream;
   150     private InputStream stdout_stream;
   232     private InputStream stdout_stream;
   151     private InputStream stderr_stream;
   233     private InputStream stderr_stream;
   152 
   234 
   155                         final String path,
   237                         final String path,
   156                         final long[] stdHandles,
   238                         final long[] stdHandles,
   157                         final boolean redirectErrorStream)
   239                         final boolean redirectErrorStream)
   158         throws IOException
   240         throws IOException
   159     {
   241     {
   160         // Win32 CreateProcess requires cmd[0] to be normalized
   242         // The [executablePath] is not quoted for any case.
   161         cmd[0] = new File(cmd[0]).getPath();
   243         String executablePath = getExecutablePath(cmd[0]);
       
   244 
       
   245         // We need to extend the argument verification procedure
       
   246         // to guarantee the only command file execution for implicit [cmd.exe]
       
   247         // run.
       
   248         String upPath = executablePath.toUpperCase();
       
   249         boolean isCmdFile = (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));
   162 
   250 
   163         StringBuilder cmdbuf = new StringBuilder(80);
   251         StringBuilder cmdbuf = new StringBuilder(80);
   164         for (int i = 0; i < cmd.length; i++) {
   252 
   165             if (i > 0) {
   253         // Quotation protects from interpretation of the [path] argument as
   166                 cmdbuf.append(' ');
   254         // start of longer path with spaces. Quotation has no influence to
   167             }
   255         // [.exe] extension heuristic.
       
   256         cmdbuf.append('"');
       
   257         cmdbuf.append(executablePath);
       
   258         cmdbuf.append('"');
       
   259 
       
   260         for (int i = 1; i < cmd.length; i++) {
       
   261             cmdbuf.append(' ');
   168             String s = cmd[i];
   262             String s = cmd[i];
   169             if (s.indexOf(' ') >= 0 || s.indexOf('\t') >= 0) {
   263             if (needsEscaping(isCmdFile, s)) {
   170                 if (s.charAt(0) != '"') {
   264                 cmdbuf.append('"');
   171                     cmdbuf.append('"');
   265                 cmdbuf.append(s);
   172                     cmdbuf.append(s);
   266 
   173                     if (s.endsWith("\\")) {
   267                 // The code protects the [java.exe] and console command line
   174                         cmdbuf.append("\\");
   268                 // parser, that interprets the [\"] combination as an escape
   175                     }
   269                 // sequence for the ["] char.
   176                     cmdbuf.append('"');
   270                 //     http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
   177                 } else if (s.endsWith("\"")) {
   271                 //
   178                     /* The argument has already been quoted. */
   272                 // If the argument is an FS path, doubling of the tail [\]
   179                     cmdbuf.append(s);
   273                 // char is not a problem for non-console applications.
   180                 } else {
   274                 //
   181                     /* Unmatched quote for the argument. */
   275                 // The [\"] sequence is not an escape sequence for the [cmd.exe]
   182                     throw new IllegalArgumentException();
   276                 // command line parser. The case of the [""] tail escape
   183                 }
   277                 // sequence could not be realized due to the argument validation
       
   278                 // procedure.
       
   279                 if (!isCmdFile && s.endsWith("\\")) {
       
   280                     cmdbuf.append('\\');
       
   281                 }
       
   282                 cmdbuf.append('"');
   184             } else {
   283             } else {
   185                 cmdbuf.append(s);
   284                 cmdbuf.append(s);
   186             }
   285             }
   187         }
   286         }
   188         String cmdstr = cmdbuf.toString();
   287         String cmdstr = cmdbuf.toString();