Skip to content

Commit

Permalink
COMPRESS-632: Fixes for dump file parsing (#442)
Browse files Browse the repository at this point in the history
* Added check for negative blocksize

* more dump tests

* removing unused imports

* fixing checkstyle violations

* moved null check to DumpArchiveUtil

* Trim whitespace

* Format and normalize tests declarations

* fix exception message to match unit test

---------

Co-authored-by: Gary Gregory <garydgregory@users.noreply.github.com>
  • Loading branch information
yakovsh and garydgregory committed Nov 28, 2023
1 parent fdc6fc2 commit 8a9a584
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public final class DumpArchiveConstants {
* The type of compression.
*/
public enum COMPRESSION_TYPE {
ZLIB(0), BZLIB(1), LZO(2);
UNKNOWN(-1), ZLIB(0), BZLIB(1), LZO(2);

public static COMPRESSION_TYPE find(final int code) {
for (final COMPRESSION_TYPE t : values()) {
Expand All @@ -35,7 +35,7 @@ public static COMPRESSION_TYPE find(final int code) {
}
}

return null;
return UNKNOWN;
}

final int code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,9 @@ final class DumpArchiveUtil {
*/
public static int calculateChecksum(final byte[] buffer) {
int calc = 0;

for (int i = 0; i < 256; i++) {
calc += DumpArchiveUtil.convert32(buffer, 4 * i);
}

return DumpArchiveConstants.CHECKSUM - (calc - DumpArchiveUtil.convert32(buffer, 28));
}

Expand Down Expand Up @@ -82,7 +80,10 @@ public static long convert64(final byte[] buffer, final int offset) {
* Decodes a byte array to a string.
*/
static String decode(final ZipEncoding encoding, final byte[] b, final int offset, final int len) throws IOException {
return encoding.decode(Arrays.copyOfRange(b, offset, offset + len));
if (offset > offset + len) {
throw new IOException("Invalid offset/length combination");
}
return encoding.decode(Arrays.copyOfRange(b, offset, offset + len));
}

/**
Expand All @@ -102,16 +103,16 @@ public static int getIno(final byte[] buffer) {
* @return Whether the buffer contains a tape segment header.
*/
public static boolean verify(final byte[] buffer) {
if (buffer == null) {
return false;
}
// verify magic. for now only accept NFS_MAGIC.
final int magic = convert32(buffer, 24);

if (magic != DumpArchiveConstants.NFS_MAGIC) {
return false;
}

// verify checksum...
final int checksum = convert32(buffer, 28);

return checksum == calculateChecksum(buffer);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,9 @@ public void resetBlockSize(final int recsPerBlock, final boolean isCompressed) t
throw new IOException("Block with " + recsPerBlock + " records found, must be at least 1");
}
blockSize = RECORD_SIZE * recsPerBlock;
if (blockSize < 1) {
throw new IOException("Block size cannot be less than or equal to 0: " + blockSize);
}

// save first block in case we need it again
final byte[] oldBuffer = blockBuffer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,20 @@ public void testSingleByteReadConsistentlyReturnsMinusOneAtEof() throws Exceptio
}
}

@Test
public void testDirectoryNullBytes() throws Exception {
try (InputStream is = newInputStream("org/apache/commons/compress/dump/directory_null_bytes.dump");
DumpArchiveInputStream archive = new DumpArchiveInputStream(is)) {
assertThrows(InvalidFormatException.class, archive::getNextEntry);
}
}

@Test
public void testInvalidCompressType() throws Exception {
try (InputStream is = newInputStream("org/apache/commons/compress/dump/invalid_compression_type.dump")) {
final ArchiveException ex = assertThrows(ArchiveException.class, () -> new DumpArchiveInputStream(is).close());
assertInstanceOf(UnsupportedCompressionAlgorithmException.class, ex.getCause());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
*/
package org.apache.commons.compress.archivers.dump;

import static org.junit.Assert.assertThrows;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;

import java.io.IOException;

import org.junit.jupiter.api.Test;

Expand All @@ -38,4 +42,21 @@ public void testConvert32() {
public void testConvert64() {
assertEquals(0xABCDEF0123456780L, DumpArchiveUtil.convert64(new byte[] { (byte) 0x80, 0x67, 0x45, 0x23, 1, (byte) 0xEF, (byte) 0xCD, (byte) 0xAB }, 0));
}

@Test
public void testDecodeInvalidArguments() {
assertThrows(IOException.class, () -> DumpArchiveUtil.decode(null, new byte[10], 10, -1));
}

@Test
public void testVerifyNullArgument() {
assertFalse(DumpArchiveUtil.verify(null));
}

@Test
public void testVerifyNoMagic() {
assertFalse(DumpArchiveUtil.verify(new byte[32]));
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.commons.compress.archivers.dump;

import static org.junit.jupiter.api.Assertions.assertThrows;

import java.io.ByteArrayInputStream;
import java.io.IOException;

import org.apache.commons.compress.AbstractTest;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class TapeInputStreamTest extends AbstractTest {
@ParameterizedTest
@ValueSource(ints = {-1, 0, Integer.MAX_VALUE / 1000, Integer.MAX_VALUE})
public void testResetBlockSizeWithInvalidValues(final int recsPerBlock) throws Exception {
try (TapeInputStream tapeInputStream = new TapeInputStream(new ByteArrayInputStream(new byte[1]))) {
assertThrows(IOException.class, () -> tapeInputStream.resetBlockSize(recsPerBlock, true));
}
}
}
Binary file not shown.
Binary file not shown.

0 comments on commit 8a9a584

Please sign in to comment.