8064601: Improve jar file handling

Reviewed-by: alanb, coffeys
This commit is contained in:
Xueming Shen 2015-01-28 12:36:25 -08:00
parent 31896469fd
commit e7cf4064cc
2 changed files with 69 additions and 13 deletions
jdk/src/jdk.jartool/share/classes/sun/tools/jar

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2015, 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
@ -74,8 +74,9 @@ class Main {
* Mflag: DO NOT generate a manifest file (just ZIP)
* iflag: generate jar index
* nflag: Perform jar normalization at the end
* pflag: preserve/don't strip leading slash and .. component from file name
*/
boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag;
boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag;
static final String MANIFEST_DIR = "META-INF/";
static final String VERSION = "1.0";
@ -187,6 +188,7 @@ class Main {
addMainClass(manifest, ename);
}
}
expand(null, files, false);
OutputStream out;
if (fname != null) {
out = new FileOutputStream(fname);
@ -208,7 +210,6 @@ class Main {
tmpfile = createTemporaryFile(tmpbase, ".jar");
out = new FileOutputStream(tmpfile);
}
expand(null, files, false);
create(new BufferedOutputStream(out, 4096), manifest);
if (in != null) {
in.close();
@ -424,6 +425,9 @@ class Main {
case 'e':
ename = args[count++];
break;
case 'P':
pflag = true;
break;
default:
error(formatMsg("error.illegal.option",
String.valueOf(flags.charAt(i))));
@ -713,6 +717,47 @@ class Main {
return true;
}
private static final boolean isWinDriveLetter(char c) {
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
}
private String safeName(String name) {
if (!pflag) {
int len = name.length();
int i = name.lastIndexOf("../");
if (i == -1) {
i = 0;
} else {
i += 3; // strip any dot-dot components
}
if (File.separatorChar == '\\') {
// the spec requests no drive letter. skip if
// the entry name has one.
while (i < len) {
int off = i;
if (i + 1 < len &&
name.charAt(i + 1) == ':' &&
isWinDriveLetter(name.charAt(i))) {
i += 2;
}
while (i < len && name.charAt(i) == '/') {
i++;
}
if (i == off) {
break;
}
}
} else {
while (i < len && name.charAt(i) == '/') {
i++;
}
}
if (i != 0) {
name = name.substring(i);
}
}
return name;
}
private String entryName(String name) {
name = name.replace(File.separatorChar, '/');
@ -723,11 +768,10 @@ class Main {
matchPath = path;
}
}
name = name.substring(matchPath.length());
if (name.startsWith("/")) {
name = name.substring(1);
} else if (name.startsWith("./")) {
name = safeName(name.substring(matchPath.length()));
// the old implementaton doesn't remove
// "./" if it was led by "/" (?)
if (name.startsWith("./")) {
name = name.substring(2);
}
return name;
@ -927,8 +971,11 @@ class Main {
for (ZipEntry ze : zes) {
long lastModified = ze.getTime();
if (lastModified != -1) {
File f = new File(ze.getName().replace('/', File.separatorChar));
f.setLastModified(lastModified);
String name = safeName(ze.getName().replace(File.separatorChar, '/'));
if (name.length() != 0) {
File f = new File(name.replace('/', File.separatorChar));
f.setLastModified(lastModified);
}
}
}
}
@ -1002,8 +1049,16 @@ class Main {
*/
ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException {
ZipEntry rc = null;
String name = e.getName();
File f = new File(e.getName().replace('/', File.separatorChar));
// The spec requres all slashes MUST be forward '/', it is possible
// an offending zip/jar entry may uses the backwards slash in its
// name. It might cause problem on Windows platform as it skips
// our "safe" check for leading slahs and dot-dot. So replace them
// with '/'.
String name = safeName(e.getName().replace(File.separatorChar, '/'));
if (name.length() == 0) {
return rc; // leading '/' or 'dot-dot' only path
}
File f = new File(name.replace('/', File.separatorChar));
if (e.isDirectory()) {
if (f.exists()) {
if (!f.isDirectory()) {

@ -68,7 +68,7 @@ out.size=\
(in = {0}) (out= {1})
usage=\
Usage: jar {ctxui}[vfmn0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...\n\
Usage: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...\n\
Options:\n\
\ \ -c create new archive\n\
\ \ -t list table of contents for archive\n\
@ -81,6 +81,7 @@ Options:\n\
\ \ -e specify application entry point for stand-alone application \n\
\ \ bundled into an executable jar file\n\
\ \ -0 store only; use no ZIP compression\n\
\ \ -P preserve leading '/' (absolute path) and ".." (parent directory) components from file names\n\
\ \ -M do not create a manifest file for the entries\n\
\ \ -i generate index information for the specified jar files\n\
\ \ -C change to the specified directory and include the following file\n\