@@ -35,43 +35,38 @@ smb_reset(void)
35
35
}
36
36
37
37
/*
38
- * interpret a 32 bit dos packed date/time to some parameters
39
- */
40
- static void
41
- interpret_dos_date (uint32_t date , struct tm * tp )
42
- {
43
- uint32_t p0 , p1 , p2 , p3 ;
44
-
45
- p0 = date & 0xFF ;
46
- p1 = ((date & 0xFF00 ) >> 8 ) & 0xFF ;
47
- p2 = ((date & 0xFF0000 ) >> 16 ) & 0xFF ;
48
- p3 = ((date & 0xFF000000 ) >> 24 ) & 0xFF ;
49
-
50
- tp -> tm_sec = 2 * (p0 & 0x1F );
51
- tp -> tm_min = ((p0 >> 5 ) & 0xFF ) + ((p1 & 0x7 ) << 3 );
52
- tp -> tm_hour = (p1 >> 3 ) & 0xFF ;
53
- tp -> tm_mday = (p2 & 0x1F );
54
- tp -> tm_mon = ((p2 >> 5 ) & 0xFF ) + ((p3 & 0x1 ) << 3 ) - 1 ;
55
- tp -> tm_year = ((p3 >> 1 ) & 0xFF ) + 80 ;
56
- }
57
-
58
- /*
59
- * common portion:
60
- * create a unix date from a dos date
38
+ * create a UNIX time_t from a 32-bit DOS packetd date/time, with
39
+ * the DOS date/time assumed to be local time in *our* location.
61
40
*/
62
41
static time_t
63
42
int_unix_date (uint32_t dos_date )
64
43
{
44
+ uint32_t p0 , p1 , p2 , p3 ;
65
45
struct tm t ;
66
46
67
47
if (dos_date == 0 )
68
48
return (0 );
69
49
70
- interpret_dos_date (dos_date , & t );
71
- t .tm_wday = 1 ;
72
- t .tm_yday = 1 ;
73
- t .tm_isdst = 0 ;
74
-
50
+ p0 = dos_date & 0xFF ;
51
+ p1 = ((dos_date & 0xFF00 ) >> 8 ) & 0xFF ;
52
+ p2 = ((dos_date & 0xFF0000 ) >> 16 ) & 0xFF ;
53
+ p3 = ((dos_date & 0xFF000000 ) >> 24 ) & 0xFF ;
54
+
55
+ t .tm_sec = 2 * (p0 & 0x1F );
56
+ t .tm_min = ((p0 >> 5 ) & 0xFF ) + ((p1 & 0x7 ) << 3 );
57
+ t .tm_hour = (p1 >> 3 ) & 0xFF ;
58
+ t .tm_mday = (p2 & 0x1F );
59
+ t .tm_mon = ((p2 >> 5 ) & 0xFF ) + ((p3 & 0x1 ) << 3 ) - 1 ;
60
+ t .tm_year = ((p3 >> 1 ) & 0xFF ) + 80 ;
61
+
62
+ t .tm_wday = 1 ; /* XXX - should not affect the result; why 1? */
63
+ t .tm_yday = 1 ; /* XXX - should not affect the result; why 1? */
64
+ t .tm_isdst = 0 ; /* XXX - should be -1, to handle DST? */
65
+
66
+ /*
67
+ * XXX - if tm_year is 2038 or later, this might not fit in a
68
+ * 32-bit time_t.
69
+ */
75
70
return (mktime (& t ));
76
71
}
77
72
@@ -103,31 +98,38 @@ make_unix_date2(netdissect_options *ndo, const u_char *date_ptr)
103
98
return int_unix_date (x2 );
104
99
}
105
100
101
+ /* Delta between the NT FILETIME epoch and the POSIX epoch. */
102
+ #define FILETIME_TO_POSIX_DELTA INT64_C(11644473600)
103
+
106
104
/*
107
- * interpret an 8 byte "filetime" structure to a time_t
105
+ * interpret an 8 byte NT FILETIME structure to a time_t
108
106
* It's originally in "100ns units since jan 1st 1601"
109
107
*/
110
108
static time_t
111
- interpret_long_date (netdissect_options * ndo , const u_char * p )
109
+ interpret_filetime (netdissect_options * ndo , const u_char * p )
112
110
{
113
- double d ;
114
- time_t ret ;
115
-
116
- /* this gives us seconds since jan 1st 1601 (approx) */
117
- d = (GET_LE_U_4 (p + 4 ) * 256.0 + GET_U_1 (p + 3 )) * (1.0e-7 * (1 << 24 ));
118
-
119
- /* now adjust by 369 years to make the secs since 1970 */
120
- d -= 369.0 * 365.25 * 24 * 60 * 60 ;
121
-
122
- /* and a fudge factor as we got it wrong by a few days */
123
- d += (3 * 24 * 60 * 60 + 6 * 60 * 60 + 2 );
124
-
125
- if (d < 0 )
126
- return (0 );
127
-
128
- ret = (time_t )d ;
129
-
130
- return (ret );
111
+ int64_t ret ;
112
+ time_t ret_time_t ;
113
+
114
+ /*
115
+ * Fetch a FILETIME structure; the first 4 bytes are the low-order
116
+ * 32 bits of a 64-bit count of 100ns units since 1601-01-01
117
+ * at some specific time, and the next 4 bytes are the high-order
118
+ * 32 bits of that count.
119
+ */
120
+ ret = (int64_t )(((uint64_t )GET_LE_U_4 (p + 4 ) << 32 ) + (uint64_t )GET_LE_U_4 (p ));
121
+
122
+ /* Now convert from FILETIME to POSIX time. */
123
+ ret += FILETIME_TO_POSIX_DELTA ;
124
+
125
+ ret_time_t = (time_t )ret ;
126
+ if (ret_time_t != ret ) {
127
+ /*
128
+ * It doesn't fit in a time_t. Return 0, as an error indication.
129
+ */
130
+ return (0 );
131
+ }
132
+ return (ret_time_t );
131
133
}
132
134
133
135
/*
@@ -790,7 +792,7 @@ smb_fdata1(netdissect_options *ndo,
790
792
break ;
791
793
case 3 :
792
794
ND_TCHECK_8 (buf );
793
- t = interpret_long_date (ndo , buf );
795
+ t = interpret_filetime (ndo , buf );
794
796
buf += 8 ;
795
797
break ;
796
798
default :
0 commit comments