Преглед изворни кода

Merge branch 'bugfix/fatfs_mtime_dst' into 'master'

fatfs: fix incorrect mtime returned for files created during DST

Closes IDFGH-7467

See merge request espressif/esp-idf!18333
Martin Vychodil пре 3 година
родитељ
комит
aa2cf79e13

+ 36 - 7
components/fatfs/test/test_fatfs_common.c

@@ -382,13 +382,14 @@ void test_fatfs_ftruncate_file(const char* filename)
 
 
 void test_fatfs_stat(const char* filename, const char* root_dir)
 void test_fatfs_stat(const char* filename, const char* root_dir)
 {
 {
-    struct tm tm;
-    tm.tm_year = 2017 - 1900;
-    tm.tm_mon = 11;
-    tm.tm_mday = 8;
-    tm.tm_hour = 19;
-    tm.tm_min = 51;
-    tm.tm_sec = 10;
+    struct tm tm = {
+        .tm_year = 2017 - 1900,
+        .tm_mon = 11,
+        .tm_mday = 8,
+        .tm_hour = 19,
+        .tm_min = 51,
+        .tm_sec = 10
+    };
     time_t t = mktime(&tm);
     time_t t = mktime(&tm);
     printf("Setting time: %s", asctime(&tm));
     printf("Setting time: %s", asctime(&tm));
     struct timeval now = { .tv_sec = t };
     struct timeval now = { .tv_sec = t };
@@ -413,6 +414,34 @@ void test_fatfs_stat(const char* filename, const char* root_dir)
     TEST_ASSERT_FALSE(st.st_mode & S_IFREG);
     TEST_ASSERT_FALSE(st.st_mode & S_IFREG);
 }
 }
 
 
+void test_fatfs_mtime_dst(const char* filename, const char* root_dir)
+{
+    struct timeval tv = { 1653638041, 0 };
+    settimeofday(&tv, NULL);
+    setenv("TZ", "MST7MDT,M3.2.0,M11.1.0", 1);
+    tzset();
+
+    struct tm tm;
+    time_t sys_time = tv.tv_sec;
+    localtime_r(&sys_time, &tm);
+    printf("Setting time: %s", asctime(&tm));
+
+    test_fatfs_create_file_with_text(filename, "foo\n");
+
+    struct stat st;
+    TEST_ASSERT_EQUAL(0, stat(filename, &st));
+
+    time_t mtime = st.st_mtime;
+    struct tm mtm;
+    localtime_r(&mtime, &mtm);
+    printf("File time: %s", asctime(&mtm));
+
+    TEST_ASSERT(llabs(mtime - sys_time) < 2);    // fatfs library stores time with 2 second precision
+
+    unsetenv("TZ");
+    tzset();
+}
+
 void test_fatfs_utime(const char* filename, const char* root_dir)
 void test_fatfs_utime(const char* filename, const char* root_dir)
 {
 {
     struct stat achieved_stat;
     struct stat achieved_stat;

+ 2 - 0
components/fatfs/test/test_fatfs_common.h

@@ -47,6 +47,8 @@ void test_fatfs_ftruncate_file(const char* path);
 
 
 void test_fatfs_stat(const char* filename, const char* root_dir);
 void test_fatfs_stat(const char* filename, const char* root_dir);
 
 
+void test_fatfs_mtime_dst(const char* filename, const char* root_dir);
+
 void test_fatfs_utime(const char* filename, const char* root_dir);
 void test_fatfs_utime(const char* filename, const char* root_dir);
 
 
 void test_fatfs_unlink(const char* filename);
 void test_fatfs_unlink(const char* filename);

+ 7 - 0
components/fatfs/test/test_fatfs_spiflash.c

@@ -119,6 +119,13 @@ TEST_CASE("(WL) stat returns correct values", "[fatfs][wear_levelling]")
     test_teardown();
     test_teardown();
 }
 }
 
 
+TEST_CASE("(WL) stat returns correct mtime if DST is enabled", "[fatfs][wear_levelling]")
+{
+    test_setup();
+    test_fatfs_mtime_dst("/spiflash/statdst.txt", "/spiflash");
+    test_teardown();
+}
+
 TEST_CASE("(WL) utime sets modification time", "[fatfs][wear_levelling]")
 TEST_CASE("(WL) utime sets modification time", "[fatfs][wear_levelling]")
 {
 {
     test_setup();
     test_setup();

+ 7 - 1
components/fatfs/vfs/vfs_fat.c

@@ -637,7 +637,13 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
         .tm_year = fdate.year + 80,
         .tm_year = fdate.year + 80,
         .tm_sec = ftime.sec * 2,
         .tm_sec = ftime.sec * 2,
         .tm_min = ftime.min,
         .tm_min = ftime.min,
-        .tm_hour = ftime.hour
+        .tm_hour = ftime.hour,
+        /* FAT doesn't keep track if the time was DST or not, ask the C library
+         * to try to figure this out. Note that this may yield incorrect result
+         * in the hour before the DST comes in effect, when the local time can't
+         * be converted to UTC uniquely.
+         */
+        .tm_isdst = -1
     };
     };
     st->st_mtime = mktime(&tm);
     st->st_mtime = mktime(&tm);
     st->st_atime = 0;
     st->st_atime = 0;