src/share/classes/sun/tools/jar/Main.java

Print this page




  57 
  58     // Directories specified by "-C" operation.
  59     List<String> paths = new ArrayList<String>();
  60 
  61     CRC32 crc32 = new CRC32();
  62     /*
  63      * cflag: create
  64      * uflag: update
  65      * xflag: xtract
  66      * tflag: table
  67      * vflag: verbose
  68      * flag0: no zip compression (store only)
  69      * Mflag: DO NOT generate a manifest file (just ZIP)
  70      * iflag: generate jar index
  71      */
  72     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag;
  73 
  74     static final String MANIFEST = JarFile.MANIFEST_NAME;
  75     static final String MANIFEST_DIR = "META-INF/";
  76     static final String VERSION = "1.0";
  77     static final char SEPARATOR = File.separatorChar;
  78     static final String INDEX = JarIndex.INDEX_NAME;
  79 
  80     private static ResourceBundle rsrc;
  81 
  82     /**
  83      * If true, maintain compatibility with JDK releases prior to 6.0 by
  84      * timestamping extracted files with the time at which they are extracted.
  85      * Default is to use the time given in the archive.
  86      */
  87     private static final boolean useExtractionTime =
  88         Boolean.getBoolean("sun.tools.jar.useExtractionTime");
  89 
  90     /**
  91      * Initialize ResourceBundle
  92      */
  93     static {
  94         try {
  95             rsrc = ResourceBundle.getBundle("sun.tools.jar.resources.jar");
  96         } catch (MissingResourceException e) {
  97             throw new Error("Fatal: Resource for jar is missing");


 210                     (new FileInputStream(mname)) : null;
 211                 expand(null, files, true);
 212                 boolean updateOk = update(in, new BufferedOutputStream(out), manifest, null);
 213                 if (ok) {
 214                     ok = updateOk;
 215                 }
 216                 in.close();
 217                 out.close();
 218                 if (manifest != null) {
 219                     manifest.close();
 220                 }
 221                 if (fname != null) {
 222                     // on Win32, we need this delete
 223                     inputFile.delete();
 224                     if (!tmpFile.renameTo(inputFile)) {
 225                         tmpFile.delete();
 226                         throw new IOException(getMsg("error.write.file"));
 227                     }
 228                     tmpFile.delete();
 229                 }
 230             } else if (xflag || tflag) {
 231                 InputStream in;
 232                 if (fname != null) {
 233                     in = new FileInputStream(fname);
 234                 } else {
 235                     in = new FileInputStream(FileDescriptor.in);
 236                 }
 237                 if (xflag) {
 238                     extract(new BufferedInputStream(in), files);
 239                 } else {
 240                     list(new BufferedInputStream(in), files);


 241                 }












 242                 in.close();


 243             } else if (iflag) {
 244                 genIndex(rootjar, files);
 245             }
 246         } catch (IOException e) {
 247             fatalError(e);
 248             ok = false;
 249         } catch (Error ee) {
 250             ee.printStackTrace();
 251             ok = false;
 252         } catch (Throwable t) {
 253             t.printStackTrace();
 254             ok = false;
 255         }
 256         out.flush();
 257         err.flush();
 258         return ok;
 259     }
 260 
 261     /*
 262      * Parse command line arguments.


 743      */
 744     private void crc32File(ZipEntry e, File f) throws IOException {
 745         InputStream is = new BufferedInputStream(new FileInputStream(f));
 746         byte[] buf = new byte[8192];
 747         crc32.reset();
 748         int r = 0;
 749         int nread = 0;
 750         long len = f.length();
 751         while ((r = is.read(buf)) != -1) {
 752             nread += r;
 753             crc32.update(buf, 0, r);
 754         }
 755         is.close();
 756         if (nread != (int) len) {
 757             throw new JarException(formatMsg(
 758                         "error.incorrect.length", f.getPath()));
 759         }
 760         e.setCrc(crc32.getValue());
 761     }
 762 

























 763     /*
 764      * Extracts specified entries from JAR file.
 765      */
 766     void extract(InputStream in, String files[]) throws IOException {
 767         ZipInputStream zis = new ZipInputStream(in);
 768         ZipEntry e;
 769         // Set of all directory entries specified in archive.  Disallows
 770         // null entries.  Disallows all entries if using pre-6.0 behavior.
 771         Set<ZipEntry> dirs = new HashSet<ZipEntry>() {
 772             public boolean add(ZipEntry e) {
 773                 return ((e == null || useExtractionTime) ? false : super.add(e));
 774             }};
 775 
 776         while ((e = zis.getNextEntry()) != null) {
 777             if (files == null) {
 778                 dirs.add(extractFile(zis, e));
 779 
 780             } else {
 781                 String name = e.getName();
 782                 for (int i = 0; i < files.length; i++) {
 783                     String file = files[i].replace(File.separatorChar, '/');
 784                     if (name.startsWith(file)) {
 785                         dirs.add(extractFile(zis, e));
 786                         break;
 787                     }
 788                 }
 789             }
 790         }
 791 
 792         // Update timestamps of directories specified in archive with their
 793         // timestamps as given in the archive.  We do this after extraction,
 794         // instead of during, because creating a file in a directory changes
 795         // that directory's timestamp.
 796         for (ZipEntry dirEntry : dirs) {
 797             long lastModified = dirEntry.getTime();
 798             if (lastModified != -1) {
 799                 File dir = new File(dirEntry.getName().replace('/', File.separatorChar));
 800                 dir.setLastModified(lastModified);
 801             }



















 802         }
 803     }





 804 
 805     /*
 806      * Extracts next entry from JAR file, creating directories as needed.  If
 807      * the entry is for a directory which doesn't exist prior to this
 808      * invocation, returns that entry, otherwise returns null.
 809      */
 810     ZipEntry extractFile(ZipInputStream zis, ZipEntry e) throws IOException {
 811         ZipEntry rc = null;
 812         String name = e.getName();
 813         File f = new File(e.getName().replace('/', File.separatorChar));
 814         if (e.isDirectory()) {
 815             if (f.exists()) {
 816                 if (!f.isDirectory()) {
 817                     throw new IOException(formatMsg("error.create.dir",
 818                         f.getPath()));
 819                 }
 820             } else {
 821                 if (!f.mkdirs()) {
 822                     throw new IOException(formatMsg("error.create.dir",
 823                         f.getPath()));
 824                 } else {
 825                     rc = e;
 826                 }
 827             }
 828 
 829             if (vflag) {
 830                 output(formatMsg("out.create", name));
 831             }
 832         } else {
 833             if (f.getParent() != null) {
 834                 File d = new File(f.getParent());
 835                 if (!d.exists() && !d.mkdirs() || !d.isDirectory()) {
 836                     throw new IOException(formatMsg(
 837                         "error.create.dir", d.getPath()));
 838                 }
 839             }
 840             OutputStream os = new FileOutputStream(f);
 841             byte[] b = new byte[512];
 842             int len;
 843             while ((len = zis.read(b, 0, b.length)) != -1) {

 844                 os.write(b, 0, len);
 845             }
 846             zis.closeEntry();




 847             os.close();

 848             if (vflag) {
 849                 if (e.getMethod() == ZipEntry.DEFLATED) {
 850                     output(formatMsg("out.inflated", name));
 851                 } else {
 852                     output(formatMsg("out.extracted", name));
 853                 }
 854             }
 855         }
 856         if (!useExtractionTime) {
 857             long lastModified = e.getTime();
 858             if (lastModified != -1) {
 859                 f.setLastModified(lastModified);
 860             }
 861         }
 862         return rc;
 863     }
 864 
 865     /*
 866      * Lists contents of JAR file.
 867      */
 868     void list(InputStream in, String files[]) throws IOException {
 869         ZipInputStream zis = new ZipInputStream(in);
 870         ZipEntry e;
 871         while ((e = zis.getNextEntry()) != null) {
 872             String name = e.getName();
 873             /*
 874              * In the case of a compressed (deflated) entry, the entry size
 875              * is stored immediately following the entry data and cannot be
 876              * determined until the entry is fully read. Therefore, we close
 877              * the entry first before printing out its attributes.
 878              */
 879             zis.closeEntry();
 880             if (files == null) {
 881                 printEntry(e);
 882             } else {
 883                 for (int i = 0; i < files.length; i++) {
 884                     String file = files[i].replace(File.separatorChar, '/');
 885                     if (name.startsWith(file)) {
 886                         printEntry(e);
 887                         break;
 888                     }
 889                 }









 890             }

 891         }
 892     }
 893 
 894     /**
 895      * Output the class index table to the INDEX.LIST file of the
 896      * root jar file.
 897      */
 898     void dumpIndex(String rootjar, JarIndex index) throws IOException {
 899         File scratchFile = File.createTempFile("scratch", null, new File("."));
 900         File jarFile = new File(rootjar);
 901         boolean updateOk = update(new FileInputStream(jarFile),
 902                                   new FileOutputStream(scratchFile),
 903                                   null, index);
 904         jarFile.delete();
 905         if (!scratchFile.renameTo(jarFile)) {
 906             scratchFile.delete();
 907             throw new IOException(getMsg("error.write.file"));
 908         }
 909         scratchFile.delete();
 910     }
 911 
 912     private Hashtable jarTable = new Hashtable();


 957      * Generate class index file for the specified root jar file.
 958      */
 959     void genIndex(String rootjar, String[] files) throws IOException {
 960         Vector jars = getJarPath(rootjar);
 961         int njars = jars.size();
 962         String[] jarfiles;
 963 
 964         if (njars == 1 && files != null) {
 965             // no class-path attribute defined in rootjar, will
 966             // use command line specified list of jars
 967             for (int i = 0; i < files.length; i++) {
 968                 jars.addAll(getJarPath(files[i]));
 969             }
 970             njars = jars.size();
 971         }
 972         jarfiles = (String[])jars.toArray(new String[njars]);
 973         JarIndex index = new JarIndex(jarfiles);
 974         dumpIndex(rootjar, index);
 975     }
 976 
















 977 
 978     /*
 979      * Prints entry information.
 980      */
 981     void printEntry(ZipEntry e) throws IOException {
 982         if (vflag) {
 983             StringBuffer sb = new StringBuffer();
 984             String s = Long.toString(e.getSize());
 985             for (int i = 6 - s.length(); i > 0; --i) {
 986                 sb.append(' ');
 987             }
 988             sb.append(s).append(' ').append(new Date(e.getTime()).toString());
 989             sb.append(' ').append(e.getName());
 990             output(sb.toString());
 991         } else {
 992             output(e.getName());
 993         }
 994     }
 995 
 996     /*
 997      * Print usage message and die.
 998      */
 999     void usageError() {
1000         error(getMsg("usage"));
1001     }
1002 
1003     /*




  57 
  58     // Directories specified by "-C" operation.
  59     List<String> paths = new ArrayList<String>();
  60 
  61     CRC32 crc32 = new CRC32();
  62     /*
  63      * cflag: create
  64      * uflag: update
  65      * xflag: xtract
  66      * tflag: table
  67      * vflag: verbose
  68      * flag0: no zip compression (store only)
  69      * Mflag: DO NOT generate a manifest file (just ZIP)
  70      * iflag: generate jar index
  71      */
  72     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag;
  73 
  74     static final String MANIFEST = JarFile.MANIFEST_NAME;
  75     static final String MANIFEST_DIR = "META-INF/";
  76     static final String VERSION = "1.0";

  77     static final String INDEX = JarIndex.INDEX_NAME;
  78 
  79     private static ResourceBundle rsrc;
  80 
  81     /**
  82      * If true, maintain compatibility with JDK releases prior to 6.0 by
  83      * timestamping extracted files with the time at which they are extracted.
  84      * Default is to use the time given in the archive.
  85      */
  86     private static final boolean useExtractionTime =
  87         Boolean.getBoolean("sun.tools.jar.useExtractionTime");
  88 
  89     /**
  90      * Initialize ResourceBundle
  91      */
  92     static {
  93         try {
  94             rsrc = ResourceBundle.getBundle("sun.tools.jar.resources.jar");
  95         } catch (MissingResourceException e) {
  96             throw new Error("Fatal: Resource for jar is missing");


 209                     (new FileInputStream(mname)) : null;
 210                 expand(null, files, true);
 211                 boolean updateOk = update(in, new BufferedOutputStream(out), manifest, null);
 212                 if (ok) {
 213                     ok = updateOk;
 214                 }
 215                 in.close();
 216                 out.close();
 217                 if (manifest != null) {
 218                     manifest.close();
 219                 }
 220                 if (fname != null) {
 221                     // on Win32, we need this delete
 222                     inputFile.delete();
 223                     if (!tmpFile.renameTo(inputFile)) {
 224                         tmpFile.delete();
 225                         throw new IOException(getMsg("error.write.file"));
 226                     }
 227                     tmpFile.delete();
 228                 }
 229             } else if (tflag) {
 230                 replaceFSC(files);
 231                 if (fname != null) {
 232                     list(fname, files);
 233                 } else {
 234                     InputStream in = new FileInputStream(FileDescriptor.in);
 235                     try{



 236                         list(new BufferedInputStream(in), files);
 237                     } finally {
 238                         in.close();
 239                     }
 240                 }
 241             } else if (xflag) {
 242                 replaceFSC(files);
 243                 if (fname != null && files != null) {
 244                     extract(fname, files);
 245                 } else {
 246                     InputStream in = (fname == null)
 247                         ? new FileInputStream(FileDescriptor.in)
 248                         : new FileInputStream(fname);
 249                     try {
 250                         extract(new BufferedInputStream(in), files);
 251                     } finally {
 252                         in.close();
 253                     }
 254                 }
 255             } else if (iflag) {
 256                 genIndex(rootjar, files);
 257             }
 258         } catch (IOException e) {
 259             fatalError(e);
 260             ok = false;
 261         } catch (Error ee) {
 262             ee.printStackTrace();
 263             ok = false;
 264         } catch (Throwable t) {
 265             t.printStackTrace();
 266             ok = false;
 267         }
 268         out.flush();
 269         err.flush();
 270         return ok;
 271     }
 272 
 273     /*
 274      * Parse command line arguments.


 755      */
 756     private void crc32File(ZipEntry e, File f) throws IOException {
 757         InputStream is = new BufferedInputStream(new FileInputStream(f));
 758         byte[] buf = new byte[8192];
 759         crc32.reset();
 760         int r = 0;
 761         int nread = 0;
 762         long len = f.length();
 763         while ((r = is.read(buf)) != -1) {
 764             nread += r;
 765             crc32.update(buf, 0, r);
 766         }
 767         is.close();
 768         if (nread != (int) len) {
 769             throw new JarException(formatMsg(
 770                         "error.incorrect.length", f.getPath()));
 771         }
 772         e.setCrc(crc32.getValue());
 773     }
 774 
 775     void replaceFSC(String files[]) {
 776         if (files != null) {
 777             for (String file : files) {
 778                 file = file.replace(File.separatorChar, '/');
 779             } 
 780         }
 781     }
 782 
 783     Set<ZipEntry> newDirSet() {
 784         return new HashSet<ZipEntry>() {
 785             public boolean add(ZipEntry e) {
 786                 return ((e == null || useExtractionTime) ? false : super.add(e));
 787             }};
 788     }
 789 
 790     void updateLastModifiedTime(Set<ZipEntry> zes) throws IOException {
 791         for (ZipEntry ze : zes) {
 792             long lastModified = ze.getTime();
 793             if (lastModified != -1) {
 794                 File f = new File(ze.getName().replace('/', File.separatorChar));
 795                 f.setLastModified(lastModified);
 796             }
 797         }
 798     }
 799 
 800     /*
 801      * Extracts specified entries from JAR file.
 802      */
 803     void extract(InputStream in, String files[]) throws IOException {
 804         ZipInputStream zis = new ZipInputStream(in);
 805         ZipEntry e;
 806         // Set of all directory entries specified in archive.  Disallows
 807         // null entries.  Disallows all entries if using pre-6.0 behavior.
 808         Set<ZipEntry> dirs = newDirSet();




 809         while ((e = zis.getNextEntry()) != null) {
 810             if (files == null) {
 811                 dirs.add(extractFile(zis, e));

 812             } else {
 813                 String name = e.getName();
 814                 for (String file : files) {

 815                     if (name.startsWith(file)) {
 816                         dirs.add(extractFile(zis, e));
 817                         break;
 818                     }
 819                 }
 820             }
 821         }
 822 
 823         // Update timestamps of directories specified in archive with their
 824         // timestamps as given in the archive.  We do this after extraction,
 825         // instead of during, because creating a file in a directory changes
 826         // that directory's timestamp.
 827         updateLastModifiedTime(dirs);




 828     }
 829 
 830     /*
 831      * Extracts specified entries from JAR file, via ZipFile.
 832      */
 833     void extract(String fname, String files[]) throws IOException {
 834         ZipFile zf = new ZipFile(fname);
 835         Set<ZipEntry> dirs = newDirSet();
 836         Enumeration<? extends ZipEntry> zes = zf.entries();
 837         while (zes.hasMoreElements()) {
 838             ZipEntry e = zes.nextElement();
 839             InputStream is;
 840             if (files == null) {
 841                 dirs.add(extractFile(zf.getInputStream(e), e));
 842             } else {
 843                 String name = e.getName();
 844                 for (String file : files) {
 845                     if (name.startsWith(file)) {
 846                         dirs.add(extractFile(zf.getInputStream(e), e));
 847                         break;
 848                     }
 849                 }
 850             }
 851         }
 852         zf.close();
 853         updateLastModifiedTime(dirs);
 854     }
 855 
 856     /*
 857      * Extracts next entry from JAR file, creating directories as needed.  If
 858      * the entry is for a directory which doesn't exist prior to this
 859      * invocation, returns that entry, otherwise returns null.
 860      */
 861     ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException {
 862         ZipEntry rc = null;
 863         String name = e.getName();
 864         File f = new File(e.getName().replace('/', File.separatorChar));
 865         if (e.isDirectory()) {
 866             if (f.exists()) {
 867                 if (!f.isDirectory()) {
 868                     throw new IOException(formatMsg("error.create.dir",
 869                         f.getPath()));
 870                 }
 871             } else {
 872                 if (!f.mkdirs()) {
 873                     throw new IOException(formatMsg("error.create.dir",
 874                         f.getPath()));
 875                 } else {
 876                     rc = e;
 877                 }
 878             }
 879 
 880             if (vflag) {
 881                 output(formatMsg("out.create", name));
 882             }
 883         } else {
 884             if (f.getParent() != null) {
 885                 File d = new File(f.getParent());
 886                 if (!d.exists() && !d.mkdirs() || !d.isDirectory()) {
 887                     throw new IOException(formatMsg(
 888                         "error.create.dir", d.getPath()));
 889                 }
 890             }
 891             OutputStream os = new FileOutputStream(f);
 892             byte[] b = new byte[8192];
 893             int len;
 894             try {
 895                 while ((len = is.read(b, 0, b.length)) != -1) {
 896                     os.write(b, 0, len);
 897                 }
 898             } finally {
 899                 if (is instanceof ZipInputStream)
 900                     ((ZipInputStream)is).closeEntry();
 901                 else 
 902                     is.close();
 903                 os.close();
 904             }
 905             if (vflag) {
 906                 if (e.getMethod() == ZipEntry.DEFLATED) {
 907                     output(formatMsg("out.inflated", name));
 908                 } else {
 909                     output(formatMsg("out.extracted", name));
 910                 }
 911             }
 912         }
 913         if (!useExtractionTime) {
 914             long lastModified = e.getTime();
 915             if (lastModified != -1) {
 916                 f.setLastModified(lastModified);
 917             }
 918         }
 919         return rc;
 920     }
 921 
 922     /*
 923      * Lists contents of JAR file.
 924      */
 925     void list(InputStream in, String files[]) throws IOException {
 926         ZipInputStream zis = new ZipInputStream(in);
 927         ZipEntry e;
 928         while ((e = zis.getNextEntry()) != null) {

 929             /*
 930              * In the case of a compressed (deflated) entry, the entry size
 931              * is stored immediately following the entry data and cannot be
 932              * determined until the entry is fully read. Therefore, we close
 933              * the entry first before printing out its attributes.
 934              */
 935             zis.closeEntry();
 936             printEntry(e, files);







 937         }
 938     }
 939 
 940     /*
 941      * Lists contents of JAR file, via ZipFile.
 942      */
 943     void list(String fname, String files[]) throws IOException {
 944         ZipFile zf = new ZipFile(fname);
 945         Enumeration<? extends ZipEntry> zes = zf.entries();
 946         while (zes.hasMoreElements()) {
 947             printEntry(zes.nextElement(), files);
 948         }
 949         zf.close();
 950     }

 951 
 952     /**
 953      * Output the class index table to the INDEX.LIST file of the
 954      * root jar file.
 955      */
 956     void dumpIndex(String rootjar, JarIndex index) throws IOException {
 957         File scratchFile = File.createTempFile("scratch", null, new File("."));
 958         File jarFile = new File(rootjar);
 959         boolean updateOk = update(new FileInputStream(jarFile),
 960                                   new FileOutputStream(scratchFile),
 961                                   null, index);
 962         jarFile.delete();
 963         if (!scratchFile.renameTo(jarFile)) {
 964             scratchFile.delete();
 965             throw new IOException(getMsg("error.write.file"));
 966         }
 967         scratchFile.delete();
 968     }
 969 
 970     private Hashtable jarTable = new Hashtable();


1015      * Generate class index file for the specified root jar file.
1016      */
1017     void genIndex(String rootjar, String[] files) throws IOException {
1018         Vector jars = getJarPath(rootjar);
1019         int njars = jars.size();
1020         String[] jarfiles;
1021 
1022         if (njars == 1 && files != null) {
1023             // no class-path attribute defined in rootjar, will
1024             // use command line specified list of jars
1025             for (int i = 0; i < files.length; i++) {
1026                 jars.addAll(getJarPath(files[i]));
1027             }
1028             njars = jars.size();
1029         }
1030         jarfiles = (String[])jars.toArray(new String[njars]);
1031         JarIndex index = new JarIndex(jarfiles);
1032         dumpIndex(rootjar, index);
1033     }
1034 
1035     /*
1036      * Prints entry information, if requested.
1037      */
1038     void printEntry(ZipEntry e, String[] files) throws IOException {
1039         if (files == null) {
1040             printEntry(e);
1041         } else {
1042             String name = e.getName();
1043             for (String file : files) {
1044                 if (name.startsWith(file)) {
1045                     printEntry(e);
1046                     return;
1047                 }
1048             }
1049         }
1050     }
1051 
1052     /*
1053      * Prints entry information.
1054      */
1055     void printEntry(ZipEntry e) throws IOException {
1056         if (vflag) {
1057             StringBuilder sb = new StringBuilder();
1058             String s = Long.toString(e.getSize());
1059             for (int i = 6 - s.length(); i > 0; --i) {
1060                 sb.append(' ');
1061             }
1062             sb.append(s).append(' ').append(new Date(e.getTime()).toString());
1063             sb.append(' ').append(e.getName());
1064             output(sb.toString());
1065         } else {
1066             output(e.getName());
1067         }
1068     }
1069 
1070     /*
1071      * Print usage message and die.
1072      */
1073     void usageError() {
1074         error(getMsg("usage"));
1075     }
1076 
1077     /*