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]

Reply via email to