kali834x commented on code in PR #780:
URL: https://github.com/apache/commons-compress/pull/780#discussion_r3534037907
##########
src/test/java/org/apache/commons/compress/archivers/tar/SparseFilesTest.java:
##########
@@ -532,4 +536,89 @@ void testTarFilePaxGNU() throws IOException {
assertPaxGNUEntry(entries.get(2), "1.0");
}
}
+
+ private static void appendPadded(final ByteArrayOutputStream out, final
byte[] data) {
+ out.write(data, 0, data.length);
+ final int rem = data.length % 512;
+ if (rem != 0) {
+ out.write(new byte[512 - rem], 0, 512 - rem);
+ }
+ }
+
+ private static String paxRecord(final String key, final String value) {
+ final int size = key.length() + value.length() + 3; // ' ', '=', '\n'
+ int len = size + Integer.toString(size).length();
+ while (len != size + Integer.toString(len).length()) {
+ len = size + Integer.toString(len).length();
+ }
+ return len + " " + key + "=" + value + "\n";
+ }
+
+ private static void putField(final byte[] header, final int offset, final
int length, final String value) {
+ final byte[] bytes =
value.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ System.arraycopy(bytes, 0, header, offset, Math.min(length,
bytes.length));
+ }
+
+ private static void putOctal(final byte[] header, final int offset, final
int length, final long value) {
+ putField(header, offset, length, String.format("%0" + (length - 1) +
"o", value));
+ }
+
+ private static byte[] ustarHeader(final String name, final long size,
final char typeFlag) {
+ final byte[] header = new byte[512];
+ putField(header, 0, 100, name);
+ putOctal(header, 100, 8, 0644);
+ putOctal(header, 108, 8, 0);
+ putOctal(header, 116, 8, 0);
+ putOctal(header, 124, 12, size);
+ putOctal(header, 136, 12, 0);
+ java.util.Arrays.fill(header, 148, 156, (byte) ' '); // checksum
placeholder
+ header[156] = (byte) typeFlag;
+ putField(header, 257, 6, "ustar");
+ header[263] = '0';
+ header[264] = '0';
+ long checksum = 0;
+ for (final byte b : header) {
+ checksum += b & 0xff;
+ }
+ putField(header, 148, 6, String.format("%06o", checksum));
+ header[154] = 0;
+ header[155] = ' ';
+ return header;
+ }
+
+ // Builds a PAX GNU 0.1 sparse entry whose stored size is 4 bytes but
whose sparse map claims a
+ // single 1 MiB data block. realsize equals the block size, so the
existing realSize check passes.
+ // A second entry follows, whose bytes must not be reachable through the
sparse entry.
+ private byte[] sparseArchiveWithNumbytesLargerThanSize() {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final String pax = paxRecord("GNU.sparse.size", "1048576") +
paxRecord("GNU.sparse.map", "0,1048576");
+ final byte[] paxData =
pax.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ appendPadded(bos, ustarHeader("PaxHeaders/sparse.bin", paxData.length,
'x'));
+ appendPadded(bos, paxData);
+ appendPadded(bos, ustarHeader("sparse.bin", 4, '0'));
+ appendPadded(bos, new byte[] { 1, 2, 3, 4 });
+ final byte[] payload = "the following
entry".getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ appendPadded(bos, ustarHeader("next.bin", payload.length, '0'));
+ appendPadded(bos, payload);
+ bos.write(new byte[1024], 0, 1024); // two zero EOF records
Review Comment:
Not a coincidence, it's exactly two 512-byte end-of-archive records. Now
written as 2 * TarConstants.DEFAULT_RCDSIZE so the relationship is explicit.
##########
src/test/java/org/apache/commons/compress/archivers/tar/SparseFilesTest.java:
##########
@@ -532,4 +536,89 @@ void testTarFilePaxGNU() throws IOException {
assertPaxGNUEntry(entries.get(2), "1.0");
}
}
+
+ private static void appendPadded(final ByteArrayOutputStream out, final
byte[] data) {
+ out.write(data, 0, data.length);
+ final int rem = data.length % 512;
+ if (rem != 0) {
+ out.write(new byte[512 - rem], 0, 512 - rem);
+ }
+ }
+
+ private static String paxRecord(final String key, final String value) {
+ final int size = key.length() + value.length() + 3; // ' ', '=', '\n'
+ int len = size + Integer.toString(size).length();
+ while (len != size + Integer.toString(len).length()) {
+ len = size + Integer.toString(len).length();
+ }
+ return len + " " + key + "=" + value + "\n";
+ }
+
+ private static void putField(final byte[] header, final int offset, final
int length, final String value) {
+ final byte[] bytes =
value.getBytes(java.nio.charset.StandardCharsets.US_ASCII);
+ System.arraycopy(bytes, 0, header, offset, Math.min(length,
bytes.length));
+ }
+
+ private static void putOctal(final byte[] header, final int offset, final
int length, final long value) {
+ putField(header, offset, length, String.format("%0" + (length - 1) +
"o", value));
+ }
+
+ private static byte[] ustarHeader(final String name, final long size,
final char typeFlag) {
+ final byte[] header = new byte[512];
+ putField(header, 0, 100, name);
+ putOctal(header, 100, 8, 0644);
+ putOctal(header, 108, 8, 0);
+ putOctal(header, 116, 8, 0);
+ putOctal(header, 124, 12, size);
+ putOctal(header, 136, 12, 0);
+ java.util.Arrays.fill(header, 148, 156, (byte) ' '); // checksum
placeholder
+ header[156] = (byte) typeFlag;
+ putField(header, 257, 6, "ustar");
+ header[263] = '0';
+ header[264] = '0';
+ long checksum = 0;
+ for (final byte b : header) {
+ checksum += b & 0xff;
+ }
+ putField(header, 148, 6, String.format("%06o", checksum));
+ header[154] = 0;
+ header[155] = ' ';
+ return header;
+ }
+
+ // Builds a PAX GNU 0.1 sparse entry whose stored size is 4 bytes but
whose sparse map claims a
+ // single 1 MiB data block. realsize equals the block size, so the
existing realSize check passes.
+ // A second entry follows, whose bytes must not be reachable through the
sparse entry.
+ private byte[] sparseArchiveWithNumbytesLargerThanSize() {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final String pax = paxRecord("GNU.sparse.size", "1048576") +
paxRecord("GNU.sparse.map", "0,1048576");
Review Comment:
Yes, intentionally the same value: realsize has to equal the map's numbytes
sum so the archive passes the existing realSize check and only the new bound
rejects it. Pulled it into a SPARSE_MAP_NUMBYTES constant used by both records.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]