Merge
This commit is contained in:
commit
86a1239bd0
nashorn
@ -28,3 +28,4 @@ test/script/external/*
|
||||
.project
|
||||
.externalToolBuilders/*
|
||||
.settings/*
|
||||
NashornProfile.txt
|
||||
|
@ -2724,12 +2724,9 @@ public final class Global extends Scope {
|
||||
// Retrieve current state of ENV variables.
|
||||
env.putAll(System.getenv(), scriptEnv._strict);
|
||||
|
||||
// Some platforms, e.g., Windows, do not define the PWD environment
|
||||
// variable, so that the $ENV.PWD property needs to be explicitly
|
||||
// set.
|
||||
if (!env.containsKey(ScriptingFunctions.PWD_NAME)) {
|
||||
env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict);
|
||||
}
|
||||
// Set the PWD variable to a value that is guaranteed to be understood
|
||||
// by the underlying platform.
|
||||
env.put(ScriptingFunctions.PWD_NAME, System.getProperty("user.dir"), scriptEnv._strict);
|
||||
}
|
||||
addOwnProperty(ScriptingFunctions.ENV_NAME, Attribute.NOT_ENUMERABLE, env);
|
||||
|
||||
|
88
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java
88
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java
@ -64,6 +64,9 @@ class CommandExecutor {
|
||||
return System.getProperty("os.name").contains("Windows");
|
||||
});
|
||||
|
||||
// Cygwin drive alias prefix.
|
||||
private static final String CYGDRIVE = "/cygdrive/";
|
||||
|
||||
// User's home directory
|
||||
private static final String HOME_DIRECTORY =
|
||||
AccessController.doPrivileged((PrivilegedAction<String>)() -> {
|
||||
@ -246,18 +249,22 @@ class CommandExecutor {
|
||||
// Stream to copy to.
|
||||
private final OutputStream output;
|
||||
|
||||
private final Thread thread;
|
||||
|
||||
Piper(final InputStream input, final OutputStream output) {
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
this.thread = new Thread(this, "$EXEC Piper");
|
||||
}
|
||||
|
||||
/**
|
||||
* start - start the Piper in a new daemon thread
|
||||
* @return this Piper
|
||||
*/
|
||||
void start() {
|
||||
Thread thread = new Thread(this, "$EXEC Piper");
|
||||
Piper start() {
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,6 +299,10 @@ class CommandExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
public void join() throws InterruptedException {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
// Exit thread.
|
||||
}
|
||||
|
||||
@ -388,7 +399,7 @@ class CommandExecutor {
|
||||
* @return resolved Path to file
|
||||
*/
|
||||
private static Path resolvePath(final String cwd, final String fileName) {
|
||||
return Paths.get(cwd).resolve(fileName).normalize();
|
||||
return Paths.get(sanitizePath(cwd)).resolve(fileName).normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -402,7 +413,8 @@ class CommandExecutor {
|
||||
switch (cmd.get(0)) {
|
||||
// Set current working directory.
|
||||
case "cd":
|
||||
// If zero args then use home dirrectory as cwd else use first arg.
|
||||
final boolean cygpath = IS_WINDOWS && cwd.startsWith(CYGDRIVE);
|
||||
// If zero args then use home directory as cwd else use first arg.
|
||||
final String newCWD = cmd.size() < 2 ? HOME_DIRECTORY : cmd.get(1);
|
||||
// Normalize the cwd
|
||||
final Path cwdPath = resolvePath(cwd, newCWD);
|
||||
@ -418,7 +430,13 @@ class CommandExecutor {
|
||||
}
|
||||
|
||||
// Set PWD environment variable to be picked up as cwd.
|
||||
environment.put("PWD", cwdPath.toString());
|
||||
// Make sure Cygwin paths look like Unix paths.
|
||||
String scwd = cwdPath.toString();
|
||||
if (cygpath && scwd.length() >= 2 &&
|
||||
Character.isLetter(scwd.charAt(0)) && scwd.charAt(1) == ':') {
|
||||
scwd = CYGDRIVE + Character.toLowerCase(scwd.charAt(0)) + "/" + scwd.substring(2);
|
||||
}
|
||||
environment.put("PWD", scwd);
|
||||
return true;
|
||||
|
||||
// Set an environment variable.
|
||||
@ -445,7 +463,8 @@ class CommandExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* preprocessCommand - scan the command for redirects
|
||||
* preprocessCommand - scan the command for redirects, and sanitize the
|
||||
* executable path
|
||||
* @param tokens command tokens
|
||||
* @param cwd current working directory
|
||||
* @param redirectInfo redirection information
|
||||
@ -471,9 +490,38 @@ class CommandExecutor {
|
||||
command.add(stripQuotes(token));
|
||||
}
|
||||
|
||||
if (command.size() > 0) {
|
||||
command.set(0, sanitizePath(command.get(0)));
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a path in case the underlying platform is Cygwin. In that case,
|
||||
* convert from the {@code /cygdrive/x} drive specification to the usual
|
||||
* Windows {@code X:} format.
|
||||
*
|
||||
* @param d a String representing a path
|
||||
* @return a String representing the same path in a form that can be
|
||||
* processed by the underlying platform
|
||||
*/
|
||||
private static String sanitizePath(final String d) {
|
||||
if (!IS_WINDOWS || (IS_WINDOWS && !d.startsWith(CYGDRIVE))) {
|
||||
return d;
|
||||
}
|
||||
final String pd = d.substring(CYGDRIVE.length());
|
||||
if (pd.length() >= 2 && pd.charAt(1) == '/') {
|
||||
// drive letter plus / -> convert /cygdrive/x/... to X:/...
|
||||
return pd.charAt(0) + ":" + pd.substring(1);
|
||||
} else if (pd.length() == 1) {
|
||||
// just drive letter -> convert /cygdrive/x to X:
|
||||
return pd.charAt(0) + ":";
|
||||
}
|
||||
// remaining case: /cygdrive/ -> can't convert
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* createProcessBuilder - create a ProcessBuilder for the command.
|
||||
* @param command command tokens
|
||||
@ -485,7 +533,7 @@ class CommandExecutor {
|
||||
// Create new ProcessBuilder.
|
||||
final ProcessBuilder pb = new ProcessBuilder(command);
|
||||
// Set current working directory.
|
||||
pb.directory(new File(cwd));
|
||||
pb.directory(new File(sanitizePath(cwd)));
|
||||
|
||||
// Map environment variables.
|
||||
final Map<String, String> processEnvironment = pb.environment();
|
||||
@ -523,7 +571,7 @@ class CommandExecutor {
|
||||
// Create ProcessBuilder with cwd and redirects set.
|
||||
createProcessBuilder(command, cwd, redirectInfo);
|
||||
|
||||
// If piped the wait for the next command.
|
||||
// If piped, wait for the next command.
|
||||
if (isPiped) {
|
||||
return;
|
||||
}
|
||||
@ -581,15 +629,17 @@ class CommandExecutor {
|
||||
ByteArrayOutputStream byteOutputStream = null;
|
||||
ByteArrayOutputStream byteErrorStream = null;
|
||||
|
||||
final List<Piper> piperThreads = new ArrayList<>();
|
||||
|
||||
// If input is not redirected.
|
||||
if (inputIsPipe) {
|
||||
// If inputStream other than System.in is provided.
|
||||
if (inputStream != null) {
|
||||
// Pipe inputStream to first process output stream.
|
||||
new Piper(inputStream, firstProcess.getOutputStream()).start();
|
||||
piperThreads.add(new Piper(inputStream, firstProcess.getOutputStream()).start());
|
||||
} else {
|
||||
// Otherwise assume an input string has been provided.
|
||||
new Piper(new ByteArrayInputStream(inputString.getBytes()), firstProcess.getOutputStream()).start();
|
||||
piperThreads.add(new Piper(new ByteArrayInputStream(inputString.getBytes()), firstProcess.getOutputStream()).start());
|
||||
}
|
||||
}
|
||||
|
||||
@ -598,11 +648,11 @@ class CommandExecutor {
|
||||
// If outputStream other than System.out is provided.
|
||||
if (outputStream != null ) {
|
||||
// Pipe outputStream from last process input stream.
|
||||
new Piper(lastProcess.getInputStream(), outputStream).start();
|
||||
piperThreads.add(new Piper(lastProcess.getInputStream(), outputStream).start());
|
||||
} else {
|
||||
// Otherwise assume an output string needs to be prepared.
|
||||
byteOutputStream = new ByteArrayOutputStream(BUFFER_SIZE);
|
||||
new Piper(lastProcess.getInputStream(), byteOutputStream).start();
|
||||
piperThreads.add(new Piper(lastProcess.getInputStream(), byteOutputStream).start());
|
||||
}
|
||||
}
|
||||
|
||||
@ -610,11 +660,11 @@ class CommandExecutor {
|
||||
if (errorIsPipe) {
|
||||
// If errorStream other than System.err is provided.
|
||||
if (errorStream != null) {
|
||||
new Piper(lastProcess.getErrorStream(), errorStream).start();
|
||||
piperThreads.add(new Piper(lastProcess.getErrorStream(), errorStream).start());
|
||||
} else {
|
||||
// Otherwise assume an error string needs to be prepared.
|
||||
byteErrorStream = new ByteArrayOutputStream(BUFFER_SIZE);
|
||||
new Piper(lastProcess.getErrorStream(), byteErrorStream).start();
|
||||
piperThreads.add(new Piper(lastProcess.getErrorStream(), byteErrorStream).start());
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,13 +672,13 @@ class CommandExecutor {
|
||||
for (int i = 0, n = processes.size() - 1; i < n; i++) {
|
||||
final Process prev = processes.get(i);
|
||||
final Process next = processes.get(i + 1);
|
||||
new Piper(prev.getInputStream(), next.getOutputStream()).start();
|
||||
piperThreads.add(new Piper(prev.getInputStream(), next.getOutputStream()).start());
|
||||
}
|
||||
|
||||
// Wind up processes.
|
||||
try {
|
||||
// Get the user specified timeout.
|
||||
long timeout = envVarLongValue("JJS_TIMEOUT");
|
||||
final long timeout = envVarLongValue("JJS_TIMEOUT");
|
||||
|
||||
// If user specified timeout (milliseconds.)
|
||||
if (timeout != 0) {
|
||||
@ -643,6 +693,10 @@ class CommandExecutor {
|
||||
// Wait for last process and get exit code.
|
||||
exitCode = lastProcess.waitFor();
|
||||
}
|
||||
// Wait for all piper threads to terminate
|
||||
for (final Piper piper : piperThreads) {
|
||||
piper.join();
|
||||
}
|
||||
|
||||
// Accumulate the output and error streams.
|
||||
outputString += byteOutputStream != null ? byteOutputStream.toString() : "";
|
||||
@ -765,7 +819,7 @@ class CommandExecutor {
|
||||
|
||||
/**
|
||||
* process - process a command array of strings
|
||||
* @param script command script to be processed
|
||||
* @param tokens command script to be processed
|
||||
*/
|
||||
void process(final List<String> tokens) {
|
||||
// Prepare to accumulate command tokens.
|
||||
|
2
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java
2
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java
@ -72,7 +72,7 @@ public final class ScriptingFunctions {
|
||||
public static final String EXIT_NAME = "$EXIT";
|
||||
|
||||
/** Names of special properties used by $ENV API. */
|
||||
public static final String ENV_NAME = "$ENV";
|
||||
public static final String ENV_NAME = "$ENV";
|
||||
|
||||
/** Name of the environment variable for the current working directory. */
|
||||
public static final String PWD_NAME = "PWD";
|
||||
|
68
nashorn/test/script/nosecurity/JDK-8151291.js
Normal file
68
nashorn/test/script/nosecurity/JDK-8151291.js
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test $EXEC and $ENV.PWD handling across platforms.
|
||||
* There must be a java executable in the PATH.
|
||||
*
|
||||
* @test
|
||||
* @option -scripting
|
||||
* @run
|
||||
*/
|
||||
|
||||
$EXEC(["java", "-version"])
|
||||
if ($EXIT != 0) {
|
||||
throw 'java executable problem: ' + $ERR
|
||||
}
|
||||
|
||||
function eq(p, q, e) {
|
||||
if (p != q) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
function neq(p, q, e) {
|
||||
if (p == q) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
var File = Java.type("java.io.File"),
|
||||
System = Java.type("java.lang.System"),
|
||||
win = System.getProperty("os.name").startsWith("Windows"),
|
||||
sep = File.separator,
|
||||
startwd = $ENV.PWD,
|
||||
upwd = startwd.substring(0, startwd.lastIndexOf(sep))
|
||||
|
||||
$EXEC("ls")
|
||||
var ls_startwd = $OUT
|
||||
$EXEC("cd ..; ls")
|
||||
var ls_cdupwd = $OUT
|
||||
eq($ENV.PWD, startwd, 'PWD changed during $EXEC cd')
|
||||
neq(ls_startwd, ls_cdupwd, 'same ls result for startwd and upwd with $EXEC cd')
|
||||
|
||||
$ENV.PWD = upwd
|
||||
eq($ENV.PWD, upwd, '$ENV.PWD change had no effect')
|
||||
$EXEC("ls")
|
||||
var ls_epupwd = $OUT
|
||||
neq(ls_startwd, ls_epupwd, 'same ls result for startwd and upwd with $ENV.PWD cd')
|
Loading…
x
Reference in New Issue
Block a user