git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@677597 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -63,6 +63,20 @@ Changes that could break older environments: | |||||
| set failOnEmptyArchive to false to restore the old behavior. | set failOnEmptyArchive to false to restore the old behavior. | ||||
| Bugzilla report 35000. | Bugzilla report 35000. | ||||
| * Ant's <zip> family of tasks tries to preserve the existing Unix | |||||
| permissions when updating archives or copying entries from one | |||||
| archive to another. | |||||
| Since not all archiving tools support storing Unix permissions in | |||||
| the same way that is used by Ant, sometimes the permissions read by | |||||
| Ant seem to be 0, which means nobody is allowed to do anything to | |||||
| the file or directory. | |||||
| If Ant now encounters a permission set of 0 it will assume that | |||||
| this is not the intended value and instead apply its own default | |||||
| values. Ant used to create entries with 0 permissions itself. | |||||
| The <zip> family of tasks has a new attribute preservce0permissions | |||||
| that can be set to restore the old behavior. | |||||
| Bugzilla Report 42122. | |||||
| Fixed bugs: | Fixed bugs: | ||||
| ----------- | ----------- | ||||
| @@ -185,6 +185,18 @@ to a value other than its default, <code>"add"</code>.</b></p> | |||||
| (maximum compression/slowest). <em>Since Ant 1.7</em></td> | (maximum compression/slowest). <em>Since Ant 1.7</em></td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">preserve0permissions</td> | |||||
| <td valign="top">when updating an archive or adding entries from a | |||||
| different archive Ant will assume that a Unix permissions value of | |||||
| 0 (nobody is allowed to do anything to the file/directory) means | |||||
| that the permissions haven't been stored at all rather than real | |||||
| permissions and will instead apply its own default values.<br/> | |||||
| Set this attribute to true if you really want to preserve the | |||||
| original permission field.<em>since Ant 1.8.0</em> | |||||
| </td> | |||||
| <td valign="top" align="center">No, default is false</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Nested elements</h3> | <h3>Nested elements</h3> | ||||
| @@ -239,6 +239,18 @@ to a value other than its default, <code>"add"</code>.</b></p> | |||||
| <em>Since Ant 1.7.1</em></td> | <em>Since Ant 1.7.1</em></td> | ||||
| <td valign="top" align="center">No, defaults to <tt>ignore</tt>. </td> | <td valign="top" align="center">No, defaults to <tt>ignore</tt>. </td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">preserve0permissions</td> | |||||
| <td valign="top">when updating an archive or adding entries from a | |||||
| different archive Ant will assume that a Unix permissions value of | |||||
| 0 (nobody is allowed to do anything to the file/directory) means | |||||
| that the permissions haven't been stored at all rather than real | |||||
| permissions and will instead apply its own default values.<br/> | |||||
| Set this attribute to true if you really want to preserve the | |||||
| original permission field.<em>since Ant 1.8.0</em> | |||||
| </td> | |||||
| <td valign="top" align="center">No, default is false</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Nested elements</h3> | <h3>Nested elements</h3> | ||||
| @@ -202,6 +202,18 @@ to a value other than its default, <code>"add"</code>.</b></p> | |||||
| (maximum compression/slowest). <em>Since Ant 1.7</em></td> | (maximum compression/slowest). <em>Since Ant 1.7</em></td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">preserve0permissions</td> | |||||
| <td valign="top">when updating an archive or adding entries from a | |||||
| different archive Ant will assume that a Unix permissions value of | |||||
| 0 (nobody is allowed to do anything to the file/directory) means | |||||
| that the permissions haven't been stored at all rather than real | |||||
| permissions and will instead apply its own default values.<br/> | |||||
| Set this attribute to true if you really want to preserve the | |||||
| original permission field.<em>since Ant 1.8.0</em> | |||||
| </td> | |||||
| <td valign="top" align="center">No, default is false</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Nested elements</h3> | <h3>Nested elements</h3> | ||||
| @@ -229,6 +229,18 @@ archive.</p> | |||||
| (maximum compression/slowest). <em>Since Ant 1.7</em></td> | (maximum compression/slowest). <em>Since Ant 1.7</em></td> | ||||
| <td valign="top" align="center">No</td> | <td valign="top" align="center">No</td> | ||||
| </tr> | </tr> | ||||
| <tr> | |||||
| <td valign="top">preserve0permissions</td> | |||||
| <td valign="top">when updating an archive or adding entries from a | |||||
| different archive Ant will assume that a Unix permissions value of | |||||
| 0 (nobody is allowed to do anything to the file/directory) means | |||||
| that the permissions haven't been stored at all rather than real | |||||
| permissions and will instead apply its own default values.<br/> | |||||
| Set this attribute to true if you really want to preserve the | |||||
| original permission field.<em>since Ant 1.8.0</em> | |||||
| </td> | |||||
| <td valign="top" align="center">No, default is false</td> | |||||
| </tr> | |||||
| </table> | </table> | ||||
| <h3>Parameters specified as nested elements</h3> | <h3>Parameters specified as nested elements</h3> | ||||
| @@ -248,6 +248,18 @@ | |||||
| </zip> | </zip> | ||||
| </target> | </target> | ||||
| <target name="rewriteZeroPermissions"> | |||||
| <zip destfile="test3.zip"> | |||||
| <zipfileset src="nopermissions.zip"/> | |||||
| </zip> | |||||
| </target> | |||||
| <target name="acceptZeroPermissions"> | |||||
| <zip destfile="test3.zip" preserve0permissions="true"> | |||||
| <zipfileset src="nopermissions.zip"/> | |||||
| </zip> | |||||
| </target> | |||||
| <target name="cleanup"> | <target name="cleanup"> | ||||
| <delete file="testLevel.zip"/> | <delete file="testLevel.zip"/> | ||||
| <delete file="test3.zip"/> | <delete file="test3.zip"/> | ||||
| @@ -53,6 +53,7 @@ import org.apache.tools.ant.util.GlobPatternMapper; | |||||
| import org.apache.tools.ant.util.IdentityMapper; | import org.apache.tools.ant.util.IdentityMapper; | ||||
| import org.apache.tools.ant.util.MergingMapper; | import org.apache.tools.ant.util.MergingMapper; | ||||
| import org.apache.tools.ant.util.ResourceUtils; | import org.apache.tools.ant.util.ResourceUtils; | ||||
| import org.apache.tools.zip.UnixStat; | |||||
| import org.apache.tools.zip.ZipEntry; | import org.apache.tools.zip.ZipEntry; | ||||
| import org.apache.tools.zip.ZipExtraField; | import org.apache.tools.zip.ZipExtraField; | ||||
| import org.apache.tools.zip.ZipFile; | import org.apache.tools.zip.ZipFile; | ||||
| @@ -139,6 +140,12 @@ public class Zip extends MatchingTask { | |||||
| private int level = ZipOutputStream.DEFAULT_COMPRESSION; | private int level = ZipOutputStream.DEFAULT_COMPRESSION; | ||||
| /** | |||||
| * Assume 0 Unix mode is intentional. | |||||
| * @since Ant 1.8.0 | |||||
| */ | |||||
| private boolean preserve0Permissions = false; | |||||
| /** | /** | ||||
| * This is the name/location of where to | * This is the name/location of where to | ||||
| * create the .zip file. | * create the .zip file. | ||||
| @@ -401,6 +408,22 @@ public class Zip extends MatchingTask { | |||||
| roundUp = r; | roundUp = r; | ||||
| } | } | ||||
| /** | |||||
| * Assume 0 Unix mode is intentional. | |||||
| * @since Ant 1.8.0 | |||||
| */ | |||||
| public void setPreserve0Permissions(boolean b) { | |||||
| preserve0Permissions = b; | |||||
| } | |||||
| /** | |||||
| * Assume 0 Unix mode is intentional. | |||||
| * @since Ant 1.8.0 | |||||
| */ | |||||
| public boolean getPreserve0Permissions() { | |||||
| return preserve0Permissions; | |||||
| } | |||||
| /** | /** | ||||
| * validate and build | * validate and build | ||||
| * @throws BuildException on error | * @throws BuildException on error | ||||
| @@ -774,8 +797,13 @@ public class Zip extends MatchingTask { | |||||
| } | } | ||||
| if (zf != null) { | if (zf != null) { | ||||
| ZipEntry ze = zf.getEntry(resources[i].getName()); | ZipEntry ze = zf.getEntry(resources[i].getName()); | ||||
| int unixMode = ze.getUnixMode(); | |||||
| if ((unixMode == 0 || unixMode == UnixStat.DIR_FLAG) | |||||
| && !preserve0Permissions) { | |||||
| unixMode = dirMode; | |||||
| } | |||||
| addParentDirs(base, name, zOut, prefix, | addParentDirs(base, name, zOut, prefix, | ||||
| ze.getUnixMode()); | |||||
| unixMode); | |||||
| } else { | } else { | ||||
| ArchiveResource tr = (ArchiveResource) resources[i]; | ArchiveResource tr = (ArchiveResource) resources[i]; | ||||
| addParentDirs(base, name, zOut, prefix, | addParentDirs(base, name, zOut, prefix, | ||||
| @@ -802,10 +830,16 @@ public class Zip extends MatchingTask { | |||||
| InputStream is = null; | InputStream is = null; | ||||
| try { | try { | ||||
| is = zf.getInputStream(ze); | is = zf.getInputStream(ze); | ||||
| int unixMode = ze.getUnixMode(); | |||||
| if (zfs.hasFileModeBeenSet() | |||||
| || ((unixMode == 0 | |||||
| || unixMode == UnixStat.FILE_FLAG) | |||||
| && !preserve0Permissions)) { | |||||
| unixMode = fileMode; | |||||
| } | |||||
| zipFile(is, zOut, prefix + name, | zipFile(is, zOut, prefix + name, | ||||
| ze.getTime(), zfs.getSrc(getProject()), | ze.getTime(), zfs.getSrc(getProject()), | ||||
| zfs.hasFileModeBeenSet() ? fileMode | |||||
| : ze.getUnixMode()); | |||||
| unixMode); | |||||
| } finally { | } finally { | ||||
| doCompress = oldCompress; | doCompress = oldCompress; | ||||
| FileUtils.close(is); | FileUtils.close(is); | ||||
| @@ -28,8 +28,8 @@ import java.util.zip.ZipException; | |||||
| */ | */ | ||||
| public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable { | public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable { | ||||
| private static final int PLATFORM_UNIX = 3; | |||||
| private static final int PLATFORM_FAT = 0; | |||||
| public static final int PLATFORM_UNIX = 3; | |||||
| public static final int PLATFORM_FAT = 0; | |||||
| private static final int SHORT_MASK = 0xFFFF; | private static final int SHORT_MASK = 0xFFFF; | ||||
| private static final int SHORT_SHIFT = 16; | private static final int SHORT_SHIFT = 16; | ||||
| @@ -145,7 +145,7 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable { | |||||
| */ | */ | ||||
| public void setUnixMode(int mode) { | public void setUnixMode(int mode) { | ||||
| // CheckStyle:MagicNumberCheck OFF - no point | // CheckStyle:MagicNumberCheck OFF - no point | ||||
| setExternalAttributes((mode << 16) | |||||
| setExternalAttributes((mode << SHORT_SHIFT) | |||||
| // MS-DOS read-only attribute | // MS-DOS read-only attribute | ||||
| | ((mode & 0200) == 0 ? 1 : 0) | | ((mode & 0200) == 0 ? 1 : 0) | ||||
| // MS-DOS directory flag | // MS-DOS directory flag | ||||
| @@ -160,15 +160,16 @@ public class ZipEntry extends java.util.zip.ZipEntry implements Cloneable { | |||||
| * @since Ant 1.6 | * @since Ant 1.6 | ||||
| */ | */ | ||||
| public int getUnixMode() { | public int getUnixMode() { | ||||
| return (int) ((getExternalAttributes() >> SHORT_SHIFT) & SHORT_MASK); | |||||
| return platform != PLATFORM_UNIX ? 0 : | |||||
| (int) ((getExternalAttributes() >> SHORT_SHIFT) & SHORT_MASK); | |||||
| } | } | ||||
| /** | /** | ||||
| * Platform specification to put into the "version made | * Platform specification to put into the "version made | ||||
| * by" part of the central file header. | * by" part of the central file header. | ||||
| * | * | ||||
| * @return 0 (MS-DOS FAT) unless {@link #setUnixMode setUnixMode} | |||||
| * has been called, in which case 3 (Unix) will be returned. | |||||
| * @return PLATFORM_FAT unless {@link #setUnixMode setUnixMode} | |||||
| * has been called, in which case PLATORM_UNIX will be returned. | |||||
| * | * | ||||
| * @since Ant 1.5.2 | * @since Ant 1.5.2 | ||||
| */ | */ | ||||
| @@ -188,4 +188,35 @@ public class ZipTest extends BuildFileTest { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| public void testRewriteZeroPermissions() throws IOException { | |||||
| executeTarget("rewriteZeroPermissions"); | |||||
| org.apache.tools.zip.ZipFile zf = null; | |||||
| try { | |||||
| zf = new org.apache.tools.zip.ZipFile(getProject() | |||||
| .resolveFile("test3.zip")); | |||||
| org.apache.tools.zip.ZipEntry ze = zf.getEntry("testdir/test.txt"); | |||||
| assertEquals(UnixStat.FILE_FLAG | 0644, ze.getUnixMode()); | |||||
| } finally { | |||||
| if (zf != null) { | |||||
| zf.close(); | |||||
| } | |||||
| } | |||||
| } | |||||
| public void testAcceptZeroPermissions() throws IOException { | |||||
| executeTarget("acceptZeroPermissions"); | |||||
| org.apache.tools.zip.ZipFile zf = null; | |||||
| try { | |||||
| zf = new org.apache.tools.zip.ZipFile(getProject() | |||||
| .resolveFile("test3.zip")); | |||||
| org.apache.tools.zip.ZipEntry ze = zf.getEntry("testdir/test.txt"); | |||||
| assertEquals(0000, ze.getUnixMode()); | |||||
| } finally { | |||||
| if (zf != null) { | |||||
| zf.close(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||