Fix and speedup timestamp calculations which is roughly based on the patch in
the mentioned PR: - bounds check time->month as it is used as an array index - fix usage of time->month as array index (month is 1-12) - fix calculation based on time->day (day is 1-31) - fix the speedup code as it doesn't calculate correct timestamps before the year 2000 and reduce the number of calculation in the year-by-year code - speedup month calculations by replacing the array content with cumulative values - add microseconds calculation - fix an endian problem PR: kern/97786 Submitted by: Andriy Gapon <avg@topspin.kiev.ua> Reviewed by: scottl (earlier version) Approved by: emax (mentor) MFC after: 1 week
This commit is contained in:
parent
8d0c1fa2be
commit
9c2bf69d32
@ -173,9 +173,9 @@ udf_open(struct vop_open_args *ap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mon_lens[2][12] = {
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
static const int mon_lens[2][12] = {
|
||||
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
|
||||
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
|
||||
};
|
||||
|
||||
static int
|
||||
@ -191,25 +191,25 @@ udf_isaleapyear(int year)
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX This is just a rough hack. Daylight savings isn't calculated and tv_nsec
|
||||
* is ignored.
|
||||
* Timezone calculation compliments of Julian Elischer <julian@elischer.org>.
|
||||
*/
|
||||
static void
|
||||
udf_timetotimespec(struct timestamp *time, struct timespec *t)
|
||||
{
|
||||
int i, lpyear, daysinyear, year;
|
||||
int i, lpyear, daysinyear, year, startyear;
|
||||
union {
|
||||
uint16_t u_tz_offset;
|
||||
int16_t s_tz_offset;
|
||||
} tz;
|
||||
|
||||
t->tv_nsec = 0;
|
||||
|
||||
/* DirectCD seems to like using bogus year values */
|
||||
/*
|
||||
* DirectCD seems to like using bogus year values.
|
||||
* Don't trust time->month as it will be used for an array index.
|
||||
*/
|
||||
year = le16toh(time->year);
|
||||
if (year < 1970) {
|
||||
if (year < 1970 || time->month < 1 || time->month > 12) {
|
||||
t->tv_sec = 0;
|
||||
t->tv_nsec = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -217,25 +217,37 @@ udf_timetotimespec(struct timestamp *time, struct timespec *t)
|
||||
t->tv_sec = time->second;
|
||||
t->tv_sec += time->minute * 60;
|
||||
t->tv_sec += time->hour * 3600;
|
||||
t->tv_sec += time->day * 3600 * 24;
|
||||
t->tv_sec += (time->day - 1) * 3600 * 24;
|
||||
|
||||
/* Calculate the month */
|
||||
lpyear = udf_isaleapyear(year);
|
||||
for (i = 1; i < time->month; i++)
|
||||
t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
|
||||
t->tv_sec += mon_lens[lpyear][time->month - 1] * 3600 * 24;
|
||||
|
||||
/* Speed up the calculation */
|
||||
if (year > 1979)
|
||||
startyear = 1970;
|
||||
if (year > 2009) {
|
||||
t->tv_sec += 1262304000;
|
||||
startyear += 40;
|
||||
} else if (year > 1999) {
|
||||
t->tv_sec += 946684800;
|
||||
startyear += 30;
|
||||
} else if (year > 1989) {
|
||||
t->tv_sec += 631152000;
|
||||
startyear += 20;
|
||||
} else if (year > 1979) {
|
||||
t->tv_sec += 315532800;
|
||||
if (year > 1989)
|
||||
t->tv_sec += 315619200;
|
||||
if (year > 1999)
|
||||
t->tv_sec += 315532800;
|
||||
for (i = 2000; i < year; i++) {
|
||||
daysinyear = udf_isaleapyear(i) + 365 ;
|
||||
t->tv_sec += daysinyear * 3600 * 24;
|
||||
startyear += 10;
|
||||
}
|
||||
|
||||
daysinyear = (year - startyear) * 365;
|
||||
for (i = startyear; i < year; i++)
|
||||
daysinyear += udf_isaleapyear(i);
|
||||
t->tv_sec += daysinyear * 3600 * 24;
|
||||
|
||||
/* Calculate microseconds */
|
||||
t->tv_nsec = time->centisec * 10000 + time->hund_usec * 100 +
|
||||
time->usec;
|
||||
|
||||
/*
|
||||
* Calculate the time zone. The timezone is 12 bit signed 2's
|
||||
* complement, so we gotta do some extra magic to handle it right.
|
||||
@ -244,7 +256,7 @@ udf_timetotimespec(struct timestamp *time, struct timespec *t)
|
||||
tz.u_tz_offset &= 0x0fff;
|
||||
if (tz.u_tz_offset & 0x0800)
|
||||
tz.u_tz_offset |= 0xf000; /* extend the sign to 16 bits */
|
||||
if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
|
||||
if ((le16toh(time->type_tz) & 0x1000) && (tz.s_tz_offset != -2047))
|
||||
t->tv_sec -= tz.s_tz_offset * 60;
|
||||
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user