X-Git-Url: https://git.sven.stormbind.net/?a=blobdiff_plain;f=libexfat%2Ftime.c;h=31ae5a264dd11e4353dfa829d6eb81e985f96f84;hb=HEAD;hp=7d2becdae68871c756731e94471f71295a14d351;hpb=27e1f57eb453f17910bb032e7fd8caea53d2f6de;p=sven%2Ffuse-exfat.git

diff --git a/libexfat/time.c b/libexfat/time.c
index 7d2becd..3ab2a15 100644
--- a/libexfat/time.c
+++ b/libexfat/time.c
@@ -3,7 +3,7 @@
 	exFAT file system implementation library.
 
 	Free exFAT implementation.
-	Copyright (C) 2010-2016  Andrew Nayenko
+	Copyright (C) 2010-2023  Andrew Nayenko
 
 	This program is free software; you can redistribute it and/or modify
 	it under the terms of the GNU General Public License as published by
@@ -53,7 +53,8 @@ static const time_t days_in_year[] =
 	0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
 };
 
-time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec)
+time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec,
+		uint8_t tzoffset)
 {
 	time_t unix_time = EPOCH_DIFF_SEC;
 	uint16_t ndate = le16_to_cpu(date);
@@ -100,13 +101,18 @@ time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec)
 	unix_time += centisec / 100;
 
 	/* exFAT stores timestamps in local time, so we correct it to UTC */
-	unix_time += exfat_timezone;
+	if (tzoffset & 0x80)
+		/* lower 7 bits are signed timezone offset in 15 minute increments */
+		unix_time -= (int8_t)(tzoffset << 1) * 15 * 60 / 2;
+	else
+		/* timezone offset not present, assume our local timezone */
+		unix_time += exfat_timezone;
 
 	return unix_time;
 }
 
 void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
-		uint8_t* centisec)
+		uint8_t* centisec, uint8_t* tzoffset)
 {
 	time_t shift = EPOCH_DIFF_SEC + exfat_timezone;
 	uint16_t day, month, year;
@@ -146,13 +152,22 @@ void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
 	*time = cpu_to_le16(twosec | (min << 5) | (hour << 11));
 	if (centisec)
 		*centisec = (unix_time % 2) * 100;
+
+	/* record our local timezone offset in exFAT (15 minute increment) format */
+	*tzoffset = (uint8_t)(-exfat_timezone / 60 / 15) | 0x80;
 }
 
 void exfat_tzset(void)
 {
 	time_t now;
+	struct tm* utc;
 
 	tzset();
 	now = time(NULL);
-	exfat_timezone = mktime(gmtime(&now)) - now;
+	utc = gmtime(&now);
+	/* gmtime() always sets tm_isdst to 0 because daylight savings never
+	   affect UTC. Setting tm_isdst to -1 makes mktime() to determine whether
+	   summer time is in effect. */
+	utc->tm_isdst = -1;
+	exfat_timezone = mktime(utc) - now;
 }