Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
garydgregory committed Mar 18, 2022
2 parents 104bf55 + b7f0cbb commit 9248afd
Show file tree
Hide file tree
Showing 28 changed files with 1,149 additions and 48 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ public TarArchiveEntry getNextTarEntry() throws IOException {
}

try {
currEntry = new TarArchiveEntry(headerBuf, zipEncoding, lenient);
currEntry = new TarArchiveEntry(globalPaxHeaders, headerBuf, zipEncoding, lenient);
} catch (final IllegalArgumentException e) {
throw new IOException("Error detected parsing the header", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,17 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
Expand Down Expand Up @@ -230,8 +234,8 @@ public TarArchiveOutputStream(final OutputStream os, final int blockSize,
}

/**
* Set the long file mode. This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1) or
* LONGFILE_GNU(2). This specifies the treatment of long file names (names >=
* Set the long file mode. This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1), LONGFILE_GNU(2) or
* LONGFILE_POSIX(3). This specifies the treatment of long file names (names >=
* TarConstants.NAMELEN). Default is LONGFILE_ERROR.
*
* @param longFileMode the mode to use
Expand All @@ -241,9 +245,9 @@ public void setLongFileMode(final int longFileMode) {
}

/**
* Set the big number mode. This can be BIGNUMBER_ERROR(0), BIGNUMBER_POSIX(1) or
* BIGNUMBER_STAR(2). This specifies the treatment of big files (sizes >
* TarConstants.MAXSIZE) and other numeric values to big to fit into a traditional tar header.
* Set the big number mode. This can be BIGNUMBER_ERROR(0), BIGNUMBER_STAR(1) or
* BIGNUMBER_POSIX(2). This specifies the treatment of big files (sizes >
* TarConstants.MAXSIZE) and other numeric values too big to fit into a traditional tar header.
* Default is BIGNUMBER_ERROR.
*
* @param bigNumberMode the mode to use
Expand Down Expand Up @@ -367,7 +371,6 @@ public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException
final String entryName = entry.getName();
final boolean paxHeaderContainsPath = handleLongName(entry, entryName, paxHeaders, "path",
TarConstants.LF_GNUTYPE_LONGNAME, "file name");

final String linkName = entry.getLinkName();
final boolean paxHeaderContainsLinkPath = linkName != null && !linkName.isEmpty()
&& handleLongName(entry, linkName, paxHeaders, "linkpath",
Expand Down Expand Up @@ -602,12 +605,20 @@ private void addPaxHeadersForBigNumbers(final Map<String, String> paxHeaders,
TarConstants.MAXSIZE);
addPaxHeaderForBigNumber(paxHeaders, "gid", entry.getLongGroupId(),
TarConstants.MAXID);
addPaxHeaderForBigNumber(paxHeaders, "mtime",
entry.getModTime().getTime() / 1000,
TarConstants.MAXSIZE);
addFileTimePaxHeaderForBigNumber(paxHeaders, "mtime",
entry.getLastModifiedTime(), TarConstants.MAXSIZE);
addFileTimePaxHeader(paxHeaders, "atime", entry.getLastAccessTime());
if (entry.getStatusChangeTime() != null) {
addFileTimePaxHeader(paxHeaders, "ctime", entry.getStatusChangeTime());
} else {
// ctime is usually set from creation time on platforms where the real ctime is not available
addFileTimePaxHeader(paxHeaders, "ctime", entry.getCreationTime());
}
addPaxHeaderForBigNumber(paxHeaders, "uid", entry.getLongUserId(),
TarConstants.MAXID);
// star extensions by J\u00f6rg Schilling
// libarchive extensions
addFileTimePaxHeader(paxHeaders, "LIBARCHIVE.creationtime", entry.getCreationTime());
// star extensions by Jörg Schilling
addPaxHeaderForBigNumber(paxHeaders, "SCHILY.devmajor",
entry.getDevMajor(), TarConstants.MAXID);
addPaxHeaderForBigNumber(paxHeaders, "SCHILY.devminor",
Expand All @@ -624,11 +635,48 @@ private void addPaxHeaderForBigNumber(final Map<String, String> paxHeaders,
}
}

private void addFileTimePaxHeaderForBigNumber(final Map<String, String> paxHeaders,
final String header, final FileTime value,
final long maxValue) {
if (value != null) {
final Instant instant = value.toInstant();
final long seconds = instant.getEpochSecond();
final int nanos = instant.getNano();
if (nanos == 0) {
addPaxHeaderForBigNumber(paxHeaders, header, seconds, maxValue);
} else {
addInstantPaxHeader(paxHeaders, header, seconds, nanos);
}
}
}

private void addFileTimePaxHeader(final Map<String, String> paxHeaders,
final String header, final FileTime value) {
if (value != null) {
final Instant instant = value.toInstant();
final long seconds = instant.getEpochSecond();
final int nanos = instant.getNano();
if (nanos == 0) {
paxHeaders.put(header, String.valueOf(seconds));
} else {
addInstantPaxHeader(paxHeaders, header, seconds, nanos);
}
}
}

private void addInstantPaxHeader(final Map<String, String> paxHeaders,
final String header, final long seconds, final int nanos) {
final BigDecimal bdSeconds = BigDecimal.valueOf(seconds);
final BigDecimal bdNanos = BigDecimal.valueOf(nanos).movePointLeft(9).setScale(7, RoundingMode.DOWN);
final BigDecimal timestamp = bdSeconds.add(bdNanos);
paxHeaders.put(header, timestamp.toPlainString());
}

private void failForBigNumbers(final TarArchiveEntry entry) {
failForBigNumber("entry size", entry.getSize(), TarConstants.MAXSIZE);
failForBigNumberWithPosixMessage("group id", entry.getLongGroupId(), TarConstants.MAXID);
failForBigNumber("last modification time",
entry.getModTime().getTime() / 1000,
entry.getLastModifiedTime().to(TimeUnit.SECONDS),
TarConstants.MAXSIZE);
failForBigNumber("user id", entry.getLongUserId(), TarConstants.MAXID);
failForBigNumber("mode", entry.getMode(), TarConstants.MAXID);
Expand Down Expand Up @@ -711,11 +759,10 @@ private boolean handleLongName(final TarArchiveEntry entry, final String name,
}

private void transferModTime(final TarArchiveEntry from, final TarArchiveEntry to) {
Date fromModTime = from.getModTime();
final long fromModTimeSeconds = fromModTime.getTime() / 1000;
long fromModTimeSeconds = from.getLastModifiedTime().to(TimeUnit.SECONDS);
if (fromModTimeSeconds < 0 || fromModTimeSeconds > TarConstants.MAXSIZE) {
fromModTime = new Date(0);
fromModTimeSeconds = 0;
}
to.setModTime(fromModTime);
to.setLastModifiedTime(FileTime.from(fromModTimeSeconds, TimeUnit.SECONDS));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,14 @@ public interface TarConstants {
*/
byte LF_OLDNORM = 0;

/**
* Offset inside the header for the "link flag" field.
*
* @since 1.22
* @see TarArchiveEntry
*/
int LF_OFFSET = 156;

/**
* Normal file type.
*/
Expand Down Expand Up @@ -305,6 +313,13 @@ public interface TarConstants {
*/
byte LF_PAX_GLOBAL_EXTENDED_HEADER = (byte) 'g';

/**
* Identifies the entry as a multi-volume past volume #0
*
* @since 1.22
*/
byte LF_MULTIVOLUME = (byte) 'M';

/**
* The magic tag representing a POSIX tar archive.
*/
Expand Down Expand Up @@ -347,6 +362,14 @@ public interface TarConstants {
*/
String MAGIC_XSTAR = "tar\0";

/**
* Offset inside the header for the xtar multivolume data
*
* @since 1.22
* @see TarArchiveEntry
*/
int XSTAR_MULTIVOLUME_OFFSET = 464;

/**
* Offset inside the header for the xstar magic bytes.
* @since 1.11
Expand All @@ -366,13 +389,37 @@ public interface TarConstants {
*/
int PREFIXLEN_XSTAR = 131;

/**
* Offset inside the header for the prefix field in xstar archives.
*
* @since 1.22
* @see TarArchiveEntry
*/
int XSTAR_PREFIX_OFFSET = 345;

/**
* Offset inside the header for the atime field in xstar archives.
*
* @since 1.22
* @see TarArchiveEntry
*/
int XSTAR_ATIME_OFFSET = 476;

/**
* The length of the access time field in a xstar header buffer.
*
* @since 1.11
*/
int ATIMELEN_XSTAR = 12;

/**
* Offset inside the header for the ctime field in xstar archives.
*
* @since 1.22
* @see TarArchiveEntry
*/
int XSTAR_CTIME_OFFSET = 488;

/**
* The length of the created time field in a xstar header buffer.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ private TarArchiveEntry getNextTarEntry() throws IOException {
}

try {
currEntry = new TarArchiveEntry(headerBuf.array(), zipEncoding, lenient, archive.position());
final long position = archive.position();
currEntry = new TarArchiveEntry(globalPaxHeaders, headerBuf.array(), zipEncoding, lenient, position);
} catch (final IllegalArgumentException e) {
throw new IOException("Error detected parsing the header", e);
}
Expand Down
Loading

0 comments on commit 9248afd

Please sign in to comment.