United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4129445 An API to incrementally update ZIP files
JDK-4129445 : An API to incrementally update ZIP files

Details
Type:
Enhancement
Submit Date:
1998-04-16
Status:
Open
Updated Date:
2009-06-20
Project Name:
JDK
Resolved Date:
Component:
core-libs
OS:
solaris_8,windows_nt,solaris_7,solaris_2.5.1,generic,windows_95,windows_2000
Sub-Component:
java.util.jar
CPU:
x86,sparc,generic
Priority:
P4
Resolution:
Unresolved
Affected Versions:
1.1.6,1.1.8,1.2.0,1.3.0,1.4.0,1.4.2,6
Targeted Versions:

Related Reports
Duplicate:
Duplicate:
Duplicate:
Duplicate:

Sub Tasks

Description
- Problem:

    The class java.util.ZipFile cannot be used to write or modify
    ZIP files. This functionality is needed by the JAR tool in
    order to support updating existing JAR files. Currently,
    the tool can only be used to read or create JAR files.
    These enhancements have also been frequently requested from
    outside users.

- Solution:

    Solution is to add additional methods to java.util.ZipFile
    to support writing and modifying ZIP files.


- Proposed API change:

    Have ZipFile implement java.util.Map, and add the following
    new methods:

    /**
     * Opens a ZIP file for reading, overwriting or modifying
     * given the specified file name and access mode.
     * <p>
     * The mode argument must be <code>"r"<code>, <code>"w"<code> 
     * or <code>"rw"</code>, indicating to open the file for input, 
     * to overwrite or to modify.
     *
     */
    public ZipFile(String name, String mode) throws IOException {
    }


    /**
     * Opens a ZIP file for reading, overwriting or modifying
     * given the specified file name.
     * <p>
     * The mode argument must be <code>"r"<code>, <code>"w"<code> 
     * or <code>"rw"</code>, indicating to open the file for input, 
     * to overwrite or to modify.
     * 
     */
    public ZipFile(File file, String mode) throws ZipException, IOException {
    }

    /**
     * Returns an output stream for writing the contents of the specified
     * ZIP file entry.
     *
     */
    public OutputStream getOutputStream(ZipEntry ze) throws IOException {
    }	

    /**
     * Adds the specified zip entry to the end of the zip file.
     * If the zip file already contains this entry, an exception
     * will be thrown.
     */
    public void add(ZipEntry ze) {
    }

    /**
     * Adds the specified zip entry to the current zip file at the
     * specified index. If the zip file already contains this
     * entry, an exception will be thrown.
     */
    public void add(int index, ZipEntry ze) {
    }

    /**
     * Returns the position of the zip entry for the specified
     * file name in the current zip file.
     */
    public int indexOf(String name) {
    }

Name: nt126004			Date: 06/28/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
SunOS ruyaksun 5.8 Generic_108528-14 sun4u sparc SUNW,Ultra-5_10

ADDITIONAL OPERATING SYSTEMS :
Windows



A DESCRIPTION OF THE PROBLEM :
There should be an api for inserting a file (or other entry)
into an already existing archive (zip or jar file) much like
the jar utility provides.

For example:

jar -uf <jar-file> <input-file-name>

This inserts the <input-file-name> into the <jar-file>
without having to explode the already existing jar file in a
temporary location, copying over the file to insert, and
then jaring this up in a new jar file.

The ZipFile api does include a putNextEntry(ZipEntry entry)
 method, but this only inserts an entry into a new ZipFile
obj. through a ZipOutputStream (or JarOutPutStream) NOT an
existing archive.  It would be helpful to have this feature
so that one can programmatically insert a new entry into an
existing archive without having to create a new one.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Execute code below using an existing zip or jar file with
entries.

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected helloworld.war when issuing a jar -tvf:

 0 Thu Jun 06 13:32:30 PDT 2002 META-INF/
    68 Thu Jun 06 13:32:30 PDT 2002 META-INF/MANIFEST.MF
   352 Tue Apr 30 21:28:38 PDT 2002 GreeterView.jsp
     0 Thu Jun 06 13:31:56 PDT 2002 WEB-INF/
     0 Tue Apr 30 21:28:38 PDT 2002 WEB-INF/classes/
     0 Tue Apr 30 21:28:38 PDT 2002 WEB-INF/classes/samples/
     0 Tue Apr 30 21:28:38 PDT 2002
WEB-INF/classes/samples/helloworld/
     0 Tue Apr 30 21:28:38 PDT 2002
WEB-INF/classes/samples/helloworld/servlet/
  3146 Tue Apr 30 21:28:38 PDT 2002
WEB-INF/classes/samples/helloworld/servlet/GreeterServlet.class
  1046 Tue Apr 30 21:28:38 PDT 2002 WEB-INF/web.xml
   462 Thu Jun 06 13:31:52 PDT 2002 WEB-INF/sun-web.xml
   934 Tue Apr 30 21:28:38 PDT 2002 index.html
   934 Tue Apr 30 21:28:38 PDT 2002 name.xml

Actual helloworld.war after performing a jar -tvf:

76 Thu Jun 20 16:39:32 PDT 2002 name.xml


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Here is sample code that I wrote to attempt to insert an entry into an existing
archive.  The result was that a new archive is created with that new entry only.
None of the entries from the existing archive were there.

/**
 * Inserts a entry into an existing archive file.
 *
 * @param java.lang.String File name of file to insert into archive.
 * @param java.util.zip.ZipFile Archive into which file in inserted.
 */
private static void insertFileIntoArchive(String fileName, java.util.zip.ZipFile
zipFile){
        java.util.Date today;
	long systime;
        today = new java.util.Date();
        systime = today.getTime();
        
        try{
            //reading new File
            File newFile = new File(fileName);
            System.out.println("Reading new File: " + newFile.getName());
            FileInputStream fileStream = new FileInputStream(newFile);
            byte[] fileData = new byte[new Long(newFile.length()).intValue()];
            fileStream.read(fileData);
            fileStream.close();
               
            //outputStream stuff
            FileOutputStream output = new FileOutputStream(zipFile.getName());
            JarOutputStream jarStream = new JarOutputStream(output);
            jarStream.setMethod(JarOutputStream.DEFLATED);
            
            //zipEntry
            ZipEntry zipentry = new ZipEntry(fileName);
            zipentry.setMethod(zipentry.DEFLATED);
            zipentry.setSize(fileData.length);
            zipentry.setTime(systime);
            CRC32 crc321 = new CRC32();
            crc321.update(fileData);
            zipentry.setCrc(crc321.getValue());
            
            //adding to the new jarOutputStream
            jarStream.putNextEntry(zipentry);
            jarStream.write(fileData);
            jarStream.flush();
            jarStream.flush();
            jarStream.closeEntry();
            
            //finished
            jarStream.finish();
            jarStream.close();
            
        }catch(java.io.FileNotFoundException fnfe){
            System.out.println("Exception: " + fnfe.getMessage());
            fnfe.printStackTrace();
        }catch( IOException io){
            System.out.println("Exception: " + io.getMessage());
            io.printStackTrace();
        }
    
    }//end insertFileIntoArchive
---------- END SOURCE ----------
(Review ID: 153930)
======================================================================

                                    

Comments
EVALUATION

This is certainly a reasonable request, but...
- the jar command already offers the functionality from the command line.
- the jar/zip code is already fragile enough without adding a new dimension
  to the testing matrix.
- there are easy workarounds.

One can argue that the functionality would not be used by enough users
to make it worth the maintenance cost.  Certainly other improvements
to jar/zip take precedence.
###@###.### 2003-10-30
                                     
2003-10-30
EVALUATION

It is easy to sympathize with those who want this bug fixed.  It is perhaps easier to sympathize with those who have, inadvertently, overwritten JAR files that are already in-use by a running JVM.  Consider this sampling of bugs:
4425695, 6390352, 4826081, 4843994, 6426429, 6553958, 5086611, 5082306, 6228479, 6571563

Some of the above show that replacing a JAR resulted in a JVM crash.  Readily allowing JAR files to change by providing an API to do so could result in more such.  The situation is such that it is difficult to even provide the name of the JAR which caused the crash, or to throw an IOException instead of having the crash.  See 5086611 for details on how to crash a JVM in this way.

It would have been nice if the jar & zip APIs had allowed for mutable zip files from day one.  But at this point adding mutability to jar & zip files from Java(or rather, increasing the ease of mutating them) seems likely to introduce more hard-to-debug problems.
                                     
2008-02-29



Hardware and Software, Engineered to Work Together