diff --git a/ChangeLog b/ChangeLog index ec6052472..045f04573 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-10-26 Vladimir Serbinenko + + * grub-core/normal/datetime.c (grub_unixtime2datetime): Fix mishandling + of first three years after start of validity of unixtime. + 2013-10-26 Vladimir Serbinenko * grub-core/normal/menu_entry.c (get_logical_num_lines): Use unsigned diff --git a/grub-core/normal/datetime.c b/grub-core/normal/datetime.c index bbc2cdea9..2b0faca90 100644 --- a/grub-core/normal/datetime.c +++ b/grub-core/normal/datetime.c @@ -52,50 +52,55 @@ grub_get_weekday_name (struct grub_datetime *datetime) #define SECPERMIN 60 #define SECPERHOUR (60*SECPERMIN) #define SECPERDAY (24*SECPERHOUR) -#define SECPERYEAR (365*SECPERDAY) -#define SECPER4YEARS (4*SECPERYEAR+SECPERDAY) +#define DAYSPERYEAR 365 +#define DAYSPER4YEARS (4*DAYSPERYEAR+1) void grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime) { int i; - int div; grub_uint8_t months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* In the period of validity of unixtime all years divisible by 4 are bissextile*/ /* Convenience: let's have 3 consecutive non-bissextile years - at the beginning of the epoch. So count from 1973 instead of 1970 */ - nix -= 3*SECPERYEAR + SECPERDAY; + at the beginning of the counting date. So count from 1901. */ + int days_epoch; + /* Number of days since 1st Januar, 1901. */ + unsigned days; + /* Seconds into current day. */ + unsigned secs_in_day; /* Transform C divisions and modulos to mathematical ones */ - div = nix / SECPER4YEARS; if (nix < 0) - div--; - datetime->year = 1973 + 4 * div; - nix -= div * SECPER4YEARS; + days_epoch = -(((unsigned) (SECPERDAY-nix-1)) / SECPERDAY); + else + days_epoch = ((unsigned) nix) / SECPERDAY; + secs_in_day = nix - days_epoch * SECPERDAY; + days = days_epoch + 69 * DAYSPERYEAR + 17; + datetime->year = 1901 + 4 * (days / DAYSPER4YEARS); + days %= DAYSPER4YEARS; /* On 31st December of bissextile years 365 days from the beginning of the year elapsed but year isn't finished yet */ - if (nix / SECPERYEAR == 4) + if (days / DAYSPERYEAR == 4) { datetime->year += 3; - nix -= 3*SECPERYEAR; + days -= 3*DAYSPERYEAR; } else { - datetime->year += nix / SECPERYEAR; - nix %= SECPERYEAR; + datetime->year += days / DAYSPERYEAR; + days %= DAYSPERYEAR; } for (i = 0; i < 12 - && nix >= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 - ? 29 : months[i]))*SECPERDAY; i++) - nix -= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 - ? 29 : months[i]))*SECPERDAY; + && days >= (i==1 && datetime->year % 4 == 0 + ? 29 : months[i]); i++) + days -= (i==1 && datetime->year % 4 == 0 + ? 29 : months[i]); datetime->month = i + 1; - datetime->day = 1 + (nix / SECPERDAY); - nix %= SECPERDAY; - datetime->hour = (nix / SECPERHOUR); - nix %= SECPERHOUR; - datetime->minute = nix / SECPERMIN; - datetime->second = nix % SECPERMIN; + datetime->day = 1 + days; + datetime->hour = (secs_in_day / SECPERHOUR); + secs_in_day %= SECPERHOUR; + datetime->minute = secs_in_day / SECPERMIN; + datetime->second = secs_in_day % SECPERMIN; } diff --git a/include/grub/types.h b/include/grub/types.h index 02e1182f2..8c737aa6f 100644 --- a/include/grub/types.h +++ b/include/grub/types.h @@ -129,6 +129,8 @@ typedef grub_int32_t grub_ssize_t; #define GRUB_SHRT_MAX 0x7fff #define GRUB_UINT_MAX 4294967295U #define GRUB_INT_MAX 0x7fffffff +#define GRUB_INT32_MIN (-2147483647 - 1) +#define GRUB_INT32_MAX 2147483647 #if GRUB_CPU_SIZEOF_LONG == 8 # define GRUB_ULONG_MAX 18446744073709551615UL