diff --git a/cores/esp8266/FS.cpp b/cores/esp8266/FS.cpp index d73be017a3..f897a52d1d 100644 --- a/cores/esp8266/FS.cpp +++ b/cores/esp8266/FS.cpp @@ -206,6 +206,7 @@ void File::setTimeCallback(time_t (*cb)(void)) { if (!_p) return; _p->setTimeCallback(cb); + _timeCallback = cb; } File Dir::openFile(const char* mode) { @@ -221,7 +222,7 @@ File Dir::openFile(const char* mode) { } File f(_impl->openFile(om, am), _baseFS); - f.setTimeCallback(timeCallback); + f.setTimeCallback(_timeCallback); return f; } @@ -287,7 +288,7 @@ void Dir::setTimeCallback(time_t (*cb)(void)) { if (!_impl) return; _impl->setTimeCallback(cb); - timeCallback = cb; + _timeCallback = cb; } @@ -304,7 +305,7 @@ bool FS::begin() { DEBUGV("#error: FS: no implementation"); return false; } - _impl->setTimeCallback(timeCallback); + _impl->setTimeCallback(_timeCallback); bool ret = _impl->begin(); DEBUGV("%s\n", ret? "": "#error: FS could not start"); return ret; @@ -367,7 +368,7 @@ File FS::open(const char* path, const char* mode) { return File(); } File f(_impl->open(path, om, am), this); - f.setTimeCallback(timeCallback); + f.setTimeCallback(_timeCallback); return f; } @@ -388,7 +389,7 @@ Dir FS::openDir(const char* path) { } DirImplPtr p = _impl->openDir(path); Dir d(p, this); - d.setTimeCallback(timeCallback); + d.setTimeCallback(_timeCallback); return d; } @@ -444,6 +445,7 @@ void FS::setTimeCallback(time_t (*cb)(void)) { if (!_impl) return; _impl->setTimeCallback(cb); + _timeCallback = cb; } diff --git a/cores/esp8266/FS.h b/cores/esp8266/FS.h index b1f1c528aa..99c71cdcea 100644 --- a/cores/esp8266/FS.h +++ b/cores/esp8266/FS.h @@ -118,6 +118,7 @@ class File : public Stream protected: FileImplPtr _p; + time_t (*_timeCallback)(void) = nullptr; // Arduino SD class emulation std::shared_ptr _fakeDir; @@ -145,7 +146,7 @@ class Dir { protected: DirImplPtr _impl; FS *_baseFS; - time_t (*timeCallback)(void) = nullptr; + time_t (*_timeCallback)(void) = nullptr; }; // Backwards compatible, <4GB filesystem usage @@ -198,7 +199,7 @@ class SPIFFSConfig : public FSConfig class FS { public: - FS(FSImplPtr impl) : _impl(impl) { timeCallback = _defaultTimeCB; } + FS(FSImplPtr impl) : _impl(impl) { _timeCallback = _defaultTimeCB; } bool setConfig(const FSConfig &cfg); @@ -240,7 +241,7 @@ class FS protected: FSImplPtr _impl; FSImplPtr getImpl() { return _impl; } - time_t (*timeCallback)(void); + time_t (*_timeCallback)(void) = nullptr; static time_t _defaultTimeCB(void) { return time(NULL); } }; diff --git a/cores/esp8266/FSImpl.h b/cores/esp8266/FSImpl.h index 373b26f2ca..801a8d9c0d 100644 --- a/cores/esp8266/FSImpl.h +++ b/cores/esp8266/FSImpl.h @@ -45,8 +45,8 @@ class FileImpl { // Filesystems *may* support a timestamp per-file, so allow the user to override with // their own callback for *this specific* file (as opposed to the FSImpl call of the - // same name. The default implementation simply returns time(&null) - virtual void setTimeCallback(time_t (*cb)(void)) { timeCallback = cb; } + // same name. The default implementation simply returns time(null) + virtual void setTimeCallback(time_t (*cb)(void)) { _timeCallback = cb; } // Return the last written time for a file. Undefined when called on a writable file // as the FS is allowed to return either the time of the last write() operation or the @@ -56,7 +56,7 @@ class FileImpl { virtual time_t getCreationTime() { return 0; } // Default is to not support timestamps protected: - time_t (*timeCallback)(void) = nullptr; + time_t (*_timeCallback)(void) = nullptr; }; enum OpenMode { @@ -90,11 +90,11 @@ class DirImpl { // Filesystems *may* support a timestamp per-file, so allow the user to override with // their own callback for *this specific* file (as opposed to the FSImpl call of the - // same name. The default implementation simply returns time(&null) - virtual void setTimeCallback(time_t (*cb)(void)) { timeCallback = cb; } + // same name. The default implementation simply returns time(null) + virtual void setTimeCallback(time_t (*cb)(void)) { _timeCallback = cb; } protected: - time_t (*timeCallback)(void) = nullptr; + time_t (*_timeCallback)(void) = nullptr; }; class FSImpl { @@ -118,11 +118,11 @@ class FSImpl { // Filesystems *may* support a timestamp per-file, so allow the user to override with // their own callback for all files on this FS. The default implementation simply - // returns the present time as reported by time(&null) - virtual void setTimeCallback(time_t (*cb)(void)) { timeCallback = cb; } + // returns the present time as reported by time(null) + virtual void setTimeCallback(time_t (*cb)(void)) { _timeCallback = cb; } protected: - time_t (*timeCallback)(void) = nullptr; + time_t (*_timeCallback)(void) = nullptr; }; } // namespace fs diff --git a/libraries/LittleFS/src/LittleFS.cpp b/libraries/LittleFS/src/LittleFS.cpp index 7fd4351fcb..16f4df55e9 100644 --- a/libraries/LittleFS/src/LittleFS.cpp +++ b/libraries/LittleFS/src/LittleFS.cpp @@ -70,14 +70,14 @@ FileImplPtr LittleFSImpl::open(const char* path, OpenMode openMode, AccessMode a } time_t creation = 0; - if (timeCallback && (openMode & OM_CREATE)) { + if (_timeCallback && (openMode & OM_CREATE)) { // O_CREATE means we *may* make the file, but not if it already exists. // See if it exists, and only if not update the creation time int rc = lfs_file_open(&_lfs, fd.get(), path, LFS_O_RDONLY); if (rc == 0) { lfs_file_close(&_lfs, fd.get()); // It exists, don't update create time } else { - creation = timeCallback(); // File didn't exist or otherwise, so we're going to create this time + creation = _timeCallback(); // File didn't exist or otherwise, so we're going to create this time } } diff --git a/libraries/LittleFS/src/LittleFS.h b/libraries/LittleFS/src/LittleFS.h index f78680f662..495b63421e 100644 --- a/libraries/LittleFS/src/LittleFS.h +++ b/libraries/LittleFS/src/LittleFS.h @@ -424,7 +424,7 @@ class LittleFSFileImpl : public FileImpl lfs_file_close(_fs->getFS(), _getFD()); _opened = false; DEBUGV("lfs_file_close: fd=%p\n", _getFD()); - if (timeCallback && (_flags & LFS_O_WRONLY)) { + if (_timeCallback && (_flags & LFS_O_WRONLY)) { // If the file opened with O_CREAT, write the creation time attribute if (_creation) { int rc = lfs_setattr(_fs->getFS(), _name.get(), 'c', (const void *)&_creation, sizeof(_creation)); @@ -433,7 +433,7 @@ class LittleFSFileImpl : public FileImpl } } // Add metadata with last write time - time_t now = timeCallback(); + time_t now = _timeCallback(); int rc = lfs_setattr(_fs->getFS(), _name.get(), 't', (const void *)&now, sizeof(now)); if (rc < 0) { DEBUGV("Unable to set last write time on '%s' to %d\n", _name.get(), now); diff --git a/tests/host/fs/test_fs.cpp b/tests/host/fs/test_fs.cpp index e82d212fb0..fb73a6a271 100644 --- a/tests/host/fs/test_fs.cpp +++ b/tests/host/fs/test_fs.cpp @@ -162,35 +162,4 @@ 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(); -} - }; diff --git a/tests/host/fs/test_fs.inc b/tests/host/fs/test_fs.inc index 683f3a99ba..b7e7692a46 100644 --- a/tests/host/fs/test_fs.inc +++ b/tests/host/fs/test_fs.inc @@ -220,6 +220,40 @@ TEST_CASE(TESTPRE "Rewriting file frees space immediately (#7426)", TESTPAT) } } +#if FSTYPE != SPIFFS + +// Timestamp setter (#7682, #7775) +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("Verify timeCallback works properly") +{ + FS_MOCK_DECLARE(64, 8, 512, ""); + REQUIRE(FSTYPE.begin()); + + FSTYPE.setTimeCallback(_my_time); + File f = FSTYPE.open("/file.txt", "w"); + f.write("Had we but world enough, and time,"); + f.close(); + time_t expected = _my_time(); + f = FSTYPE.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(); +} + +#endif + #ifdef FS_HAS_DIRS #if FSTYPE != SDFS