/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
*
* @author Martin Buchholz
* @since 1.5
*/
/**
* Open a file for writing. If {@code append} is {@code true} then the file
* is opened for atomic append directly and a FileOutputStream constructed
* with the resulting handle. This is because a FileOutputStream created
* to append to a file does not open the file in a manner that guarantees
* that writes by the child process will be atomic.
*/
throws IOException
{
if (append) {
return AccessController.doPrivileged(
new PrivilegedAction<FileOutputStream>() {
public FileOutputStream run() {
return new FileOutputStream(fd);
}
}
);
} else {
return new FileOutputStream(f);
}
}
// System-dependent portion of ProcessBuilder.start()
boolean redirectErrorStream)
throws IOException
{
try {
long[] stdHandles;
} else {
stdHandles = new long[3];
else {
}
else {
}
else {
}
}
} finally {
// In theory, close() can throw IOException
// (although it is rather unlikely to happen here)
finally {
}
}
}
private static class LazyPattern {
// Escape-support version:
// "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)";
};
/* Parses the command string parameter into the executable name and
* program arguments.
*
* The command string is broken into tokens. The token separator is a space
* or quota character. The space inside quotation is not a token separator.
* There are no escape sequences.
*/
while (regexMatcher.find())
}
private static final char ESCAPE_VERIFICATION[][] = {
// We guarantee the only command file execution for implicit [cmd.exe] run.
{' ', '\t', '<', '>', '&', '|', '^'},
{' ', '\t', '<', '>'},
{' ', '\t'}
};
final String executablePath,
{
if (needsEscaping(verificationType, s)) {
// The code protects the [java.exe] and console command line
// parser, that interprets the [\"] combination as an escape
// sequence for the ["] char.
//
// If the argument is an FS path, doubling of the tail [\]
// char is not a problem for non-console applications.
//
// The [\"] sequence is not an escape sequence for the [cmd.exe]
// command line parser. The case of the [""] tail escape
// sequence could not be realized due to the argument validation
// procedure.
}
} else {
}
}
}
// The argument has already been quoted.
if (noQuotesInside) {
// There is ["] inside.
throw new IllegalArgumentException(errorMessage);
}
}
return true;
}
if (noQuotesInside) {
// There is ["] inside.
throw new IllegalArgumentException(errorMessage);
}
}
return false;
}
// Switch off MS heuristic for internal ["].
// Please, use the explicit [cmd.exe] call
// if you need the internal ["].
// Example: "cmd.exe", "/C", "Extended_MS_Syntax"
// in the argument is not a problem.
boolean argIsQuoted = isQuoted(
arg, "Argument has embedded quote, use the explicit CMD.EXE call.");
if (!argIsQuoted) {
return true;
}
}
}
return false;
}
throws IOException
{
"Executable name has embedded quote, split the arguments");
// Win32 CreateProcess requires path to be normalized
: path);
// From the [CreateProcess] function documentation:
//
// "If the file name does not contain an extension, .exe is appended.
// Therefore, if the file name extension is .com, this parameter
// must include the .com extension. If the file name ends in
// a period (.) with no extension, or if the file name contains a path,
// .exe is not appended."
//
// "If the file name !does not contain a directory path!,
// the system searches for the executable file in the following
// sequence:..."
//
// In practice ANY non-existent path is extended by [.exe] extension
// in the [CreateProcess] funcion with the only exception:
// the path ends by (.)
}
}
}
final long[] stdHandles,
final boolean redirectErrorStream)
throws IOException
{
boolean allowAmbiguousCommands = false;
allowAmbiguousCommands = true;
}
if (allowAmbiguousCommands) {
// Legacy mode.
// Normalize path if possible.
// No worry about internal, unpaired ["], and redirection/piping.
//legacy mode doesn't worry about extended verification
cmd);
} else {
try {
} catch (IllegalArgumentException e) {
// Workaround for the calls like
// Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar")
// right from the beginning. Otherwise we have too many corner
// cases from
// Runtime.getRuntime().exec(String[] cmd [, ...])
// calls with internal ["] and escape sequences.
// Restore original command line.
// terminal space in command line is ok
// Parse the command line again.
// Check new executable name once more
}
// Quotation protects from interpretation of the [path] argument as
// start of longer path with spaces. Quotation has no influence to
// [.exe] extension heuristic.
// We need the extended verification procedure for CMD files.
cmd);
}
else {
stdin_stream = new BufferedOutputStream(
new FileOutputStream(stdin_fd));
}
else {
stdout_stream = new BufferedInputStream(
new FileInputStream(stdout_fd));
}
else {
}
return null; }});
}
return stdin_stream;
}
return stdout_stream;
}
return stderr_stream;
}
public void finalize() {
}
private static native int getStillActive();
public int exitValue() {
if (exitCode == STILL_ACTIVE)
throw new IllegalThreadStateException("process has not exited");
return exitCode;
}
if (Thread.interrupted())
throw new InterruptedException();
return exitValue();
}
/**
* Create a process using the win32 function CreateProcess.
*
* @param cmdstr the Windows commandline
* @param envblock NUL-separated, double-NUL-terminated list of
* environment strings in VAR=VALUE form
* @param dir the working directory of the process, or null if
* inheriting the current directory from the parent process
* @param stdHandles array of windows HANDLEs. Indexes 0, 1, and
* 2 correspond to standard input, standard output and
* standard error, respectively. On input, a value of -1
* means to create a pipe to connect child and parent
* processes. On output, a value which is not -1 is the
* parent pipe handle corresponding to the pipe which has
* been created. An element of this array is -1 on input
* if and only if it is <em>not</em> -1 on output.
* @param redirectErrorStream redirectErrorStream attribute
* @return the native subprocess HANDLE returned by CreateProcess
*/
long[] stdHandles,
boolean redirectErrorStream)
throws IOException;
/**
* Opens a file for atomic append. The file is created if it doesn't
* already exist.
*
* @param file the file to open or create
* @return the native HANDLE
*/
throws IOException;
}