@@ -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 )
0 commit comments