1 /*
2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.tools.jar;
27
28 import java.io.*;
29 import java.lang.module.Configuration;
30 import java.lang.module.FindException;
31 import java.lang.module.InvalidModuleDescriptorException;
32 import java.lang.module.ModuleDescriptor;
33 import java.lang.module.ModuleDescriptor.Exports;
34 import java.lang.module.ModuleDescriptor.Opens;
35 import java.lang.module.ModuleDescriptor.Provides;
36 import java.lang.module.ModuleDescriptor.Version;
37 import java.lang.module.ModuleFinder;
38 import java.lang.module.ModuleReader;
39 import java.lang.module.ModuleReference;
40 import java.lang.module.ResolvedModule;
41 import java.net.URI;
42 import java.nio.ByteBuffer;
43 import java.nio.file.Files;
44 import java.nio.file.Path;
45 import java.nio.file.Paths;
46 import java.nio.file.StandardCopyOption;
47 import java.text.MessageFormat;
48 import java.util.*;
49 import java.util.function.Consumer;
50 import java.util.jar.Attributes;
51 import java.util.jar.JarFile;
52 import java.util.jar.JarOutputStream;
53 import java.util.jar.Manifest;
54 import java.util.regex.Pattern;
55 import java.util.stream.Collectors;
56 import java.util.stream.Stream;
57 import java.util.zip.CRC32;
58 import java.util.zip.ZipEntry;
59 import java.util.zip.ZipFile;
60 import java.util.zip.ZipInputStream;
61 import java.util.zip.ZipOutputStream;
62 import jdk.internal.module.Checks;
63 import jdk.internal.module.ModuleHashes;
64 import jdk.internal.module.ModuleHashesBuilder;
65 import jdk.internal.module.ModuleInfo;
66 import jdk.internal.module.ModuleInfoExtender;
67 import jdk.internal.module.ModuleResolution;
68 import jdk.internal.module.ModuleTarget;
69 import jdk.internal.util.jar.JarIndex;
70
71 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
72 import static java.util.jar.JarFile.MANIFEST_NAME;
73 import static java.util.stream.Collectors.joining;
74 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
75
76 /**
77 * This class implements a simple utility for creating files in the JAR
78 * (Java Archive) file format. The JAR format is based on the ZIP file
79 * format, with optional meta-information stored in a MANIFEST entry.
80 */
81 public class Main {
82 String program;
83 PrintWriter out, err;
84 String fname, mname, ename;
85 String zname = "";
86 String rootjar = null;
87
88 private static final int BASE_VERSION = 0;
89
90 private static class Entry {
91 final String name;
92 final File file;
93 final boolean isDir;
94
95 Entry(File file, String name, boolean isDir) {
132 // Do we think this is a multi-release jar? Set to true
133 // if --release option found followed by at least file
134 boolean isMultiRelease;
135
136 // The last parsed --release value, if any. Used in conjunction with
137 // "-d,--describe-module" to select the operative module descriptor.
138 int releaseValue = -1;
139
140 /*
141 * cflag: create
142 * uflag: update
143 * xflag: xtract
144 * tflag: table
145 * vflag: verbose
146 * flag0: no zip compression (store only)
147 * Mflag: DO NOT generate a manifest file (just ZIP)
148 * iflag: generate jar index
149 * nflag: Perform jar normalization at the end
150 * pflag: preserve/don't strip leading slash and .. component from file name
151 * dflag: print module descriptor
152 */
153 boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag, dflag;
154
155 boolean suppressDeprecateMsg = false;
156
157 /* To support additional GNU Style informational options */
158 Consumer<PrintWriter> info;
159
160 /* Modular jar related options */
161 Version moduleVersion;
162 Pattern modulesToHash;
163 ModuleResolution moduleResolution = ModuleResolution.empty();
164 ModuleFinder moduleFinder = ModuleFinder.of();
165
166 static final String MODULE_INFO = "module-info.class";
167 static final String MANIFEST_DIR = "META-INF/";
168 static final String VERSIONS_DIR = MANIFEST_DIR + "versions/";
169 static final String VERSION = "1.0";
170 static final int VERSIONS_DIR_LENGTH = VERSIONS_DIR.length();
171 private static ResourceBundle rsrc;
172
173 /**
382 InputStream in = new FileInputStream(FileDescriptor.in);
383 try {
384 list(new BufferedInputStream(in), files);
385 } finally {
386 in.close();
387 }
388 }
389 } else if (xflag) {
390 replaceFSC(filesMap);
391 // For the extract action, when extracting all the entries,
392 // access using the ZipInputStream class is most efficient,
393 // since only a single sequential scan through the zip file is
394 // required. When using the ZipFile class, a "two-finger" scan
395 // is required, but this is likely to be more efficient when a
396 // partial extract is requested. In case the zip file has
397 // "leading garbage", we fall back from the ZipInputStream
398 // implementation to the ZipFile implementation, since only the
399 // latter can handle it.
400
401 String[] files = filesMapToFiles(filesMap);
402 if (fname != null && files != null) {
403 extract(fname, files);
404 } else {
405 InputStream in = (fname == null)
406 ? new FileInputStream(FileDescriptor.in)
407 : new FileInputStream(fname);
408 try {
409 if (!extract(new BufferedInputStream(in), files) && fname != null) {
410 extract(fname, files);
411 }
412 } finally {
413 in.close();
414 }
415 }
416 } else if (iflag) {
417 String[] files = filesMap.get(BASE_VERSION); // base entries only, can be null
418 genIndex(rootjar, files);
419 } else if (dflag) {
420 boolean found;
421 if (fname != null) {
422 try (ZipFile zf = new ZipFile(fname)) {
1189 }
1190 return;
1191 } else if (name.equals(MODULE_INFO)) {
1192 throw new Error("Unexpected module info: " + name);
1193 }
1194
1195 long size = isDir ? 0 : file.length();
1196
1197 if (vflag) {
1198 out.print(formatMsg("out.adding", name));
1199 }
1200 ZipEntry e = new ZipEntry(name);
1201 e.setTime(file.lastModified());
1202 if (size == 0) {
1203 e.setMethod(ZipEntry.STORED);
1204 e.setSize(0);
1205 e.setCrc(0);
1206 } else if (flag0) {
1207 crc32File(e, file);
1208 }
1209 zos.putNextEntry(e);
1210 if (!isDir) {
1211 copy(file, zos);
1212 }
1213 zos.closeEntry();
1214 /* report how much compression occurred. */
1215 if (vflag) {
1216 size = e.getSize();
1217 long csize = e.getCompressedSize();
1218 out.print(formatMsg2("out.size", String.valueOf(size),
1219 String.valueOf(csize)));
1220 if (e.getMethod() == ZipEntry.DEFLATED) {
1221 long ratio = 0;
1222 if (size != 0) {
1223 ratio = ((size - csize) * 100) / size;
1224 }
1225 output(formatMsg("out.deflated", String.valueOf(ratio)));
1226 } else {
1227 output(getMsg("out.stored"));
1228 }
1453 try {
1454 copy(is, f);
1455 } finally {
1456 if (is instanceof ZipInputStream)
1457 ((ZipInputStream)is).closeEntry();
1458 else
1459 is.close();
1460 }
1461 if (vflag) {
1462 if (e.getMethod() == ZipEntry.DEFLATED) {
1463 output(formatMsg("out.inflated", name));
1464 } else {
1465 output(formatMsg("out.extracted", name));
1466 }
1467 }
1468 }
1469 if (!useExtractionTime) {
1470 long lastModified = e.getTime();
1471 if (lastModified != -1) {
1472 f.setLastModified(lastModified);
1473 }
1474 }
1475 return rc;
1476 }
1477
1478 /**
1479 * Lists contents of JAR file.
1480 */
1481 void list(InputStream in, String files[]) throws IOException {
1482 ZipInputStream zis = new ZipInputStream(in);
1483 ZipEntry e;
1484 while ((e = zis.getNextEntry()) != null) {
1485 /*
1486 * In the case of a compressed (deflated) entry, the entry size
1487 * is stored immediately following the entry data and cannot be
1488 * determined until the entry is fully read. Therefore, we close
1489 * the entry first before printing out its attributes.
1490 */
1491 zis.closeEntry();
1492 printEntry(e, files);
|
1 /*
2 * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package sun.tools.jar;
27
28 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
29 import static java.util.jar.JarFile.MANIFEST_NAME;
30 import static java.util.stream.Collectors.joining;
31 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
32
33 import java.io.*;
34 import java.lang.module.Configuration;
35 import java.lang.module.FindException;
36 import java.lang.module.InvalidModuleDescriptorException;
37 import java.lang.module.ModuleDescriptor;
38 import java.lang.module.ModuleDescriptor.Exports;
39 import java.lang.module.ModuleDescriptor.Opens;
40 import java.lang.module.ModuleDescriptor.Provides;
41 import java.lang.module.ModuleDescriptor.Version;
42 import java.lang.module.ModuleFinder;
43 import java.lang.module.ModuleReader;
44 import java.lang.module.ModuleReference;
45 import java.lang.module.ResolvedModule;
46 import java.net.URI;
47 import java.nio.ByteBuffer;
48 import java.nio.file.Files;
49 import java.nio.file.Path;
50 import java.nio.file.Paths;
51 import java.nio.file.StandardCopyOption;
52 import java.nio.file.attribute.PosixFilePermission;
53 import java.text.MessageFormat;
54 import java.util.*;
55 import java.util.function.Consumer;
56 import java.util.jar.Attributes;
57 import java.util.jar.JarFile;
58 import java.util.jar.JarOutputStream;
59 import java.util.jar.Manifest;
60 import java.util.regex.Pattern;
61 import java.util.stream.Collectors;
62 import java.util.stream.Stream;
63 import java.util.zip.CRC32;
64 import java.util.zip.ZipEntry;
65 import java.util.zip.ZipFile;
66 import java.util.zip.ZipInputStream;
67 import java.util.zip.ZipOutputStream;
68
69 import jdk.internal.module.Checks;
70 import jdk.internal.module.ModuleHashes;
71 import jdk.internal.module.ModuleHashesBuilder;
72 import jdk.internal.module.ModuleInfo;
73 import jdk.internal.module.ModuleInfoExtender;
74 import jdk.internal.module.ModuleResolution;
75 import jdk.internal.module.ModuleTarget;
76 import jdk.internal.util.jar.JarIndex;
77
78 /**
79 * This class implements a simple utility for creating files in the JAR
80 * (Java Archive) file format. The JAR format is based on the ZIP file
81 * format, with optional meta-information stored in a MANIFEST entry.
82 */
83 public class Main {
84 String program;
85 PrintWriter out, err;
86 String fname, mname, ename;
87 String zname = "";
88 String rootjar = null;
89
90 private static final int BASE_VERSION = 0;
91
92 private static class Entry {
93 final String name;
94 final File file;
95 final boolean isDir;
96
97 Entry(File file, String name, boolean isDir) {
134 // Do we think this is a multi-release jar? Set to true
135 // if --release option found followed by at least file
136 boolean isMultiRelease;
137
138 // The last parsed --release value, if any. Used in conjunction with
139 // "-d,--describe-module" to select the operative module descriptor.
140 int releaseValue = -1;
141
142 /*
143 * cflag: create
144 * uflag: update
145 * xflag: xtract
146 * tflag: table
147 * vflag: verbose
148 * flag0: no zip compression (store only)
149 * Mflag: DO NOT generate a manifest file (just ZIP)
150 * iflag: generate jar index
151 * nflag: Perform jar normalization at the end
152 * pflag: preserve/don't strip leading slash and .. component from file name
153 * dflag: print module descriptor
154 * oflag: preserve Posix file attributes
155 */
156 boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag, dflag, oflag;
157
158 boolean suppressDeprecateMsg = false;
159
160 /* To support additional GNU Style informational options */
161 Consumer<PrintWriter> info;
162
163 /* Modular jar related options */
164 Version moduleVersion;
165 Pattern modulesToHash;
166 ModuleResolution moduleResolution = ModuleResolution.empty();
167 ModuleFinder moduleFinder = ModuleFinder.of();
168
169 static final String MODULE_INFO = "module-info.class";
170 static final String MANIFEST_DIR = "META-INF/";
171 static final String VERSIONS_DIR = MANIFEST_DIR + "versions/";
172 static final String VERSION = "1.0";
173 static final int VERSIONS_DIR_LENGTH = VERSIONS_DIR.length();
174 private static ResourceBundle rsrc;
175
176 /**
385 InputStream in = new FileInputStream(FileDescriptor.in);
386 try {
387 list(new BufferedInputStream(in), files);
388 } finally {
389 in.close();
390 }
391 }
392 } else if (xflag) {
393 replaceFSC(filesMap);
394 // For the extract action, when extracting all the entries,
395 // access using the ZipInputStream class is most efficient,
396 // since only a single sequential scan through the zip file is
397 // required. When using the ZipFile class, a "two-finger" scan
398 // is required, but this is likely to be more efficient when a
399 // partial extract is requested. In case the zip file has
400 // "leading garbage", we fall back from the ZipInputStream
401 // implementation to the ZipFile implementation, since only the
402 // latter can handle it.
403
404 String[] files = filesMapToFiles(filesMap);
405 // if we need to restore posix permissions (-o flag), we need to use
406 // the ZipFile approach because permissions are stored in the CEN
407 // which is not read when using a ZipInputStream.
408 if (fname != null && (files != null || oflag)) {
409 extract(fname, files);
410 } else {
411 InputStream in = (fname == null)
412 ? new FileInputStream(FileDescriptor.in)
413 : new FileInputStream(fname);
414 try {
415 if (!extract(new BufferedInputStream(in), files) && fname != null) {
416 extract(fname, files);
417 }
418 } finally {
419 in.close();
420 }
421 }
422 } else if (iflag) {
423 String[] files = filesMap.get(BASE_VERSION); // base entries only, can be null
424 genIndex(rootjar, files);
425 } else if (dflag) {
426 boolean found;
427 if (fname != null) {
428 try (ZipFile zf = new ZipFile(fname)) {
1195 }
1196 return;
1197 } else if (name.equals(MODULE_INFO)) {
1198 throw new Error("Unexpected module info: " + name);
1199 }
1200
1201 long size = isDir ? 0 : file.length();
1202
1203 if (vflag) {
1204 out.print(formatMsg("out.adding", name));
1205 }
1206 ZipEntry e = new ZipEntry(name);
1207 e.setTime(file.lastModified());
1208 if (size == 0) {
1209 e.setMethod(ZipEntry.STORED);
1210 e.setSize(0);
1211 e.setCrc(0);
1212 } else if (flag0) {
1213 crc32File(e, file);
1214 }
1215 if (oflag) {
1216 e.setPosixPermissions(Files.getPosixFilePermissions(file.toPath()));
1217 }
1218 zos.putNextEntry(e);
1219 if (!isDir) {
1220 copy(file, zos);
1221 }
1222 zos.closeEntry();
1223 /* report how much compression occurred. */
1224 if (vflag) {
1225 size = e.getSize();
1226 long csize = e.getCompressedSize();
1227 out.print(formatMsg2("out.size", String.valueOf(size),
1228 String.valueOf(csize)));
1229 if (e.getMethod() == ZipEntry.DEFLATED) {
1230 long ratio = 0;
1231 if (size != 0) {
1232 ratio = ((size - csize) * 100) / size;
1233 }
1234 output(formatMsg("out.deflated", String.valueOf(ratio)));
1235 } else {
1236 output(getMsg("out.stored"));
1237 }
1462 try {
1463 copy(is, f);
1464 } finally {
1465 if (is instanceof ZipInputStream)
1466 ((ZipInputStream)is).closeEntry();
1467 else
1468 is.close();
1469 }
1470 if (vflag) {
1471 if (e.getMethod() == ZipEntry.DEFLATED) {
1472 output(formatMsg("out.inflated", name));
1473 } else {
1474 output(formatMsg("out.extracted", name));
1475 }
1476 }
1477 }
1478 if (!useExtractionTime) {
1479 long lastModified = e.getTime();
1480 if (lastModified != -1) {
1481 f.setLastModified(lastModified);
1482 }
1483 }
1484 if (oflag) {
1485 Optional<Set<PosixFilePermission>> permissions = e.getPosixPermissions();
1486 if (permissions.isPresent()) {
1487 try {
1488 Files.setPosixFilePermissions(f.toPath(), permissions.get());
1489 } catch (UnsupportedOperationException exc) {
1490 // Ignore the exception
1491 }
1492 }
1493 }
1494 return rc;
1495 }
1496
1497 /**
1498 * Lists contents of JAR file.
1499 */
1500 void list(InputStream in, String files[]) throws IOException {
1501 ZipInputStream zis = new ZipInputStream(in);
1502 ZipEntry e;
1503 while ((e = zis.getNextEntry()) != null) {
1504 /*
1505 * In the case of a compressed (deflated) entry, the entry size
1506 * is stored immediately following the entry data and cannot be
1507 * determined until the entry is fully read. Therefore, we close
1508 * the entry first before printing out its attributes.
1509 */
1510 zis.closeEntry();
1511 printEntry(e, files);
|