提交 55efe603 编写于 作者: I igerasim

8195874: Improve jar specification adherence

Summary: Also reviewed by Chris Ries <chris.ries@oracle.com>
Reviewed-by: alanb, mchung, rriggs
上级 504c4e7f
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, 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
......@@ -37,6 +37,7 @@ import java.util.jar.Attributes;
import java.util.jar.Attributes.Name;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
......@@ -69,6 +70,8 @@ public class URLClassPath {
private static final boolean DEBUG_LOOKUP_CACHE;
private static final boolean DISABLE_JAR_CHECKING;
private static final boolean DISABLE_ACC_CHECKING;
private static final boolean DISABLE_CP_URL_CHECK;
private static final boolean DEBUG_CP_URL_CHECK;
static {
JAVA_VERSION = java.security.AccessController.doPrivileged(
......@@ -84,6 +87,13 @@ public class URLClassPath {
p = AccessController.doPrivileged(
new GetPropertyAction("jdk.net.URLClassPath.disableRestrictedPermissions"));
DISABLE_ACC_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
// This property will be removed in a later release
p = AccessController.doPrivileged(
new GetPropertyAction("jdk.net.URLClassPath.disableClassPathURLCheck"));
DISABLE_CP_URL_CHECK = p != null ? p.equals("true") || p.isEmpty() : false;
DEBUG_CP_URL_CHECK = "debug".equals(p);
}
/* The original search path of URLs. */
......@@ -1217,11 +1227,51 @@ public class URLClassPath {
int i = 0;
while (st.hasMoreTokens()) {
String path = st.nextToken();
urls[i] = new URL(base, path);
i++;
URL url = DISABLE_CP_URL_CHECK ? new URL(base, path) : safeResolve(base, path);
if (url != null) {
urls[i] = url;
i++;
}
}
if (i == 0) {
urls = null;
} else if (i != urls.length) {
// Truncate nulls from end of array
urls = Arrays.copyOf(urls, i);
}
return urls;
}
/*
* Return a URL for the given path resolved against the base URL, or
* null if the resulting URL is invalid.
*/
static URL safeResolve(URL base, String path) {
String child = path.replace(File.separatorChar, '/');
try {
if (!URI.create(child).isAbsolute()) {
URL url = new URL(base, child);
if (base.getProtocol().equalsIgnoreCase("file")) {
return url;
} else {
String bp = base.getPath();
String urlp = url.getPath();
int pos = bp.lastIndexOf('/');
if (pos == -1) {
pos = bp.length() - 1;
}
if (urlp.regionMatches(0, bp, 0, pos + 1)
&& urlp.indexOf("..", pos) == -1) {
return url;
}
}
}
} catch (MalformedURLException | IllegalArgumentException e) {}
if (DEBUG_CP_URL_CHECK) {
System.err.println("Class-Path entry: \"" + path + "\" ignored in JAR file " + base);
}
return null;
}
}
/*
......
......@@ -24,16 +24,20 @@
package jdk.testlibrary;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
......@@ -45,6 +49,72 @@ import java.util.jar.Manifest;
*/
public final class JarUtils {
/**
* Creates a JAR file.
*
* Equivalent to {@code jar cfm <jarfile> <manifest> -C <dir> file...}
*
* The input files are resolved against the given directory. Any input
* files that are directories are processed recursively.
*/
public static void createJarFile(Path jarfile, Manifest man, Path dir, Path... file)
throws IOException
{
// create the target directory
Path parent = jarfile.getParent();
if (parent != null)
Files.createDirectories(parent);
List<Path> entries = new ArrayList<>();
for (Path entry : file) {
Files.find(dir.resolve(entry), Integer.MAX_VALUE,
(p, attrs) -> attrs.isRegularFile())
.map(e -> dir.relativize(e))
.forEach(entries::add);
}
try (OutputStream out = Files.newOutputStream(jarfile);
JarOutputStream jos = new JarOutputStream(out))
{
if (man != null) {
JarEntry je = new JarEntry(JarFile.MANIFEST_NAME);
jos.putNextEntry(je);
man.write(jos);
jos.closeEntry();
}
for (Path entry : entries) {
String name = toJarEntryName(entry);
jos.putNextEntry(new JarEntry(name));
Files.copy(dir.resolve(entry), jos);
jos.closeEntry();
}
}
}
/**
* Creates a JAR file.
*
* Equivalent to {@code jar cf <jarfile> -C <dir> file...}
*
* The input files are resolved against the given directory. Any input
* files that are directories are processed recursively.
*/
public static void createJarFile(Path jarfile, Path dir, Path... file)
throws IOException
{
createJarFile(jarfile, null, dir, file);
}
/**
* Creates a JAR file from the contents of a directory.
*
* Equivalent to {@code jar cf <jarfile> -C <dir> .}
*/
public static void createJarFile(Path jarfile, Path dir) throws IOException {
createJarFile(jarfile, dir, Paths.get("."));
}
/**
* Create jar file with specified files. If a specified file does not exist,
* a new jar entry will be created with the file name itself as the content.
......@@ -196,4 +266,14 @@ public final class JarUtils {
}
}
}
/**
* Map a file path to the equivalent name in a JAR file
*/
private static String toJarEntryName(Path file) {
Path normalized = file.normalize();
return normalized.subpath(0, normalized.getNameCount()) // drop root
.toString()
.replace(File.separatorChar, '/');
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册