< prev index next >

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

Print this page
rev 51866 : 6194856: Zip Files lose ALL ownership and permissions of the files
   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);


< prev index next >