Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fileCreation/getCreation create-time accessors #7000

Merged
merged 12 commits into from
Feb 22, 2020
Merged
22 changes: 15 additions & 7 deletions cores/esp8266/FS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,13 @@ time_t File::getLastWrite() {
return _p->getLastWrite();
}

time_t File::getCreation() {
if (!_p)
return 0;

return _p->getCreation();
}

void File::setTimeCallback(time_t (*cb)(void)) {
if (!_p)
return;
Expand Down Expand Up @@ -224,6 +231,12 @@ time_t Dir::fileTime() {
return _impl->fileTime();
}

time_t Dir::fileCreation() {
if (!_impl)
return 0;
return _impl->fileCreation();
}

size_t Dir::fileSize() {
if (!_impl) {
return 0;
Expand Down Expand Up @@ -262,17 +275,11 @@ 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);
timeCallback = cb;
}


Expand All @@ -289,6 +296,7 @@ bool FS::begin() {
DEBUGV("#error: FS: no implementation");
return false;
}
_impl->setTimeCallback(timeCallback);
bool ret = _impl->begin();
DEBUGV("%s\n", ret? "": "#error: FS could not start");
return ret;
Expand Down
5 changes: 2 additions & 3 deletions cores/esp8266/FS.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class File : public Stream
String readString() override;

time_t getLastWrite();
time_t getCreation();
void setTimeCallback(time_t (*cb)(void));

protected:
Expand All @@ -120,7 +121,6 @@ class File : public Stream
// Arduino SD class emulation
std::shared_ptr<Dir> _fakeDir;
FS *_baseFS;
time_t (*timeCallback)(void) = nullptr;
};

class Dir {
Expand All @@ -132,20 +132,19 @@ class Dir {
String fileName();
size_t fileSize();
time_t fileTime();
time_t fileCreation();
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
Expand Down
11 changes: 6 additions & 5 deletions cores/esp8266/FSImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class FileImpl {
// 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
// Same for creation time.
virtual time_t getCreation() { return 0; } // Default is to not support timestamps
earlephilhower marked this conversation as resolved.
Show resolved Hide resolved

protected:
time_t (*timeCallback)(void) = nullptr;
Expand All @@ -75,7 +77,11 @@ class DirImpl {
virtual FileImplPtr openFile(OpenMode openMode, AccessMode accessMode) = 0;
virtual const char* fileName() = 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 fileCreation() { return 0; } // By default, FS doesn't report file times
virtual bool isFile() const = 0;
virtual bool isDirectory() const = 0;
virtual bool next() = 0;
Expand All @@ -86,11 +92,6 @@ class DirImpl {
// 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;
};
Expand Down
10 changes: 10 additions & 0 deletions doc/filesystem.rst
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ fileTime
Returns the time_t write time of the current file pointed
to by the internal iterator.

fileCreation
~~~~~~~~~~~~
Returns the time_t creation time of the current file
pointed to by the internal iterator.

isFile
~~~~~~

Expand Down Expand Up @@ -642,6 +647,11 @@ getLastWrite
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.

getCreation
~~~~~~~~~~~

Returns the file creation time, if available.

isFile
~~~~~~

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ void listDir(const char * dirname) {
Serial.print(root.fileName());
Serial.print(" SIZE: ");
Serial.print(file.size());
time_t t = file.getLastWrite();
struct tm * tmstruct = localtime(&t);
time_t cr = file.getCreation();
time_t lw = file.getLastWrite();
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);
}
}
Expand Down Expand Up @@ -90,6 +93,7 @@ void writeFile(const char * path, const char * message) {
} else {
Serial.println("Write failed");
}
delay(2000); // Make sure the CREATE and LASTWRITE times are different
file.close();
}

Expand Down
19 changes: 16 additions & 3 deletions libraries/LittleFS/src/LittleFS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ FileImplPtr LittleFSImpl::open(const char* path, OpenMode openMode, AccessMode a
int flags = _getFlags(openMode, accessMode);
auto fd = std::make_shared<lfs_file_t>();

if ((openMode && OM_CREATE) && strchr(path, '/')) {
if ((openMode & OM_CREATE) && strchr(path, '/')) {
// For file creation, silently make subdirs as needed. If any fail,
// it will be caught by the real file open later on
char *pathStr = strdup(path);
Expand All @@ -68,13 +68,26 @@ FileImplPtr LittleFSImpl::open(const char* path, OpenMode openMode, AccessMode a
}
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);
if (rc == LFS_ERR_ISDIR) {
// 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
return std::make_shared<LittleFSFileImpl>(this, path, nullptr, flags);
return std::make_shared<LittleFSFileImpl>(this, path, nullptr, flags, creation);
} else if (rc == 0) {
return std::make_shared<LittleFSFileImpl>(this, path, fd, flags);
return std::make_shared<LittleFSFileImpl>(this, path, fd, flags, creation);
} else {
DEBUGV("LittleFSDirImpl::openFile: rc=%d fd=%p path=`%s` openMode=%d accessMode=%d err=%d\n",
rc, fd.get(), path, openMode, accessMode, rc);
Expand Down
66 changes: 46 additions & 20 deletions libraries/LittleFS/src/LittleFS.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ class LittleFSImpl : public FSImpl
class LittleFSFileImpl : public FileImpl
{
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[]>());
strcpy(_name.get(), name);
}
Expand Down Expand Up @@ -420,12 +420,19 @@ class LittleFSFileImpl : public FileImpl
_opened = false;
DEBUGV("lfs_file_close: fd=%p\n", _getFD());
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
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 time on '%s' to %d\n", _name.get(), now);
}
DEBUGV("Unable to set last write time on '%s' to %d\n", _name.get(), now);
}
}
}
}
Expand All @@ -440,6 +447,16 @@ class LittleFSFileImpl : public FileImpl
return ftime;
}

time_t getCreation() 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 {
if (!_opened) {
return nullptr;
Expand Down Expand Up @@ -484,6 +501,7 @@ class LittleFSFileImpl : public FileImpl
std::shared_ptr<char> _name;
bool _opened;
int _flags;
time_t _creation;
};

class LittleFSDirImpl : public DirImpl
Expand Down Expand Up @@ -537,23 +555,11 @@ class LittleFSDirImpl : public DirImpl
}

time_t fileTime() override {
if (!_valid) {
return 0;
}
int nameLen = 3; // Slashes, terminator
nameLen += _dirPath.get() ? strlen(_dirPath.get()) : 0;
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;
return (time_t)_getAttr4('t');
}

time_t fileCreation() override {
return (time_t)_getAttr4('c');
}


Expand Down Expand Up @@ -592,6 +598,26 @@ class LittleFSDirImpl : public DirImpl
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 = (char*)malloc(nameLen);
earlephilhower marked this conversation as resolved.
Show resolved Hide resolved
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, attr, (void *)&ftime, sizeof(ftime));
if (rc != sizeof(ftime))
ftime = 0; // Error, so clear read value
free(tmpName);
return ftime;
}

String _pattern;
LittleFSImpl *_fs;
std::shared_ptr<lfs_dir_t> _dir;
Expand Down
23 changes: 23 additions & 0 deletions libraries/SDFS/src/SDFS.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,18 @@ class SDFSFileImpl : public FileImpl
return ftime;
}

time_t getCreation() 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:
SDFSImpl* _fs;
Expand Down Expand Up @@ -426,6 +438,14 @@ class SDFSDirImpl : public DirImpl
return _time;
}

time_t fileCreation() override
{
if (!_valid) {
return 0;
}

return _creation;
}

bool isFile() const override
{
Expand All @@ -451,8 +471,10 @@ class SDFSDirImpl : public DirImpl
sdfat::dir_t tmp;
if (file.dirEntry(&tmp)) {
_time = SDFSImpl::FatToTimeT(tmp.lastWriteDate, tmp.lastWriteTime);
_creation = SDFSImpl::FatToTimeT(tmp.creationDate, tmp.creationTime);
} else {
_time = 0;
_creation = 0;
}
file.getName(_lfn, sizeof(_lfn));
file.close();
Expand All @@ -477,6 +499,7 @@ class SDFSDirImpl : public DirImpl
bool _valid;
char _lfn[64];
time_t _time;
time_t _creation;
std::shared_ptr<char> _dirPath;
uint32_t _size;
bool _isFile;
Expand Down
Loading