mirror of
https://github.com/idolpx/libMeatloaf.git
synced 2025-12-06 04:38:49 -05:00
506 lines
13 KiB
C++
506 lines
13 KiB
C++
#include "flash.h"
|
|
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
|
|
#include "../../../include/debug.h"
|
|
#include "peoples_url_parser.h"
|
|
#include "string_utils.h"
|
|
|
|
/********************************************************
|
|
* MFileSystem implementations
|
|
********************************************************/
|
|
|
|
bool FlashFileSystem::handles(std::string path)
|
|
{
|
|
return true; // fallback fs, so it must be last on FS list
|
|
}
|
|
|
|
MFile* FlashFileSystem::getFile(std::string path)
|
|
{
|
|
//Debug_printv("path[%s]", path.c_str());
|
|
return new FlashFile(path);
|
|
}
|
|
|
|
|
|
/********************************************************
|
|
* MFile implementations
|
|
********************************************************/
|
|
|
|
bool FlashFile::pathValid(std::string path)
|
|
{
|
|
auto apath = std::string(basepath + path).c_str();
|
|
while (*apath) {
|
|
const char *slash = strchr(apath, '/');
|
|
if (!slash) {
|
|
if (strlen(apath) >= FILENAME_MAX) {
|
|
// Terminal filename is too long
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
if ((slash - apath) >= FILENAME_MAX) {
|
|
// This subdir name too long
|
|
return false;
|
|
}
|
|
apath = slash + 1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool FlashFile::isDirectory()
|
|
{
|
|
if(path=="/" || path=="")
|
|
return true;
|
|
|
|
struct stat info;
|
|
stat( std::string(basepath + path).c_str(), &info);
|
|
return S_ISDIR(info.st_mode);
|
|
}
|
|
|
|
|
|
MStream* FlashFile::getSourceStream(std::ios_base::openmode mode)
|
|
{
|
|
std::string full_path = basepath + path;
|
|
MStream* istream = new FlashIStream(full_path, mode);
|
|
//Debug_printv("FlashFile::getSourceStream() 3, not null=%d", istream != nullptr);
|
|
istream->open();
|
|
//Debug_printv("FlashFile::getSourceStream() 4");
|
|
return istream;
|
|
}
|
|
|
|
MStream* FlashFile::getDecodedStream(std::shared_ptr<MStream> is) {
|
|
return is.get(); // we don't have to process this stream in any way, just return the original stream
|
|
}
|
|
|
|
time_t FlashFile::getLastWrite()
|
|
{
|
|
struct stat info;
|
|
stat( std::string(basepath + path).c_str(), &info);
|
|
|
|
time_t ftime = info.st_mtime; // Time of last modification
|
|
return ftime;
|
|
}
|
|
|
|
time_t FlashFile::getCreationTime()
|
|
{
|
|
struct stat info;
|
|
stat( std::string(basepath + path).c_str(), &info);
|
|
|
|
time_t ftime = info.st_ctime; // Time of last status change
|
|
return ftime;
|
|
}
|
|
|
|
bool FlashFile::mkDir()
|
|
{
|
|
if (m_isNull) {
|
|
return false;
|
|
}
|
|
int rc = mkdir(std::string(basepath + path).c_str(), ALLPERMS);
|
|
return (rc==0);
|
|
}
|
|
|
|
bool FlashFile::exists()
|
|
{
|
|
if (m_isNull) {
|
|
return false;
|
|
}
|
|
if (path=="/" || path=="") {
|
|
return true;
|
|
}
|
|
|
|
//Debug_printv( "basepath[%s] path[%s]", basepath.c_str(), path.c_str() );
|
|
|
|
struct stat st;
|
|
int i = stat(std::string(basepath + path).c_str(), &st);
|
|
|
|
return (i == 0);
|
|
}
|
|
|
|
uint32_t FlashFile::size() {
|
|
if (m_isNull || path=="/" || path=="")
|
|
return 0;
|
|
else if(isDirectory()) {
|
|
return 0;
|
|
}
|
|
else {
|
|
struct stat info;
|
|
stat( std::string(basepath + path).c_str(), &info);
|
|
// Debug_printv( "size[%d]", info.st_size );
|
|
return info.st_size;
|
|
}
|
|
}
|
|
|
|
bool FlashFile::remove() {
|
|
// musi obslugiwac usuwanie plikow i katalogow!
|
|
if(path.empty())
|
|
return false;
|
|
|
|
int rc = ::remove( std::string(basepath + path).c_str() );
|
|
if (rc != 0) {
|
|
Debug_printv("remove: rc=%d path=`%s`\r\n", rc, path.c_str());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool FlashFile::rename(std::string pathTo) {
|
|
if(pathTo.empty())
|
|
return false;
|
|
|
|
int rc = ::rename( std::string(basepath + path).c_str(), std::string(basepath + pathTo).c_str() );
|
|
if (rc != 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void FlashFile::openDir(std::string path)
|
|
{
|
|
if (!isDirectory()) {
|
|
dirOpened = false;
|
|
return;
|
|
}
|
|
|
|
// Debug_printv("path[%s]", apath.c_str());
|
|
if(path.empty()) {
|
|
dir = opendir( "/" );
|
|
}
|
|
else {
|
|
dir = opendir( path.c_str() );
|
|
}
|
|
|
|
dirOpened = true;
|
|
if ( dir == NULL ) {
|
|
dirOpened = false;
|
|
}
|
|
// else {
|
|
// // Skip the . and .. entries
|
|
// struct dirent* dirent = NULL;
|
|
// dirent = readdir( dir );
|
|
// dirent = readdir( dir );
|
|
// }
|
|
}
|
|
|
|
|
|
void FlashFile::closeDir()
|
|
{
|
|
if(dirOpened) {
|
|
closedir( dir );
|
|
dirOpened = false;
|
|
}
|
|
}
|
|
|
|
|
|
bool FlashFile::rewindDirectory()
|
|
{
|
|
_valid = false;
|
|
rewinddir( dir );
|
|
|
|
// // Skip the . and .. entries
|
|
// struct dirent* dirent = NULL;
|
|
// dirent = readdir( dir );
|
|
// dirent = readdir( dir );
|
|
|
|
return (dir != NULL) ? true: false;
|
|
}
|
|
|
|
|
|
MFile* FlashFile::getNextFileInDir()
|
|
{
|
|
// Debug_printv("base[%s] path[%s]", basepath.c_str(), path.c_str());
|
|
if(!dirOpened)
|
|
openDir(std::string(basepath + path).c_str());
|
|
|
|
if(dir == nullptr)
|
|
return nullptr;
|
|
|
|
// Debug_printv("before readdir(), dir not null:%d", dir != nullptr);
|
|
struct dirent* dirent = NULL;
|
|
do
|
|
{
|
|
dirent = readdir( dir );
|
|
} while ( dirent != NULL && mstr::startsWith(dirent->d_name, ".") ); // Skip hidden files
|
|
|
|
if ( dirent != NULL )
|
|
{
|
|
//Debug_printv("path[%s] name[%s]", this->path.c_str(), dirent->d_name);
|
|
std::string entry_name = this->path + ((this->path == "/") ? "" : "/") + std::string(dirent->d_name);
|
|
return new FlashFile( entry_name );
|
|
}
|
|
else
|
|
{
|
|
closeDir();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
bool FlashFile::seekEntry( std::string filename )
|
|
{
|
|
std::string apath = (basepath + pathToFile()).c_str();
|
|
if (apath.empty()) {
|
|
apath = "/";
|
|
}
|
|
|
|
Debug_printv( "path[%s] filename[%s] size[%d]", apath.c_str(), filename.c_str(), filename.size());
|
|
|
|
DIR* d = opendir( apath.c_str() );
|
|
if(d == nullptr)
|
|
return false;
|
|
|
|
// Read Directory Entries
|
|
if ( filename.size() > 0 )
|
|
{
|
|
struct dirent* dirent = NULL;
|
|
bool found = false;
|
|
bool wildcard = ( mstr::contains(filename, "*") || mstr::contains(filename, "?") );
|
|
while ( (dirent = readdir( d )) != NULL )
|
|
{
|
|
std::string entryFilename = dirent->d_name;
|
|
|
|
Debug_printv("path[%s] filename[%s] entry.filename[%.16s]", apath.c_str(), filename.c_str(), entryFilename.c_str());
|
|
|
|
// Read Entry From Stream
|
|
if ( dirent->d_type != DT_DIR ) // Only want to match files not directories
|
|
{
|
|
// Read Entry From Stream
|
|
if (filename == "*") // Match first entry
|
|
{
|
|
filename = entryFilename;
|
|
found = true;
|
|
}
|
|
else if ( filename == entryFilename ) // Match exact
|
|
{
|
|
found = true;
|
|
}
|
|
else if ( wildcard )
|
|
{
|
|
if ( mstr::compare(filename, entryFilename) ) // X?XX?X* Wildcard match
|
|
{
|
|
// Set filename to this filename
|
|
Debug_printv( "Found! file[%s] -> entry[%s]", filename.c_str(), entryFilename.c_str() );
|
|
resetURL(apath + "/" + entryFilename);
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if ( found )
|
|
{
|
|
_exists = true;
|
|
closedir( d );
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Debug_printv( "Not Found! file[%s]", filename.c_str() );
|
|
}
|
|
|
|
closedir( d );
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
/********************************************************
|
|
* MStream implementations
|
|
********************************************************/
|
|
uint32_t FlashIStream::write(const uint8_t *buf, uint32_t size) {
|
|
if (!isOpen() || !buf) {
|
|
return 0;
|
|
}
|
|
|
|
Debug_printv("in byteWrite '%c', handle->file_h is null=[%d]\r\n", buf[0], handle->file_h == nullptr);
|
|
|
|
// buffer, element size, count, handle
|
|
int result = fwrite((void*) buf, 1, size, handle->file_h );
|
|
|
|
Debug_printv("after write rc=%d\r\n", result);
|
|
return result;
|
|
};
|
|
|
|
|
|
/********************************************************
|
|
* MIStreams implementations
|
|
********************************************************/
|
|
|
|
|
|
bool FlashIStream::open() {
|
|
if(isOpen())
|
|
return true;
|
|
|
|
//Debug_printv("IStream: trying to open flash fs, calling isOpen");
|
|
|
|
//Debug_printv("IStream: wasn't open, calling obtain");
|
|
if(mode == std::ios_base::in)
|
|
handle->obtain(localPath, "r");
|
|
else if(mode == std::ios_base::out) {
|
|
Debug_printv("FlashIStream: ok, we are in write mode!");
|
|
handle->obtain(localPath, "w");
|
|
}
|
|
else if(mode == std::ios_base::app)
|
|
handle->obtain(localPath, "a");
|
|
else if(mode == (std::ios_base::in | std::ios_base::out))
|
|
handle->obtain(localPath, "r+");
|
|
else if(mode == (std::ios_base::in | std::ios_base::app))
|
|
handle->obtain(localPath, "a+");
|
|
else if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
|
|
handle->obtain(localPath, "w+");
|
|
else if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::app))
|
|
handle->obtain(localPath, "a+");
|
|
|
|
// The below code will definitely destroy whatever open above does, because it will move the file pointer
|
|
// so I just wrapped it to be called only for in
|
|
if(isOpen() && mode == std::ios_base::in) {
|
|
//Debug_printv("IStream: past obtain");
|
|
// Set file size
|
|
fseek(handle->file_h, 0, SEEK_END);
|
|
//Debug_printv("IStream: past fseek 1");
|
|
_size = ftell(handle->file_h);
|
|
_position = 0;
|
|
//Debug_printv("IStream: past ftell");
|
|
fseek(handle->file_h, 0, SEEK_SET);
|
|
//Debug_printv("IStream: past fseek 2");
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
void FlashIStream::close() {
|
|
if(isOpen()) handle->dispose();
|
|
};
|
|
|
|
uint32_t FlashIStream::read(uint8_t* buf, uint32_t size) {
|
|
if (!isOpen() || !buf) {
|
|
Debug_printv("Not open");
|
|
return 0;
|
|
}
|
|
|
|
uint32_t bytesRead = 0;
|
|
if ( size > available() )
|
|
size = available();
|
|
|
|
if ( size > 0 )
|
|
{
|
|
bytesRead = fread((void*) buf, 1, size, handle->file_h );
|
|
// Debug_printv("bytesRead[%d]", bytesRead);
|
|
// auto hex = mstr::toHex(buf, bytesRead);
|
|
// Debug_printv("[%s]", hex.c_str());
|
|
_position += bytesRead;
|
|
}
|
|
|
|
return bytesRead;
|
|
};
|
|
|
|
|
|
// uint32_t FlashIStream::size() {
|
|
// return _size;
|
|
// };
|
|
|
|
// uint32_t FlashIStream::available() {
|
|
// if(!isOpen()) return 0;
|
|
// return _size - position();
|
|
// };
|
|
|
|
|
|
// uint32_t FlashIStream::position() {
|
|
// if(!isOpen()) return 0;
|
|
// return ftell(handle->file_h);
|
|
// };
|
|
|
|
// size_t FlashIStream::error() {
|
|
// return 0;
|
|
// };
|
|
|
|
bool FlashIStream::seek(uint32_t pos) {
|
|
// Debug_printv("pos[%d]", pos);
|
|
if (!isOpen()) {
|
|
Debug_printv("Not open");
|
|
return false;
|
|
}
|
|
return ( fseek( handle->file_h, pos, SEEK_SET ) ) ? false : true;
|
|
};
|
|
|
|
bool FlashIStream::seek(uint32_t pos, int mode) {
|
|
// Debug_printv("pos[%d] mode[%d]", pos, mode);
|
|
if (!isOpen()) {
|
|
Debug_printv("Not open");
|
|
return false;
|
|
}
|
|
return ( fseek( handle->file_h, pos, mode ) ) ? false : true;
|
|
}
|
|
|
|
bool FlashIStream::isOpen() {
|
|
// Debug_printv("Inside isOpen, handle notnull:%d", handle != nullptr);
|
|
auto temp = handle != nullptr && handle->file_h != nullptr;
|
|
// Debug_printv("returning");
|
|
return temp;
|
|
}
|
|
|
|
/********************************************************
|
|
* FlashHandle implementations
|
|
********************************************************/
|
|
|
|
|
|
FlashHandle::~FlashHandle() {
|
|
dispose();
|
|
}
|
|
|
|
void FlashHandle::dispose() {
|
|
//Debug_printv("file_h[%d]", file_h);
|
|
if (file_h != nullptr) {
|
|
|
|
fclose( file_h );
|
|
file_h = nullptr;
|
|
// rc = -255;
|
|
}
|
|
}
|
|
|
|
void FlashHandle::obtain(std::string m_path, std::string mode) {
|
|
|
|
//Serial.printf("*** Atempting opening flash handle'%s'\r\n", m_path.c_str());
|
|
|
|
if ((mode[0] == 'w') && strchr(m_path.c_str(), '/')) {
|
|
// For file creation, silently make subdirs as needed. If any fail,
|
|
// it will be caught by the real file open later on
|
|
|
|
char *pathStr = new char[m_path.length()];
|
|
strncpy(pathStr, m_path.data(), m_path.length());
|
|
|
|
if (pathStr) {
|
|
// Make dirs up to the final fnamepart
|
|
char *ptr = strchr(pathStr, '/');
|
|
while (ptr) {
|
|
*ptr = 0;
|
|
mkdir(pathStr, ALLPERMS);
|
|
*ptr = '/';
|
|
ptr = strchr(ptr+1, '/');
|
|
}
|
|
}
|
|
delete[] pathStr;
|
|
}
|
|
|
|
//Debug_printv("m_path[%s] mode[%s]", m_path.c_str(), mode.c_str());
|
|
file_h = fopen( m_path.c_str(), mode.c_str());
|
|
// rc = 1;
|
|
|
|
//Serial.printf("FSTEST: lfs_file_open file rc:%d\r\n",rc);
|
|
|
|
// if (rc == LFS_ERR_ISDIR) {
|
|
// // To support the SD.openNextFile, a null FD indicates to the FlashFSFile this is just
|
|
// // a directory whose name we are carrying around but which cannot be read or written
|
|
// } else if (rc == 0) {
|
|
// // lfs_file_sync(&FlashFileSystem::lfsStruct, &file_h);
|
|
// } else {
|
|
// Debug_printv("FlashFile::open: unknown return code rc=%d path=`%s`\r\n",
|
|
// rc, m_path.c_str());
|
|
// }
|
|
}
|