1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00

Add fileCreation/getCreation create-time accessors (#7000)

* Add fileCreation/getCreation create-time accessors

For SDFS and LittleFS, enable a creation time accessor for files and Dir
iterators, similar to the existing fileTime/getLastWrite calls.

Remove spurious Dir::getLastWrite method (the proper and only documented
way is really Dir::fileTime).

Update json to point to new mklittlefs which copies the creation date of
files to the image.

Fixes #6992

* Remove malloc(), use stack vars for temp names

LFS filenames are limited in size and generally very small.  Use a stack
variable instead of a dynamic allocation when performing full-path
computations.

* Replace "Creation" w/"CreationTime" in FS accessor

Per review, `getCreation` -> `getCreationTime`, `fileCreation` ->
`fileCreationTime`.

The names `fileTime()` and `getLastWrite()` are inherited from ESP32
implementation and unchanged.

* Add creation time to listfiles SD example

* Enable SdFat's sateTime callback for timestamping

SdFat requries the dateTimeCallback call (global for everything) to
update dates and times on created files.

Because the callback signature doesn't have space for us to provide
any parameters, we cannot get the the File, Dir, or FS object's
dateTimeCB member.  Instead, just go with `time(null)` as the callback
function which is right in all but the most esoteric cases.

* Correct DOS year/month offset in dateTime callback

* Fix docs to match new xxxCreationTime() API names

Co-authored-by: Develo <deveyes@gmail.com>
This commit is contained in:
Earle F. Philhower, III 2020-02-22 12:49:08 -08:00 committed by GitHub
parent 4eca62cb53
commit bea64dfa69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 176 additions and 83 deletions

View File

@ -187,6 +187,13 @@ time_t File::getLastWrite() {
return _p->getLastWrite(); return _p->getLastWrite();
} }
time_t File::getCreationTime() {
if (!_p)
return 0;
return _p->getCreationTime();
}
void File::setTimeCallback(time_t (*cb)(void)) { void File::setTimeCallback(time_t (*cb)(void)) {
if (!_p) if (!_p)
return; return;
@ -224,6 +231,12 @@ time_t Dir::fileTime() {
return _impl->fileTime(); return _impl->fileTime();
} }
time_t Dir::fileCreationTime() {
if (!_impl)
return 0;
return _impl->fileCreationTime();
}
size_t Dir::fileSize() { size_t Dir::fileSize() {
if (!_impl) { if (!_impl) {
return 0; return 0;
@ -262,17 +275,11 @@ bool Dir::rewind() {
return _impl->rewind(); return _impl->rewind();
} }
time_t Dir::getLastWrite() {
if (!_impl)
return 0;
return _impl->getLastWrite();
}
void Dir::setTimeCallback(time_t (*cb)(void)) { void Dir::setTimeCallback(time_t (*cb)(void)) {
if (!_impl) if (!_impl)
return; return;
_impl->setTimeCallback(cb); _impl->setTimeCallback(cb);
timeCallback = cb;
} }
@ -289,6 +296,7 @@ bool FS::begin() {
DEBUGV("#error: FS: no implementation"); DEBUGV("#error: FS: no implementation");
return false; return false;
} }
_impl->setTimeCallback(timeCallback);
bool ret = _impl->begin(); bool ret = _impl->begin();
DEBUGV("%s\n", ret? "": "#error: FS could not start"); DEBUGV("%s\n", ret? "": "#error: FS could not start");
return ret; return ret;

View File

@ -112,6 +112,7 @@ public:
String readString() override; String readString() override;
time_t getLastWrite(); time_t getLastWrite();
time_t getCreationTime();
void setTimeCallback(time_t (*cb)(void)); void setTimeCallback(time_t (*cb)(void));
protected: protected:
@ -120,7 +121,6 @@ protected:
// Arduino SD class emulation // Arduino SD class emulation
std::shared_ptr<Dir> _fakeDir; std::shared_ptr<Dir> _fakeDir;
FS *_baseFS; FS *_baseFS;
time_t (*timeCallback)(void) = nullptr;
}; };
class Dir { class Dir {
@ -132,20 +132,19 @@ public:
String fileName(); String fileName();
size_t fileSize(); size_t fileSize();
time_t fileTime(); time_t fileTime();
time_t fileCreationTime();
bool isFile() const; bool isFile() const;
bool isDirectory() const; bool isDirectory() const;
bool next(); bool next();
bool rewind(); bool rewind();
time_t getLastWrite();
void setTimeCallback(time_t (*cb)(void)); void setTimeCallback(time_t (*cb)(void));
protected: protected:
DirImplPtr _impl; DirImplPtr _impl;
FS *_baseFS; FS *_baseFS;
time_t (*timeCallback)(void) = nullptr; time_t (*timeCallback)(void) = nullptr;
}; };
// Backwards compatible, <4GB filesystem usage // Backwards compatible, <4GB filesystem usage

View File

@ -51,6 +51,8 @@ public:
// as the FS is allowed to return either the time of the last write() operation or the // 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) // 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 virtual time_t getLastWrite() { return 0; } // Default is to not support timestamps
// Same for creation time.
virtual time_t getCreationTime() { return 0; } // Default is to not support timestamps
protected: protected:
time_t (*timeCallback)(void) = nullptr; time_t (*timeCallback)(void) = nullptr;
@ -75,7 +77,11 @@ public:
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0; virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
virtual const char* fileName() = 0; virtual const char* fileName() = 0;
virtual size_t fileSize() = 0; virtual size_t fileSize() = 0;
// 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 fileTime() { return 0; } // By default, FS doesn't report file times virtual time_t fileTime() { return 0; } // By default, FS doesn't report file times
virtual time_t fileCreationTime() { return 0; } // By default, FS doesn't report file times
virtual bool isFile() const = 0; virtual bool isFile() const = 0;
virtual bool isDirectory() const = 0; virtual bool isDirectory() const = 0;
virtual bool next() = 0; virtual bool next() = 0;
@ -86,11 +92,6 @@ public:
// same name. The default implementation simply returns time(&null) // same name. The default implementation simply returns time(&null)
virtual void setTimeCallback(time_t (*cb)(void)) { timeCallback = cb; } 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: protected:
time_t (*timeCallback)(void) = nullptr; time_t (*timeCallback)(void) = nullptr;
}; };

View File

@ -535,6 +535,11 @@ fileTime
Returns the time_t write time of the current file pointed Returns the time_t write time of the current file pointed
to by the internal iterator. to by the internal iterator.
fileCreationTime
~~~~~~~~~~~~~~~~
Returns the time_t creation time of the current file
pointed to by the internal iterator.
isFile isFile
~~~~~~ ~~~~~~
@ -642,6 +647,11 @@ getLastWrite
Returns the file last write time, and only valid for files opened in read-only Returns the file last write time, and only valid for files opened in read-only
mode. If a file is opened for writing, the returned time may be indeterminate. mode. If a file is opened for writing, the returned time may be indeterminate.
getCreationTime
~~~~~~~~~~~~~~~
Returns the file creation time, if available.
isFile isFile
~~~~~~ ~~~~~~

View File

@ -53,9 +53,12 @@ void listDir(const char * dirname) {
Serial.print(root.fileName()); Serial.print(root.fileName());
Serial.print(" SIZE: "); Serial.print(" SIZE: ");
Serial.print(file.size()); Serial.print(file.size());
time_t t = file.getLastWrite(); time_t cr = file.getCreationTime();
struct tm * tmstruct = localtime(&t); time_t lw = file.getLastWrite();
file.close(); file.close();
struct tm * tmstruct = localtime(&cr);
Serial.printf(" CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
tmstruct = localtime(&lw);
Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
} }
} }
@ -90,6 +93,7 @@ void writeFile(const char * path, const char * message) {
} else { } else {
Serial.println("Write failed"); Serial.println("Write failed");
} }
delay(2000); // Make sure the CREATE and LASTWRITE times are different
file.close(); file.close();
} }

View File

@ -68,13 +68,26 @@ FileImplPtr LittleFSImpl::open(const char* path, OpenMode openMode, AccessMode a
} }
free(pathStr); free(pathStr);
} }
time_t creation = 0;
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
}
}
int rc = lfs_file_open(&_lfs, fd.get(), path, flags); int rc = lfs_file_open(&_lfs, fd.get(), path, flags);
if (rc == LFS_ERR_ISDIR) { if (rc == LFS_ERR_ISDIR) {
// To support the SD.openNextFile, a null FD indicates to the LittleFSFile this is just // To support the SD.openNextFile, a null FD indicates to the LittleFSFile this is just
// a directory whose name we are carrying around but which cannot be read or written // a directory whose name we are carrying around but which cannot be read or written
return std::make_shared<LittleFSFileImpl>(this, path, nullptr, flags); return std::make_shared<LittleFSFileImpl>(this, path, nullptr, flags, creation);
} else if (rc == 0) { } else if (rc == 0) {
return std::make_shared<LittleFSFileImpl>(this, path, fd, flags); return std::make_shared<LittleFSFileImpl>(this, path, fd, flags, creation);
} else { } else {
DEBUGV("LittleFSDirImpl::openFile: rc=%d fd=%p path=`%s` openMode=%d accessMode=%d err=%d\n", DEBUGV("LittleFSDirImpl::openFile: rc=%d fd=%p path=`%s` openMode=%d accessMode=%d err=%d\n",
rc, fd.get(), path, openMode, accessMode, rc); rc, fd.get(), path, openMode, accessMode, rc);

View File

@ -89,7 +89,7 @@ public:
DirImplPtr openDir(const char *path) override; DirImplPtr openDir(const char *path) override;
bool exists(const char* path) override { bool exists(const char* path) override {
if ( !_mounted || !path || !path[0] ) { if (!_mounted || !path || !path[0]) {
return false; return false;
} }
lfs_info info; lfs_info info;
@ -98,7 +98,7 @@ public:
} }
bool rename(const char* pathFrom, const char* pathTo) override { bool rename(const char* pathFrom, const char* pathTo) override {
if (!_mounted || !pathFrom || !pathFrom[0] || !pathTo || !pathTo[0]) { if (!_mounted || !pathFrom || !pathFrom[0] || !pathTo || !pathTo[0]) {
return false; return false;
} }
int rc = lfs_rename(&_lfs, pathFrom, pathTo); int rc = lfs_rename(&_lfs, pathFrom, pathTo);
@ -323,7 +323,7 @@ protected:
class LittleFSFileImpl : public FileImpl class LittleFSFileImpl : public FileImpl
{ {
public: public:
LittleFSFileImpl(LittleFSImpl* fs, const char *name, std::shared_ptr<lfs_file_t> fd, int flags) : _fs(fs), _fd(fd), _opened(true), _flags(flags) { LittleFSFileImpl(LittleFSImpl* fs, const char *name, std::shared_ptr<lfs_file_t> fd, int flags, time_t creation) : _fs(fs), _fd(fd), _opened(true), _flags(flags), _creation(creation) {
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>()); _name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
strcpy(_name.get(), name); strcpy(_name.get(), name);
} }
@ -419,13 +419,20 @@ public:
lfs_file_close(_fs->getFS(), _getFD()); lfs_file_close(_fs->getFS(), _getFD());
_opened = false; _opened = false;
DEBUGV("lfs_file_close: fd=%p\n", _getFD()); 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));
if (rc < 0) {
DEBUGV("Unable to set creation time on '%s' to %d\n", _name.get(), _creation);
}
}
// Add metadata with last write time // 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)); int rc = lfs_setattr(_fs->getFS(), _name.get(), 't', (const void *)&now, sizeof(now));
if (rc < 0) { if (rc < 0) {
DEBUGV("Unable to set time on '%s' to %d\n", _name.get(), now); DEBUGV("Unable to set last write time on '%s' to %d\n", _name.get(), now);
} }
} }
} }
} }
@ -440,6 +447,16 @@ public:
return ftime; return ftime;
} }
time_t getCreationTime() override {
time_t ftime = 0;
if (_opened && _fd) {
int rc = lfs_getattr(_fs->getFS(), _name.get(), 'c', (void *)&ftime, sizeof(ftime));
if (rc != sizeof(ftime))
ftime = 0; // Error, so clear read value
}
return ftime;
}
const char* name() const override { const char* name() const override {
if (!_opened) { if (!_opened) {
return nullptr; return nullptr;
@ -484,6 +501,7 @@ protected:
std::shared_ptr<char> _name; std::shared_ptr<char> _name;
bool _opened; bool _opened;
int _flags; int _flags;
time_t _creation;
}; };
class LittleFSDirImpl : public DirImpl class LittleFSDirImpl : public DirImpl
@ -512,13 +530,9 @@ public:
int nameLen = 3; // Slashes, terminator int nameLen = 3; // Slashes, terminator
nameLen += _dirPath.get() ? strlen(_dirPath.get()) : 0; nameLen += _dirPath.get() ? strlen(_dirPath.get()) : 0;
nameLen += strlen(_dirent.name); nameLen += strlen(_dirent.name);
char *tmpName = (char*)malloc(nameLen); char tmpName[nameLen];
if (!tmpName) { snprintf(tmpName, nameLen, "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _dirent.name);
return FileImplPtr();
}
snprintf(tmpName, nameLen, "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _dirent.name);
auto ret = _fs->open((const char *)tmpName, openMode, accessMode); auto ret = _fs->open((const char *)tmpName, openMode, accessMode);
free(tmpName);
return ret; return ret;
} }
@ -537,23 +551,11 @@ public:
} }
time_t fileTime() override { time_t fileTime() override {
if (!_valid) { return (time_t)_getAttr4('t');
return 0; }
}
int nameLen = 3; // Slashes, terminator time_t fileCreationTime() override {
nameLen += _dirPath.get() ? strlen(_dirPath.get()) : 0; return (time_t)_getAttr4('c');
nameLen += strlen(_dirent.name);
char *tmpName = (char*)malloc(nameLen);
if (!tmpName) {
return 0;
}
snprintf(tmpName, nameLen, "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _dirent.name);
time_t ftime = 0;
int rc = lfs_getattr(_fs->getFS(), tmpName, 't', (void *)&ftime, sizeof(ftime));
if (rc != sizeof(ftime))
ftime = 0; // Error, so clear read value
free(tmpName);
return ftime;
} }
@ -592,6 +594,22 @@ protected:
return _dir.get(); return _dir.get();
} }
uint32_t _getAttr4(char attr) {
if (!_valid) {
return 0;
}
int nameLen = 3; // Slashes, terminator
nameLen += _dirPath.get() ? strlen(_dirPath.get()) : 0;
nameLen += strlen(_dirent.name);
char tmpName[nameLen];
snprintf(tmpName, nameLen, "%s%s%s", _dirPath.get() ? _dirPath.get() : "", _dirPath.get()&&_dirPath.get()[0]?"/":"", _dirent.name);
time_t ftime = 0;
int rc = lfs_getattr(_fs->getFS(), tmpName, attr, (void *)&ftime, sizeof(ftime));
if (rc != sizeof(ftime))
ftime = 0; // Error, so clear read value
return ftime;
}
String _pattern; String _pattern;
LittleFSImpl *_fs; LittleFSImpl *_fs;
std::shared_ptr<lfs_dir_t> _dir; std::shared_ptr<lfs_dir_t> _dir;

View File

@ -29,9 +29,6 @@ File root;
void setup() { void setup() {
// Open serial communications and wait for port to open: // Open serial communications and wait for port to open:
Serial.begin(115200); Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card..."); Serial.print("Initializing SD card...");
@ -71,11 +68,12 @@ void printDirectory(File dir, int numTabs) {
// files have sizes, directories do not // files have sizes, directories do not
Serial.print("\t\t"); Serial.print("\t\t");
Serial.print(entry.size(), DEC); Serial.print(entry.size(), DEC);
Serial.print("\t\t"); time_t cr = entry.getCreationTime();
time_t ft = entry.getLastWrite(); time_t lw = entry.getLastWrite();
struct tm *tm = localtime(&ft); struct tm * tmstruct = localtime(&cr);
// US format. Feel free to convert to your own locale... Serial.printf("\tCREATION: %d-%02d-%02d %02d:%02d:%02d", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
Serial.printf("%02d-%02d-%02d %02d:%02d:%02d\n", tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100, tm->tm_hour, tm->tm_min, tm->tm_sec); tmstruct = localtime(&lw);
Serial.printf("\tLAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec);
} }
entry.close(); entry.close();
} }

View File

@ -156,6 +156,7 @@ public:
format(); format();
_mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings); _mounted = _fs.begin(_cfg._csPin, _cfg._spiSettings);
} }
sdfat::SdFile::dateTimeCallback(dateTimeCB);
return _mounted; return _mounted;
} }
@ -204,6 +205,17 @@ public:
return mktime(&tiempo); return mktime(&tiempo);
} }
// 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 void dateTimeCB(uint16_t *dosYear, uint16_t *dosTime) {
time_t 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;
}
protected: protected:
friend class SDFileImpl; friend class SDFileImpl;
friend class SDFSDirImpl; friend class SDFSDirImpl;
@ -363,6 +375,18 @@ public:
return ftime; return ftime;
} }
time_t getCreationTime() override {
time_t ftime = 0;
if (_opened && _fd) {
sdfat::dir_t tmp;
if (_fd.get()->dirEntry(&tmp)) {
ftime = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime);
}
}
return ftime;
}
protected: protected:
SDFSImpl* _fs; SDFSImpl* _fs;
@ -426,6 +450,14 @@ public:
return _time; return _time;
} }
time_t fileCreationTime() override
{
if (!_valid) {
return 0;
}
return _creation;
}
bool isFile() const override bool isFile() const override
{ {
@ -451,8 +483,10 @@ public:
sdfat::dir_t tmp; sdfat::dir_t tmp;
if (file.dirEntry(&tmp)) { if (file.dirEntry(&tmp)) {
_time = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime); _time = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime);
_creation = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime);
} else { } else {
_time = 0; _time = 0;
_creation = 0;
} }
file.getName(_lfn, sizeof(_lfn)); file.getName(_lfn, sizeof(_lfn));
file.close(); file.close();
@ -477,6 +511,7 @@ protected:
bool _valid; bool _valid;
char _lfn[64]; char _lfn[64];
time_t _time; time_t _time;
time_t _creation;
std::shared_ptr<char> _dirPath; std::shared_ptr<char> _dirPath;
uint32_t _size; uint32_t _size;
bool _isFile; bool _isFile;

View File

@ -130,7 +130,7 @@
}, },
{ {
"packager": "esp8266", "packager": "esp8266",
"version": "2.5.0-4-69bd9e6", "version": "2.5.0-4-fe5bb56",
"name": "mklittlefs" "name": "mklittlefs"
}, },
{ {
@ -311,22 +311,29 @@
] ]
}, },
{ {
"version": "2.5.0-4-69bd9e6", "version": "2.5.0-4-fe5bb56",
"name": "mklittlefs", "name": "mklittlefs",
"systems": [ "systems": [
{ {
"host": "aarch64-linux-gnu", "host": "aarch64-linux-gnu",
"url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/aarch64-linux-gnu-mklittlefs-69bd9e6.tar.gz", "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/aarch64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz",
"archiveFileName": "aarch64-linux-gnu-mklittlefs-69bd9e6.tar.gz", "archiveFileName": "aarch64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz",
"checksum": "SHA-256:74d938f15a3fb8ac20aeb0f938ace2c6759f622451419c09446aa79866302e18", "checksum": "SHA-256:ac50bae3b580053ba98a181ae3700fafd2b2f8a37ed9c16bc22a5d7c1659388e",
"size": "44342" "size": "44433"
}, },
{ {
"host": "arm-linux-gnueabihf", "host": "arm-linux-gnueabihf",
"url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/arm-linux-gnueabihf-mklittlefs-69bd9e6.tar.gz", "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/arm-linux-gnueabihf.mklittlefs-fe5bb56.1578453304.tar.gz",
"archiveFileName": "arm-linux-gnueabihf-mklittlefs-69bd9e6.tar.gz", "archiveFileName": "arm-linux-gnueabihf.mklittlefs-fe5bb56.1578453304.tar.gz",
"checksum": "SHA-256:926cca1c1f8f732a8ac79809ce0a52cabe283ab4137aa3237bca0fcca6bc2236", "checksum": "SHA-256:092555612e7e229fbe622df75db70560896c3aea8d0ac2e5fa16d92dc16857cf",
"size": "36871" "size": "36917"
},
{
"host": "i686-pc-linux-gnu",
"url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/i686-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz",
"archiveFileName": "i686-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz",
"checksum": "SHA-256:060e2525223269d2a5d01055542ff36837f0b19598d78cb02d58563aeda441cd",
"size": "47833"
}, },
{ {
"host": "i686-pc-linux-gnu", "host": "i686-pc-linux-gnu",
@ -337,35 +344,35 @@
}, },
{ {
"host": "i686-mingw32", "host": "i686-mingw32",
"url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/i686-w64-mingw32-mklittlefs-69bd9e6.zip", "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/i686-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip",
"archiveFileName": "i686-w64-mingw32-mklittlefs-69bd9e6.zip", "archiveFileName": "i686-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip",
"checksum": "SHA-256:da916c66f70e162f4aec22dbcb4542dd8b8187d12c35c915d563e2262cfe6fbd", "checksum": "SHA-256:2e570bed4ec59a9ecc73290e16c31ed53ee15e3abd8c82cb038b2148596d112e",
"size": "332325" "size": "332329"
}, },
{ {
"host": "x86_64-apple-darwin", "host": "x86_64-apple-darwin",
"url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-apple-darwin14-mklittlefs-69bd9e6.tar.gz", "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-apple-darwin14.mklittlefs-fe5bb56.1578453304.tar.gz",
"archiveFileName": "x86_64-apple-darwin14-mklittlefs-69bd9e6.tar.gz", "archiveFileName": "x86_64-apple-darwin14.mklittlefs-fe5bb56.1578453304.tar.gz",
"checksum": "SHA-256:35610be5f725121eaa9baea83c686693f340742e61739af6789d00feff4e90ba", "checksum": "SHA-256:fcb57ff58eceac79e988cc26a9e009a11ebda68d4ae97e44fed8e7c6d98a35b5",
"size": "362366" "size": "362389"
}, },
{ {
"host": "x86_64-pc-linux-gnu", "host": "x86_64-pc-linux-gnu",
"url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-linux-gnu-mklittlefs-69bd9e6.tar.gz", "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz",
"archiveFileName": "x86_64-linux-gnu-mklittlefs-69bd9e6.tar.gz", "archiveFileName": "x86_64-linux-gnu.mklittlefs-fe5bb56.1578453304.tar.gz",
"checksum": "SHA-256:e4ce7cc80eceab6a9a2e620f2badfb1ef09ee88f7af529f290c65b4b72f19358", "checksum": "SHA-256:5ef79d76e8e76f8287dc70d10c33f020d4cf5320354571adf666665eeef2e2de",
"size": "46518" "size": "46580"
}, },
{ {
"host": "x86_64-mingw32", "host": "x86_64-mingw32",
"url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-w64-mingw32-mklittlefs-69bd9e6.zip", "url": "https://github.com/earlephilhower/esp-quick-toolchain/releases/download/2.5.0-4/x86_64-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip",
"archiveFileName": "x86_64-w64-mingw32-mklittlefs-69bd9e6.zip", "archiveFileName": "x86_64-w64-mingw32.mklittlefs-fe5bb56.1578453304.zip",
"checksum": "SHA-256:c65ee1ee38f65ce67f664bb3118301ee6e93bec38a7a7efaf8e1d8455c6a4a18", "checksum": "SHA-256:a460f410a22a59e23d7f862b8d08d6b7dfbc93aa558f8161a3d640d4df2ab86f",
"size": "344780" "size": "344792"
} }
] ]
} }
] ]
} }
] ]
} }