1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7     TimeSup.c
8 
9 Abstract:
10 
11     This module implements the Fat Time conversion support routines
12 
13 
14 --*/
15 
16 #include "fatprocs.h"
17 
18 #ifdef ALLOC_PRAGMA
19 #pragma alloc_text(PAGE, FatNtTimeToFatTime)
20 #pragma alloc_text(PAGE, FatFatDateToNtTime)
21 #pragma alloc_text(PAGE, FatFatTimeToNtTime)
22 #pragma alloc_text(PAGE, FatGetCurrentFatTime)
23 #endif
24 
25 _Success_(return != FALSE)
26 BOOLEAN
27 FatNtTimeToFatTime (
28     _In_ PIRP_CONTEXT IrpContext,
29     _In_ PLARGE_INTEGER NtTime,
30     _In_ BOOLEAN Rounding,
31     _Out_ PFAT_TIME_STAMP FatTime,
32     _Out_opt_ PUCHAR TenMsecs
33     )
34 
35 /*++
36 
37 Routine Description:
38 
39     This routine converts an NtTime value to its corresponding Fat time value.
40 
41 Arguments:
42 
43     NtTime - Supplies the Nt GMT Time value to convert from
44 
45     Rounding - Indicates whether the NT time should be rounded up to a FAT boundary.
46         This should only be done *once* in the lifetime of a timestamp (important
47         for tunneling, which will cause a timestamp to pass through at least twice).
48         If true, rounded up. If false, rounded down to 10ms boundary. This obeys
49         the rules for non-creation time and creation times (respectively).
50 
51     FatTime - Receives the equivalent Fat time value
52 
53     TenMsecs - Optionally receive the number of tens of milliseconds the NtTime, after
54         any rounding, is greater than the FatTime
55 
56 Return Value:
57 
58     BOOLEAN - TRUE if the Nt time value is within the range of Fat's
59         time range, and FALSE otherwise
60 
61 --*/
62 
63 {
64     TIME_FIELDS TimeFields;
65 
66     PAGED_CODE();
67 
68     //
69     //  Convert the input to the a time field record.
70     //
71 
72     if (Rounding) {
73 
74         //
75         //   Add almost two seconds to round up to the nearest double second.
76         //
77 
78         NtTime->QuadPart = NtTime->QuadPart + AlmostTwoSeconds;
79     }
80 
81     ExSystemTimeToLocalTime( NtTime, NtTime );
82 
83     RtlTimeToTimeFields( NtTime, &TimeFields );
84 
85     //
86     //  Check the range of the date found in the time field record
87     //
88 
89     if ((TimeFields.Year < 1980) || (TimeFields.Year > (1980 + 127))) {
90 
91         ExLocalTimeToSystemTime( NtTime, NtTime );
92 
93         return FALSE;
94     }
95 
96     //
97     //  The year will fit in Fat so simply copy over the information
98     //
99 
100     FatTime->Time.DoubleSeconds = (USHORT)(TimeFields.Second / 2);
101     FatTime->Time.Minute        = (USHORT)(TimeFields.Minute);
102     FatTime->Time.Hour          = (USHORT)(TimeFields.Hour);
103 
104     FatTime->Date.Year          = (USHORT)(TimeFields.Year - 1980);
105     FatTime->Date.Month         = (USHORT)(TimeFields.Month);
106     FatTime->Date.Day           = (USHORT)(TimeFields.Day);
107 
108     if (TenMsecs) {
109 
110         if (!Rounding) {
111 
112             //
113             //  If the number of seconds was not divisible by two, then there
114             //  is another second of time (1 sec, 3 sec, etc.) Note we round down
115             //  the number of milleconds onto tens of milleseconds boundaries.
116             //
117 
118 #ifdef _MSC_VER
119 #pragma warning( push )
120 #pragma warning( disable: 4244 )
121 #endif
122             *TenMsecs = (TimeFields.Milliseconds / 10) +
123                 ((TimeFields.Second % 2) * 100);
124 #ifdef _MSC_VER
125 #pragma warning( pop )
126 #endif
127         } else {
128 
129             //
130             //  If we rounded up, we have in effect changed the NT time. Therefore,
131             //  it does not differ from the FAT time.
132             //
133 
134             *TenMsecs = 0;
135         }
136     }
137 
138     if (Rounding) {
139 
140         //
141         //  Slice off non-FAT boundary time and convert back to 64bit form
142         //
143 
144         TimeFields.Milliseconds = 0;
145         TimeFields.Second -= TimeFields.Second % 2;
146 
147     } else {
148 
149         //
150         //  Round down to 10ms boundary
151         //
152 
153         TimeFields.Milliseconds -= TimeFields.Milliseconds % 10;
154     }
155 
156     //
157     //  Convert back to NT time
158     //
159 
160     (VOID) RtlTimeFieldsToTime(&TimeFields, NtTime);
161 
162     ExLocalTimeToSystemTime( NtTime, NtTime );
163 
164     UNREFERENCED_PARAMETER( IrpContext );
165 
166     return TRUE;
167 }
168 
169 
170 LARGE_INTEGER
171 FatFatDateToNtTime (
172     _In_ PIRP_CONTEXT IrpContext,
173     _In_ FAT_DATE FatDate
174     )
175 
176 /*++
177 
178 Routine Description:
179 
180     This routine converts a Fat datev value to its corresponding Nt GMT
181     Time value.
182 
183 Arguments:
184 
185     FatDate - Supplies the Fat Date to convert from
186 
187 Return Value:
188 
189     LARGE_INTEGER - Receives the corresponding Nt Time value
190 
191 --*/
192 
193 {
194     TIME_FIELDS TimeFields;
195     LARGE_INTEGER Time;
196 
197     PAGED_CODE();
198 
199     //
200     //  Pack the input time/date into a time field record
201     //
202 
203     TimeFields.Year         = (USHORT)(FatDate.Year + 1980);
204     TimeFields.Month        = (USHORT)(FatDate.Month);
205     TimeFields.Day          = (USHORT)(FatDate.Day);
206     TimeFields.Hour         = (USHORT)0;
207     TimeFields.Minute       = (USHORT)0;
208     TimeFields.Second       = (USHORT)0;
209     TimeFields.Milliseconds = (USHORT)0;
210 
211     //
212     //  Convert the time field record to Nt LARGE_INTEGER, and set it to zero
213     //  if we were given a bogus time.
214     //
215 
216     if (!RtlTimeFieldsToTime( &TimeFields, &Time )) {
217 
218         Time.LowPart = 0;
219         Time.HighPart = 0;
220 
221     } else {
222 
223         ExLocalTimeToSystemTime( &Time, &Time );
224     }
225 
226     return Time;
227 
228     UNREFERENCED_PARAMETER( IrpContext );
229 }
230 
231 
232 LARGE_INTEGER
233 FatFatTimeToNtTime (
234     _In_ PIRP_CONTEXT IrpContext,
235     _In_ FAT_TIME_STAMP FatTime,
236     _In_ UCHAR TenMilliSeconds
237     )
238 
239 /*++
240 
241 Routine Description:
242 
243     This routine converts a Fat time value pair to its corresponding Nt GMT
244     Time value.
245 
246 Arguments:
247 
248     FatTime - Supplies the Fat Time to convert from
249 
250     TenMilliSeconds - A 10 Milisecond resolution
251 
252 Return Value:
253 
254     LARGE_INTEGER - Receives the corresponding Nt GMT Time value
255 
256 --*/
257 
258 {
259     TIME_FIELDS TimeFields;
260     LARGE_INTEGER Time;
261 
262     PAGED_CODE();
263 
264     //
265     //  Pack the input time/date into a time field record
266     //
267 
268     TimeFields.Year         = (USHORT)(FatTime.Date.Year + 1980);
269     TimeFields.Month        = (USHORT)(FatTime.Date.Month);
270     TimeFields.Day          = (USHORT)(FatTime.Date.Day);
271     TimeFields.Hour         = (USHORT)(FatTime.Time.Hour);
272     TimeFields.Minute       = (USHORT)(FatTime.Time.Minute);
273     TimeFields.Second       = (USHORT)(FatTime.Time.DoubleSeconds * 2);
274 
275     if (TenMilliSeconds != 0) {
276 
277         TimeFields.Second      += (USHORT)(TenMilliSeconds / 100);
278         TimeFields.Milliseconds = (USHORT)((TenMilliSeconds % 100) * 10);
279 
280     } else {
281 
282         TimeFields.Milliseconds = (USHORT)0;
283     }
284 
285     //
286     //  If the second value is greater than 59 then we truncate it to 0.
287     //  Note that this can't happen with a proper FAT timestamp.
288     //
289 
290     if (TimeFields.Second > 59) {
291 
292         TimeFields.Second = 0;
293     }
294 
295     //
296     //  Convert the time field record to Nt LARGE_INTEGER, and set it to zero
297     //  if we were given a bogus time.
298     //
299 
300     if (!RtlTimeFieldsToTime( &TimeFields, &Time )) {
301 
302         Time.LowPart = 0;
303         Time.HighPart = 0;
304 
305     } else {
306 
307         ExLocalTimeToSystemTime( &Time, &Time );
308     }
309 
310     return Time;
311 
312     UNREFERENCED_PARAMETER( IrpContext );
313 }
314 
315 
316 FAT_TIME_STAMP
317 FatGetCurrentFatTime (
318     _In_ PIRP_CONTEXT IrpContext
319     )
320 
321 /*++
322 
323 Routine Description:
324 
325     This routine returns the current system time in Fat time
326 
327 Arguments:
328 
329 Return Value:
330 
331     FAT_TIME_STAMP - Receives the current system time
332 
333 --*/
334 
335 {
336     LARGE_INTEGER Time;
337     TIME_FIELDS TimeFields;
338     FAT_TIME_STAMP FatTime;
339 
340     PAGED_CODE();
341 
342     //
343     //  Get the current system time, and map it into a time field record.
344     //
345 
346     KeQuerySystemTime( &Time );
347 
348     ExSystemTimeToLocalTime( &Time, &Time );
349 
350     //
351     //  Always add almost two seconds to round up to the nearest double second.
352     //
353 
354     Time.QuadPart = Time.QuadPart + AlmostTwoSeconds;
355 
356     (VOID)RtlTimeToTimeFields( &Time, &TimeFields );
357 
358     //
359     //  Now simply copy over the information
360     //
361 
362     FatTime.Time.DoubleSeconds = (USHORT)(TimeFields.Second / 2);
363     FatTime.Time.Minute        = (USHORT)(TimeFields.Minute);
364     FatTime.Time.Hour          = (USHORT)(TimeFields.Hour);
365 
366     FatTime.Date.Year          = (USHORT)(TimeFields.Year - 1980);
367     FatTime.Date.Month         = (USHORT)(TimeFields.Month);
368     FatTime.Date.Day           = (USHORT)(TimeFields.Day);
369 
370     UNREFERENCED_PARAMETER( IrpContext );
371 
372     return FatTime;
373 }
374 
375 
376