Skip to content

Commit 20e633e

Browse files
committed
Merge pull request #93 from nano-byte/pull-request
Multiple tweaks and bugfixes
2 parents ad8a8d0 + 3bd09a7 commit 20e633e

6 files changed

Lines changed: 97 additions & 107 deletions

File tree

ICSharpCode.SharpZipLib/Tar/TarArchive.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,9 @@ public void ExtractContents(string destinationDirectory)
556556
break;
557557
}
558558

559+
if (entry.TarHeader.TypeFlag == TarHeader.LF_LINK || entry.TarHeader.TypeFlag == TarHeader.LF_SYMLINK)
560+
continue;
561+
559562
ExtractEntry(destinationDirectory, entry);
560563
}
561564
}

ICSharpCode.SharpZipLib/Tar/TarHeader.cs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ public class TarHeader : ICloneable
147147
/// </summary>
148148
public const int DEVLEN = 8;
149149

150+
/// <summary>
151+
/// The length of the name prefix field in a header buffer.
152+
/// </summary>
153+
public const int PREFIXLEN = 155;
154+
150155
//
151156
// LF_ constants represent the "type" of an entry
152157
//
@@ -597,21 +602,26 @@ public void ParseBuffer(byte[] header)
597602
Magic = ParseName(header, offset, MAGICLEN).ToString();
598603
offset += MAGICLEN;
599604

600-
Version = ParseName(header, offset, VERSIONLEN).ToString();
601-
offset += VERSIONLEN;
605+
if (Magic == "ustar")
606+
{
607+
Version = ParseName(header, offset, VERSIONLEN).ToString();
608+
offset += VERSIONLEN;
602609

603-
UserName = ParseName(header, offset, UNAMELEN).ToString();
604-
offset += UNAMELEN;
610+
UserName = ParseName(header, offset, UNAMELEN).ToString();
611+
offset += UNAMELEN;
605612

606-
GroupName = ParseName(header, offset, GNAMELEN).ToString();
607-
offset += GNAMELEN;
613+
GroupName = ParseName(header, offset, GNAMELEN).ToString();
614+
offset += GNAMELEN;
608615

609-
DevMajor = (int)ParseOctal(header, offset, DEVLEN);
610-
offset += DEVLEN;
616+
DevMajor = (int) ParseOctal(header, offset, DEVLEN);
617+
offset += DEVLEN;
611618

612-
DevMinor = (int)ParseOctal(header, offset, DEVLEN);
619+
DevMinor = (int) ParseOctal(header, offset, DEVLEN);
620+
offset += DEVLEN;
613621

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

616626
isChecksumValid = Checksum == TarHeader.MakeCheckSum(header);
617627
}

ICSharpCode.SharpZipLib/Tar/TarInputStream.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,8 @@ public TarEntry GetNextEntry()
491491
headerBuf = this.tarBuffer.ReadBlock();
492492
} else if (header.TypeFlag != TarHeader.LF_NORMAL &&
493493
header.TypeFlag != TarHeader.LF_OLDNORM &&
494+
header.TypeFlag != TarHeader.LF_LINK &&
495+
header.TypeFlag != TarHeader.LF_SYMLINK &&
494496
header.TypeFlag != TarHeader.LF_DIR) {
495497
// Ignore things we dont understand completely for now
496498
SkipToNextEntry();

ICSharpCode.SharpZipLib/Zip/ZipEntry.cs

Lines changed: 33 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ public ZipEntry(ZipEntry entry)
257257
compressedSize = entry.compressedSize;
258258
crc = entry.crc;
259259
dosTime = entry.dosTime;
260+
dateTime = entry.dateTime;
260261
method = entry.method;
261262
comment = entry.comment;
262263
versionToExtract = entry.versionToExtract;
@@ -706,16 +707,7 @@ public long DosTime
706707
/// </remarks>
707708
public DateTime DateTime
708709
{
709-
get
710-
{
711-
uint sec = Math.Min(59, 2 * (dosTime & 0x1f));
712-
uint min = Math.Min(59, (dosTime >> 5) & 0x3f);
713-
uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f);
714-
uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
715-
uint year = ((dosTime >> 25) & 0x7f) + 1980;
716-
int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
717-
return new System.DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec);
718-
}
710+
get { return dateTime; }
719711

720712
set
721713
{
@@ -1041,49 +1033,41 @@ internal void ProcessExtraData(bool localHeader)
10411033
}
10421034
}
10431035

1044-
if (extraData.Find(10)) {
1045-
// No room for any tags.
1046-
if (extraData.ValueLength < 4) {
1047-
throw new ZipException("NTFS Extra data invalid");
1048-
}
1049-
1050-
extraData.ReadInt(); // Reserved
1051-
1052-
while (extraData.UnreadCount >= 4) {
1053-
int ntfsTag = extraData.ReadShort();
1054-
int ntfsLength = extraData.ReadShort();
1055-
if (ntfsTag == 1) {
1056-
if (ntfsLength >= 24) {
1057-
long lastModification = extraData.ReadLong();
1058-
long lastAccess = extraData.ReadLong();
1059-
long createTime = extraData.ReadLong();
1060-
1061-
DateTime = System.DateTime.FromFileTime(lastModification);
1062-
}
1063-
break;
1064-
} else {
1065-
// An unknown NTFS tag so simply skip it.
1066-
extraData.Skip(ntfsLength);
1067-
}
1068-
}
1069-
} else if (extraData.Find(0x5455)) {
1070-
int length = extraData.ValueLength;
1071-
int flags = extraData.ReadByte();
1072-
1073-
// Can include other times but these are ignored. Length of data should
1074-
// actually be 1 + 4 * no of bits in flags.
1075-
if (((flags & 1) != 0) && (length >= 5)) {
1076-
int iTime = extraData.ReadInt();
1077-
1078-
DateTime = (new System.DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
1079-
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
1080-
}
1081-
}
1036+
dateTime = GetDateTime(extraData);
10821037
if (method == CompressionMethod.WinZipAES) {
10831038
ProcessAESExtraData(extraData);
10841039
}
10851040
}
10861041

1042+
private DateTime GetDateTime(ZipExtraData extraData) {
1043+
// Check for NT timestamp
1044+
// NOTE: Disable by default to match behavior of InfoZIP
1045+
#if RESPECT_NT_TIMESTAMP
1046+
NTTaggedData ntData = extraData.GetData<NTTaggedData>();
1047+
if (ntData != null)
1048+
return ntData.LastModificationTime;
1049+
#endif
1050+
1051+
// Check for Unix timestamp
1052+
ExtendedUnixData unixData = extraData.GetData<ExtendedUnixData>();
1053+
if (unixData != null &&
1054+
// Only apply modification time, but require all other values to be present
1055+
// This is done to match InfoZIP's behaviour
1056+
((unixData.Include & ExtendedUnixData.Flags.ModificationTime) != 0) &&
1057+
((unixData.Include & ExtendedUnixData.Flags.AccessTime) != 0) &&
1058+
((unixData.Include & ExtendedUnixData.Flags.CreateTime) != 0))
1059+
return unixData.ModificationTime;
1060+
1061+
// Fall back to DOS time
1062+
uint sec = Math.Min(59, 2 * (dosTime & 0x1f));
1063+
uint min = Math.Min(59, (dosTime >> 5) & 0x3f);
1064+
uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f);
1065+
uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
1066+
uint year = ((dosTime >> 25) & 0x7f) + 1980;
1067+
int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
1068+
return new DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec, DateTimeKind.Utc);
1069+
}
1070+
10871071
// For AES the method in the entry is 99, and the real compression method is in the extradata
10881072
//
10891073
private void ProcessAESExtraData(ZipExtraData extraData)
@@ -1281,6 +1265,7 @@ public static string CleanName(string name)
12811265
ushort versionToExtract; // Version required to extract (library handles <= 2.0)
12821266
uint crc;
12831267
uint dosTime;
1268+
DateTime dateTime;
12841269

12851270
CompressionMethod method = CompressionMethod.Deflated;
12861271
byte[] extra;

ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -190,25 +190,29 @@ public void SetData(byte[] data, int index, int count)
190190
// bit 2 if set, creation time is present
191191

192192
_flags = (Flags)helperStream.ReadByte();
193-
if (((_flags & Flags.ModificationTime) != 0) && (count >= 5)) {
193+
if (((_flags & Flags.ModificationTime) != 0))
194+
{
194195
int iTime = helperStream.ReadLEInt();
195196

196-
_modificationTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
197-
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
197+
_modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
198+
new TimeSpan(0, 0, 0, iTime, 0);
199+
200+
// Central-header version is truncated after modification time
201+
if (count <= 5) return;
198202
}
199203

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

203-
_lastAccessTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
204-
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
207+
_lastAccessTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
208+
new TimeSpan(0, 0, 0, iTime, 0);
205209
}
206210

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

210-
_createTime = (new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime() +
211-
new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
214+
_createTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
215+
new TimeSpan(0, 0, 0, iTime, 0);
212216
}
213217
}
214218
}
@@ -224,17 +228,17 @@ public byte[] GetData()
224228
helperStream.IsStreamOwner = false;
225229
helperStream.WriteByte((byte)_flags); // Flags
226230
if ((_flags & Flags.ModificationTime) != 0) {
227-
TimeSpan span = _modificationTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
231+
TimeSpan span = _modificationTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
228232
var seconds = (int)span.TotalSeconds;
229233
helperStream.WriteLEInt(seconds);
230234
}
231235
if ((_flags & Flags.AccessTime) != 0) {
232-
TimeSpan span = _lastAccessTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
236+
TimeSpan span = _lastAccessTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
233237
var seconds = (int)span.TotalSeconds;
234238
helperStream.WriteLEInt(seconds);
235239
}
236240
if ((_flags & Flags.CreateTime) != 0) {
237-
TimeSpan span = _createTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0).ToUniversalTime();
241+
TimeSpan span = _createTime - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
238242
var seconds = (int)span.TotalSeconds;
239243
helperStream.WriteLEInt(seconds);
240244
}
@@ -321,7 +325,7 @@ public DateTime CreateTime
321325
/// <summary>
322326
/// Get/set the <see cref="Flags">values</see> to include.
323327
/// </summary>
324-
Flags Include
328+
public Flags Include
325329
{
326330
get { return _flags; }
327331
set { _flags = value; }
@@ -365,13 +369,13 @@ public void SetData(byte[] data, int index, int count)
365369
if (ntfsTag == 1) {
366370
if (ntfsLength >= 24) {
367371
long lastModificationTicks = helperStream.ReadLELong();
368-
_lastModificationTime = DateTime.FromFileTime(lastModificationTicks);
372+
_lastModificationTime = DateTime.FromFileTimeUtc(lastModificationTicks);
369373

370374
long lastAccessTicks = helperStream.ReadLELong();
371-
_lastAccessTime = DateTime.FromFileTime(lastAccessTicks);
375+
_lastAccessTime = DateTime.FromFileTimeUtc(lastAccessTicks);
372376

373377
long createTimeTicks = helperStream.ReadLELong();
374-
_createTime = DateTime.FromFileTime(createTimeTicks);
378+
_createTime = DateTime.FromFileTimeUtc(createTimeTicks);
375379
}
376380
break;
377381
} else {
@@ -394,9 +398,9 @@ public byte[] GetData()
394398
helperStream.WriteLEInt(0); // Reserved
395399
helperStream.WriteLEShort(1); // Tag
396400
helperStream.WriteLEShort(24); // Length = 3 x 8.
397-
helperStream.WriteLELong(_lastModificationTime.ToFileTime());
398-
helperStream.WriteLELong(_lastAccessTime.ToFileTime());
399-
helperStream.WriteLELong(_createTime.ToFileTime());
401+
helperStream.WriteLELong(_lastModificationTime.ToFileTimeUtc());
402+
helperStream.WriteLELong(_lastAccessTime.ToFileTimeUtc());
403+
helperStream.WriteLELong(_createTime.ToFileTimeUtc());
400404
return ms.ToArray();
401405
}
402406
}
@@ -469,9 +473,9 @@ public DateTime LastAccessTime
469473
}
470474

471475
#region Instance Fields
472-
DateTime _lastAccessTime = DateTime.FromFileTime(0);
473-
DateTime _lastModificationTime = DateTime.FromFileTime(0);
474-
DateTime _createTime = DateTime.FromFileTime(0);
476+
DateTime _lastAccessTime = DateTime.FromFileTimeUtc(0);
477+
DateTime _lastModificationTime = DateTime.FromFileTimeUtc(0);
478+
DateTime _createTime = DateTime.FromFileTimeUtc(0);
475479
#endregion
476480
}
477481

@@ -575,33 +579,18 @@ public Stream GetStreamForTag(int tag)
575579
/// <summary>
576580
/// Get the <see cref="ITaggedData">tagged data</see> for a tag.
577581
/// </summary>
578-
/// <param name="tag">The tag to search for.</param>
582+
/// <typeparam name="T">The tag to search for.</typeparam>
579583
/// <returns>Returns a <see cref="ITaggedData">tagged value</see> or null if none found.</returns>
580-
private ITaggedData GetData(short tag)
584+
public T GetData<T>()
585+
where T : class, ITaggedData, new()
581586
{
582-
ITaggedData result = null;
583-
if (Find(tag)) {
584-
result = Create(tag, _data, _readValueStart, _readValueLength);
585-
}
586-
return result;
587-
}
588-
589-
static ITaggedData Create(short tag, byte[] data, int offset, int count)
590-
{
591-
ITaggedData result = null;
592-
switch (tag) {
593-
case 0x000A:
594-
result = new NTTaggedData();
595-
break;
596-
case 0x5455:
597-
result = new ExtendedUnixData();
598-
break;
599-
default:
600-
result = new RawTaggedData(tag);
601-
break;
587+
T result = new T();
588+
if (Find(result.TagID))
589+
{
590+
result.SetData(_data, _readValueStart, _readValueLength);
591+
return result;
602592
}
603-
result.SetData(data, offset, count);
604-
return result;
593+
else return null;
605594
}
606595

607596
/// <summary>

ICSharpCode.SharpZipLib/Zip/ZipFile.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,16 +1194,17 @@ long TestLocalHeader(ZipEntry entry, HeaderTest tests)
11941194
// Size can be verified only if it is known in the local header.
11951195
// it will always be known in the central header.
11961196
if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
1197-
((size > 0) || (compressedSize > 0))) {
1197+
((size > 0 || compressedSize > 0) && entry.Size > 0)) {
11981198

1199-
if (size != entry.Size) {
1199+
if ((size != 0)
1200+
&& (size != entry.Size)) {
12001201
throw new ZipException(
12011202
string.Format("Size mismatch between central header({0}) and local header({1})",
12021203
entry.Size, size));
12031204
}
12041205

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

0 commit comments

Comments
 (0)