]> git.sven.stormbind.net Git - sven/fuse-exfat.git/blobdiff - libexfat/time.c
Snapshot from upstream git repo at commit 11e4f032d1782a606e3b004c89990a72cadf91bf
[sven/fuse-exfat.git] / libexfat / time.c
index 10a826a99858bb5d913f5aa88858250b6ffba9e6..e2a3b23d631fd7bad127ee979bf62ffe50d8f963 100644 (file)
@@ -2,11 +2,12 @@
        time.c (03.02.12)
        exFAT file system implementation library.
 
        time.c (03.02.12)
        exFAT file system implementation library.
 
-       Copyright (C) 2010-2013  Andrew Nayenko
+       Free exFAT implementation.
+       Copyright (C) 2010-2018  Andrew Nayenko
 
 
-       This program is free software: you can redistribute it and/or modify
+       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
        it under the terms of the GNU General Public License as published by
-       the Free Software Foundation, either version 3 of the License, or
+       the Free Software Foundation, either version 2 of the License, or
        (at your option) any later version.
 
        This program is distributed in the hope that it will be useful,
        (at your option) any later version.
 
        This program is distributed in the hope that it will be useful,
@@ -14,8 +15,9 @@
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
 
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
 
-       You should have received a copy of the GNU General Public License
-       along with this program.  If not, see <http://www.gnu.org/licenses/>.
+       You should have received a copy of the GNU General Public License along
+       with this program; if not, write to the Free Software Foundation, Inc.,
+       51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
 
 #include "exfat.h"
 */
 
 #include "exfat.h"
@@ -51,7 +53,8 @@ static const time_t days_in_year[] =
        0,   0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334
 };
 
        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);
 {
        time_t unix_time = EPOCH_DIFF_SEC;
        uint16_t ndate = le16_to_cpu(date);
@@ -98,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 += 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,
 
        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;
 {
        time_t shift = EPOCH_DIFF_SEC + exfat_timezone;
        uint16_t day, month, year;
@@ -144,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;
        *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;
 }
 
 void exfat_tzset(void)
 {
        time_t now;
+       struct tm* utc;
 
        tzset();
        now = time(NULL);
 
        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;
 }
 }