void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
struct stat* stbuf);
-time_t exfat_exfat2unix(le16_t date, le16_t time);
-void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time);
+time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec);
+void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
+ uint8_t* centisec);
void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n);
uint16_t exfat_start_checksum(const struct exfat_entry_meta1* entry);
uint16_t exfat_add_checksum(const void* entry, uint16_t sum);
const struct exfat_entry_meta1* meta1)
{
node->flags = le16_to_cpu(meta1->attrib);
- node->mtime = exfat_exfat2unix(meta1->mdate, meta1->mtime);
- node->atime = exfat_exfat2unix(meta1->adate, meta1->atime);
+ node->mtime = exfat_exfat2unix(meta1->mdate, meta1->mtime,
+ meta1->mtime_cs);
+ /* there is no centiseconds field for atime */
+ node->atime = exfat_exfat2unix(meta1->adate, meta1->atime, 0);
}
static void init_node_meta2(struct exfat_node* node,
if (meta1.type != EXFAT_ENTRY_FILE)
exfat_bug("invalid type of meta1: 0x%hhx", meta1.type);
meta1.attrib = cpu_to_le16(node->flags);
- exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime);
- exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime);
+ exfat_unix2exfat(node->mtime, &meta1.mdate, &meta1.mtime, &meta1.mtime_cs);
+ exfat_unix2exfat(node->atime, &meta1.adate, &meta1.atime, NULL);
exfat_read_raw(&meta2, sizeof(meta2), meta2_offset, ef->fd);
if (meta2.type != EXFAT_ENTRY_FILE_INFO)
meta1.type = EXFAT_ENTRY_FILE;
meta1.continuations = 1 + name_entries;
meta1.attrib = cpu_to_le16(attrib);
- exfat_unix2exfat(time(NULL), &meta1.crdate, &meta1.crtime);
+ exfat_unix2exfat(time(NULL), &meta1.crdate, &meta1.crtime,
+ &meta1.crtime_cs);
meta1.adate = meta1.mdate = meta1.crdate;
meta1.atime = meta1.mtime = meta1.crtime;
/* crtime_cs and mtime_cs contain addition to the time in centiseconds;
0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
-time_t exfat_exfat2unix(le16_t date, le16_t time)
+time_t exfat_exfat2unix(le16_t date, le16_t time, uint8_t centisec)
{
time_t unix_time = EPOCH_DIFF_SEC;
uint16_t ndate = le16_to_cpu(date);
hour, min, twosec * 2);
return 0;
}
+ if (centisec > 199)
+ {
+ exfat_error("bad centiseconds count %hhu", centisec);
+ return 0;
+ }
/* every 4th year between 1904 and 2096 is leap */
unix_time += year * SEC_IN_YEAR + LEAP_YEARS(year) * SEC_IN_DAY;
unix_time += min * SEC_IN_MIN;
/* exFAT represents time with 2 sec granularity */
unix_time += twosec * 2;
+ unix_time += centisec / 100;
/* exFAT stores timestamps in local time, so we correct it to UTC */
unix_time += timezone;
return unix_time;
}
-void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time)
+void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time,
+ uint8_t* centisec)
{
time_t shift = EPOCH_DIFF_SEC + timezone;
uint16_t day, month, year;
*date = cpu_to_le16(day | (month << 5) | (year << 9));
*time = cpu_to_le16(twosec | (min << 5) | (hour << 11));
+ if (centisec)
+ *centisec = (unix_time % 2) * 100;
}
void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n)