Copilot commented on code in PR #684:
URL: https://github.com/apache/commons-compress/pull/684#discussion_r2265205411
##########
src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java:
##########
@@ -831,8 +831,131 @@ public static boolean verifyCheckSum(final byte[] header)
{
return storedSum == unsignedSum || storedSum == signedSum;
}
- /** Prevents instantiation. */
- private TarUtils() {
+ /**
+ * Determines if the given tar entry is a special tar record.
+ * <p>
+ * Special tar records are used to store metadata such as long file
names, long link names, or PAX headers
+ * that apply to the entire archive or to the next file entry.
+ * </p>
+ *
+ * @param entry the tar record to check
+ * @return {@code true} if the entry is a special tar record, {@code
false} otherwise
+ */
+ static boolean isSpecialTarRecord(final TarArchiveEntry entry) {
+ return entry.isGNULongLinkEntry()
+ || entry.isGNULongNameEntry()
+ || entry.isGlobalPaxHeader()
+ || entry.isPaxHeader();
+ }
+
+ /**
+ * Processes a special tar record and updates the provided PAX global and
per entry headers.
+ * <p>
+ * This method reads the content of the special entry from the input
stream and updates the relevant metadata structures.
+ * </p>
+ * <p>
+ * GNU long file and link names are translated to their equivalent PAX
headers.
+ * </p>
+ *
+ * @param input the input stream from which to read the special tar entry
content
+ * @param encoding the encoding to use for reading names
+ * @param entry the tar entry to handle
+ * @param paxHeaders the map to update with PAX headers
+ * @param sparseHeaders the list to update with sparse headers
+ * @param globalPaxHeaders the map to update with global PAX headers
+ * @param globalSparseHeaders the list to update with global sparse headers
+ * @throws IOException if an I/O error occurs while reading the entry
+ */
+ static void handleSpecialTarRecord(
+ final InputStream input,
+ final ZipEncoding encoding,
+ final TarArchiveEntry entry,
+ final Map<String, String> paxHeaders,
+ final List<TarArchiveStructSparse> sparseHeaders,
+ final Map<String, String> globalPaxHeaders,
+ final List<TarArchiveStructSparse> globalSparseHeaders)
+ throws IOException {
+ if (entry.isGNULongLinkEntry()) {
+ // GNU long link entry: read and store the link path
+ final String longLinkName = readLongName(input, encoding, entry);
+ paxHeaders.put("linkpath", longLinkName);
+ } else if (entry.isGNULongNameEntry()) {
+ // GNU long name entry: read and store the file path
+ final String longName = readLongName(input, encoding, entry);
+ paxHeaders.put("path", longName);
+ } else if (entry.isGlobalPaxHeader()) {
+ // Global PAX header: clear and update global PAX and sparse
headers
+ globalSparseHeaders.clear();
+ globalPaxHeaders.clear();
+ globalPaxHeaders.putAll(parsePaxHeaders(input,
globalSparseHeaders, globalPaxHeaders, entry.getSize()));
+ } else if (entry.isPaxHeader()) {
+ // PAX header: clear and update local PAX and sparse headers,
parse GNU sparse headers if present
+ sparseHeaders.clear();
+ paxHeaders.clear();
+ paxHeaders.putAll(parsePaxHeaders(input, sparseHeaders,
globalPaxHeaders, entry.getSize()));
+ if (paxHeaders.containsKey(TarGnuSparseKeys.MAP)) {
+
sparseHeaders.addAll(parseFromPAX01SparseHeaders(paxHeaders.get(TarGnuSparseKeys.MAP)));
+ }
+ }
}
+ /**
+ * Applies the PAX headers and sparse headers to the given tar entry.
+ *
+ * @param entry the tar entry to handle
+ * @param paxHeaders per file PAX headers
+ * @param sparseHeaders per file sparse headers
+ * @param globalPaxHeaders global PAX headers
+ * @param globalSparseHeaders global sparse headers
+ * @throws IOException if an I/O error occurs while reading the entry
+ */
+ static void applyPaxHeadersToEntry(
+ final TarArchiveEntry entry,
+ final Map<String, String> paxHeaders,
+ final List<TarArchiveStructSparse> sparseHeaders,
+ final Map<String, String> globalPaxHeaders,
+ final List<TarArchiveStructSparse> globalSparseHeaders) throws
IOException {
+ // Apply PAX headers to the entry
+ entry.updateEntryFromPaxHeaders(globalPaxHeaders);
+ entry.updateEntryFromPaxHeaders(paxHeaders);
+ // Apply sparse headers to the entry, unless it is a pre-pax GNU
sparse entry
+ if (!entry.isOldGNUSparse()) {
+ entry.setSparseHeaders(globalSparseHeaders);
+ if (!sparseHeaders.isEmpty()) {
+ // If there are local sparse headers, they override the global
ones
+ entry.setSparseHeaders(sparseHeaders);
+ }
+ }
+ }
+
+ /**
+ * Reads a long name (file or link name) from the input stream for a
special tar record.
+ *
+ * @param input the input stream from which to read the long name
+ * @param encoding the encoding to use for reading the name
+ * @param entry the tar entry containing the long name
+ * @return the decoded long name, with trailing NULs removed
+ * @throws IOException if an I/O error occurs or the entry is truncated
+ * @throws ArchiveException if the entry size is invalid
+ */
+ private static String readLongName(final InputStream input, final
ZipEncoding encoding, final TarArchiveEntry entry)
+ throws IOException {
+ final long size = entry.getSize();
+ if (size < 0 || size > Integer.MAX_VALUE) {
+ throw new ArchiveException("Invalid long name size: " +
entry.getSize());
+ }
+ final int sizeInt = (int) size;
+ final byte[] buffer = new byte[sizeInt];
+ if (IOUtils.readFully(input, buffer, 0, sizeInt) < buffer.length) {
Review Comment:
The comparison should be `< sizeInt` instead of `< buffer.length` since
`buffer.length` is always equal to `sizeInt`. This comparison is redundant but
not incorrect.
```suggestion
if (IOUtils.readFully(input, buffer, 0, sizeInt) < sizeInt) {
```
##########
src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java:
##########
@@ -1473,8 +1473,20 @@ private void parseTarHeader(final Map<String, String>
globalPaxHeaders, final by
}
}
- private int parseTarHeaderBlock(final byte[] header, final ZipEncoding
encoding, final boolean oldStyle, final boolean lenient, int offset)
+ /**
+ * Parses a UNIX V7 tar header block.
+ *
+ * @param header The tar entry header buffer to get information from.
+ * @param encoding The encoding to use for file names.
+ * @param oldStyle If {@code true}, file names are parsed using the old
style, i.e. without encoding.
+ * @param lenient If {@code true}, parsing of numeric fields is lenient,
i.e. it will not throw an exception if the field is not a valid octal number.
+ * @return The offset at which the UNIX V7 tar header block ends.
+ * @throws IllegalArgumentException If any of the numeric fields have an
invalid format and lenient is {@code false}.
+ * @throws IOException If an encoding error occurs while parsing the file
name or if the header is malformed.
+ */
+ private int parseTarHeaderBlock(final byte[] header, final ZipEncoding
encoding, final boolean oldStyle, final boolean lenient)
Review Comment:
The method signature changed to remove the `offset` parameter, but the
method still declares `int offset = 0` internally. This suggests the offset
should be passed as a parameter for flexibility, especially since the method is
used in parsing contexts where offset tracking is important.
##########
src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java:
##########
@@ -831,8 +831,131 @@ public static boolean verifyCheckSum(final byte[] header)
{
return storedSum == unsignedSum || storedSum == signedSum;
}
- /** Prevents instantiation. */
- private TarUtils() {
+ /**
+ * Determines if the given tar entry is a special tar record.
+ * <p>
+ * Special tar records are used to store metadata such as long file
names, long link names, or PAX headers
+ * that apply to the entire archive or to the next file entry.
+ * </p>
+ *
+ * @param entry the tar record to check
+ * @return {@code true} if the entry is a special tar record, {@code
false} otherwise
+ */
+ static boolean isSpecialTarRecord(final TarArchiveEntry entry) {
+ return entry.isGNULongLinkEntry()
+ || entry.isGNULongNameEntry()
+ || entry.isGlobalPaxHeader()
+ || entry.isPaxHeader();
+ }
+
+ /**
+ * Processes a special tar record and updates the provided PAX global and
per entry headers.
+ * <p>
+ * This method reads the content of the special entry from the input
stream and updates the relevant metadata structures.
+ * </p>
+ * <p>
+ * GNU long file and link names are translated to their equivalent PAX
headers.
+ * </p>
+ *
+ * @param input the input stream from which to read the special tar entry
content
+ * @param encoding the encoding to use for reading names
+ * @param entry the tar entry to handle
+ * @param paxHeaders the map to update with PAX headers
+ * @param sparseHeaders the list to update with sparse headers
+ * @param globalPaxHeaders the map to update with global PAX headers
+ * @param globalSparseHeaders the list to update with global sparse headers
+ * @throws IOException if an I/O error occurs while reading the entry
+ */
+ static void handleSpecialTarRecord(
+ final InputStream input,
+ final ZipEncoding encoding,
+ final TarArchiveEntry entry,
+ final Map<String, String> paxHeaders,
+ final List<TarArchiveStructSparse> sparseHeaders,
+ final Map<String, String> globalPaxHeaders,
+ final List<TarArchiveStructSparse> globalSparseHeaders)
+ throws IOException {
+ if (entry.isGNULongLinkEntry()) {
+ // GNU long link entry: read and store the link path
+ final String longLinkName = readLongName(input, encoding, entry);
+ paxHeaders.put("linkpath", longLinkName);
+ } else if (entry.isGNULongNameEntry()) {
+ // GNU long name entry: read and store the file path
+ final String longName = readLongName(input, encoding, entry);
+ paxHeaders.put("path", longName);
+ } else if (entry.isGlobalPaxHeader()) {
+ // Global PAX header: clear and update global PAX and sparse
headers
+ globalSparseHeaders.clear();
+ globalPaxHeaders.clear();
+ globalPaxHeaders.putAll(parsePaxHeaders(input,
globalSparseHeaders, globalPaxHeaders, entry.getSize()));
+ } else if (entry.isPaxHeader()) {
+ // PAX header: clear and update local PAX and sparse headers,
parse GNU sparse headers if present
+ sparseHeaders.clear();
+ paxHeaders.clear();
+ paxHeaders.putAll(parsePaxHeaders(input, sparseHeaders,
globalPaxHeaders, entry.getSize()));
+ if (paxHeaders.containsKey(TarGnuSparseKeys.MAP)) {
+
sparseHeaders.addAll(parseFromPAX01SparseHeaders(paxHeaders.get(TarGnuSparseKeys.MAP)));
+ }
+ }
}
+ /**
+ * Applies the PAX headers and sparse headers to the given tar entry.
+ *
+ * @param entry the tar entry to handle
+ * @param paxHeaders per file PAX headers
+ * @param sparseHeaders per file sparse headers
+ * @param globalPaxHeaders global PAX headers
+ * @param globalSparseHeaders global sparse headers
+ * @throws IOException if an I/O error occurs while reading the entry
+ */
+ static void applyPaxHeadersToEntry(
+ final TarArchiveEntry entry,
+ final Map<String, String> paxHeaders,
+ final List<TarArchiveStructSparse> sparseHeaders,
+ final Map<String, String> globalPaxHeaders,
+ final List<TarArchiveStructSparse> globalSparseHeaders) throws
IOException {
+ // Apply PAX headers to the entry
+ entry.updateEntryFromPaxHeaders(globalPaxHeaders);
+ entry.updateEntryFromPaxHeaders(paxHeaders);
+ // Apply sparse headers to the entry, unless it is a pre-pax GNU
sparse entry
+ if (!entry.isOldGNUSparse()) {
+ entry.setSparseHeaders(globalSparseHeaders);
+ if (!sparseHeaders.isEmpty()) {
+ // If there are local sparse headers, they override the global
ones
+ entry.setSparseHeaders(sparseHeaders);
+ }
+ }
+ }
+
+ /**
+ * Reads a long name (file or link name) from the input stream for a
special tar record.
+ *
+ * @param input the input stream from which to read the long name
+ * @param encoding the encoding to use for reading the name
+ * @param entry the tar entry containing the long name
+ * @return the decoded long name, with trailing NULs removed
+ * @throws IOException if an I/O error occurs or the entry is truncated
+ * @throws ArchiveException if the entry size is invalid
+ */
+ private static String readLongName(final InputStream input, final
ZipEncoding encoding, final TarArchiveEntry entry)
+ throws IOException {
+ final long size = entry.getSize();
+ if (size < 0 || size > Integer.MAX_VALUE) {
Review Comment:
The condition `size < 0` will never be true because `entry.getSize()`
returns a `long` and tar entry sizes cannot be negative in valid tar files.
This check is redundant and should be removed.
```suggestion
if (size > Integer.MAX_VALUE) {
```
--
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]