From fb4e7b0755575296c3b111b48a54a10014c9256d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 29 Oct 2020 21:54:55 -0700 Subject: [PATCH 1/2] Hook up custom timestamp proc for SD/SDFS The SDFS implementation didn't include plumbing to support user-supplied timestamp generators (for file create/write times) because the SDFat library doesn't support a callback parameter. Work around it by using a single, global (inside sdfs namespace) that the static timestamp callback member can see and use. Add a test of the feature in CI. Fixes #7682 --- libraries/SDFS/src/SDFS.cpp | 2 ++ libraries/SDFS/src/SDFS.h | 17 +++++++++++++---- tests/host/fs/test_fs.cpp | 30 ++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/libraries/SDFS/src/SDFS.cpp b/libraries/SDFS/src/SDFS.cpp index d862ff5d89..cbcc166000 100644 --- a/libraries/SDFS/src/SDFS.cpp +++ b/libraries/SDFS/src/SDFS.cpp @@ -37,6 +37,8 @@ FS SDFS = FS(FSImplPtr(new sdfs::SDFSImpl())); namespace sdfs { +// Required to be global because SDFAT doesn't allow a this pointer in it's own time call +time_t (*__sdfs_timeCallback)(void) = nullptr; FileImplPtr SDFSImpl::open(const char* path, OpenMode openMode, AccessMode accessMode) { diff --git a/libraries/SDFS/src/SDFS.h b/libraries/SDFS/src/SDFS.h index d92d400923..a3d159fbb3 100644 --- a/libraries/SDFS/src/SDFS.h +++ b/libraries/SDFS/src/SDFS.h @@ -205,12 +205,21 @@ class SDFSImpl : public FSImpl return mktime(&tiempo); } + virtual void setTimeCallback(time_t (*cb)(void)) override { + extern time_t (*__sdfs_timeCallback)(void); + __sdfs_timeCallback = cb; + } + // Because SdFat has a single, global setting for this we can only use a - // static member of our class to return the time/date. However, since - // this is static, we can't see the time callback variable. Punt for now, - // using time(NULL) as the best we can do. + // static member of our class to return the time/date. static void dateTimeCB(uint16_t *dosYear, uint16_t *dosTime) { - time_t now = time(nullptr); + time_t now; + extern time_t (*__sdfs_timeCallback)(void); + if (__sdfs_timeCallback) { + now = __sdfs_timeCallback(); + } else { + now = time(nullptr); + } struct tm *tiempo = localtime(&now); *dosYear = ((tiempo->tm_year - 80) << 9) | ((tiempo->tm_mon + 1) << 5) | tiempo->tm_mday; *dosTime = (tiempo->tm_hour << 11) | (tiempo->tm_min << 5) | tiempo->tm_sec; diff --git a/tests/host/fs/test_fs.cpp b/tests/host/fs/test_fs.cpp index fb73a6a271..3ca1c4b7f3 100644 --- a/tests/host/fs/test_fs.cpp +++ b/tests/host/fs/test_fs.cpp @@ -162,4 +162,34 @@ TEST_CASE("SD.h FILE_WRITE macro is append", "[fs]") REQUIRE(u == 0); } +// SDFS timestamp setter (#7682) +static time_t _my_time(void) +{ + struct tm t; + t.tm_year = 120; + t.tm_mon = 9; + t.tm_mday = 22; + t.tm_hour = 12; + t.tm_min = 13; + t.tm_sec = 14; + return mktime(&t); +} + +TEST_CASE("SDFS timeCallback") +{ + SDFS_MOCK_DECLARE(64, 8, 512, ""); + REQUIRE(SDFS.begin()); + REQUIRE(SD.begin(4)); + + SDFS.setTimeCallback(_my_time); + File f = SD.open("/file.txt", "w"); + f.write("Had we but world enough, and time,"); + f.close(); + time_t expected = _my_time(); + f = SD.open("/file.txt", "r"); + REQUIRE(abs(f.getCreationTime() - expected) < 60); // FAT has less precision in timestamp than time_t + REQUIRE(abs(f.getLastWrite() - expected) < 60); // FAT has less precision in timestamp than time_t + f.close(); +} + }; From d848a2aa26a9b06feb8389e0598ff1ae56e94663 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 29 Oct 2020 22:16:39 -0700 Subject: [PATCH 2/2] Clear all fields in time_t test --- tests/host/fs/test_fs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/host/fs/test_fs.cpp b/tests/host/fs/test_fs.cpp index 3ca1c4b7f3..e82d212fb0 100644 --- a/tests/host/fs/test_fs.cpp +++ b/tests/host/fs/test_fs.cpp @@ -166,6 +166,7 @@ TEST_CASE("SD.h FILE_WRITE macro is append", "[fs]") static time_t _my_time(void) { struct tm t; + bzero(&t, sizeof(t)); t.tm_year = 120; t.tm_mon = 9; t.tm_mday = 22;