Skip to content
17 changes: 2 additions & 15 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ Brotli, Zstandard and ar, cpio, jar, tar, zip, dump, 7z, arj.
<checkstyle.config.file>${basedir}/src/conf/checkstyle/checkstyle.xml</checkstyle.config.file>
<checkstyle.suppress.file>${basedir}/src/conf/checkstyle/checkstyle-suppressions.xml</checkstyle.suppress.file>
<checkstyle.resourceExcludes>LICENSE.txt, NOTICE.txt, **/maven-archiver/pom.properties</checkstyle.resourceExcludes>
<!-- Temporary overrides of versions defined by parent pom. -->
<commons.japicmp.version>0.24.1</commons.japicmp.version>
</properties>
<issueManagement>
<system>jira</system>
Expand Down Expand Up @@ -289,21 +291,6 @@ Brotli, Zstandard and ar, cpio, jar, tar, zip, dump, 7z, arj.
<artifactId>maven-bundle-plugin</artifactId>
<version>${commons.felix.version}</version>
</plugin>
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<configuration>
<parameter>
<excludes>
<!-- Compress 1.21 -> 1.22 updates ASM from 3.2 to 9.2 for pack200 implementation. -->
<exclude>org.apache.commons.compress.harmony.pack200.Segment</exclude>
<exclude>org.apache.commons.compress.harmony.pack200.SegmentMethodVisitor</exclude>
<exclude>org.apache.commons.compress.harmony.pack200.SegmentAnnotationVisitor</exclude>
<exclude>org.apache.commons.compress.harmony.pack200.SegmentFieldVisitor</exclude>
</excludes>
</parameter>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
Expand Down
2 changes: 2 additions & 0 deletions src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ The <action> type attribute can be add,update,fix,remove.
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary Gregory">Bump org.apache.commons:commons-parent from 85 to 88 #707.</action>
<action type="update" dev="ggregory" due-to="Gary Gregory">Bump org.apache.commons:commons-lang3 from 3.18.0 to 3.19.0.</action>
<!-- REMOVE -->
<action type="remove" dev="pkarwasz" due-to="Piotr P. Karwasz">Makes TarUtils final and cleans up protected methods #712.</action>
</release>
<release version="1.28.0" date="2025-07-26" description="This is a feature and maintenance release. Java 8 or later is required.">
<!-- FIX -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@
*
* @Immutable
*/
// CheckStyle:HideUtilityClassConstructorCheck OFF (bc)
public class TarUtils {
public final class TarUtils {

private static final Pattern HEADER_STRINGS_PATTERN = Pattern.compile(",");

Expand Down Expand Up @@ -461,7 +460,7 @@ public static boolean parseBoolean(final byte[] buffer, final int offset) {
* @throws IOException Corrupted TAR archive.
* @since 1.21
*/
protected static List<TarArchiveStructSparse> parseFromPAX01SparseHeaders(final String sparseMap) throws IOException {
static List<TarArchiveStructSparse> parseFromPAX01SparseHeaders(final String sparseMap) throws IOException {
final List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
final String[] sparseHeaderStrings = HEADER_STRINGS_PATTERN.split(sparseMap);
if (sparseHeaderStrings.length % 2 == 1) {
Expand Down Expand Up @@ -614,30 +613,6 @@ public static long parseOctalOrBinary(final byte[] buffer, final int offset, fin
return parseBinaryBigInteger(buffer, offset, length, negative);
}

/**
* For PAX Format 0.1, the sparse headers are stored in a single variable : GNU.sparse.map
*
* <p>
* <em>GNU.sparse.map</em>: Map of non-null data chunks. It is a string consisting of comma-separated values "offset,size[,offset-1,size-1...]"
* </p>
* <p>
* Will internally invoke {@link #parseFromPAX01SparseHeaders} and map IOExceptions to a RzuntimeException, You should use
* {@link #parseFromPAX01SparseHeaders} directly instead.
* </p>
*
* @param sparseMap the sparse map string consisting of comma-separated values "offset,size[,offset-1,size-1...]".
* @return sparse headers parsed from sparse map.
* @deprecated use #parseFromPAX01SparseHeaders instead.
*/
@Deprecated
protected static List<TarArchiveStructSparse> parsePAX01SparseHeaders(final String sparseMap) {
try {
return parseFromPAX01SparseHeaders(sparseMap);
} catch (final IOException ex) {
throw new UncheckedIOException(ex.getMessage(), ex);
}
}

/**
* For PAX Format 1.X: The sparse map itself is stored in the file data block, preceding the actual file data. It consists of a series of decimal numbers
* delimited by newlines. The map is padded with nulls to the nearest block boundary. The first number gives the number of entries in the map. Following are
Expand All @@ -648,7 +623,7 @@ protected static List<TarArchiveStructSparse> parsePAX01SparseHeaders(final Stri
* @return sparse headers.
* @throws IOException if an I/O error occurs.
*/
protected static List<TarArchiveStructSparse> parsePAX1XSparseHeaders(final InputStream inputStream, final int recordSize) throws IOException {
static List<TarArchiveStructSparse> parsePAX1XSparseHeaders(final InputStream inputStream, final int recordSize) throws IOException {
// for 1.X PAX Headers
final List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();
long bytesRead = 0;
Expand Down Expand Up @@ -681,37 +656,6 @@ protected static List<TarArchiveStructSparse> parsePAX1XSparseHeaders(final Inpu
return sparseHeaders;
}

/**
* For PAX Format 0.0, the sparse headers(GNU.sparse.offset and GNU.sparse.numbytes) may appear multi times, and they look like:
*
* <pre>
* GNU.sparse.size=size
* GNU.sparse.numblocks=numblocks
* repeat numblocks times
* GNU.sparse.offset=offset
* GNU.sparse.numbytes=numbytes
* end repeat
* </pre>
* <p>
* For PAX Format 0.1, the sparse headers are stored in a single variable: GNU.sparse.map
* </p>
* <p>
* <em>GNU.sparse.map</em>: Map of non-null data chunks. It is a string consisting of comma-separated values "offset,size[,offset-1,size-1...]"
* </p>
*
* @param inputStream input stream to read keys and values.
* @param sparseHeaders used in PAX Format 0.0 &amp; 0.1, as it may appear multiple times, the sparse headers need to be stored in an array, not a map.
* @param globalPaxHeaders global PAX headers of the tar archive.
* @return map of PAX headers values found inside the current (local or global) PAX headers tar entry.
* @throws IOException if an I/O error occurs.
* @deprecated use the four-arg version instead.
*/
@Deprecated
protected static Map<String, String> parsePaxHeaders(final InputStream inputStream, final List<TarArchiveStructSparse> sparseHeaders,
final Map<String, String> globalPaxHeaders) throws IOException {
return parsePaxHeaders(inputStream, sparseHeaders, globalPaxHeaders, -1);
}

/**
* For PAX Format 0.0, the sparse headers(GNU.sparse.offset and GNU.sparse.numbytes) may appear multi times, and they look like:
*
Expand All @@ -733,13 +677,17 @@ protected static Map<String, String> parsePaxHeaders(final InputStream inputStre
* @param inputStream input stream to read keys and values
* @param sparseHeaders used in PAX Format 0.0 &amp; 0.1, as it may appear multiple times, the sparse headers need to be stored in an array, not a map
* @param globalPaxHeaders global PAX headers of the tar archive
* @param headerSize total size of the PAX header, will be ignored if negative
* @param headerSize total size of the PAX header
* @return map of PAX headers values found inside the current (local or global) PAX headers tar entry.
* @throws IOException if an I/O error occurs.
* @since 1.21
*/
protected static Map<String, String> parsePaxHeaders(final InputStream inputStream, final List<TarArchiveStructSparse> sparseHeaders,
final Map<String, String> globalPaxHeaders, final long headerSize) throws IOException {
static Map<String, String> parsePaxHeaders(
final InputStream inputStream,
final List<TarArchiveStructSparse> sparseHeaders,
final Map<String, String> globalPaxHeaders,
final long headerSize)
throws IOException {
final Map<String, String> headers = new HashMap<>(globalPaxHeaders);
Long offset = null;
// Format is "length keyword=value\n";
Expand All @@ -760,7 +708,7 @@ protected static Map<String, String> parsePaxHeaders(final InputStream inputStre
while ((ch = inputStream.read()) != -1) {
read++;
totalRead++;
if (totalRead < 0 || headerSize >= 0 && totalRead >= headerSize) {
if (totalRead < 0 || totalRead >= headerSize) {
break;
}
if (ch == '=') { // end of keyword
Expand All @@ -769,7 +717,7 @@ protected static Map<String, String> parsePaxHeaders(final InputStream inputStre
final int restLen = len - read;
if (restLen <= 1) { // only NL
headers.remove(keyword);
} else if (headerSize >= 0 && restLen > headerSize - totalRead) {
} else if (restLen > headerSize - totalRead) {
throw new ArchiveException("PAX header value size %,d exceeds size of header record.", restLen);
} else {
final byte[] rest = IOUtils.readRange(inputStream, restLen);
Expand All @@ -791,9 +739,10 @@ protected static Map<String, String> parsePaxHeaders(final InputStream inputStre
sparseHeaders.add(new TarArchiveStructSparse(offset, 0));
}
try {
offset = Long.valueOf(value);
} catch (final NumberFormatException ex) {
throw new ArchiveException("Failed to read PAX header: Offset %s contains a non-numeric value.",
offset = ParsingUtils.parseLongValue(value);
} catch (final IOException ex) {
throw new ArchiveException(
"Failed to read PAX header: Offset %s contains a non-numeric value.",
TarGnuSparseKeys.OFFSET);
}
if (offset < 0) {
Expand All @@ -806,7 +755,14 @@ protected static Map<String, String> parsePaxHeaders(final InputStream inputStre
throw new ArchiveException("Failed to read PAX header: %s is expected before GNU.sparse.numbytes shows up.",
TarGnuSparseKeys.OFFSET);
}
final long numbytes = ParsingUtils.parseLongValue(value);
final long numbytes;
try {
numbytes = ParsingUtils.parseLongValue(value);
} catch (final IOException ex) {
throw new ArchiveException(
"Failed to read PAX header: Numbytes %s contains a non-numeric value.",
TarGnuSparseKeys.NUMBYTES);
}
if (numbytes < 0) {
throw new ArchiveException("Failed to read PAX header: %s contains negative value.", TarGnuSparseKeys.NUMBYTES);
}
Expand Down
Loading
Loading