Split magic into magic and version
Improve match() method so it works for Posix and GNU
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/compress/trunk@761475 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
index fdba86c..860d0eb 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java
@@ -54,24 +54,25 @@
* The C structure for a Tar Entry's header is:
* <pre>
* struct header {
- * char name[100]; // TarConstants.NAMELEN
- * char mode[8]; // TarConstants.MODELEN
- * char uid[8]; // TarConstants.UIDLEN
- * char gid[8]; // TarConstants.GIDLEN
- * char size[12]; // TarConstants.SIZELEN
- * char mtime[12]; // TarConstants.MODTIMELEN
- * char chksum[8]; // TarConstants.CHKSUMLEN
- * char linkflag[1];
- * char linkname[100]; // TarConstants.NAMELEN
+ * char name[100]; // TarConstants.NAMELEN - offset 0
+ * char mode[8]; // TarConstants.MODELEN - offset 100
+ * char uid[8]; // TarConstants.UIDLEN - offset 108
+ * char gid[8]; // TarConstants.GIDLEN - offset 116
+ * char size[12]; // TarConstants.SIZELEN - offset 124
+ * char mtime[12]; // TarConstants.MODTIMELEN - offset 136
+ * char chksum[8]; // TarConstants.CHKSUMLEN - offset 148
+ * char linkflag[1]; // - offset 156
+ * char linkname[100]; // TarConstants.NAMELEN - offset 157
* The following fields are only present in new-style POSIX tar archives:
- * char magic[8]; // TarConstants.MAGICLEN
- * TODO: Posix/GNU split this into magic[6] and char version[2];
- * char uname[32]; // TarConstants.UNAMELEN
- * char gname[32]; // TarConstants.GNAMELEN
- * char devmajor[8]; // TarConstants.DEVLEN
- * char devminor[8]; // TarConstants.DEVLEN
- * char prefix[155]; // Used if "name" field is not long enough to hold the path
- * char pad[12]; // NULs
+ * char magic[6]; // TarConstants.MAGICLEN - offset 257
+ * char version[2]; // TarConstants.VERSIONLEN - offset 263
+ * char uname[32]; // TarConstants.UNAMELEN - offset 265
+ * char gname[32]; // TarConstants.GNAMELEN - offset 297
+ * char devmajor[8]; // TarConstants.DEVLEN - offset 329
+ * char devminor[8]; // TarConstants.DEVLEN - offset 337
+ * char prefix[155]; // TarConstants.PREFIXLEN - offset 345
+ * // Used if "name" field is not long enough to hold the path
+ * char pad[12]; // NULs - offset 500
* } header;
* All unused bytes are set to null.
* New-style GNU tar files are slightly different from the above.
@@ -107,6 +108,8 @@
/** The entry's magic tag. */
private String magic;
+ /** The version of the format */
+ private String version;
/** The entry's user name. */
private String userName;
@@ -140,6 +143,7 @@
*/
private TarArchiveEntry () {
this.magic = MAGIC_POSIX;
+ this.version = VERSION_POSIX;
this.name = "";
this.linkName = "";
@@ -577,6 +581,7 @@
outbuf[offset++] = linkFlag;
offset = TarUtils.formatNameBytes(linkName, outbuf, offset, NAMELEN);
offset = TarUtils.formatNameBytes(magic, outbuf, offset, MAGICLEN);
+ offset = TarUtils.formatNameBytes(version, outbuf, offset, VERSIONLEN);
offset = TarUtils.formatNameBytes(userName, outbuf, offset, UNAMELEN);
offset = TarUtils.formatNameBytes(groupName, outbuf, offset, GNAMELEN);
offset = TarUtils.formatOctalBytes(devMajor, outbuf, offset, DEVLEN);
@@ -617,6 +622,8 @@
offset += NAMELEN;
magic = TarUtils.parseName(header, offset, MAGICLEN);
offset += MAGICLEN;
+ version = TarUtils.parseName(header, offset, VERSIONLEN);
+ offset += VERSIONLEN;
userName = TarUtils.parseName(header, offset, UNAMELEN);
offset += UNAMELEN;
groupName = TarUtils.parseName(header, offset, GNAMELEN);
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
index d3b9611..1d18efa 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java
@@ -28,6 +28,7 @@
import java.io.OutputStream;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
+import org.apache.commons.compress.utils.ArchiveUtils;
/**
* The TarInputStream reads a UNIX tar archive as an InputStream.
@@ -380,39 +381,32 @@
// ArchiveInputStream
public static boolean matches(byte[] signature, int length) {
- // 6574 7473 2e31 6d78 == "test1.xml"
- // TODO replace with a proper test if possible - see COMPRESS-65
-
- if (length < 8) {
+ if (length < TarConstants.VERSION_OFFSET+TarConstants.VERSIONLEN) {
return false;
}
- if (signature[0] != 0x74) {
- return false;
+ if (ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_POSIX,
+ signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN)
+ &&
+ ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_POSIX,
+ signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN)
+ ){
+ return true;
}
- if (signature[1] != 0x65) {
- return false;
+ if (ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_GNU,
+ signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN)
+ &&
+ (
+ ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_GNU_SPACE,
+ signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN)
+ ||
+ ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_GNU_ZERO,
+ signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN)
+ )
+ ){
+ return true;
}
- if (signature[2] != 0x73) {
- return false;
- }
- if (signature[3] != 0x74) {
- return false;
- }
- if (signature[4] != 0x31) {
- return false;
- }
- if (signature[5] != 0x2e) {
- return false;
- }
- if (signature[6] != 0x78) {
- return false;
- }
- if (signature[7] != 0x6d) {
- return false;
- }
-
- return true;
+ return false;
}
}
diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
index 00aebe7..8abf3d3 100644
--- a/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
+++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java
@@ -60,10 +60,19 @@
*/
long MAXSIZE = 077777777777L;
+ /** Offset of start of magic field within header record */
+ int MAGIC_OFFSET = 257;
/**
* The length of the magic field in a header buffer.
*/
- int MAGICLEN = 8; // TODO split this into MAGICLEN=6 and VERSIONLEN=2
+ int MAGICLEN = 6;
+
+ /** Offset of start of magic field within header record */
+ int VERSION_OFFSET = 263;
+ /**
+ * Previously this was regarded as part of "magic" field, but it is separate.
+ */
+ int VERSIONLEN = 2;
/**
* The length of the modification time field in a header buffer.
@@ -86,6 +95,12 @@
int DEVLEN = 8;
/**
+ * Length of the prefix field.
+ *
+ */
+ int PREFIXLEN = 155;
+
+ /**
* LF_ constants represent the "link flag" of an entry, or more commonly,
* the "entry type". This is the "old way" of indicating a normal file.
*/
@@ -134,12 +149,16 @@
/**
* The magic tag representing a POSIX tar archive.
*/
- String MAGIC_POSIX = "ustar"; // TODO this should be NUL-terminated
+ String MAGIC_POSIX = "ustar\0";
+ String VERSION_POSIX = "00";
/**
* The magic tag representing a GNU tar archive.
*/
- String MAGIC_GNU = "ustar "; // TODO this should have single space terminator
+ String MAGIC_GNU = "ustar ";
+ // Appear to be two possible GNU versions
+ String VERSION_GNU_SPACE = " \0";
+ String VERSION_GNU_ZERO = "0\0";
/**
* The name of the GNU tar entry which contains a long name.