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 /*
|