mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-16 00:43:00 +03:00
Add time to filesystem API (#6544)
* Add time to filesystem API Support the ESP32 File::getLastWrite() call and setting the time on all filesystems automatically (assuming the system clock has been set properly and time(NULL) returns the proper time!). Adds Dir::fileTime() to get the time of a file being listed, similar to Dir::fileName() and Dir::fileSize(). Adds ::setTimeCallback(time_t (*cb)()) to File, Dir, and FS, allowing users to override the default timestamp on a per-file, directory, or filesystem basis. By default, a simple callback returning time(nullptr) is implemented. LittleFS uses the 't' attribute and should be backwards compatible. SD/SDFS work and include wrappers for obsolete SdFat timestamp callbacks using the MSDOS time. This PR does not update SPIFFS, due to compatability concerns and a possible massive rewrite which would make it possible to determine if an old-style ot metadata enabled FS is present at mount time. Includes an updated SD/listfiles and LittleFS_time example. Replaces #6315 * Add links to new mklittlefs w/timestamp support Include the update mklittlefs which generated 't' metadata on imported files. ../tools/sdk/lwip2/include/netif/lowpan6_opts.h * Add explicit note about timestamp being local time * Address review concerns Clean up some awkward object instantiations. Remove the _enableTime flag/setter from SPIFFS. Clean up the FSConfig constructors using C++ style init lists.
This commit is contained in:
committed by
david gauchard
parent
b4c28e74d6
commit
72dd589599
@ -180,6 +180,19 @@ String File::readString()
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_t File::getLastWrite() {
|
||||
if (!_p)
|
||||
return 0;
|
||||
|
||||
return _p->getLastWrite();
|
||||
}
|
||||
|
||||
void File::setTimeCallback(time_t (*cb)(void)) {
|
||||
if (!_p)
|
||||
return;
|
||||
_p->setTimeCallback(cb);
|
||||
}
|
||||
|
||||
File Dir::openFile(const char* mode) {
|
||||
if (!_impl) {
|
||||
return File();
|
||||
@ -192,7 +205,9 @@ File Dir::openFile(const char* mode) {
|
||||
return File();
|
||||
}
|
||||
|
||||
return File(_impl->openFile(om, am), _baseFS);
|
||||
File f(_impl->openFile(om, am), _baseFS);
|
||||
f.setTimeCallback(timeCallback);
|
||||
return f;
|
||||
}
|
||||
|
||||
String Dir::fileName() {
|
||||
@ -203,6 +218,12 @@ String Dir::fileName() {
|
||||
return _impl->fileName();
|
||||
}
|
||||
|
||||
time_t Dir::fileTime() {
|
||||
if (!_impl)
|
||||
return 0;
|
||||
return _impl->fileTime();
|
||||
}
|
||||
|
||||
size_t Dir::fileSize() {
|
||||
if (!_impl) {
|
||||
return 0;
|
||||
@ -241,6 +262,20 @@ bool Dir::rewind() {
|
||||
return _impl->rewind();
|
||||
}
|
||||
|
||||
time_t Dir::getLastWrite() {
|
||||
if (!_impl)
|
||||
return 0;
|
||||
|
||||
return _impl->getLastWrite();
|
||||
}
|
||||
|
||||
void Dir::setTimeCallback(time_t (*cb)(void)) {
|
||||
if (!_impl)
|
||||
return;
|
||||
_impl->setTimeCallback(cb);
|
||||
}
|
||||
|
||||
|
||||
bool FS::setConfig(const FSConfig &cfg) {
|
||||
if (!_impl) {
|
||||
return false;
|
||||
@ -315,7 +350,9 @@ File FS::open(const char* path, const char* mode) {
|
||||
DEBUGV("FS::open: invalid mode `%s`\r\n", mode);
|
||||
return File();
|
||||
}
|
||||
return File(_impl->open(path, om, am), this);
|
||||
File f(_impl->open(path, om, am), this);
|
||||
f.setTimeCallback(timeCallback);
|
||||
return f;
|
||||
}
|
||||
|
||||
bool FS::exists(const char* path) {
|
||||
@ -334,7 +371,9 @@ Dir FS::openDir(const char* path) {
|
||||
return Dir();
|
||||
}
|
||||
DirImplPtr p = _impl->openDir(path);
|
||||
return Dir(p, this);
|
||||
Dir d(p, this);
|
||||
d.setTimeCallback(timeCallback);
|
||||
return d;
|
||||
}
|
||||
|
||||
Dir FS::openDir(const String& path) {
|
||||
@ -385,6 +424,11 @@ bool FS::rename(const String& pathFrom, const String& pathTo) {
|
||||
return rename(pathFrom.c_str(), pathTo.c_str());
|
||||
}
|
||||
|
||||
void FS::setTimeCallback(time_t (*cb)(void)) {
|
||||
if (!_impl)
|
||||
return;
|
||||
_impl->setTimeCallback(cb);
|
||||
}
|
||||
|
||||
|
||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
|
||||
|
@ -110,12 +110,16 @@ public:
|
||||
|
||||
String readString() override;
|
||||
|
||||
time_t getLastWrite();
|
||||
void setTimeCallback(time_t (*cb)(void));
|
||||
|
||||
protected:
|
||||
FileImplPtr _p;
|
||||
|
||||
// Arduino SD class emulation
|
||||
std::shared_ptr<Dir> _fakeDir;
|
||||
FS *_baseFS;
|
||||
time_t (*timeCallback)(void) = nullptr;
|
||||
};
|
||||
|
||||
class Dir {
|
||||
@ -126,15 +130,21 @@ public:
|
||||
|
||||
String fileName();
|
||||
size_t fileSize();
|
||||
time_t fileTime();
|
||||
bool isFile() const;
|
||||
bool isDirectory() const;
|
||||
|
||||
bool next();
|
||||
bool rewind();
|
||||
|
||||
time_t getLastWrite();
|
||||
void setTimeCallback(time_t (*cb)(void));
|
||||
|
||||
protected:
|
||||
DirImplPtr _impl;
|
||||
FS *_baseFS;
|
||||
time_t (*timeCallback)(void) = nullptr;
|
||||
|
||||
};
|
||||
|
||||
// Backwards compatible, <4GB filesystem usage
|
||||
@ -161,12 +171,10 @@ struct FSInfo64 {
|
||||
class FSConfig
|
||||
{
|
||||
public:
|
||||
FSConfig(bool autoFormat = true) {
|
||||
_type = FSConfig::fsid::FSId;
|
||||
_autoFormat = autoFormat;
|
||||
}
|
||||
static constexpr uint32_t FSId = 0x00000000;
|
||||
|
||||
FSConfig(uint32_t type = FSId, bool autoFormat = true) : _type(type), _autoFormat(autoFormat) { }
|
||||
|
||||
enum fsid { FSId = 0x00000000 };
|
||||
FSConfig setAutoFormat(bool val = true) {
|
||||
_autoFormat = val;
|
||||
return *this;
|
||||
@ -179,17 +187,17 @@ public:
|
||||
class SPIFFSConfig : public FSConfig
|
||||
{
|
||||
public:
|
||||
SPIFFSConfig(bool autoFormat = true) {
|
||||
_type = SPIFFSConfig::fsid::FSId;
|
||||
_autoFormat = autoFormat;
|
||||
}
|
||||
enum fsid { FSId = 0x53504946 };
|
||||
static constexpr uint32_t FSId = 0x53504946;
|
||||
SPIFFSConfig(bool autoFormat = true) : FSConfig(FSId, autoFormat) { }
|
||||
|
||||
// Inherit _type and _autoFormat
|
||||
// nothing yet, enableTime TBD when SPIFFS has metadate
|
||||
};
|
||||
|
||||
class FS
|
||||
{
|
||||
public:
|
||||
FS(FSImplPtr impl) : _impl(impl) { }
|
||||
FS(FSImplPtr impl) : _impl(impl) { timeCallback = _defaultTimeCB; }
|
||||
|
||||
bool setConfig(const FSConfig &cfg);
|
||||
|
||||
@ -225,10 +233,14 @@ public:
|
||||
bool gc();
|
||||
bool check();
|
||||
|
||||
void setTimeCallback(time_t (*cb)(void));
|
||||
|
||||
friend class ::SDClass; // More of a frenemy, but SD needs internal implementation to get private FAT bits
|
||||
protected:
|
||||
FSImplPtr _impl;
|
||||
FSImplPtr getImpl() { return _impl; }
|
||||
time_t (*timeCallback)(void);
|
||||
static time_t _defaultTimeCB(void) { return time(NULL); }
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
@ -41,6 +41,19 @@ public:
|
||||
virtual const char* fullName() const = 0;
|
||||
virtual bool isFile() const = 0;
|
||||
virtual bool isDirectory() const = 0;
|
||||
|
||||
// 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; }
|
||||
|
||||
// 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
|
||||
// time present in the filesystem metadata (often the last time the file was closed)
|
||||
virtual time_t getLastWrite() { return 0; } // Default is to not support timestamps
|
||||
|
||||
protected:
|
||||
time_t (*timeCallback)(void) = nullptr;
|
||||
};
|
||||
|
||||
enum OpenMode {
|
||||
@ -62,10 +75,24 @@ public:
|
||||
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
|
||||
virtual const char* fileName() = 0;
|
||||
virtual size_t fileSize() = 0;
|
||||
virtual time_t fileTime() { return 0; } // By default, FS doesn't report file times
|
||||
virtual bool isFile() const = 0;
|
||||
virtual bool isDirectory() const = 0;
|
||||
virtual bool next() = 0;
|
||||
virtual bool rewind() = 0;
|
||||
|
||||
// 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; }
|
||||
|
||||
// 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
|
||||
// time present in the filesystem metadata (often the last time the file was closed)
|
||||
virtual time_t getLastWrite() { return 0; } // Default is to not support timestamps
|
||||
|
||||
protected:
|
||||
time_t (*timeCallback)(void) = nullptr;
|
||||
};
|
||||
|
||||
class FSImpl {
|
||||
@ -86,6 +113,14 @@ public:
|
||||
virtual bool rmdir(const char* path) = 0;
|
||||
virtual bool gc() { return true; } // May not be implemented in all file systems.
|
||||
virtual bool check() { return true; } // May not be implemented in all file systems.
|
||||
|
||||
// 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; }
|
||||
|
||||
protected:
|
||||
time_t (*timeCallback)(void) = nullptr;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
@ -162,7 +162,7 @@ public:
|
||||
|
||||
bool setConfig(const FSConfig &cfg) override
|
||||
{
|
||||
if ((cfg._type != SPIFFSConfig::fsid::FSId) || (SPIFFS_mounted(&_fs) != 0)) {
|
||||
if ((cfg._type != SPIFFSConfig::FSId) || (SPIFFS_mounted(&_fs) != 0)) {
|
||||
return false;
|
||||
}
|
||||
_cfg = *static_cast<const SPIFFSConfig *>(&cfg);
|
||||
|
Reference in New Issue
Block a user