Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ICSharpCode.SharpZipLib/Tar/TarArchive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,9 @@ public void ExtractContents(string destinationDirectory)
break;
}

if (entry.TarHeader.TypeFlag == TarHeader.LF_LINK || entry.TarHeader.TypeFlag == TarHeader.LF_SYMLINK)
continue;

ExtractEntry(destinationDirectory, entry);
}
}
Expand Down
30 changes: 20 additions & 10 deletions ICSharpCode.SharpZipLib/Tar/TarHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ public class TarHeader : ICloneable
/// </summary>
public const int DEVLEN = 8;

/// <summary>
/// The length of the name prefix field in a header buffer.
/// </summary>
public const int PREFIXLEN = 155;

//
// LF_ constants represent the "type" of an entry
//
Expand Down Expand Up @@ -597,21 +602,26 @@ public void ParseBuffer(byte[] header)
Magic = ParseName(header, offset, MAGICLEN).ToString();
offset += MAGICLEN;

Version = ParseName(header, offset, VERSIONLEN).ToString();
offset += VERSIONLEN;
if (Magic == "ustar")
{
Version = ParseName(header, offset, VERSIONLEN).ToString();
offset += VERSIONLEN;

UserName = ParseName(header, offset, UNAMELEN).ToString();
offset += UNAMELEN;
UserName = ParseName(header, offset, UNAMELEN).ToString();
offset += UNAMELEN;

GroupName = ParseName(header, offset, GNAMELEN).ToString();
offset += GNAMELEN;
GroupName = ParseName(header, offset, GNAMELEN).ToString();
offset += GNAMELEN;

DevMajor = (int)ParseOctal(header, offset, DEVLEN);
offset += DEVLEN;
DevMajor = (int) ParseOctal(header, offset, DEVLEN);
offset += DEVLEN;

DevMinor = (int)ParseOctal(header, offset, DEVLEN);
DevMinor = (int) ParseOctal(header, offset, DEVLEN);
offset += DEVLEN;

// Fields past this point not currently parsed or used...
string prefix = ParseName(header, offset, PREFIXLEN).ToString();
if (!string.IsNullOrEmpty(prefix)) Name = prefix + '/' + Name;
}

isChecksumValid = Checksum == TarHeader.MakeCheckSum(header);
}
Expand Down
2 changes: 2 additions & 0 deletions ICSharpCode.SharpZipLib/Tar/TarInputStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ public TarEntry GetNextEntry()
headerBuf = this.tarBuffer.ReadBlock();
} else if (header.TypeFlag != TarHeader.LF_NORMAL &&
header.TypeFlag != TarHeader.LF_OLDNORM &&
header.TypeFlag != TarHeader.LF_LINK &&
header.TypeFlag != TarHeader.LF_SYMLINK &&
header.TypeFlag != TarHeader.LF_DIR) {
// Ignore things we dont understand completely for now
SkipToNextEntry();
Expand Down
81 changes: 33 additions & 48 deletions ICSharpCode.SharpZipLib/Zip/ZipEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ public ZipEntry(ZipEntry entry)
compressedSize = entry.compressedSize;
crc = entry.crc;
dosTime = entry.dosTime;
dateTime = entry.dateTime;
method = entry.method;
comment = entry.comment;
versionToExtract = entry.versionToExtract;
Expand Down Expand Up @@ -706,16 +707,7 @@ public long DosTime
/// </remarks>
public DateTime DateTime
{
get
{
uint sec = Math.Min(59, 2 * (dosTime & 0x1f));
uint min = Math.Min(59, (dosTime >> 5) & 0x3f);
uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f);
uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
uint year = ((dosTime >> 25) & 0x7f) + 1980;
int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
return new System.DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec);
}
get { return dateTime; }

set
{
Expand Down Expand Up @@ -1041,49 +1033,41 @@ internal void ProcessExtraData(bool localHeader)
}
}

if (extraData.Find(10)) {
// No room for any tags.
if (extraData.ValueLength < 4) {
throw new ZipException("NTFS Extra data invalid");
}

extraData.ReadInt(); // Reserved

while (extraData.UnreadCount >= 4) {
int ntfsTag = extraData.ReadShort();
int ntfsLength = extraData.ReadShort();
if (ntfsTag == 1) {
if (ntfsLength >= 24) {
long lastModification = extraData.ReadLong();
long lastAccess = extraData.ReadLong();
long createTime = extraData.ReadLong();

DateTime = System.DateTime.FromFileTime(lastModification);
}
break;
} else {
// An unknown NTFS tag so simply skip it.
extraData.Skip(ntfsLength);
}
}
} else if (extraData.Find(0x5455)) {
int length = extraData.ValueLength;
int flags = extraData.ReadByte();

// Can include other times but these are ignored. Length of data should
// actually be 1 + 4 * no of bits in flags.
if (((flags & 1) != 0) && (length >= 5)) {
int iTime = extraData.ReadInt();

DateTime = (new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
}
}
dateTime = GetDateTime(extraData);
if (method == CompressionMethod.WinZipAES) {
ProcessAESExtraData(extraData);
}
}

private DateTime GetDateTime(ZipExtraData extraData) {
// Check for NT timestamp
// NOTE: Disable by default to match behavior of InfoZIP
#if RESPECT_NT_TIMESTAMP
NTTaggedData ntData = extraData.GetData<NTTaggedData>();
if (ntData != null)
return ntData.LastModificationTime;
#endif

// Check for Unix timestamp
ExtendedUnixData unixData = extraData.GetData<ExtendedUnixData>();
if (unixData != null &&
// Only apply modification time, but require all other values to be present
// This is done to match InfoZIP's behaviour
((unixData.Include & ExtendedUnixData.Flags.ModificationTime) != 0) &&
((unixData.Include & ExtendedUnixData.Flags.AccessTime) != 0) &&
((unixData.Include & ExtendedUnixData.Flags.CreateTime) != 0))
return unixData.ModificationTime;

// Fall back to DOS time
uint sec = Math.Min(59, 2 * (dosTime & 0x1f));
uint min = Math.Min(59, (dosTime >> 5) & 0x3f);
uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f);
uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
uint year = ((dosTime >> 25) & 0x7f) + 1980;
int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
return new DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec, DateTimeKind.Utc);
}

// For AES the method in the entry is 99, and the real compression method is in the extradata
//
private void ProcessAESExtraData(ZipExtraData extraData)
Expand Down Expand Up @@ -1281,6 +1265,7 @@ public static string CleanName(string name)
ushort versionToExtract; // Version required to extract (library handles <= 2.0)
uint crc;
uint dosTime;
DateTime dateTime;

CompressionMethod method = CompressionMethod.Deflated;
byte[] extra;
Expand Down
77 changes: 33 additions & 44 deletions ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,25 +190,29 @@ public void SetData(byte[] data, int index, int count)
// bit 2 if set, creation time is present

_flags = (Flags)helperStream.ReadByte();
if (((_flags & Flags.ModificationTime) != 0) && (count >= 5)) {
if (((_flags & Flags.ModificationTime) != 0))
{
int iTime = helperStream.ReadLEInt();

_modificationTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
_modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
new TimeSpan(0, 0, 0, iTime, 0);

// Central-header version is truncated after modification time
if (count <= 5) return;
}

if ((_flags & Flags.AccessTime) != 0) {
int iTime = helperStream.ReadLEInt();

_lastAccessTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
_lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
new TimeSpan(0, 0, 0, iTime, 0);
}

if ((_flags & Flags.CreateTime) != 0) {
int iTime = helperStream.ReadLEInt();

_createTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
_createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
new TimeSpan(0, 0, 0, iTime, 0);
}
}
}
Expand All @@ -224,17 +228,17 @@ public byte[] GetData()
helperStream.IsStreamOwner = false;
helperStream.WriteByte((byte)_flags); // Flags
if ((_flags & Flags.ModificationTime) != 0) {
TimeSpan span = _modificationTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
TimeSpan span = _modificationTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var seconds = (int)span.TotalSeconds;
helperStream.WriteLEInt(seconds);
}
if ((_flags & Flags.AccessTime) != 0) {
TimeSpan span = _lastAccessTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
TimeSpan span = _lastAccessTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var seconds = (int)span.TotalSeconds;
helperStream.WriteLEInt(seconds);
}
if ((_flags & Flags.CreateTime) != 0) {
TimeSpan span = _createTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
TimeSpan span = _createTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var seconds = (int)span.TotalSeconds;
helperStream.WriteLEInt(seconds);
}
Expand Down Expand Up @@ -321,7 +325,7 @@ public DateTime CreateTime
/// <summary>
/// Get/set the <see cref="Flags">values</see> to include.
/// </summary>
Flags Include
public Flags Include
{
get { return _flags; }
set { _flags = value; }
Expand Down Expand Up @@ -365,13 +369,13 @@ public void SetData(byte[] data, int index, int count)
if (ntfsTag == 1) {
if (ntfsLength >= 24) {
long lastModificationTicks = helperStream.ReadLELong();
_lastModificationTime = DateTime.FromFileTime(lastModificationTicks);
_lastModificationTime = DateTime.FromFileTimeUtc(lastModificationTicks);

long lastAccessTicks = helperStream.ReadLELong();
_lastAccessTime = DateTime.FromFileTime(lastAccessTicks);
_lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);

long createTimeTicks = helperStream.ReadLELong();
_createTime = DateTime.FromFileTime(createTimeTicks);
_createTime = DateTime.FromFileTimeUtc(createTimeTicks);
}
break;
} else {
Expand All @@ -394,9 +398,9 @@ public byte[] GetData()
helperStream.WriteLEInt(0); // Reserved
helperStream.WriteLEShort(1); // Tag
helperStream.WriteLEShort(24); // Length = 3 x 8.
helperStream.WriteLELong(_lastModificationTime.ToFileTime());
helperStream.WriteLELong(_lastAccessTime.ToFileTime());
helperStream.WriteLELong(_createTime.ToFileTime());
helperStream.WriteLELong(_lastModificationTime.ToFileTimeUtc());
helperStream.WriteLELong(_lastAccessTime.ToFileTimeUtc());
helperStream.WriteLELong(_createTime.ToFileTimeUtc());
return ms.ToArray();
}
}
Expand Down Expand Up @@ -469,9 +473,9 @@ public DateTime LastAccessTime
}

#region Instance Fields
DateTime _lastAccessTime = DateTime.FromFileTime(0);
DateTime _lastModificationTime = DateTime.FromFileTime(0);
DateTime _createTime = DateTime.FromFileTime(0);
DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);
DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);
DateTime _createTime = DateTime.FromFileTimeUtc(0);
#endregion
}

Expand Down Expand Up @@ -575,33 +579,18 @@ public Stream GetStreamForTag(int tag)
/// <summary>
/// Get the <see cref="ITaggedData">tagged data</see> for a tag.
/// </summary>
/// <param name="tag">The tag to search for.</param>
/// <typeparam name="T">The tag to search for.</typeparam>
/// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
private ITaggedData GetData(short tag)
public T GetData<T>()
where T : class, ITaggedData, new()
{
ITaggedData result = null;
if (Find(tag)) {
result = Create(tag, _data, _readValueStart, _readValueLength);
}
return result;
}

static ITaggedData Create(short tag, byte[] data, int offset, int count)
{
ITaggedData result = null;
switch (tag) {
case 0x000A:
result = new NTTaggedData();
break;
case 0x5455:
result = new ExtendedUnixData();
break;
default:
result = new RawTaggedData(tag);
break;
T result = new T();
if (Find(result.TagID))
{
result.SetData(_data, _readValueStart, _readValueLength);
return result;
}
result.SetData(data, offset, count);
return result;
else return null;
}

/// <summary>
Expand Down
11 changes: 6 additions & 5 deletions ICSharpCode.SharpZipLib/Zip/ZipFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1194,16 +1194,17 @@ long TestLocalHeader(ZipEntry entry, HeaderTest tests)
// Size can be verified only if it is known in the local header.
// it will always be known in the central header.
if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
((size > 0) || (compressedSize > 0))) {
((size > 0 || compressedSize > 0) && entry.Size > 0)) {

if (size != entry.Size) {
if ((size != 0)
&& (size != entry.Size)) {
throw new ZipException(
string.Format("Size mismatch between central header({0}) and local header({1})",
entry.Size, size));
}

if (compressedSize != entry.CompressedSize &&
compressedSize != 0xFFFFFFFF && compressedSize != -1) {
if ((compressedSize != 0)
&& (compressedSize != entry.CompressedSize && compressedSize != 0xFFFFFFFF && compressedSize != -1)) {
throw new ZipException(
string.Format("Compressed size mismatch between central header({0}) and local header({1})",
entry.CompressedSize, compressedSize));
Expand Down Expand Up @@ -3196,7 +3197,7 @@ Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
var decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
byte[] pwdVerifyCalc = decryptor.PwdVerifier;
if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
throw new Exception("Invalid password for AES");
throw new ZipException("Invalid password for AES");
result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
} else {
throw new ZipException("Decryption method not supported");
Expand Down