/** Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.*********************/package java.lang;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileDescriptor;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.lang.ProcessBuilder.Redirect;import java.security.AccessController;import java.security.PrivilegedAction;import java.util.ArrayList;import java.util.concurrent.CompletableFuture;import java.util.concurrent.TimeUnit;import java.util.regex.Matcher;import java.util.regex.Pattern;import jdk.internal.misc.JavaIOFileDescriptorAccess;import jdk.internal.misc.SharedSecrets;import jdk.internal.ref.CleanerFactory;/* This class is for the exclusive use of ProcessBuilder.start() to* create new processes.** @author Martin Buchholz* @since 1.5*/final class ProcessImpl extends Process {private static final JavaIOFileDescriptorAccess fdAccess= SharedSecrets.getJavaIOFileDescriptorAccess();// Windows platforms support a forcible kill signal.static final boolean SUPPORTS_NORMAL_TERMINATION = false;/*** 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.*/private static FileOutputStream newFileOutputStream(File f, boolean append)throws IOException{if (append) {String path = f.getPath();SecurityManager sm = System.getSecurityManager();if (sm != null)sm.checkWrite(path);long handle = openForAtomicAppend(path);final FileDescriptor fd = new FileDescriptor();fdAccess.setHandle(fd, handle);return AccessController.doPrivileged(new PrivilegedAction<FileOutputStream>() {public FileOutputStream run() {return new FileOutputStream(fd);}});} else {return new FileOutputStream(f);}}// System-dependent portion of ProcessBuilder.start()static Process start(String cmdarray[],java.util.Map<String,String> environment,String dir,ProcessBuilder.Redirect[] redirects,boolean redirectErrorStream)throws IOException{String envblock = ProcessEnvironment.toEnvironmentBlock(environment);FileInputStream f0 = null;FileOutputStream f1 = null;FileOutputStream f2 = null;try {long[] stdHandles;if (redirects == null) {stdHandles = new long[] { -1L, -1L, -1L };} else {stdHandles = new long[3];if (redirects[0] == Redirect.PIPE) {stdHandles[0] = -1L;} else if (redirects[0] == Redirect.INHERIT) {stdHandles[0] = fdAccess.getHandle(FileDescriptor.in);} else if (redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {stdHandles[0] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd());} else {f0 = new FileInputStream(redirects[0].file());stdHandles[0] = fdAccess.getHandle(f0.getFD());}if (redirects[1] == Redirect.PIPE) {stdHandles[1] = -1L;} else if (redirects[1] == Redirect.INHERIT) {stdHandles[1] = fdAccess.getHandle(FileDescriptor.out);} else if (redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {stdHandles[1] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd());} else {f1 = newFileOutputStream(redirects[1].file(),redirects[1].append());stdHandles[1] = fdAccess.getHandle(f1.getFD());}if (redirects[2] == Redirect.PIPE) {stdHandles[2] = -1L;} else if (redirects[2] == Redirect.INHERIT) {stdHandles[2] = fdAccess.getHandle(FileDescriptor.err);} else if (redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {stdHandles[2] = fdAccess.getHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd());} else {f2 = newFileOutputStream(redirects[2].file(),redirects[2].append());stdHandles[2] = fdAccess.getHandle(f2.getFD());}}Process p = new ProcessImpl(cmdarray, envblock, dir,stdHandles, redirectErrorStream);if (redirects != null) {// Copy the handles's if they are to be redirected to another processif (stdHandles[0] >= 0&& redirects[0] instanceof ProcessBuilder.RedirectPipeImpl) {fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[0]).getFd(),stdHandles[0]);}if (stdHandles[1] >= 0&& redirects[1] instanceof ProcessBuilder.RedirectPipeImpl) {fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[1]).getFd(),stdHandles[1]);}if (stdHandles[2] >= 0&& redirects[2] instanceof ProcessBuilder.RedirectPipeImpl) {fdAccess.setHandle(((ProcessBuilder.RedirectPipeImpl) redirects[2]).getFd(),stdHandles[2]);}}return p;} finally {// In theory, close() can throw IOException// (although it is rather unlikely to happen here)try { if (f0 != null) f0.close(); }finally {try { if (f1 != null) f1.close(); }finally { if (f2 != null) f2.close(); }}}}private static class LazyPattern {// Escape-support version:// "(\")((?:\\\\\1円|.)+?)\1円|([^\\s\"]+)";private static final Pattern PATTERN =Pattern.compile("[^\\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.*/private static String[] getTokensFromCommand(String command) {ArrayList<String> matchList = new ArrayList<>(8);Matcher regexMatcher = LazyPattern.PATTERN.matcher(command);while (regexMatcher.find())matchList.add(regexMatcher.group());return matchList.toArray(new String[matchList.size()]);}private static final int VERIFICATION_CMD_BAT = 0;private static final int VERIFICATION_WIN32 = 1;private static final int VERIFICATION_LEGACY = 2;private static final char ESCAPE_VERIFICATION[][] = {// We guarantee the only command file execution for implicit [cmd.exe] run.// http://technet.microsoft.com/en-us/library/bb490954.aspx{' ', '\t', '<', '>', '&', '|', '^'},{' ', '\t', '<', '>'},{' ', '\t'}};private static String createCommandLine(int verificationType,final String executablePath,final String cmd[]){StringBuilder cmdbuf = new StringBuilder(80);cmdbuf.append(executablePath);for (int i = 1; i < cmd.length; ++i) {cmdbuf.append(' ');String s = cmd[i];if (needsEscaping(verificationType, s)) {cmdbuf.append('"').append(s);// The code protects the [java.exe] and console command line// parser, that interprets the [\"] combination as an escape// sequence for the ["] char.// http://msdn.microsoft.com/en-us/library/17w5ykft.aspx//// 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.if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) {cmdbuf.append('\\');}cmdbuf.append('"');} else {cmdbuf.append(s);}}return cmdbuf.toString();}private static boolean isQuoted(boolean noQuotesInside, String arg,String errorMessage) {int lastPos = arg.length() - 1;if (lastPos >=1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') {// The argument has already been quoted.if (noQuotesInside) {if (arg.indexOf('"', 1) != lastPos) {// There is ["] inside.throw new IllegalArgumentException(errorMessage);}}return true;}if (noQuotesInside) {if (arg.indexOf('"') >= 0) {// There is ["] inside.throw new IllegalArgumentException(errorMessage);}}return false;}private static boolean needsEscaping(int verificationType, String arg) {// 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"// For [.exe] or [.com] file the unpaired/internal ["]// in the argument is not a problem.boolean argIsQuoted = isQuoted((verificationType == VERIFICATION_CMD_BAT),arg, "Argument has embedded quote, use the explicit CMD.EXE call.");if (!argIsQuoted) {char testEscape[] = ESCAPE_VERIFICATION[verificationType];for (int i = 0; i < testEscape.length; ++i) {if (arg.indexOf(testEscape[i]) >= 0) {return true;}}}return false;}private static String getExecutablePath(String path)throws IOException{boolean pathIsQuoted = isQuoted(true, path,"Executable name has embedded quote, split the arguments");// Win32 CreateProcess requires path to be normalizedFile fileToRun = new File(pathIsQuoted? path.substring(1, path.length() - 1): 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 (.)return fileToRun.getPath();}private boolean isShellFile(String executablePath) {String upPath = executablePath.toUpperCase();return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT"));}private String quoteString(String arg) {StringBuilder argbuf = new StringBuilder(arg.length() + 2);return argbuf.append('"').append(arg).append('"').toString();}private final long handle;private final ProcessHandle processHandle;private OutputStream stdin_stream;private InputStream stdout_stream;private InputStream stderr_stream;private ProcessImpl(String cmd[],final String envblock,final String path,final long[] stdHandles,final boolean redirectErrorStream)throws IOException{String cmdstr;SecurityManager security = System.getSecurityManager();boolean allowAmbiguousCommands = false;if (security == null) {allowAmbiguousCommands = true;String value = System.getProperty("jdk.lang.Process.allowAmbiguousCommands");if (value != null)allowAmbiguousCommands = !"false".equalsIgnoreCase(value);}if (allowAmbiguousCommands) {// Legacy mode.// Normalize path if possible.String executablePath = new File(cmd[0]).getPath();// No worry about internal, unpaired ["], and redirection/piping.if (needsEscaping(VERIFICATION_LEGACY, executablePath) )executablePath = quoteString(executablePath);cmdstr = createCommandLine(//legacy mode doesn't worry about extended verificationVERIFICATION_LEGACY,executablePath,cmd);} else {String executablePath;try {executablePath = getExecutablePath(cmd[0]);} catch (IllegalArgumentException e) {// Workaround for the calls like// Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar")// No chance to avoid CMD/BAT injection, except to do the work// 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.StringBuilder join = new StringBuilder();// terminal space in command line is okfor (String s : cmd)join.append(s).append(' ');// Parse the command line again.cmd = getTokensFromCommand(join.toString());executablePath = getExecutablePath(cmd[0]);// Check new executable name once moreif (security != null)security.checkExec(executablePath);}// Quotation protects from interpretation of the [path] argument as// start of longer path with spaces. Quotation has no influence to// [.exe] extension heuristic.cmdstr = createCommandLine(// We need the extended verification procedure for CMD files.isShellFile(executablePath)? VERIFICATION_CMD_BAT: VERIFICATION_WIN32,quoteString(executablePath),cmd);}handle = create(cmdstr, envblock, path,stdHandles, redirectErrorStream);// Register a cleaning function to close the handlefinal long local_handle = handle; // local to prevent capture of thisCleanerFactory.cleaner().register(this, () -> closeHandle(local_handle));processHandle = ProcessHandleImpl.getInternal(getProcessId0(handle));java.security.AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() {public Void run() {if (stdHandles[0] == -1L)stdin_stream = ProcessBuilder.NullOutputStream.INSTANCE;else {FileDescriptor stdin_fd = new FileDescriptor();fdAccess.setHandle(stdin_fd, stdHandles[0]);stdin_stream = new BufferedOutputStream(new FileOutputStream(stdin_fd));}if (stdHandles[1] == -1L)stdout_stream = ProcessBuilder.NullInputStream.INSTANCE;else {FileDescriptor stdout_fd = new FileDescriptor();fdAccess.setHandle(stdout_fd, stdHandles[1]);stdout_stream = new BufferedInputStream(new PipeInputStream(stdout_fd));}if (stdHandles[2] == -1L)stderr_stream = ProcessBuilder.NullInputStream.INSTANCE;else {FileDescriptor stderr_fd = new FileDescriptor();fdAccess.setHandle(stderr_fd, stdHandles[2]);stderr_stream = new PipeInputStream(stderr_fd);}return null; }});}public OutputStream getOutputStream() {return stdin_stream;}public InputStream getInputStream() {return stdout_stream;}public InputStream getErrorStream() {return stderr_stream;}private static final int STILL_ACTIVE = getStillActive();private static native int getStillActive();public int exitValue() {int exitCode = getExitCodeProcess(handle);if (exitCode == STILL_ACTIVE)throw new IllegalThreadStateException("process has not exited");return exitCode;}private static native int getExitCodeProcess(long handle);public int waitFor() throws InterruptedException {waitForInterruptibly(handle);if (Thread.interrupted())throw new InterruptedException();return exitValue();}private static native void waitForInterruptibly(long handle);@Overridepublic boolean waitFor(long timeout, TimeUnit unit)throws InterruptedException{long remainingNanos = unit.toNanos(timeout); // throw NPE before other conditionsif (getExitCodeProcess(handle) != STILL_ACTIVE) return true;if (timeout <= 0) return false;long deadline = System.nanoTime() + remainingNanos ;do {// Round up to next millisecondlong msTimeout = TimeUnit.NANOSECONDS.toMillis(remainingNanos + 999_999L);waitForTimeoutInterruptibly(handle, msTimeout);if (Thread.interrupted())throw new InterruptedException();if (getExitCodeProcess(handle) != STILL_ACTIVE) {return true;}remainingNanos = deadline - System.nanoTime();} while (remainingNanos > 0);return (getExitCodeProcess(handle) != STILL_ACTIVE);}private static native void waitForTimeoutInterruptibly(long handle, long timeout);@Overridepublic void destroy() {terminateProcess(handle);}@Overridepublic CompletableFuture<Process> onExit() {return ProcessHandleImpl.completion(pid(), false).handleAsync((exitStatus, unusedThrowable) -> this);}@Overridepublic ProcessHandle toHandle() {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("manageProcess"));}return processHandle;}@Overridepublic boolean supportsNormalTermination() {return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;}@Overridepublic Process destroyForcibly() {destroy();return this;}private static native void terminateProcess(long handle);@Overridepublic long pid() {return processHandle.pid();}private static native int getProcessId0(long handle);@Overridepublic boolean isAlive() {return isProcessAlive(handle);}private static native boolean isProcessAlive(long handle);/*** The {@code toString} method returns a string consisting of* the native process ID of the process and the exit value of the process.** @return a string representation of the object.*/@Overridepublic String toString() {int exitCode = getExitCodeProcess(handle);return new StringBuilder("Process[pid=").append(pid()).append(", exitValue=").append(exitCode == STILL_ACTIVE ? "\"not exited\"" : exitCode).append("]").toString();}/*** Create a process using the win32 function CreateProcess.* The method is synchronized due to MS kb315939 problem.* All native handles should restore the inherit flag at the end of call.** @param cmdstr the Windows command line* @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*/private static synchronized native long create(String cmdstr,String envblock,String dir,long[] stdHandles,boolean redirectErrorStream)throws IOException;/*** Opens a file for atomic append. The file is created if it doesn't* already exist.** @param path the file to open or create* @return the native HANDLE*/private static native long openForAtomicAppend(String path)throws IOException;private static native boolean closeHandle(long handle);}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。