#include "exfat.h"
#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
#define _XOPEN_SOURCE /* for timezone in Linux */
#include <time.h>
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)
return cpu_to_le16(checksum);
}
+uint32_t exfat_vbr_start_checksum(const void* sector, size_t size)
+{
+ size_t i;
+ uint32_t sum = 0;
+
+ for (i = 0; i < size; i++)
+ /* skip volume_state and allocated_percent fields */
+ if (i != 0x6a && i != 0x6b && i != 0x70)
+ sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i];
+ return sum;
+}
+
+uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ sum = ((sum << 31) | (sum >> 1)) + ((const uint8_t*) sector)[i];
+ return sum;
+}
+
+
le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name)
{
size_t i;
}
return cpu_to_le16(hash);
}
+
+void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb)
+{
+ size_t i;
+ const char* units[] = {"bytes", "KB", "MB", "GB", "TB", "PB"};
+ uint64_t divisor = 1;
+
+ for (i = 0; i < sizeof(units) / sizeof(units[0]) - 1; i++)
+ {
+ if ((value + divisor / 2) / divisor < 1024)
+ break;
+ divisor *= 1024;
+ }
+ hb->value = (value + divisor / 2) / divisor;
+ hb->unit = units[i];
+}
+
+void exfat_print_info(const struct exfat_super_block* sb,
+ uint32_t free_clusters)
+{
+ struct exfat_human_bytes hb;
+ off_t total_space = le64_to_cpu(sb->sector_count) * SECTOR_SIZE(*sb);
+ off_t avail_space = (off_t) free_clusters * CLUSTER_SIZE(*sb);
+
+ printf("File system version %hhu.%hhu\n",
+ sb->version.major, sb->version.minor);
+ exfat_humanize_bytes(SECTOR_SIZE(*sb), &hb);
+ printf("Sector size %10"PRIu64" %s\n", hb.value, hb.unit);
+ exfat_humanize_bytes(CLUSTER_SIZE(*sb), &hb);
+ printf("Cluster size %10"PRIu64" %s\n", hb.value, hb.unit);
+ exfat_humanize_bytes(total_space, &hb);
+ printf("Volume size %10"PRIu64" %s\n", hb.value, hb.unit);
+ exfat_humanize_bytes(total_space - avail_space, &hb);
+ printf("Used space %10"PRIu64" %s\n", hb.value, hb.unit);
+ exfat_humanize_bytes(avail_space, &hb);
+ printf("Available space %10"PRIu64" %s\n", hb.value, hb.unit);
+}