From 163fe69482aaf2db4c51b8fa13dfb81843cf7b9a Mon Sep 17 00:00:00 2001 From: sherman Date: Mon, 19 Jan 2015 13:30:38 -0800 Subject: [PATCH] 8064601: Improve jar file handling Reviewed-by: alanb, ahgross --- src/share/classes/sun/tools/jar/Main.java | 83 +++++++++++++++---- .../sun/tools/jar/resources/jar.properties | 3 +- 2 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/share/classes/sun/tools/jar/Main.java b/src/share/classes/sun/tools/jar/Main.java index 607304df3..aab29ad0b 100644 --- a/src/share/classes/sun/tools/jar/Main.java +++ b/src/share/classes/sun/tools/jar/Main.java @@ -74,8 +74,10 @@ 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 +189,7 @@ class Main { addMainClass(manifest, ename); } } + expand(null, files, false); OutputStream out; if (fname != null) { out = new FileOutputStream(fname); @@ -208,13 +211,12 @@ 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(); } out.close(); - if(nflag) { + if (nflag) { JarFile jarFile = null; File packFile = null; JarOutputStream jos = null; @@ -291,7 +293,7 @@ class Main { list(fname, files); } else { InputStream in = new FileInputStream(FileDescriptor.in); - try{ + try { list(new BufferedInputStream(in), files); } finally { in.close(); @@ -410,6 +412,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)))); @@ -662,7 +667,6 @@ class Main { return updateOk; } - private void addIndex(JarIndex index, ZipOutputStream zos) throws IOException { @@ -699,6 +703,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, '/'); @@ -710,10 +755,10 @@ class Main { } } name = name.substring(matchPath.length()); - - if (name.startsWith("/")) { - name = name.substring(1); - } else if (name.startsWith("./")) { + name = safeName(name); + // the old implementaton doesn't remove + // "./" if it was led by "/" (?) + if (name.startsWith("./")) { name = name.substring(2); } return name; @@ -913,8 +958,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); + } } } } @@ -958,7 +1006,6 @@ class Main { Enumeration zes = zf.entries(); while (zes.hasMoreElements()) { ZipEntry e = zes.nextElement(); - InputStream is; if (files == null) { dirs.add(extractFile(zf.getInputStream(e), e)); } else { @@ -982,8 +1029,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()) { diff --git a/src/share/classes/sun/tools/jar/resources/jar.properties b/src/share/classes/sun/tools/jar/resources/jar.properties index beefbd2dd..3b87385c4 100644 --- a/src/share/classes/sun/tools/jar/resources/jar.properties +++ b/src/share/classes/sun/tools/jar/resources/jar.properties @@ -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\ -- GitLab