Prvni ulozeni z chegewara githubu
This commit is contained in:
9
libraries/FS/library.properties
Normal file
9
libraries/FS/library.properties
Normal file
@ -0,0 +1,9 @@
|
||||
name=FS
|
||||
version=2.0.0
|
||||
author=Hristo Gochkov, Ivan Grokhtkov
|
||||
maintainer=Hristo Gochkov <hristo@espressif.com>
|
||||
sentence=ESP32 File System
|
||||
paragraph=
|
||||
category=Data Storage
|
||||
url=
|
||||
architectures=esp32
|
287
libraries/FS/src/FS.cpp
Normal file
287
libraries/FS/src/FS.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
/*
|
||||
FS.cpp - file system wrapper
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "FS.h"
|
||||
#include "FSImpl.h"
|
||||
|
||||
using namespace fs;
|
||||
|
||||
size_t File::write(uint8_t c)
|
||||
{
|
||||
if (!*this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->write(&c, 1);
|
||||
}
|
||||
|
||||
time_t File::getLastWrite()
|
||||
{
|
||||
if (!*this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->getLastWrite();
|
||||
}
|
||||
|
||||
size_t File::write(const uint8_t *buf, size_t size)
|
||||
{
|
||||
if (!*this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->write(buf, size);
|
||||
}
|
||||
|
||||
int File::available()
|
||||
{
|
||||
if (!*this) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _p->size() - _p->position();
|
||||
}
|
||||
|
||||
int File::read()
|
||||
{
|
||||
if (!*this) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t result;
|
||||
if (_p->read(&result, 1) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t File::read(uint8_t* buf, size_t size)
|
||||
{
|
||||
if (!*this) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _p->read(buf, size);
|
||||
}
|
||||
|
||||
int File::peek()
|
||||
{
|
||||
if (!*this) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t curPos = _p->position();
|
||||
int result = read();
|
||||
seek(curPos, SeekSet);
|
||||
return result;
|
||||
}
|
||||
|
||||
void File::flush()
|
||||
{
|
||||
if (!*this) {
|
||||
return;
|
||||
}
|
||||
|
||||
_p->flush();
|
||||
}
|
||||
|
||||
bool File::seek(uint32_t pos, SeekMode mode)
|
||||
{
|
||||
if (!*this) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _p->seek(pos, mode);
|
||||
}
|
||||
|
||||
size_t File::position() const
|
||||
{
|
||||
if (!*this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->position();
|
||||
}
|
||||
|
||||
size_t File::size() const
|
||||
{
|
||||
if (!*this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->size();
|
||||
}
|
||||
|
||||
bool File::setBufferSize(size_t size)
|
||||
{
|
||||
if (!*this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _p->setBufferSize(size);
|
||||
}
|
||||
|
||||
void File::close()
|
||||
{
|
||||
if (_p) {
|
||||
_p->close();
|
||||
_p = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
File::operator bool() const
|
||||
{
|
||||
return _p != nullptr && *_p != false;
|
||||
}
|
||||
|
||||
const char* File::path() const
|
||||
{
|
||||
if (!*this) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _p->path();
|
||||
}
|
||||
|
||||
const char* File::name() const
|
||||
{
|
||||
if (!*this) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _p->name();
|
||||
}
|
||||
|
||||
//to implement
|
||||
boolean File::isDirectory(void)
|
||||
{
|
||||
if (!*this) {
|
||||
return false;
|
||||
}
|
||||
return _p->isDirectory();
|
||||
}
|
||||
|
||||
File File::openNextFile(const char* mode)
|
||||
{
|
||||
if (!*this) {
|
||||
return File();
|
||||
}
|
||||
return _p->openNextFile(mode);
|
||||
}
|
||||
|
||||
void File::rewindDirectory(void)
|
||||
{
|
||||
if (!*this) {
|
||||
return;
|
||||
}
|
||||
_p->rewindDirectory();
|
||||
}
|
||||
|
||||
File FS::open(const String& path, const char* mode, const bool create)
|
||||
{
|
||||
return open(path.c_str(), mode, create);
|
||||
}
|
||||
|
||||
File FS::open(const char* path, const char* mode, const bool create)
|
||||
{
|
||||
if (!_impl) {
|
||||
return File();
|
||||
}
|
||||
|
||||
return File(_impl->open(path, mode, create));
|
||||
}
|
||||
|
||||
bool FS::exists(const char* path)
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->exists(path);
|
||||
}
|
||||
|
||||
bool FS::exists(const String& path)
|
||||
{
|
||||
return exists(path.c_str());
|
||||
}
|
||||
|
||||
bool FS::remove(const char* path)
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->remove(path);
|
||||
}
|
||||
|
||||
bool FS::remove(const String& path)
|
||||
{
|
||||
return remove(path.c_str());
|
||||
}
|
||||
|
||||
bool FS::rename(const char* pathFrom, const char* pathTo)
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->rename(pathFrom, pathTo);
|
||||
}
|
||||
|
||||
bool FS::rename(const String& pathFrom, const String& pathTo)
|
||||
{
|
||||
return rename(pathFrom.c_str(), pathTo.c_str());
|
||||
}
|
||||
|
||||
|
||||
bool FS::mkdir(const char *path)
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->mkdir(path);
|
||||
}
|
||||
|
||||
bool FS::mkdir(const String &path)
|
||||
{
|
||||
return mkdir(path.c_str());
|
||||
}
|
||||
|
||||
bool FS::rmdir(const char *path)
|
||||
{
|
||||
if (!_impl) {
|
||||
return false;
|
||||
}
|
||||
return _impl->rmdir(path);
|
||||
}
|
||||
|
||||
bool FS::rmdir(const String &path)
|
||||
{
|
||||
return rmdir(path.c_str());
|
||||
}
|
||||
|
||||
|
||||
void FSImpl::mountpoint(const char * mp)
|
||||
{
|
||||
_mountpoint = mp;
|
||||
}
|
||||
|
||||
const char * FSImpl::mountpoint()
|
||||
{
|
||||
return _mountpoint;
|
||||
}
|
127
libraries/FS/src/FS.h
Normal file
127
libraries/FS/src/FS.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
FS.h - file system wrapper
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef FS_H
|
||||
#define FS_H
|
||||
|
||||
#include <memory>
|
||||
#include <Arduino.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
|
||||
#define FILE_READ "r"
|
||||
#define FILE_WRITE "w"
|
||||
#define FILE_APPEND "a"
|
||||
|
||||
class File;
|
||||
|
||||
class FileImpl;
|
||||
typedef std::shared_ptr<FileImpl> FileImplPtr;
|
||||
class FSImpl;
|
||||
typedef std::shared_ptr<FSImpl> FSImplPtr;
|
||||
|
||||
enum SeekMode {
|
||||
SeekSet = 0,
|
||||
SeekCur = 1,
|
||||
SeekEnd = 2
|
||||
};
|
||||
|
||||
class File : public Stream
|
||||
{
|
||||
public:
|
||||
File(FileImplPtr p = FileImplPtr()) : _p(p) {
|
||||
_timeout = 0;
|
||||
}
|
||||
|
||||
size_t write(uint8_t) override;
|
||||
size_t write(const uint8_t *buf, size_t size) override;
|
||||
int available() override;
|
||||
int read() override;
|
||||
int peek() override;
|
||||
void flush() override;
|
||||
size_t read(uint8_t* buf, size_t size);
|
||||
size_t readBytes(char *buffer, size_t length)
|
||||
{
|
||||
return read((uint8_t*)buffer, length);
|
||||
}
|
||||
|
||||
bool seek(uint32_t pos, SeekMode mode);
|
||||
bool seek(uint32_t pos)
|
||||
{
|
||||
return seek(pos, SeekSet);
|
||||
}
|
||||
size_t position() const;
|
||||
size_t size() const;
|
||||
bool setBufferSize(size_t size);
|
||||
void close();
|
||||
operator bool() const;
|
||||
time_t getLastWrite();
|
||||
const char* path() const;
|
||||
const char* name() const;
|
||||
|
||||
boolean isDirectory(void);
|
||||
File openNextFile(const char* mode = FILE_READ);
|
||||
void rewindDirectory(void);
|
||||
|
||||
protected:
|
||||
FileImplPtr _p;
|
||||
};
|
||||
|
||||
class FS
|
||||
{
|
||||
public:
|
||||
FS(FSImplPtr impl) : _impl(impl) { }
|
||||
|
||||
File open(const char* path, const char* mode = FILE_READ, const bool create = false);
|
||||
File open(const String& path, const char* mode = FILE_READ, const bool create = false);
|
||||
|
||||
bool exists(const char* path);
|
||||
bool exists(const String& path);
|
||||
|
||||
bool remove(const char* path);
|
||||
bool remove(const String& path);
|
||||
|
||||
bool rename(const char* pathFrom, const char* pathTo);
|
||||
bool rename(const String& pathFrom, const String& pathTo);
|
||||
|
||||
bool mkdir(const char *path);
|
||||
bool mkdir(const String &path);
|
||||
|
||||
bool rmdir(const char *path);
|
||||
bool rmdir(const String &path);
|
||||
|
||||
|
||||
protected:
|
||||
FSImplPtr _impl;
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
||||
#ifndef FS_NO_GLOBALS
|
||||
using fs::FS;
|
||||
using fs::File;
|
||||
using fs::SeekMode;
|
||||
using fs::SeekSet;
|
||||
using fs::SeekCur;
|
||||
using fs::SeekEnd;
|
||||
#endif //FS_NO_GLOBALS
|
||||
|
||||
#endif //FS_H
|
69
libraries/FS/src/FSImpl.h
Normal file
69
libraries/FS/src/FSImpl.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
FSImpl.h - base file system interface
|
||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef FSIMPL_H
|
||||
#define FSIMPL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
|
||||
class FileImpl
|
||||
{
|
||||
public:
|
||||
virtual ~FileImpl() { }
|
||||
virtual size_t write(const uint8_t *buf, size_t size) = 0;
|
||||
virtual size_t read(uint8_t* buf, size_t size) = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual bool seek(uint32_t pos, SeekMode mode) = 0;
|
||||
virtual size_t position() const = 0;
|
||||
virtual size_t size() const = 0;
|
||||
virtual bool setBufferSize(size_t size) = 0;
|
||||
virtual void close() = 0;
|
||||
virtual time_t getLastWrite() = 0;
|
||||
virtual const char* path() const = 0;
|
||||
virtual const char* name() const = 0;
|
||||
virtual boolean isDirectory(void) = 0;
|
||||
virtual FileImplPtr openNextFile(const char* mode) = 0;
|
||||
virtual void rewindDirectory(void) = 0;
|
||||
virtual operator bool() = 0;
|
||||
};
|
||||
|
||||
class FSImpl
|
||||
{
|
||||
protected:
|
||||
const char * _mountpoint;
|
||||
public:
|
||||
FSImpl() : _mountpoint(NULL) { }
|
||||
virtual ~FSImpl() { }
|
||||
virtual FileImplPtr open(const char* path, const char* mode, const bool create) = 0;
|
||||
virtual bool exists(const char* path) = 0;
|
||||
virtual bool rename(const char* pathFrom, const char* pathTo) = 0;
|
||||
virtual bool remove(const char* path) = 0;
|
||||
virtual bool mkdir(const char *path) = 0;
|
||||
virtual bool rmdir(const char *path) = 0;
|
||||
void mountpoint(const char *);
|
||||
const char * mountpoint();
|
||||
};
|
||||
|
||||
} // namespace fs
|
||||
|
||||
#endif //FSIMPL_H
|
485
libraries/FS/src/vfs_api.cpp
Normal file
485
libraries/FS/src/vfs_api.cpp
Normal file
@ -0,0 +1,485 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "vfs_api.h"
|
||||
|
||||
using namespace fs;
|
||||
|
||||
#define DEFAULT_FILE_BUFFER_SIZE 4096
|
||||
|
||||
FileImplPtr VFSImpl::open(const char* fpath, const char* mode, const bool create)
|
||||
{
|
||||
if(!_mountpoint) {
|
||||
log_e("File system is not mounted");
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
if(!fpath || fpath[0] != '/') {
|
||||
log_e("%s does not start with /", fpath);
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+2);
|
||||
if(!temp) {
|
||||
log_e("malloc failed");
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
sprintf(temp,"%s%s", _mountpoint, fpath);
|
||||
|
||||
struct stat st;
|
||||
//file found
|
||||
if(!stat(temp, &st)) {
|
||||
free(temp);
|
||||
if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
}
|
||||
log_e("%s has wrong mode 0x%08X", fpath, st.st_mode);
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
//try to open this as directory (might be mount point)
|
||||
DIR * d = opendir(temp);
|
||||
if(d) {
|
||||
closedir(d);
|
||||
free(temp);
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
}
|
||||
|
||||
//file not found but mode permits file creation without folder creation
|
||||
if((mode && mode[0] != 'r') && (!create)){
|
||||
free(temp);
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
}
|
||||
|
||||
////file not found but mode permits file creation and folder creation
|
||||
if((mode && mode[0] != 'r') && create){
|
||||
|
||||
char *token;
|
||||
char *folder = (char *)malloc(strlen(fpath));
|
||||
|
||||
int start_index = 0;
|
||||
int end_index = 0;
|
||||
|
||||
token = strchr(fpath+1,'/');
|
||||
end_index = (token-fpath);
|
||||
|
||||
while (token != NULL)
|
||||
{
|
||||
memcpy(folder,fpath + start_index, end_index-start_index);
|
||||
folder[end_index-start_index] = '\0';
|
||||
|
||||
if(!VFSImpl::mkdir(folder))
|
||||
{
|
||||
log_e("Creating folder: %s failed!",folder);
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
token=strchr(token+1,'/');
|
||||
if(token != NULL)
|
||||
{
|
||||
end_index = (token-fpath);
|
||||
memset(folder, 0, strlen(folder));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(folder);
|
||||
free(temp);
|
||||
return std::make_shared<VFSFileImpl>(this, fpath, mode);
|
||||
|
||||
}
|
||||
|
||||
log_e("%s does not exist, no permits for creation", temp);
|
||||
free(temp);
|
||||
return FileImplPtr();
|
||||
}
|
||||
|
||||
bool VFSImpl::exists(const char* fpath)
|
||||
{
|
||||
if(!_mountpoint) {
|
||||
log_e("File system is not mounted");
|
||||
return false;
|
||||
}
|
||||
|
||||
VFSFileImpl f(this, fpath, "r");
|
||||
if(f) {
|
||||
f.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VFSImpl::rename(const char* pathFrom, const char* pathTo)
|
||||
{
|
||||
if(!_mountpoint) {
|
||||
log_e("File system is not mounted");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pathFrom || pathFrom[0] != '/' || !pathTo || pathTo[0] != '/') {
|
||||
log_e("bad arguments");
|
||||
return false;
|
||||
}
|
||||
if(!exists(pathFrom)) {
|
||||
log_e("%s does not exists", pathFrom);
|
||||
return false;
|
||||
}
|
||||
char * temp1 = (char *)malloc(strlen(pathFrom)+strlen(_mountpoint)+1);
|
||||
if(!temp1) {
|
||||
log_e("malloc failed");
|
||||
return false;
|
||||
}
|
||||
char * temp2 = (char *)malloc(strlen(pathTo)+strlen(_mountpoint)+1);
|
||||
if(!temp2) {
|
||||
free(temp1);
|
||||
log_e("malloc failed");
|
||||
return false;
|
||||
}
|
||||
sprintf(temp1,"%s%s", _mountpoint, pathFrom);
|
||||
sprintf(temp2,"%s%s", _mountpoint, pathTo);
|
||||
auto rc = ::rename(temp1, temp2);
|
||||
free(temp1);
|
||||
free(temp2);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
bool VFSImpl::remove(const char* fpath)
|
||||
{
|
||||
if(!_mountpoint) {
|
||||
log_e("File system is not mounted");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!fpath || fpath[0] != '/') {
|
||||
log_e("bad arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
VFSFileImpl f(this, fpath, "r");
|
||||
if(!f || f.isDirectory()) {
|
||||
if(f) {
|
||||
f.close();
|
||||
}
|
||||
log_e("%s does not exists or is directory", fpath);
|
||||
return false;
|
||||
}
|
||||
f.close();
|
||||
|
||||
char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+1);
|
||||
if(!temp) {
|
||||
log_e("malloc failed");
|
||||
return false;
|
||||
}
|
||||
sprintf(temp,"%s%s", _mountpoint, fpath);
|
||||
auto rc = unlink(temp);
|
||||
free(temp);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
bool VFSImpl::mkdir(const char *fpath)
|
||||
{
|
||||
if(!_mountpoint) {
|
||||
log_e("File system is not mounted");
|
||||
return false;
|
||||
}
|
||||
|
||||
VFSFileImpl f(this, fpath, "r");
|
||||
if(f && f.isDirectory()) {
|
||||
f.close();
|
||||
//log_w("%s already exists", fpath);
|
||||
return true;
|
||||
} else if(f) {
|
||||
f.close();
|
||||
log_e("%s is a file", fpath);
|
||||
return false;
|
||||
}
|
||||
|
||||
char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+1);
|
||||
if(!temp) {
|
||||
log_e("malloc failed");
|
||||
return false;
|
||||
}
|
||||
sprintf(temp,"%s%s", _mountpoint, fpath);
|
||||
auto rc = ::mkdir(temp, ACCESSPERMS);
|
||||
free(temp);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
bool VFSImpl::rmdir(const char *fpath)
|
||||
{
|
||||
if(!_mountpoint) {
|
||||
log_e("File system is not mounted");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(_mountpoint, "/spiffs") == 0) {
|
||||
log_e("rmdir is unnecessary in SPIFFS");
|
||||
return false;
|
||||
}
|
||||
|
||||
VFSFileImpl f(this, fpath, "r");
|
||||
if(!f || !f.isDirectory()) {
|
||||
if(f) {
|
||||
f.close();
|
||||
}
|
||||
log_e("%s does not exists or is a file", fpath);
|
||||
return false;
|
||||
}
|
||||
f.close();
|
||||
|
||||
char * temp = (char *)malloc(strlen(fpath)+strlen(_mountpoint)+1);
|
||||
if(!temp) {
|
||||
log_e("malloc failed");
|
||||
return false;
|
||||
}
|
||||
sprintf(temp,"%s%s", _mountpoint, fpath);
|
||||
auto rc = ::rmdir(temp);
|
||||
free(temp);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
VFSFileImpl::VFSFileImpl(VFSImpl* fs, const char* fpath, const char* mode)
|
||||
: _fs(fs)
|
||||
, _f(NULL)
|
||||
, _d(NULL)
|
||||
, _path(NULL)
|
||||
, _isDirectory(false)
|
||||
, _written(false)
|
||||
{
|
||||
char * temp = (char *)malloc(strlen(fpath)+strlen(_fs->_mountpoint)+1);
|
||||
if(!temp) {
|
||||
return;
|
||||
}
|
||||
sprintf(temp,"%s%s", _fs->_mountpoint, fpath);
|
||||
|
||||
_path = strdup(fpath);
|
||||
if(!_path) {
|
||||
log_e("strdup(%s) failed", fpath);
|
||||
free(temp);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!stat(temp, &_stat)) {
|
||||
//file found
|
||||
if (S_ISREG(_stat.st_mode)) {
|
||||
_isDirectory = false;
|
||||
_f = fopen(temp, mode);
|
||||
if(!_f) {
|
||||
log_e("fopen(%s) failed", temp);
|
||||
}
|
||||
if(_f && (_stat.st_blksize == 0))
|
||||
{
|
||||
setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE);
|
||||
}
|
||||
} else if(S_ISDIR(_stat.st_mode)) {
|
||||
_isDirectory = true;
|
||||
_d = opendir(temp);
|
||||
if(!_d) {
|
||||
log_e("opendir(%s) failed", temp);
|
||||
}
|
||||
} else {
|
||||
log_e("Unknown type 0x%08X for file %s", ((_stat.st_mode)&_IFMT), temp);
|
||||
}
|
||||
} else {
|
||||
//file not found
|
||||
if(!mode || mode[0] == 'r') {
|
||||
//try to open as directory
|
||||
_d = opendir(temp);
|
||||
if(_d) {
|
||||
_isDirectory = true;
|
||||
} else {
|
||||
_isDirectory = false;
|
||||
//log_w("stat(%s) failed", temp);
|
||||
}
|
||||
} else {
|
||||
//lets create this new file
|
||||
_isDirectory = false;
|
||||
_f = fopen(temp, mode);
|
||||
if(!_f) {
|
||||
log_e("fopen(%s) failed", temp);
|
||||
}
|
||||
if(_f && (_stat.st_blksize == 0))
|
||||
{
|
||||
setvbuf(_f,NULL,_IOFBF,DEFAULT_FILE_BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(temp);
|
||||
}
|
||||
|
||||
VFSFileImpl::~VFSFileImpl()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void VFSFileImpl::close()
|
||||
{
|
||||
if(_path) {
|
||||
free(_path);
|
||||
_path = NULL;
|
||||
}
|
||||
if(_isDirectory && _d) {
|
||||
closedir(_d);
|
||||
_d = NULL;
|
||||
_isDirectory = false;
|
||||
} else if(_f) {
|
||||
fclose(_f);
|
||||
_f = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
VFSFileImpl::operator bool()
|
||||
{
|
||||
return (_isDirectory && _d != NULL) || _f != NULL;
|
||||
}
|
||||
|
||||
time_t VFSFileImpl::getLastWrite() {
|
||||
_getStat() ;
|
||||
return _stat.st_mtime;
|
||||
}
|
||||
|
||||
void VFSFileImpl::_getStat() const
|
||||
{
|
||||
if(!_path) {
|
||||
return;
|
||||
}
|
||||
char * temp = (char *)malloc(strlen(_path)+strlen(_fs->_mountpoint)+1);
|
||||
if(!temp) {
|
||||
return;
|
||||
}
|
||||
sprintf(temp,"%s%s", _fs->_mountpoint, _path);
|
||||
if(!stat(temp, &_stat)) {
|
||||
_written = false;
|
||||
}
|
||||
free(temp);
|
||||
}
|
||||
|
||||
size_t VFSFileImpl::write(const uint8_t *buf, size_t size)
|
||||
{
|
||||
if(_isDirectory || !_f || !buf || !size) {
|
||||
return 0;
|
||||
}
|
||||
_written = true;
|
||||
return fwrite(buf, 1, size, _f);
|
||||
}
|
||||
|
||||
size_t VFSFileImpl::read(uint8_t* buf, size_t size)
|
||||
{
|
||||
if(_isDirectory || !_f || !buf || !size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fread(buf, 1, size, _f);
|
||||
}
|
||||
|
||||
void VFSFileImpl::flush()
|
||||
{
|
||||
if(_isDirectory || !_f) {
|
||||
return;
|
||||
}
|
||||
fflush(_f);
|
||||
// workaround for https://github.com/espressif/arduino-esp32/issues/1293
|
||||
fsync(fileno(_f));
|
||||
}
|
||||
|
||||
bool VFSFileImpl::seek(uint32_t pos, SeekMode mode)
|
||||
{
|
||||
if(_isDirectory || !_f) {
|
||||
return false;
|
||||
}
|
||||
auto rc = fseek(_f, pos, mode);
|
||||
return rc == 0;
|
||||
}
|
||||
|
||||
size_t VFSFileImpl::position() const
|
||||
{
|
||||
if(_isDirectory || !_f) {
|
||||
return 0;
|
||||
}
|
||||
return ftell(_f);
|
||||
}
|
||||
|
||||
size_t VFSFileImpl::size() const
|
||||
{
|
||||
if(_isDirectory || !_f) {
|
||||
return 0;
|
||||
}
|
||||
if (_written) {
|
||||
_getStat();
|
||||
}
|
||||
return _stat.st_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change size of files internal buffer used for read / write operations.
|
||||
* Need to be called right after opening file before any other operation!
|
||||
*/
|
||||
bool VFSFileImpl::setBufferSize(size_t size)
|
||||
{
|
||||
if(_isDirectory || !_f) {
|
||||
return 0;
|
||||
}
|
||||
int res = setvbuf(_f,NULL,_IOFBF,size);
|
||||
return res == 0;
|
||||
}
|
||||
|
||||
const char* VFSFileImpl::path() const
|
||||
{
|
||||
return (const char*) _path;
|
||||
}
|
||||
|
||||
const char* VFSFileImpl::name() const
|
||||
{
|
||||
return pathToFileName(path());
|
||||
}
|
||||
|
||||
//to implement
|
||||
boolean VFSFileImpl::isDirectory(void)
|
||||
{
|
||||
return _isDirectory;
|
||||
}
|
||||
|
||||
FileImplPtr VFSFileImpl::openNextFile(const char* mode)
|
||||
{
|
||||
if(!_isDirectory || !_d) {
|
||||
return FileImplPtr();
|
||||
}
|
||||
struct dirent *file = readdir(_d);
|
||||
if(file == NULL) {
|
||||
return FileImplPtr();
|
||||
}
|
||||
if(file->d_type != DT_REG && file->d_type != DT_DIR) {
|
||||
return openNextFile(mode);
|
||||
}
|
||||
String fname = String(file->d_name);
|
||||
String name = String(_path);
|
||||
if(!fname.startsWith("/") && !name.endsWith("/")) {
|
||||
name += "/";
|
||||
}
|
||||
name += fname;
|
||||
|
||||
return std::make_shared<VFSFileImpl>(_fs, name.c_str(), mode);
|
||||
}
|
||||
|
||||
void VFSFileImpl::rewindDirectory(void)
|
||||
{
|
||||
if(!_isDirectory || !_d) {
|
||||
return;
|
||||
}
|
||||
rewinddir(_d);
|
||||
}
|
79
libraries/FS/src/vfs_api.h
Normal file
79
libraries/FS/src/vfs_api.h
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef vfs_api_h
|
||||
#define vfs_api_h
|
||||
|
||||
#include "FS.h"
|
||||
#include "FSImpl.h"
|
||||
|
||||
extern "C" {
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
}
|
||||
|
||||
using namespace fs;
|
||||
|
||||
class VFSFileImpl;
|
||||
|
||||
class VFSImpl : public FSImpl
|
||||
{
|
||||
|
||||
protected:
|
||||
friend class VFSFileImpl;
|
||||
|
||||
public:
|
||||
FileImplPtr open(const char* path, const char* mode, const bool create) override;
|
||||
bool exists(const char* path) override;
|
||||
bool rename(const char* pathFrom, const char* pathTo) override;
|
||||
bool remove(const char* path) override;
|
||||
bool mkdir(const char *path) override;
|
||||
bool rmdir(const char *path) override;
|
||||
};
|
||||
|
||||
class VFSFileImpl : public FileImpl
|
||||
{
|
||||
protected:
|
||||
VFSImpl* _fs;
|
||||
FILE * _f;
|
||||
DIR * _d;
|
||||
char * _path;
|
||||
bool _isDirectory;
|
||||
mutable struct stat _stat;
|
||||
mutable bool _written;
|
||||
|
||||
void _getStat() const;
|
||||
|
||||
public:
|
||||
VFSFileImpl(VFSImpl* fs, const char* path, const char* mode);
|
||||
~VFSFileImpl() override;
|
||||
size_t write(const uint8_t *buf, size_t size) override;
|
||||
size_t read(uint8_t* buf, size_t size) override;
|
||||
void flush() override;
|
||||
bool seek(uint32_t pos, SeekMode mode) override;
|
||||
size_t position() const override;
|
||||
size_t size() const override;
|
||||
bool setBufferSize(size_t size);
|
||||
void close() override;
|
||||
const char* path() const override;
|
||||
const char* name() const override;
|
||||
time_t getLastWrite() override;
|
||||
boolean isDirectory(void) override;
|
||||
FileImplPtr openNextFile(const char* mode) override;
|
||||
void rewindDirectory(void) override;
|
||||
operator bool();
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user