From 3255fa8ff4d68ae67f32a9df7a54c163fdddb9a0 Mon Sep 17 00:00:00 2001
From: Stefan Bodewig
Starting with Ant 1.6, <zip> can store Unix permissions +inside the archive (see description of the filemode and dirmode +attributes for <zipfileset>). +Unfortunately there is no portable way to store these permissions. +Ant uses the algorithm used by Info-Zip's +implementation of the zip and unzip commands - these are the default +versions of zip and unzip for many Unix and Unix-like systems.
+Attribute | +Description | +Required | +
prefix | +all files in the fileset are prefixed with that + path in the archive. | +No | +
fullpath | +the file described by the fileset is placed at + that exact location in the archive. | +No | +
src | +may be used in place of the dir attribute + to specify a zip file whose contents will be extracted and + included in the archive. | +No | +
filemode | +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. since Ant 1.6. | +No | +
dirmode | +A 3 digit octal string, specify the user, group + and other modes in the standard Unix fashion. Only applies to + directories. Default is 755. since Ant 1.6. | +No | +
The fullpath attribute can only be set for filesets that +represent a single file. The prefix and fullpath +attributes cannot both be set on the same fileset.
+ +When using the src attribute, include and exclude patterns +may be used to specify a subset of the zip file for inclusion in the +archive as with the dir attribute.
+A <zipgroupfileset>
allows for multiple zip files to be
merged into the archive. Each file found in this fileset is added to the archive
diff --git a/src/main/org/apache/tools/ant/taskdefs/Ear.java b/src/main/org/apache/tools/ant/taskdefs/Ear.java
index 95e79f260..2c1ee87be 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Ear.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Ear.java
@@ -134,7 +134,8 @@ public class Ear extends Jar {
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 {
// If the file being added is META-INF/application.xml, we
// 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 "
+ archiveType + " task)", Project.MSG_WARN);
} else {
- super.zipFile(file, zOut, vPath);
+ super.zipFile(file, zOut, vPath, mode);
descriptorAdded = true;
}
} else {
- super.zipFile(file, zOut, vPath);
+ super.zipFile(file, zOut, vPath, mode);
}
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/Jar.java b/src/main/org/apache/tools/ant/taskdefs/Jar.java
index 586c94672..4d19a21c3 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Jar.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Jar.java
@@ -314,7 +314,7 @@ public class Jar extends Zip {
Project.MSG_WARN);
}
- zipDir(null, zOut, "META-INF/");
+ zipDir(null, zOut, "META-INF/", ZipFileSet.DEFAULT_DIR_MODE);
// time to write the manifest
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter writer = new PrintWriter(baos);
@@ -324,7 +324,8 @@ public class Jar extends Zip {
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
super.zipFile(bais, zOut, "META-INF/MANIFEST.MF",
- System.currentTimeMillis(), null);
+ System.currentTimeMillis(), null,
+ ZipFileSet.DEFAULT_FILE_MODE);
super.initZipOutputStream(zOut);
}
@@ -387,20 +388,22 @@ public class Jar extends Zip {
writer.flush();
ByteArrayInputStream bais =
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
*/
- protected void zipFile(File file, ZipOutputStream zOut, String vPath)
+ protected void zipFile(File file, ZipOutputStream zOut, String vPath,
+ int mode)
throws IOException {
if ("META-INF/MANIFEST.MF".equalsIgnoreCase(vPath)) {
if (! doubleFilePass || (doubleFilePass && skipWriting)) {
filesetManifest(file, null);
}
} 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
*/
protected void zipFile(InputStream is, ZipOutputStream zOut, String vPath,
- long lastModified, File file)
+ long lastModified, File file, int mode)
throws IOException {
if ("META-INF/MANIFEST.MF".equalsIgnoreCase(vPath)) {
if (! doubleFilePass || (doubleFilePass && skipWriting)) {
filesetManifest(file, is);
}
} else {
- super.zipFile(is, zOut, vPath, lastModified, null);
+ super.zipFile(is, zOut, vPath, lastModified, null, mode);
}
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/War.java b/src/main/org/apache/tools/ant/taskdefs/War.java
index 5071780d8..bd778e38f 100644
--- a/src/main/org/apache/tools/ant/taskdefs/War.java
+++ b/src/main/org/apache/tools/ant/taskdefs/War.java
@@ -172,7 +172,8 @@ public class War extends Jar {
/**
* 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 {
// 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
@@ -187,11 +188,11 @@ public class War extends Jar {
+ "(please use webxml attribute to "
+ archiveType + " task)", Project.MSG_WARN);
} else {
- super.zipFile(file, zOut, vPath);
+ super.zipFile(file, zOut, vPath, mode);
descriptorAdded = true;
}
} else {
- super.zipFile(file, zOut, vPath);
+ super.zipFile(file, zOut, vPath, mode);
}
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/Zip.java b/src/main/org/apache/tools/ant/taskdefs/Zip.java
index 3e597be4f..76b51e2ae 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Zip.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Zip.java
@@ -388,7 +388,9 @@ public class Zip extends MatchingTask {
// Add the implicit fileset to the archive.
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.
addFiles(filesets, zOut);
@@ -473,10 +475,28 @@ public class Zip extends MatchingTask {
* prependig the given prefix to each filename.
*
*
Ensure parent directories have been added as well. + * + * @deprecated use six-arg version instead. */ protected void addFiles(FileScanner scanner, ZipOutputStream zOut, String prefix, String fullpath) 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. + * + *
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) { throw new BuildException("Both prefix and fullpath attributes must" @@ -500,7 +520,7 @@ public class Zip extends MatchingTask { if (!name.endsWith("/")) { name += "/"; } - addParentDirs(thisBaseDir, name, zOut, prefix); + addParentDirs(thisBaseDir, name, zOut, prefix, dirMode); } // files that matched include patterns @@ -514,13 +534,13 @@ public class Zip extends MatchingTask { File f = new File(thisBaseDir, files[i]); if (fullpath.length() > 0) { // 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 { // Add this file with the specified prefix. 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(); if (zipScanner.match(vPath)) { 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 { - addParentDirs(null, vPath, zOut, prefix); + addParentDirs(null, vPath, zOut, prefix, + fs.getDirMode()); if (!entry.isDirectory()) { zipFile(in, zOut, prefix + vPath, entry.getTime(), - zipSrc); + zipSrc, fs.getFileMode()); } } } @@ -701,8 +724,20 @@ public class Zip extends MatchingTask { return result; } + /** + * @deprecated use four-arg version instead. + */ protected void zipDir(File dir, ZipOutputStream zOut, String vPath) 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) { // don't add directories we've already added. // 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); // This is faintly ridiculous: ze.setCrc (EMPTY_CRC); - - // this is 040775 | MS-DOS directory flag in reverse byte order - ze.setExternalAttributes(0x41FD0010L); + ze.setUnixMode(mode); zOut.putNextEntry (ze); } } + /** + * @deprecated use six-arg version instead. + */ protected void zipFile(InputStream in, ZipOutputStream zOut, String vPath, long lastModified, File file) 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 (duplicate.equals("preserve")) { @@ -759,14 +805,15 @@ public class Zip extends MatchingTask { 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. * - * 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) { long size = 0; @@ -800,6 +847,7 @@ public class Zip extends MatchingTask { ze.setCrc(cal.getValue()); } + ze.setUnixMode(mode); zOut.putNextEntry(ze); byte[] buffer = new byte[8 * 1024]; @@ -814,8 +862,20 @@ public class Zip extends MatchingTask { addedFiles.addElement(vPath); } + /** + * @deprecated use six-arg version instead. + */ protected void zipFile(File file, ZipOutputStream zOut, String vPath) 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)) { throw new BuildException("A zip file cannot include itself", getLocation()); @@ -823,18 +883,31 @@ public class Zip extends MatchingTask { FileInputStream fIn = new FileInputStream(file); try { - zipFile(fIn, zOut, vPath, file.lastModified(), null); + zipFile(fIn, zOut, vPath, file.lastModified(), null, mode); } finally { 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, ZipOutputStream zOut, String prefix) 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) { Stack directories = new Stack(); int slashPos = entry.length(); @@ -855,7 +928,7 @@ public class Zip extends MatchingTask { } else { 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 fullpath = ""; + int fileMode = ZipFileSet.DEFAULT_FILE_MODE; + int dirMode = ZipFileSet.DEFAULT_DIR_MODE; if (fs instanceof ZipFileSet) { ZipFileSet zfs = (ZipFileSet) fs; prefix = zfs.getPrefix(); fullpath = zfs.getFullpath(); + fileMode = zfs.getFileMode(); + dirMode = zfs.getDirMode(); } if (prefix.length() > 0 @@ -889,10 +966,10 @@ public class Zip extends MatchingTask { // Need to manually add either fullpath's parent directory, or // the prefix directory, to the archive. 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) { - addParentDirs(null, fullpath, zOut, ""); + addParentDirs(null, fullpath, zOut, "", dirMode); } if (fs instanceof ZipFileSet @@ -900,7 +977,7 @@ public class Zip extends MatchingTask { addZipEntries((ZipFileSet) fs, ds, zOut, prefix, fullpath); } else { // Add the fileset. - addFiles(ds, zOut, prefix, fullpath); + addFiles(ds, zOut, prefix, fullpath, dirMode, fileMode); } } } diff --git a/src/main/org/apache/tools/ant/types/ZipFileSet.java b/src/main/org/apache/tools/ant/types/ZipFileSet.java index 5859ad799..870a4f283 100644 --- a/src/main/org/apache/tools/ant/types/ZipFileSet.java +++ b/src/main/org/apache/tools/ant/types/ZipFileSet.java @@ -80,12 +80,28 @@ import org.apache.tools.zip.UnixStat; */ 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 String prefix = ""; private String fullpath = ""; 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() { super(); diff --git a/src/main/org/apache/tools/zip/ZipEntry.java b/src/main/org/apache/tools/zip/ZipEntry.java index 351de763d..06f6797ea 100644 --- a/src/main/org/apache/tools/zip/ZipEntry.java +++ b/src/main/org/apache/tools/zip/ZipEntry.java @@ -198,6 +198,8 @@ public class ZipEntry extends java.util.zip.ZipEntry { */ public void setUnixMode(int mode) { setExternalAttributes((mode << 16) + // MS-DOS read-only attribute + | ((mode & 0200) == 0 ? 1 : 0) // MS-DOS directory flag | (isDirectory() ? 0x10 : 0)); platform = PLATFORM_UNIX; diff --git a/src/testcases/org/apache/tools/zip/ZipEntryTest.java b/src/testcases/org/apache/tools/zip/ZipEntryTest.java index 9633e06ef..db151d654 100644 --- a/src/testcases/org/apache/tools/zip/ZipEntryTest.java +++ b/src/testcases/org/apache/tools/zip/ZipEntryTest.java @@ -131,12 +131,25 @@ public class ZipEntryTest extends TestCase { (ze.getExternalAttributes() >> 16) & 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/"); + 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); assertEquals(3, ze.getPlatform()); assertEquals(0577, (ze.getExternalAttributes() >> 16) & 0xFFFF); - assertEquals(0x10, ze.getExternalAttributes() & 0xFFFF); + assertEquals(0x11, ze.getExternalAttributes() & 0xFFFF); } }