From 1bb0815fed4e0601f49e934b601e4912ff25a4e9 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 31 Oct 2020 08:05:34 -0700 Subject: [PATCH] Hook up custom timestamp proc for SD/SDFS (#7686) 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 | 31 +++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/libraries/SDFS/src/SDFS.cpp b/libraries/SDFS/src/SDFS.cpp index d862ff5d8..cbcc16600 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 d92d40092..a3d159fbb 100644 --- a/libraries/SDFS/src/SDFS.h +++ b/libraries/SDFS/src/SDFS.h @@ -205,12 +205,21 @@ public: 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 fb73a6a27..e82d212fb 100644 --- a/tests/host/fs/test_fs.cpp +++ b/tests/host/fs/test_fs.cpp @@ -162,4 +162,35 @@ 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; + bzero(&t, sizeof(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(); +} + };