changeset 10642:165947f5448a

8064601: Improve jar file handling Reviewed-by: alanb, ahgross
author sherman
date Mon, 19 Jan 2015 13:30:38 -0800
parents 4cc9179f6fce
children 09d1946d3a2a
files src/share/classes/sun/tools/jar/Main.java src/share/classes/sun/tools/jar/resources/jar.properties
diffstat 2 files changed, 71 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/sun/tools/jar/Main.java	Thu Apr 09 13:45:01 2015 -0700
+++ b/src/share/classes/sun/tools/jar/Main.java	Mon Jan 19 13:30:38 2015 -0800
@@ -74,8 +74,10 @@
      * 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 @@
                         addMainClass(manifest, ename);
                     }
                 }
+                expand(null, files, false);
                 OutputStream out;
                 if (fname != null) {
                     out = new FileOutputStream(fname);
@@ -208,13 +211,12 @@
                     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 @@
                     list(fname, files);
                 } else {
                     InputStream in = new FileInputStream(FileDescriptor.in);
-                    try{
+                    try {
                         list(new BufferedInputStream(in), files);
                     } finally {
                         in.close();
@@ -410,6 +412,9 @@
                 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 @@
         return updateOk;
     }
 
-
     private void addIndex(JarIndex index, ZipOutputStream zos)
         throws IOException
     {
@@ -699,6 +703,47 @@
         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 @@
             }
         }
         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 @@
         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 @@
         Enumeration<? extends ZipEntry> 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 @@
      */
     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()) {
--- a/src/share/classes/sun/tools/jar/resources/jar.properties	Thu Apr 09 13:45:01 2015 -0700
+++ b/src/share/classes/sun/tools/jar/resources/jar.properties	Mon Jan 19 13:30:38 2015 -0800
@@ -68,7 +68,7 @@
         (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 @@
 \ \   -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\