[RESEND,2/2] rtc: make rtc_time64_to_tm save to use for dates before 1970

Message ID 1462950684-3661-3-git-send-email-uwe@kleine-koenig.org
State New
Headers show

Commit Message

Uwe Kleine-König May 11, 2016, 7:11 a.m.
When the time parameter to rtc_time64_to_tm is negative and so
represents a date before 1970 several outputs were calculated wrongly.
A comment in the code signaled that the code doesn't handle negative
times but that didn't stop __rtc_read_alarm to still pass negative
values.

For example with time=-2208565980 (1900-01-05 21:27 UTC) the days variable
was assigned a negative value (-25562) which was then used to calculate

	secs = time - (unsigned int) days * 86400;

resulting in an overflow in both the multiplication and the subtraction
yielding secs = 4294958116 which is then used to calculate
tm_hour = 1193043; tm_min = 55; tm_sec = 16.

With the changes in this patch the time stamp from the example above is
converted correctly.

Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
---
 drivers/rtc/rtc-lib.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

Patch

diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index e6bfb9c42a10..0140ce7088ac 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -53,15 +53,20 @@  EXPORT_SYMBOL(rtc_year_days);
 void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
 {
 	unsigned int month, year;
-	unsigned long secs;
+	s32 secs
 	int days;
 
-	/* time must be positive */
-	days = div_s64(time, 86400);
-	secs = time - (unsigned int) days * 86400;
+	days = div_s64_rem(time, 86400, &secs);
+
+	if (secs < 0) {
+		secs += 86400;
+		days -= 1;
+	}
 
 	/* day of the week, 1970-01-01 was a Thursday */
 	tm->tm_wday = (days + 4) % 7;
+	if (tm->tm_wday < 0)
+		tm->tm_wday += 7;
 
 	year = 1970 + days / 365;
 	days -= (year - 1970) * 365