int exfat_mount(struct exfat* ef, const char* spec, const char* options);
void exfat_unmount(struct exfat* ef);
-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);
void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
- uint8_t* centisec);
+ uint8_t* centisec, uint8_t* tzoffset);
void exfat_tzset(void);
bool exfat_ask_to_fix(const struct exfat* ef);
le16_t atime, adate; /* latest access date and time */
uint8_t crtime_cs; /* creation time in cs (centiseconds) */
uint8_t mtime_cs; /* latest modification time in cs */
- uint8_t __unknown2[10];
+ uint8_t crtime_tzo, mtime_tzo, atime_tzo; /* timezone offset encoded */
+ uint8_t __unknown2[7];
}
PACKED;
STATIC_ASSERT(sizeof(struct exfat_entry_meta1) == 32);
node->attrib = le16_to_cpu(meta1->attrib);
node->continuations = meta1->continuations;
node->mtime = exfat_exfat2unix(meta1->mdate, meta1->mtime,
- meta1->mtime_cs);
+ meta1->mtime_cs, meta1->mtime_tzo);
/* there is no centiseconds field for atime */
- node->atime = exfat_exfat2unix(meta1->adate, meta1->atime, 0);
+ node->atime = exfat_exfat2unix(meta1->adate, meta1->atime,
+ 0, meta1->atime_tzo);
}
static void init_node_meta2(struct exfat_node* node,
meta1->attrib = cpu_to_le16(node->attrib);
exfat_unix2exfat(node->mtime, &meta1->mdate, &meta1->mtime,
- &meta1->mtime_cs);
- exfat_unix2exfat(node->atime, &meta1->adate, &meta1->atime, NULL);
+ &meta1->mtime_cs, &meta1->mtime_tzo);
+ exfat_unix2exfat(node->atime, &meta1->adate, &meta1->atime,
+ NULL, &meta1->atime_tzo);
meta2->size = meta2->valid_size = cpu_to_le64(node->size);
meta2->start_cluster = cpu_to_le32(node->start_cluster);
meta2->flags = EXFAT_FLAG_ALWAYS1;
meta1->continuations = 1 + name_entries;
meta1->attrib = cpu_to_le16(attrib);
exfat_unix2exfat(time(NULL), &meta1->crdate, &meta1->crtime,
- &meta1->crtime_cs);
+ &meta1->crtime_cs, &meta1->crtime_tzo);
meta1->adate = meta1->mdate = meta1->crdate;
meta1->atime = meta1->mtime = meta1->crtime;
meta1->mtime_cs = meta1->crtime_cs; /* there is no atime_cs */
+ meta1->atime_tzo = meta1->mtime_tzo = meta1->crtime_tzo;
meta2->type = EXFAT_ENTRY_FILE_INFO;
meta2->flags = EXFAT_FLAG_ALWAYS1;
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);
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;
*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)