mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
fatfs: fix incorrect mtime returned for files created during DST
mktime function uses tm_isdst member as an indicator whether the time stamp is expected to be in daylight saving time (1) or not (0). FAT filesystem uses local time as mtime, so no information about DST is available from the filesystem. According to mktime documentation, tm_isdst can be set to -1, in which case the C library will try to determine if DST was or wasn't in effect at that time, and will set UTC time accordingly. Note that the conversion from UTC to local time and then back to UTC (time_t -> localtime_r -> FAT timestamp -> mktime -> time_t) does not always recover the same UTC time. In particular, the local time in the hour before DST comes into effect can be interpreted as "before DST" or "after DST", which would correspond to different UTC values. In this case which option the C library chooses is undefined. Closes https://github.com/espressif/esp-idf/issues/9039 Originally reported in https://github.com/espressif/arduino-esp32/issues/6786
This commit is contained in:
parent
dc4c9c087f
commit
d7db6c3148
@ -317,13 +317,14 @@ void test_fatfs_truncate_file(const char* filename)
|
||||
|
||||
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);
|
||||
printf("Setting time: %s", asctime(&tm));
|
||||
struct timeval now = { .tv_sec = t };
|
||||
@ -348,6 +349,34 @@ void test_fatfs_stat(const char* filename, const char* root_dir)
|
||||
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)
|
||||
{
|
||||
struct stat achieved_stat;
|
||||
|
@ -53,6 +53,8 @@ void test_fatfs_truncate_file(const char* path);
|
||||
|
||||
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_unlink(const char* filename);
|
||||
|
@ -125,6 +125,13 @@ TEST_CASE("(WL) stat returns correct values", "[fatfs][wear_levelling]")
|
||||
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_setup();
|
||||
|
@ -611,7 +611,13 @@ static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
|
||||
.tm_year = fdate.year + 80,
|
||||
.tm_sec = ftime.sec * 2,
|
||||
.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_atime = 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user