Info-Zip way. PR: 6492 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@273629 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -132,6 +132,9 @@ Other changes: | |||||
| * <tarfileset> has a new dirmode attribute to specify the permissions | * <tarfileset> has a new dirmode attribute to specify the permissions | ||||
| for directories. | for directories. | ||||
| * <zip> can now store Unix permissions in a way that can be | |||||
| reconstructed by Info-Zip's unzip command. | |||||
| Changes from Ant 1.5.1Beta1 to 1.5.1 | Changes from Ant 1.5.1Beta1 to 1.5.1 | ||||
| ==================================== | ==================================== | ||||
| @@ -1183,9 +1183,21 @@ | |||||
| <antcall inheritAll="false" target="internal_dist"> | <antcall inheritAll="false" target="internal_dist"> | ||||
| <param name="dist.dir" value="${dist.name}"/> | <param name="dist.dir" value="${dist.name}"/> | ||||
| </antcall> | </antcall> | ||||
| <zip destfile="${dist.base}/bin/${dist.name}-bin.zip" | |||||
| basedir="${dist.name}/.." | |||||
| includes="${dist.name}/**"/> | |||||
| <zip destfile="${dist.base}/bin/${dist.name}-bin.zip"> | |||||
| <zipfileset dir="${dist.name}/.." filemode="755"> | |||||
| <include name="${dist.name}/bin/ant"/> | |||||
| <include name="${dist.name}/bin/antRun"/> | |||||
| <include name="${dist.name}/bin/*.pl"/> | |||||
| <include name="${dist.name}/bin/*.py"/> | |||||
| </zipfileset> | |||||
| <fileset dir="${dist.name}/.."> | |||||
| <include name="${dist.name}/**"/> | |||||
| <exclude name="${dist.name}/bin/ant"/> | |||||
| <exclude name="${dist.name}/bin/antRun"/> | |||||
| <exclude name="${dist.name}/bin/*.pl"/> | |||||
| <exclude name="${dist.name}/bin/*.py"/> | |||||
| </fileset> | |||||
| </zip> | |||||
| <tar longfile="gnu" | <tar longfile="gnu" | ||||
| destfile="${dist.base}/bin/${dist.name}-bin.tar"> | destfile="${dist.base}/bin/${dist.name}-bin.tar"> | ||||
| <tarfileset dir="${dist.name}/.." mode="755" username="ant" group="ant"> | <tarfileset dir="${dist.name}/.." mode="755" username="ant" group="ant"> | ||||
| @@ -1219,9 +1231,17 @@ | |||||
| <antcall inheritAll="false" target="src-dist"> | <antcall inheritAll="false" target="src-dist"> | ||||
| <param name="src.dist.dir" value="${dist.name}"/> | <param name="src.dist.dir" value="${dist.name}"/> | ||||
| </antcall> | </antcall> | ||||
| <zip destfile="${dist.base}/src/${dist.name}-src.zip" | |||||
| basedir="${dist.name}/.." | |||||
| includes="${dist.name}/**"/> | |||||
| <zip destfile="${dist.base}/src/${dist.name}-src.zip"> | |||||
| <zipfileset dir="${dist.name}/.." filemode="755"> | |||||
| <include name="${dist.name}/bootstrap.sh"/> | |||||
| <include name="${dist.name}/build.sh"/> | |||||
| </zipfileset> | |||||
| <fileset dir="${dist.name}/.."> | |||||
| <include name="${dist.name}/**"/> | |||||
| <exclude name="${dist.name}/bootstrap.sh"/> | |||||
| <exclude name="${dist.name}/build.sh"/> | |||||
| </fileset> | |||||
| </zip> | |||||
| <tar longfile="gnu" | <tar longfile="gnu" | ||||
| destfile="${dist.base}/src/${dist.name}-src.tar" > | destfile="${dist.base}/src/${dist.name}-src.tar" > | ||||
| <tarfileset dir="${dist.name}/.." mode="755" username="ant" group="ant"> | <tarfileset dir="${dist.name}/.." mode="755" username="ant" group="ant"> | ||||
| @@ -52,6 +52,15 @@ but causes problems if you try to open them from within Java and your | |||||
| filenames contain non US-ASCII characters. Use the encoding attribute | filenames contain non US-ASCII characters. Use the encoding attribute | ||||
| and set it to UTF8 to create zip files that can safely be read by | and set it to UTF8 to create zip files that can safely be read by | ||||
| Java.</p> | Java.</p> | ||||
| <p>Starting with Ant 1.6, <zip> can store Unix permissions | |||||
| inside the archive (see description of the filemode and dirmode | |||||
| attributes for <a href="#zipfileset"><zipfileset></a>). | |||||
| Unfortunately there is no portable way to store these permissions. | |||||
| Ant uses the algorithm used by <a href="http://www.info-zip.org">Info-Zip's</a> | |||||
| implementation of the zip and unzip commands - these are the default | |||||
| versions of zip and unzip for many Unix and Unix-like systems.</p> | |||||
| <h3>Parameters</h3> | <h3>Parameters</h3> | ||||
| <table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
| <tr> | <tr> | ||||
| @@ -144,15 +153,64 @@ Java.</p> | |||||
| <p>The zip task supports any number of nested <a | <p>The zip task supports any number of nested <a | ||||
| href="../CoreTypes/fileset.html"><code><fileset></code></a> elements to specify | href="../CoreTypes/fileset.html"><code><fileset></code></a> elements to specify | ||||
| the files to be included in the archive.</p> | the files to be included in the archive.</p> | ||||
| <h4>zipfileset</h4> | |||||
| <p>A <code><zipfileset></code> has three additional attributes: <i>prefix</i>, <i>fullpath</i>, and <i>src</i>. The | |||||
| <i>prefix</i> and <i>fullpath</i> attributes modify the location of the files when they are placed | |||||
| inside the archive. If the <i>prefix</i> attribute is set, all files in the fileset are prefixed | |||||
| with that path in the archive. If the <i>fullpath</i> attribute is set, the file described by the fileset is placed at that | |||||
| exact location in the archive. (The <i>fullpath</i> attribute can only be set for filesets that represent a single file. The <i>prefix</i> and <i>fullpath</i> attributes cannot both be set on the same fileset.) The <i>src</i> attribute | |||||
| may be used in place of the <i>dir</i> attribute to specify a zip file whose | |||||
| contents will be extracted and included in the archive. As with directories, include and exclude patterns may be used to specify a subset of the zip file | |||||
| for inclusion in the archive.</p> | |||||
| <h4><a name="zipfileset">zipfileset</a></h4> | |||||
| <p>A <code><zipfileset></code> is a special form of a | |||||
| <code><fileset></code> that adds some extra functionality. It | |||||
| supports all attributes of <code><fileset></code> in addition to | |||||
| those listed below.</p> | |||||
| <h3>Parameters</h3> | |||||
| <table border="1" cellpadding="2" cellspacing="0"> | |||||
| <tr> | |||||
| <td valign="top"><b>Attribute</b></td> | |||||
| <td valign="top"><b>Description</b></td> | |||||
| <td valign="top" align="center"><b>Required</b></td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">prefix</td> | |||||
| <td valign="top">all files in the fileset are prefixed with that | |||||
| path in the archive.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">fullpath</td> | |||||
| <td valign="top">the file described by the fileset is placed at | |||||
| that exact location in the archive.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">src</td> | |||||
| <td valign="top">may be used in place of the <i>dir</i> attribute | |||||
| to specify a zip file whose contents will be extracted and | |||||
| included in the archive.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">filemode</td> | |||||
| <td valign="top">A 3 digit octal string, specify the user, group | |||||
| and other modes in the standard Unix fashion. Only applies to | |||||
| plain files. Default is 644. <em>since Ant 1.6</em>.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| <tr> | |||||
| <td valign="top">dirmode</td> | |||||
| <td valign="top">A 3 digit octal string, specify the user, group | |||||
| and other modes in the standard Unix fashion. Only applies to | |||||
| directories. Default is 755. <em>since Ant 1.6</em>.</td> | |||||
| <td align="center" valign="top">No</td> | |||||
| </tr> | |||||
| </table> | |||||
| <p>The <i>fullpath</i> attribute can only be set for filesets that | |||||
| represent a single file. The <i>prefix</i> and <i>fullpath</i> | |||||
| attributes cannot both be set on the same fileset.</p> | |||||
| <p>When using the <i>src</i> attribute, include and exclude patterns | |||||
| may be used to specify a subset of the zip file for inclusion in the | |||||
| archive as with the <i>dir</i> attribute.</p> | |||||
| <h4>zipgroupfileset</h4> | <h4>zipgroupfileset</h4> | ||||
| <p>A <code><zipgroupfileset></code> allows for multiple zip files to be | <p>A <code><zipgroupfileset></code> allows for multiple zip files to be | ||||
| merged into the archive. Each file found in this fileset is added to the archive | merged into the archive. Each file found in this fileset is added to the archive | ||||
| @@ -134,7 +134,8 @@ public class Ear extends Jar { | |||||
| super.initZipOutputStream(zOut); | super.initZipOutputStream(zOut); | ||||
| } | } | ||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath) | |||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath, | |||||
| int mode) | |||||
| throws IOException { | throws IOException { | ||||
| // If the file being added is META-INF/application.xml, we | // If the file being added is META-INF/application.xml, we | ||||
| // warn if it's not the one specified in the "appxml" | // warn if it's not the one specified in the "appxml" | ||||
| @@ -150,11 +151,11 @@ public class Ear extends Jar { | |||||
| + " be ignored (please use appxml attribute to " | + " be ignored (please use appxml attribute to " | ||||
| + archiveType + " task)", Project.MSG_WARN); | + archiveType + " task)", Project.MSG_WARN); | ||||
| } else { | } else { | ||||
| super.zipFile(file, zOut, vPath); | |||||
| super.zipFile(file, zOut, vPath, mode); | |||||
| descriptorAdded = true; | descriptorAdded = true; | ||||
| } | } | ||||
| } else { | } else { | ||||
| super.zipFile(file, zOut, vPath); | |||||
| super.zipFile(file, zOut, vPath, mode); | |||||
| } | } | ||||
| } | } | ||||
| @@ -314,7 +314,7 @@ public class Jar extends Zip { | |||||
| Project.MSG_WARN); | Project.MSG_WARN); | ||||
| } | } | ||||
| zipDir(null, zOut, "META-INF/"); | |||||
| zipDir(null, zOut, "META-INF/", ZipFileSet.DEFAULT_DIR_MODE); | |||||
| // time to write the manifest | // time to write the manifest | ||||
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||||
| PrintWriter writer = new PrintWriter(baos); | PrintWriter writer = new PrintWriter(baos); | ||||
| @@ -324,7 +324,8 @@ public class Jar extends Zip { | |||||
| ByteArrayInputStream bais = | ByteArrayInputStream bais = | ||||
| new ByteArrayInputStream(baos.toByteArray()); | new ByteArrayInputStream(baos.toByteArray()); | ||||
| super.zipFile(bais, zOut, "META-INF/MANIFEST.MF", | super.zipFile(bais, zOut, "META-INF/MANIFEST.MF", | ||||
| System.currentTimeMillis(), null); | |||||
| System.currentTimeMillis(), null, | |||||
| ZipFileSet.DEFAULT_FILE_MODE); | |||||
| super.initZipOutputStream(zOut); | super.initZipOutputStream(zOut); | ||||
| } | } | ||||
| @@ -387,20 +388,22 @@ public class Jar extends Zip { | |||||
| writer.flush(); | writer.flush(); | ||||
| ByteArrayInputStream bais = | ByteArrayInputStream bais = | ||||
| new ByteArrayInputStream(baos.toByteArray()); | new ByteArrayInputStream(baos.toByteArray()); | ||||
| super.zipFile(bais, zOut, INDEX_NAME, System.currentTimeMillis(), null); | |||||
| super.zipFile(bais, zOut, INDEX_NAME, System.currentTimeMillis(), null, | |||||
| ZipFileSet.DEFAULT_FILE_MODE); | |||||
| } | } | ||||
| /** | /** | ||||
| * Overriden from Zip class to deal with manifests | * Overriden from Zip class to deal with manifests | ||||
| */ | */ | ||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath) | |||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath, | |||||
| int mode) | |||||
| throws IOException { | throws IOException { | ||||
| if ("META-INF/MANIFEST.MF".equalsIgnoreCase(vPath)) { | if ("META-INF/MANIFEST.MF".equalsIgnoreCase(vPath)) { | ||||
| if (! doubleFilePass || (doubleFilePass && skipWriting)) { | if (! doubleFilePass || (doubleFilePass && skipWriting)) { | ||||
| filesetManifest(file, null); | filesetManifest(file, null); | ||||
| } | } | ||||
| } else { | } else { | ||||
| super.zipFile(file, zOut, vPath); | |||||
| super.zipFile(file, zOut, vPath, mode); | |||||
| } | } | ||||
| } | } | ||||
| @@ -408,14 +411,14 @@ public class Jar extends Zip { | |||||
| * Overriden from Zip class to deal with manifests | * Overriden from Zip class to deal with manifests | ||||
| */ | */ | ||||
| protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath, | protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath, | ||||
| long lastModified, File file) | |||||
| long lastModified, File file, int mode) | |||||
| throws IOException { | throws IOException { | ||||
| if ("META-INF/MANIFEST.MF".equalsIgnoreCase(vPath)) { | if ("META-INF/MANIFEST.MF".equalsIgnoreCase(vPath)) { | ||||
| if (! doubleFilePass || (doubleFilePass && skipWriting)) { | if (! doubleFilePass || (doubleFilePass && skipWriting)) { | ||||
| filesetManifest(file, is); | filesetManifest(file, is); | ||||
| } | } | ||||
| } else { | } else { | ||||
| super.zipFile(is, zOut, vPath, lastModified, null); | |||||
| super.zipFile(is, zOut, vPath, lastModified, null, mode); | |||||
| } | } | ||||
| } | } | ||||
| @@ -172,7 +172,8 @@ public class War extends Jar { | |||||
| /** | /** | ||||
| * add another file to the stream | * add another file to the stream | ||||
| */ | */ | ||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath) | |||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath, | |||||
| int mode) | |||||
| throws IOException { | throws IOException { | ||||
| // If the file being added is WEB-INF/web.xml, we warn if it's | // If the file being added is WEB-INF/web.xml, we warn if it's | ||||
| // not the one specified in the "webxml" attribute - or if | // not the one specified in the "webxml" attribute - or if | ||||
| @@ -187,11 +188,11 @@ public class War extends Jar { | |||||
| + "(please use webxml attribute to " | + "(please use webxml attribute to " | ||||
| + archiveType + " task)", Project.MSG_WARN); | + archiveType + " task)", Project.MSG_WARN); | ||||
| } else { | } else { | ||||
| super.zipFile(file, zOut, vPath); | |||||
| super.zipFile(file, zOut, vPath, mode); | |||||
| descriptorAdded = true; | descriptorAdded = true; | ||||
| } | } | ||||
| } else { | } else { | ||||
| super.zipFile(file, zOut, vPath); | |||||
| super.zipFile(file, zOut, vPath, mode); | |||||
| } | } | ||||
| } | } | ||||
| @@ -388,7 +388,9 @@ public class Zip extends MatchingTask { | |||||
| // Add the implicit fileset to the archive. | // Add the implicit fileset to the archive. | ||||
| if (baseDir != null) { | if (baseDir != null) { | ||||
| addFiles(getDirectoryScanner(baseDir), zOut, "", ""); | |||||
| addFiles(getDirectoryScanner(baseDir), zOut, "", "", | |||||
| ZipFileSet.DEFAULT_DIR_MODE, | |||||
| ZipFileSet.DEFAULT_FILE_MODE); | |||||
| } | } | ||||
| // Add the explicit filesets to the archive. | // Add the explicit filesets to the archive. | ||||
| addFiles(filesets, zOut); | addFiles(filesets, zOut); | ||||
| @@ -473,10 +475,28 @@ public class Zip extends MatchingTask { | |||||
| * prependig the given prefix to each filename. | * prependig the given prefix to each filename. | ||||
| * | * | ||||
| * <p>Ensure parent directories have been added as well. | * <p>Ensure parent directories have been added as well. | ||||
| * | |||||
| * @deprecated use six-arg version instead. | |||||
| */ | */ | ||||
| protected void addFiles(FileScanner scanner, ZipOutputStream zOut, | protected void addFiles(FileScanner scanner, ZipOutputStream zOut, | ||||
| String prefix, String fullpath) | String prefix, String fullpath) | ||||
| throws IOException { | throws IOException { | ||||
| addFiles(scanner, zOut, prefix, fullpath, ZipFileSet.DEFAULT_DIR_MODE, | |||||
| ZipFileSet.DEFAULT_FILE_MODE); | |||||
| } | |||||
| /** | |||||
| * Add all files of the given FileScanner to the ZipOutputStream | |||||
| * prependig the given prefix to each filename. | |||||
| * | |||||
| * <p>Ensure parent directories have been added as well. | |||||
| * | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| protected void addFiles(FileScanner scanner, ZipOutputStream zOut, | |||||
| String prefix, String fullpath, int dirMode, | |||||
| int fileMode) | |||||
| throws IOException { | |||||
| if (prefix.length() > 0 && fullpath.length() > 0) { | if (prefix.length() > 0 && fullpath.length() > 0) { | ||||
| throw new BuildException("Both prefix and fullpath attributes must" | throw new BuildException("Both prefix and fullpath attributes must" | ||||
| @@ -500,7 +520,7 @@ public class Zip extends MatchingTask { | |||||
| if (!name.endsWith("/")) { | if (!name.endsWith("/")) { | ||||
| name += "/"; | name += "/"; | ||||
| } | } | ||||
| addParentDirs(thisBaseDir, name, zOut, prefix); | |||||
| addParentDirs(thisBaseDir, name, zOut, prefix, dirMode); | |||||
| } | } | ||||
| // files that matched include patterns | // files that matched include patterns | ||||
| @@ -514,13 +534,13 @@ public class Zip extends MatchingTask { | |||||
| File f = new File(thisBaseDir, files[i]); | File f = new File(thisBaseDir, files[i]); | ||||
| if (fullpath.length() > 0) { | if (fullpath.length() > 0) { | ||||
| // Add this file at the specified location. | // Add this file at the specified location. | ||||
| addParentDirs(null, fullpath, zOut, ""); | |||||
| zipFile(f, zOut, fullpath); | |||||
| addParentDirs(null, fullpath, zOut, "", dirMode); | |||||
| zipFile(f, zOut, fullpath, fileMode); | |||||
| } else { | } else { | ||||
| // Add this file with the specified prefix. | // Add this file with the specified prefix. | ||||
| String name = files[i].replace(File.separatorChar, '/'); | String name = files[i].replace(File.separatorChar, '/'); | ||||
| addParentDirs(thisBaseDir, name, zOut, prefix); | |||||
| zipFile(f, zOut, prefix + name); | |||||
| addParentDirs(thisBaseDir, name, zOut, prefix, dirMode); | |||||
| zipFile(f, zOut, prefix + name, fileMode); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -550,13 +570,16 @@ public class Zip extends MatchingTask { | |||||
| String vPath = entry.getName(); | String vPath = entry.getName(); | ||||
| if (zipScanner.match(vPath)) { | if (zipScanner.match(vPath)) { | ||||
| if (fullpath.length() > 0) { | if (fullpath.length() > 0) { | ||||
| addParentDirs(null, fullpath, zOut, ""); | |||||
| zipFile(in, zOut, fullpath, entry.getTime(), zipSrc); | |||||
| addParentDirs(null, fullpath, zOut, "", | |||||
| fs.getDirMode()); | |||||
| zipFile(in, zOut, fullpath, entry.getTime(), zipSrc, | |||||
| fs.getFileMode()); | |||||
| } else { | } else { | ||||
| addParentDirs(null, vPath, zOut, prefix); | |||||
| addParentDirs(null, vPath, zOut, prefix, | |||||
| fs.getDirMode()); | |||||
| if (!entry.isDirectory()) { | if (!entry.isDirectory()) { | ||||
| zipFile(in, zOut, prefix + vPath, entry.getTime(), | zipFile(in, zOut, prefix + vPath, entry.getTime(), | ||||
| zipSrc); | |||||
| zipSrc, fs.getFileMode()); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -701,8 +724,20 @@ public class Zip extends MatchingTask { | |||||
| return result; | return result; | ||||
| } | } | ||||
| /** | |||||
| * @deprecated use four-arg version instead. | |||||
| */ | |||||
| protected void zipDir(File dir, ZipOutputStream zOut, String vPath) | protected void zipDir(File dir, ZipOutputStream zOut, String vPath) | ||||
| throws IOException { | throws IOException { | ||||
| zipDir(dir, zOut, vPath, ZipFileSet.DEFAULT_DIR_MODE); | |||||
| } | |||||
| /** | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| protected void zipDir(File dir, ZipOutputStream zOut, String vPath, | |||||
| int mode) | |||||
| throws IOException { | |||||
| if (addedDirs.get(vPath) != null) { | if (addedDirs.get(vPath) != null) { | ||||
| // don't add directories we've already added. | // don't add directories we've already added. | ||||
| // no warning if we try, it is harmless in and of itself | // no warning if we try, it is harmless in and of itself | ||||
| @@ -723,17 +758,28 @@ public class Zip extends MatchingTask { | |||||
| ze.setMethod (ZipEntry.STORED); | ze.setMethod (ZipEntry.STORED); | ||||
| // This is faintly ridiculous: | // This is faintly ridiculous: | ||||
| ze.setCrc (EMPTY_CRC); | ze.setCrc (EMPTY_CRC); | ||||
| // this is 040775 | MS-DOS directory flag in reverse byte order | |||||
| ze.setExternalAttributes(0x41FD0010L); | |||||
| ze.setUnixMode(mode); | |||||
| zOut.putNextEntry (ze); | zOut.putNextEntry (ze); | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * @deprecated use six-arg version instead. | |||||
| */ | |||||
| protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath, | protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath, | ||||
| long lastModified, File file) | long lastModified, File file) | ||||
| throws IOException { | throws IOException { | ||||
| zipFile(in, zOut, vPath, lastModified, file, | |||||
| ZipFileSet.DEFAULT_FILE_MODE); | |||||
| } | |||||
| /** | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath, | |||||
| long lastModified, File file, int mode) | |||||
| throws IOException { | |||||
| if (entries.contains(vPath)) { | if (entries.contains(vPath)) { | ||||
| if (duplicate.equals("preserve")) { | if (duplicate.equals("preserve")) { | ||||
| @@ -759,14 +805,15 @@ public class Zip extends MatchingTask { | |||||
| ze.setTime(lastModified); | ze.setTime(lastModified); | ||||
| /* | /* | ||||
| * XXX ZipOutputStream.putEntry expects the ZipEntry to know its | |||||
| * size and the CRC sum before you start writing the data when using | |||||
| * STORED mode. | |||||
| * ZipOutputStream.putNextEntry expects the ZipEntry to | |||||
| * know its size and the CRC sum before you start writing | |||||
| * the data when using STORED mode. | |||||
| * | * | ||||
| * This forces us to process the data twice. | * This forces us to process the data twice. | ||||
| * | * | ||||
| * I couldn't find any documentation on this, just found out by try | |||||
| * and error. | |||||
| * In DEFLATED mode, it will take advantage of a Zip | |||||
| * Version 2 feature where size can be stored after the | |||||
| * data (as the data itself signals end of data). | |||||
| */ | */ | ||||
| if (!doCompress) { | if (!doCompress) { | ||||
| long size = 0; | long size = 0; | ||||
| @@ -800,6 +847,7 @@ public class Zip extends MatchingTask { | |||||
| ze.setCrc(cal.getValue()); | ze.setCrc(cal.getValue()); | ||||
| } | } | ||||
| ze.setUnixMode(mode); | |||||
| zOut.putNextEntry(ze); | zOut.putNextEntry(ze); | ||||
| byte[] buffer = new byte[8 * 1024]; | byte[] buffer = new byte[8 * 1024]; | ||||
| @@ -814,8 +862,20 @@ public class Zip extends MatchingTask { | |||||
| addedFiles.addElement(vPath); | addedFiles.addElement(vPath); | ||||
| } | } | ||||
| /** | |||||
| * @deprecated use six-arg version instead. | |||||
| */ | |||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath) | protected void zipFile(File file, ZipOutputStream zOut, String vPath) | ||||
| throws IOException { | throws IOException { | ||||
| zipFile(file, zOut, vPath, ZipFileSet.DEFAULT_FILE_MODE); | |||||
| } | |||||
| /** | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| protected void zipFile(File file, ZipOutputStream zOut, String vPath, | |||||
| int mode) | |||||
| throws IOException { | |||||
| if (file.equals(zipFile)) { | if (file.equals(zipFile)) { | ||||
| throw new BuildException("A zip file cannot include itself", | throw new BuildException("A zip file cannot include itself", | ||||
| getLocation()); | getLocation()); | ||||
| @@ -823,18 +883,31 @@ public class Zip extends MatchingTask { | |||||
| FileInputStream fIn = new FileInputStream(file); | FileInputStream fIn = new FileInputStream(file); | ||||
| try { | try { | ||||
| zipFile(fIn, zOut, vPath, file.lastModified(), null); | |||||
| zipFile(fIn, zOut, vPath, file.lastModified(), null, mode); | |||||
| } finally { | } finally { | ||||
| fIn.close(); | fIn.close(); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Ensure all parent dirs of a given entry have been added. | |||||
| * @deprecated use five-arg version instead. | |||||
| */ | */ | ||||
| protected void addParentDirs(File baseDir, String entry, | protected void addParentDirs(File baseDir, String entry, | ||||
| ZipOutputStream zOut, String prefix) | ZipOutputStream zOut, String prefix) | ||||
| throws IOException { | throws IOException { | ||||
| addParentDirs(baseDir, entry, zOut, prefix, | |||||
| ZipFileSet.DEFAULT_DIR_MODE); | |||||
| } | |||||
| /** | |||||
| * Ensure all parent dirs of a given entry have been added. | |||||
| * | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| protected void addParentDirs(File baseDir, String entry, | |||||
| ZipOutputStream zOut, String prefix, | |||||
| int dirMode) | |||||
| throws IOException { | |||||
| if (!doFilesonly) { | if (!doFilesonly) { | ||||
| Stack directories = new Stack(); | Stack directories = new Stack(); | ||||
| int slashPos = entry.length(); | int slashPos = entry.length(); | ||||
| @@ -855,7 +928,7 @@ public class Zip extends MatchingTask { | |||||
| } else { | } else { | ||||
| f = new File(dir); | f = new File(dir); | ||||
| } | } | ||||
| zipDir(f, zOut, prefix + dir); | |||||
| zipDir(f, zOut, prefix + dir, dirMode); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -874,10 +947,14 @@ public class Zip extends MatchingTask { | |||||
| String prefix = ""; | String prefix = ""; | ||||
| String fullpath = ""; | String fullpath = ""; | ||||
| int fileMode = ZipFileSet.DEFAULT_FILE_MODE; | |||||
| int dirMode = ZipFileSet.DEFAULT_DIR_MODE; | |||||
| if (fs instanceof ZipFileSet) { | if (fs instanceof ZipFileSet) { | ||||
| ZipFileSet zfs = (ZipFileSet) fs; | ZipFileSet zfs = (ZipFileSet) fs; | ||||
| prefix = zfs.getPrefix(); | prefix = zfs.getPrefix(); | ||||
| fullpath = zfs.getFullpath(); | fullpath = zfs.getFullpath(); | ||||
| fileMode = zfs.getFileMode(); | |||||
| dirMode = zfs.getDirMode(); | |||||
| } | } | ||||
| if (prefix.length() > 0 | if (prefix.length() > 0 | ||||
| @@ -889,10 +966,10 @@ public class Zip extends MatchingTask { | |||||
| // Need to manually add either fullpath's parent directory, or | // Need to manually add either fullpath's parent directory, or | ||||
| // the prefix directory, to the archive. | // the prefix directory, to the archive. | ||||
| if (prefix.length() > 0) { | if (prefix.length() > 0) { | ||||
| addParentDirs(null, prefix, zOut, ""); | |||||
| zipDir(null, zOut, prefix); | |||||
| addParentDirs(null, prefix, zOut, "", dirMode); | |||||
| zipDir(null, zOut, prefix, dirMode); | |||||
| } else if (fullpath.length() > 0) { | } else if (fullpath.length() > 0) { | ||||
| addParentDirs(null, fullpath, zOut, ""); | |||||
| addParentDirs(null, fullpath, zOut, "", dirMode); | |||||
| } | } | ||||
| if (fs instanceof ZipFileSet | if (fs instanceof ZipFileSet | ||||
| @@ -900,7 +977,7 @@ public class Zip extends MatchingTask { | |||||
| addZipEntries((ZipFileSet) fs, ds, zOut, prefix, fullpath); | addZipEntries((ZipFileSet) fs, ds, zOut, prefix, fullpath); | ||||
| } else { | } else { | ||||
| // Add the fileset. | // Add the fileset. | ||||
| addFiles(ds, zOut, prefix, fullpath); | |||||
| addFiles(ds, zOut, prefix, fullpath, dirMode, fileMode); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -80,12 +80,28 @@ import org.apache.tools.zip.UnixStat; | |||||
| */ | */ | ||||
| public class ZipFileSet extends FileSet { | public class ZipFileSet extends FileSet { | ||||
| /** | |||||
| * Default value for the dirmode attribute. | |||||
| * | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| public static final int DEFAULT_DIR_MODE = | |||||
| UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM; | |||||
| /** | |||||
| * Default value for the filemode attribute. | |||||
| * | |||||
| * @since Ant 1.6 | |||||
| */ | |||||
| public static final int DEFAULT_FILE_MODE = | |||||
| UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM; | |||||
| private File srcFile = null; | private File srcFile = null; | ||||
| private String prefix = ""; | private String prefix = ""; | ||||
| private String fullpath = ""; | private String fullpath = ""; | ||||
| private boolean hasDir = false; | private boolean hasDir = false; | ||||
| private int fileMode = UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM; | |||||
| private int dirMode = UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM; | |||||
| private int fileMode = DEFAULT_FILE_MODE; | |||||
| private int dirMode = DEFAULT_DIR_MODE; | |||||
| public ZipFileSet() { | public ZipFileSet() { | ||||
| super(); | super(); | ||||
| @@ -198,6 +198,8 @@ public class ZipEntry extends java.util.zip.ZipEntry { | |||||
| */ | */ | ||||
| public void setUnixMode(int mode) { | public void setUnixMode(int mode) { | ||||
| setExternalAttributes((mode << 16) | setExternalAttributes((mode << 16) | ||||
| // MS-DOS read-only attribute | |||||
| | ((mode & 0200) == 0 ? 1 : 0) | |||||
| // MS-DOS directory flag | // MS-DOS directory flag | ||||
| | (isDirectory() ? 0x10 : 0)); | | (isDirectory() ? 0x10 : 0)); | ||||
| platform = PLATFORM_UNIX; | platform = PLATFORM_UNIX; | ||||
| @@ -131,12 +131,25 @@ public class ZipEntryTest extends TestCase { | |||||
| (ze.getExternalAttributes() >> 16) & 0xFFFF); | (ze.getExternalAttributes() >> 16) & 0xFFFF); | ||||
| assertEquals(0, ze.getExternalAttributes() & 0xFFFF); | assertEquals(0, ze.getExternalAttributes() & 0xFFFF); | ||||
| ze.setUnixMode(0444); | |||||
| assertEquals(3, ze.getPlatform()); | |||||
| assertEquals(0444, | |||||
| (ze.getExternalAttributes() >> 16) & 0xFFFF); | |||||
| assertEquals(1, ze.getExternalAttributes() & 0xFFFF); | |||||
| ze = new ZipEntry("foo/"); | ze = new ZipEntry("foo/"); | ||||
| assertEquals(0, ze.getPlatform()); | |||||
| ze.setUnixMode(0777); | |||||
| assertEquals(3, ze.getPlatform()); | |||||
| assertEquals(0777, | |||||
| (ze.getExternalAttributes() >> 16) & 0xFFFF); | |||||
| assertEquals(0x10, ze.getExternalAttributes() & 0xFFFF); | |||||
| ze.setUnixMode(0577); | ze.setUnixMode(0577); | ||||
| assertEquals(3, ze.getPlatform()); | assertEquals(3, ze.getPlatform()); | ||||
| assertEquals(0577, | assertEquals(0577, | ||||
| (ze.getExternalAttributes() >> 16) & 0xFFFF); | (ze.getExternalAttributes() >> 16) & 0xFFFF); | ||||
| assertEquals(0x10, ze.getExternalAttributes() & 0xFFFF); | |||||
| assertEquals(0x11, ze.getExternalAttributes() & 0xFFFF); | |||||
| } | } | ||||
| } | } | ||||