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]

Reply via email to