Use PAX headers for big or negative numeric values in tar headers. COMPRESS-182
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@1297339 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
index 9c05fe7..ca95de3 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java
@@ -237,14 +237,10 @@
}
}
- if (entry.getSize() > TarConstants.MAXSIZE) {
- if (bigFileMode == BIGFILE_POSIX) {
- paxHeaders.put("size", String.valueOf(entry.getSize()));
- } else if (bigFileMode != BIGFILE_STAR) {
- throw new RuntimeException("file size '" + entry.getSize()
- + "' is too big ( > "
- + TarConstants.MAXSIZE + " bytes)");
- }
+ if (bigFileMode == BIGFILE_POSIX) {
+ addPaxHeadersForBigNumbers(paxHeaders, entry);
+ } else if (bigFileMode != BIGFILE_STAR) {
+ failForBigNumbers(entry);
}
if (paxHeaders.size() > 0) {
@@ -450,4 +446,58 @@
}
return new TarArchiveEntry(inputFile, entryName);
}
+
+ private void addPaxHeadersForBigNumbers(Map<String, String> paxHeaders,
+ TarArchiveEntry entry) {
+ if (entry.getSize() > TarConstants.MAXSIZE) {
+ paxHeaders.put("size", String.valueOf(entry.getSize()));
+ }
+ if (entry.getGroupId() > TarConstants.MAXID) {
+ paxHeaders.put("gid", String.valueOf(entry.getGroupId()));
+ }
+ final long mtime = entry.getModTime().getTime() / 1000;
+ if (mtime < 0 || mtime > TarConstants.MAXSIZE) {
+ paxHeaders.put("mtime", String.valueOf(mtime));
+ }
+ if (entry.getUserId() > TarConstants.MAXID) {
+ paxHeaders.put("uid", String.valueOf(entry.getUserId()));
+ }
+ if (entry.getMode() > TarConstants.MAXID) {
+ throw new RuntimeException("mode '" + entry.getMode()
+ + "' is too big ( > "
+ + TarConstants.MAXID + " bytes)");
+ }
+ // TODO add devMajor and devMinor
+ }
+
+ private void failForBigNumbers(TarArchiveEntry entry) {
+ if (entry.getSize() > TarConstants.MAXSIZE) {
+ throw new RuntimeException("file size '" + entry.getSize()
+ + "' is too big ( > "
+ + TarConstants.MAXSIZE + " bytes)");
+ }
+ if (entry.getGroupId() > TarConstants.MAXID) {
+ throw new RuntimeException("group id '" + entry.getGroupId()
+ + "' is too big ( > "
+ + TarConstants.MAXID + " bytes)");
+ }
+ final long mtime = entry.getModTime().getTime() / 1000;
+ if (mtime < 0 || mtime > TarConstants.MAXSIZE) {
+ throw new RuntimeException("last modification time '"
+ + entry.getModTime()
+ + "' is too big ( > "
+ + TarConstants.MAXSIZE + " bytes)");
+ }
+ if (entry.getUserId() > TarConstants.MAXID) {
+ throw new RuntimeException("user id '" + entry.getUserId()
+ + "' is too big ( > "
+ + TarConstants.MAXID + " bytes)");
+ }
+ if (entry.getMode() > TarConstants.MAXID) {
+ throw new RuntimeException("mode '" + entry.getMode()
+ + "' is too big ( > "
+ + TarConstants.MAXID + " bytes)");
+ }
+ // TODO add devMajor and devMinor
+ }
}
diff --git a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStreamTest.java b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStreamTest.java
index 0e8a52b..1b1f656 100644
--- a/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStreamTest.java
+++ b/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStreamTest.java
@@ -233,4 +233,45 @@
assertEquals(cal.getTime(), e.getLastModifiedDate());
}
+ public void testOldEntryPosixMode() throws Exception {
+ TarArchiveEntry t = new TarArchiveEntry("foo");
+ t.setSize(Integer.MAX_VALUE);
+ t.setModTime(-1000);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ TarArchiveOutputStream tos = new TarArchiveOutputStream(bos);
+ tos.setBigFileMode(TarArchiveOutputStream.BIGFILE_POSIX);
+ tos.putArchiveEntry(t);
+ // make sure header is written to byte array
+ tos.write(new byte[10 * 1024]);
+ byte[] data = bos.toByteArray();
+ assertEquals("00000000000 ",
+ new String(data,
+ 1024 + TarConstants.NAMELEN
+ + TarConstants.MODELEN
+ + TarConstants.UIDLEN
+ + TarConstants.GIDLEN
+ + TarConstants.SIZELEN, 12,
+ "UTF-8"));
+ TarArchiveInputStream tin =
+ new TarArchiveInputStream(new ByteArrayInputStream(data));
+ TarArchiveEntry e = tin.getNextTarEntry();
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+ cal.set(1969, 11, 31, 23, 59, 59);
+ cal.set(Calendar.MILLISECOND, 0);
+ assertEquals(cal.getTime(), e.getLastModifiedDate());
+ }
+
+ public void testOldEntryError() throws Exception {
+ TarArchiveEntry t = new TarArchiveEntry("foo");
+ t.setSize(Integer.MAX_VALUE);
+ t.setModTime(-1000);
+ TarArchiveOutputStream tos =
+ new TarArchiveOutputStream(new ByteArrayOutputStream());
+ try {
+ tos.putArchiveEntry(t);
+ fail("Should have generated RuntimeException");
+ } catch (RuntimeException expected) {
+ }
+ }
+
}
\ No newline at end of file