Skip to content

Commit 6c31a45

Browse files
committed
Improve extracting Unix and NT timestamps from ZipExtraData
1 parent 51605f8 commit 6c31a45

2 files changed

Lines changed: 45 additions & 72 deletions

File tree

ICSharpCode.SharpZipLib/Zip/ZipEntry.cs

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,57 +1033,41 @@ internal void ProcessExtraData(bool localHeader)
10331033
}
10341034
}
10351035

1036-
if (extraData.Find(10)) {
1037-
// No room for any tags.
1038-
if (extraData.ValueLength < 4) {
1039-
throw new ZipException("NTFS Extra data invalid");
1040-
}
1041-
1042-
extraData.ReadInt(); // Reserved
1043-
1044-
while (extraData.UnreadCount >= 4) {
1045-
int ntfsTag = extraData.ReadShort();
1046-
int ntfsLength = extraData.ReadShort();
1047-
if (ntfsTag == 1) {
1048-
if (ntfsLength >= 24) {
1049-
long lastModification = extraData.ReadLong();
1050-
long lastAccess = extraData.ReadLong();
1051-
long createTime = extraData.ReadLong();
1052-
1053-
dateTime = System.DateTime.FromFileTimeUtc(lastModification);
1054-
}
1055-
break;
1056-
} else {
1057-
// An unknown NTFS tag so simply skip it.
1058-
extraData.Skip(ntfsLength);
1059-
}
1060-
}
1061-
} else if (extraData.Find(0x5455)) {
1062-
int length = extraData.ValueLength;
1063-
int flags = extraData.ReadByte();
1064-
1065-
// Can include other times but these are ignored. Length of data should
1066-
// actually be 1 + 4 * no of bits in flags.
1067-
if (((flags & 1) != 0) && (length >= 5)) {
1068-
int iTime = extraData.ReadInt();
1069-
1070-
dateTime = (new System.DateTime ( 1970, 1, 1, 0, 0, 0, DateTimeKind.Utc ) +
1071-
new TimeSpan ( 0, 0, 0, iTime, 0 ));
1072-
}
1073-
} else {
1074-
uint sec = Math.Min(59, 2 * (dosTime & 0x1f));
1075-
uint min = Math.Min(59, (dosTime >> 5) & 0x3f);
1076-
uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f);
1077-
uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
1078-
uint year = ((dosTime >> 25) & 0x7f) + 1980;
1079-
int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
1080-
dateTime = new DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec, DateTimeKind.Utc);
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)

ICSharpCode.SharpZipLib/Zip/ZipExtraData.cs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,15 @@ 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

196197
_modificationTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) +
197198
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) {
@@ -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; }
@@ -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>

0 commit comments

Comments
 (0)