]> git.sven.stormbind.net Git - sven/exfat-utils.git/blobdiff - libexfat/utils.c
Update the Homepage field in d/control.
[sven/exfat-utils.git] / libexfat / utils.c
index 31b7e8cce38b9d91d1a5a9de0009734b648802ce..388f360d975af01cfd479a64e5220fbf0f18e53d 100644 (file)
@@ -2,11 +2,12 @@
        utils.c (04.09.09)
        exFAT file system implementation library.
 
        utils.c (04.09.09)
        exFAT file system implementation library.
 
-       Copyright (C) 2009, 2010  Andrew Nayenko
+       Free exFAT implementation.
+       Copyright (C) 2010-2015  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,
        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 <string.h>
 #include <stdio.h>
 #include <inttypes.h>
 */
 
 #include "exfat.h"
 #include <string.h>
 #include <stdio.h>
 #include <inttypes.h>
-#define _XOPEN_SOURCE /* for timezone in Linux */
-#include <time.h>
 
 void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
                struct stat* stbuf)
 
 void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
                struct stat* stbuf)
@@ -46,128 +46,6 @@ void exfat_stat(const struct exfat* ef, const struct exfat_node* node,
        stbuf->st_ctime = node->mtime;
 }
 
        stbuf->st_ctime = node->mtime;
 }
 
-#define SEC_IN_MIN 60ll
-#define SEC_IN_HOUR (60 * SEC_IN_MIN)
-#define SEC_IN_DAY (24 * SEC_IN_HOUR)
-#define SEC_IN_YEAR (365 * SEC_IN_DAY) /* not leap year */
-/* Unix epoch started at 0:00:00 UTC 1 January 1970 */
-#define UNIX_EPOCH_YEAR 1970
-/* exFAT epoch started at 0:00:00 UTC 1 January 1980 */
-#define EXFAT_EPOCH_YEAR 1980
-/* number of years from Unix epoch to exFAT epoch */
-#define EPOCH_DIFF_YEAR (EXFAT_EPOCH_YEAR - UNIX_EPOCH_YEAR)
-/* number of days from Unix epoch to exFAT epoch (considering leap days) */
-#define EPOCH_DIFF_DAYS (EPOCH_DIFF_YEAR * 365 + EPOCH_DIFF_YEAR / 4)
-/* number of seconds from Unix epoch to exFAT epoch (considering leap days) */
-#define EPOCH_DIFF_SEC (EPOCH_DIFF_DAYS * SEC_IN_DAY)
-/* number of leap years passed from exFAT epoch to the specified year
-   (excluding the specified year itself) */
-#define LEAP_YEARS(year) ((EXFAT_EPOCH_YEAR + (year) - 1) / 4 \
-               - (EXFAT_EPOCH_YEAR - 1) / 4)
-/* checks whether the specified year is leap */
-#define IS_LEAP_YEAR(year) ((EXFAT_EPOCH_YEAR + (year)) % 4 == 0)
-
-static const time_t days_in_year[] =
-{
-       /* Jan  Feb  Mar  Apr  May  Jun  Jul  Aug  Sep  Oct  Nov  Dec */
-       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 unix_time = EPOCH_DIFF_SEC;
-       uint16_t ndate = le16_to_cpu(date);
-       uint16_t ntime = le16_to_cpu(time);
-
-       uint16_t day    = ndate & 0x1f;     /* 5 bits, 1-31 */
-       uint16_t month  = ndate >> 5 & 0xf; /* 4 bits, 1-12 */
-       uint16_t year   = ndate >> 9;       /* 7 bits, 1-127 (+1980) */
-
-       uint16_t twosec = ntime & 0x1f;     /* 5 bits, 0-29 (2 sec granularity) */
-       uint16_t min    = ntime >> 5 & 0xf; /* 6 bits, 0-59 */
-       uint16_t hour   = ntime >> 11;      /* 5 bits, 0-23 */
-
-       if (day == 0 || month == 0 || month > 12)
-       {
-               exfat_error("bad date %hu-%02hu-%02hu",
-                               year + EXFAT_EPOCH_YEAR, month, day);
-               return 0;
-       }
-       if (hour > 23 || min > 59 || twosec > 29)
-       {
-               exfat_error("bad time %hu:%02hu:%02hu",
-                               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 += days_in_year[month] * SEC_IN_DAY;
-       /* if it's leap year and February has passed we should add 1 day */
-       if ((EXFAT_EPOCH_YEAR + year) % 4 == 0 && month > 2)
-               unix_time += SEC_IN_DAY;
-       unix_time += (day - 1) * SEC_IN_DAY;
-
-       unix_time += hour * SEC_IN_HOUR;
-       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,
-               uint8_t* centisec)
-{
-       time_t shift = EPOCH_DIFF_SEC + timezone;
-       uint16_t day, month, year;
-       uint16_t twosec, min, hour;
-       int days;
-       int i;
-
-       /* time before exFAT epoch cannot be represented */
-       if (unix_time < shift)
-               unix_time = shift;
-
-       unix_time -= shift;
-
-       days = unix_time / SEC_IN_DAY;
-       year = (4 * days) / (4 * 365 + 1);
-       days -= year * 365 + LEAP_YEARS(year);
-       month = 0;
-       for (i = 1; i <= 12; i++)
-       {
-               int leap_day = (IS_LEAP_YEAR(year) && i == 2);
-               int leap_sub = (IS_LEAP_YEAR(year) && i >= 3);
-
-               if (i == 12 || days - leap_sub < days_in_year[i + 1] + leap_day)
-               {
-                       month = i;
-                       days -= days_in_year[i] + leap_sub;
-                       break;
-               }
-       }
-       day = days + 1;
-
-       hour = (unix_time % SEC_IN_DAY) / SEC_IN_HOUR;
-       min = (unix_time % SEC_IN_HOUR) / SEC_IN_MIN;
-       twosec = (unix_time % SEC_IN_MIN) / 2;
-
-       *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)
 {
        if (utf16_to_utf8(buffer, node->name, n, EXFAT_NAME_MAX) != 0)
 void exfat_get_name(const struct exfat_node* node, char* buffer, size_t n)
 {
        if (utf16_to_utf8(buffer, node->name, n, EXFAT_NAME_MAX) != 0)
@@ -207,7 +85,8 @@ le16_t exfat_calc_checksum(const struct exfat_entry_meta1* meta1,
        {
                struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0};
                memcpy(name_entry.name, name + i * EXFAT_ENAME_MAX,
        {
                struct exfat_entry_name name_entry = {EXFAT_ENTRY_FILE_NAME, 0};
                memcpy(name_entry.name, name + i * EXFAT_ENAME_MAX,
-                               EXFAT_ENAME_MAX * sizeof(le16_t));
+                               MIN(EXFAT_ENAME_MAX, EXFAT_NAME_MAX - i * EXFAT_ENAME_MAX) *
+                               sizeof(le16_t));
                checksum = exfat_add_checksum(&name_entry, checksum);
        }
        return cpu_to_le16(checksum);
                checksum = exfat_add_checksum(&name_entry, checksum);
        }
        return cpu_to_le16(checksum);
@@ -234,7 +113,6 @@ uint32_t exfat_vbr_add_checksum(const void* sector, size_t size, uint32_t sum)
        return sum;
 }
 
        return sum;
 }
 
-
 le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name)
 {
        size_t i;
 le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name)
 {
        size_t i;
@@ -258,11 +136,13 @@ le16_t exfat_calc_name_hash(const struct exfat* ef, const le16_t* name)
 void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb)
 {
        size_t i;
 void exfat_humanize_bytes(uint64_t value, struct exfat_human_bytes* hb)
 {
        size_t i;
-       const char* units[] = {"bytes", "KB", "MB", "GB", "TB", "PB"};
+       /* 16 EB (minus 1 byte) is the largest size that can be represented by
+          uint64_t */
+       const char* units[] = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB"};
        uint64_t divisor = 1;
        uint64_t temp = 0;
 
        uint64_t divisor = 1;
        uint64_t temp = 0;
 
-       for (i = 0; i < sizeof(units) / sizeof(units[0]) - 1; i++, divisor *= 1024)
+       for (i = 0; ; i++, divisor *= 1024)
        {
                temp = (value + divisor / 2) / divisor;
 
        {
                temp = (value + divisor / 2) / divisor;