OSDN Git Service

Rename block to sector to avoid confusion.
[android-x86/external-exfat.git] / libexfat / utils.c
index dccb0be..39fdd48 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "exfat.h"
 #include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
 #define _XOPEN_SOURCE /* for timezone in Linux */
 #include <time.h>
 
@@ -69,7 +71,7 @@ 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)
+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);
@@ -95,6 +97,11 @@ time_t exfat_exfat2unix(le16_t date, le16_t time)
                                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;
@@ -108,6 +115,7 @@ time_t exfat_exfat2unix(le16_t date, le16_t time)
        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;
@@ -115,7 +123,8 @@ time_t exfat_exfat2unix(le16_t date, le16_t time)
        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;
@@ -153,6 +162,8 @@ void exfat_unix2exfat(time_t unix_time, le16_t* date, le16_t* time)
 
        *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)
@@ -200,6 +211,28 @@ le16_t exfat_calc_checksum(const struct exfat_entry_meta1* meta1,
        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;
@@ -219,3 +252,40 @@ le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name)
        }
        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);
+}