mirror of
https://github.com/Dejvino/lilybook.git
synced 2024-11-14 12:23:28 +00:00
879 lines
20 KiB
C
879 lines
20 KiB
C
/*
|
|
* spiffs VFS operations
|
|
*
|
|
* Author: LoBo (loboris@gmail.com / https://github.com/loboris)
|
|
*
|
|
* Part of this code is copied from or inspired by LUA-RTOS_ESP32 project:
|
|
*
|
|
* https://github.com/whitecatboard/Lua-RTOS-ESP32
|
|
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
|
* Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
|
*
|
|
*/
|
|
|
|
|
|
#include <freertos/FreeRTOS.h>
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
#include "esp_log.h"
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include "esp_vfs.h"
|
|
#include "esp_attr.h"
|
|
#include <errno.h>
|
|
|
|
#include <spiffs_vfs.h>
|
|
#include <spiffs.h>
|
|
#include <esp_spiffs.h>
|
|
#include <spiffs_nucleus.h>
|
|
#include "list.h"
|
|
#include <sys/fcntl.h>
|
|
#include <sys/dirent.h>
|
|
#include "sdkconfig.h"
|
|
|
|
|
|
#ifdef PATH_MAX
|
|
#undef PATH_MAX
|
|
#endif
|
|
#define PATH_MAX MAXNAMLEN+8
|
|
|
|
#define SPIFFS_ERASE_SIZE 4096
|
|
|
|
int spiffs_is_registered = 0;
|
|
int spiffs_is_mounted = 0;
|
|
|
|
QueueHandle_t spiffs_mutex = NULL;
|
|
|
|
static int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode);
|
|
static ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size);
|
|
static ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size);
|
|
static int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st);
|
|
static int IRAM_ATTR vfs_spiffs_close(int fd);
|
|
static off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode);
|
|
|
|
typedef struct {
|
|
DIR dir;
|
|
spiffs_DIR spiffs_dir;
|
|
char path[MAXNAMLEN + 1];
|
|
struct dirent ent;
|
|
uint8_t read_mount;
|
|
} vfs_spiffs_dir_t;
|
|
|
|
typedef struct {
|
|
spiffs_file spiffs_file;
|
|
char path[MAXNAMLEN + 1];
|
|
uint8_t is_dir;
|
|
} vfs_spiffs_file_t;
|
|
|
|
typedef struct {
|
|
time_t mtime;
|
|
time_t ctime;
|
|
time_t atime;
|
|
uint8_t spare[SPIFFS_OBJ_META_LEN - (sizeof(time_t)*3)];
|
|
} spiffs_metadata_t;
|
|
|
|
static spiffs fs;
|
|
static struct list files;
|
|
|
|
static u8_t *my_spiffs_work_buf;
|
|
static u8_t *my_spiffs_fds;
|
|
static u8_t *my_spiffs_cache;
|
|
|
|
|
|
/*
|
|
* ########################################
|
|
* file names/paths passed to the functions
|
|
* do not contain '/spiffs' prefix
|
|
* ########################################
|
|
*/
|
|
|
|
//----------------------------------------------------
|
|
void spiffs_fs_stat(uint32_t *total, uint32_t *used) {
|
|
if (SPIFFS_info(&fs, total, used) != SPIFFS_OK) {
|
|
*total = 0;
|
|
*used = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Test if path corresponds to a directory. Return 0 if is not a directory,
|
|
* 1 if it's a directory.
|
|
*
|
|
*/
|
|
//-----------------------------------
|
|
static int is_dir(const char *path) {
|
|
spiffs_DIR d;
|
|
char npath[PATH_MAX + 1];
|
|
int res = 0;
|
|
|
|
struct spiffs_dirent e;
|
|
|
|
// Add /. to path
|
|
strlcpy(npath, path, PATH_MAX);
|
|
if (strcmp(path,"/") != 0) {
|
|
strlcat(npath,"/.", PATH_MAX);
|
|
} else {
|
|
strlcat(npath,".", PATH_MAX);
|
|
}
|
|
|
|
SPIFFS_opendir(&fs, "/", &d);
|
|
while (SPIFFS_readdir(&d, &e)) {
|
|
if (strncmp(npath, (const char *)e.name, strlen(npath)) == 0) {
|
|
res = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SPIFFS_closedir(&d);
|
|
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* This function translate error codes from SPIFFS to errno error codes
|
|
*
|
|
*/
|
|
//-------------------------------
|
|
static int spiffs_result(int res) {
|
|
switch (res) {
|
|
case SPIFFS_OK:
|
|
case SPIFFS_ERR_END_OF_OBJECT:
|
|
return 0;
|
|
|
|
case SPIFFS_ERR_NOT_FOUND:
|
|
case SPIFFS_ERR_CONFLICTING_NAME:
|
|
return ENOENT;
|
|
|
|
case SPIFFS_ERR_NOT_WRITABLE:
|
|
case SPIFFS_ERR_NOT_READABLE:
|
|
return EACCES;
|
|
|
|
case SPIFFS_ERR_FILE_EXISTS:
|
|
return EEXIST;
|
|
|
|
default:
|
|
return res;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_getstat(spiffs_file fd, spiffs_stat *st, spiffs_metadata_t *metadata) {
|
|
int res = SPIFFS_fstat(&fs, fd, st);
|
|
if (res == SPIFFS_OK) {
|
|
// Get file's time information from metadata
|
|
memcpy(metadata, st->meta, sizeof(spiffs_metadata_t));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// ## path does not contain '/spiffs' prefix !
|
|
//---------------------------------------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode) {
|
|
int fd, result = 0, exists = 0;
|
|
spiffs_stat stat;
|
|
spiffs_metadata_t meta;
|
|
|
|
// Allocate new file
|
|
vfs_spiffs_file_t *file = calloc(1, sizeof(vfs_spiffs_file_t));
|
|
if (!file) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
// Add file to file list. List index is file descriptor.
|
|
int res = list_add(&files, file, &fd);
|
|
if (res) {
|
|
free(file);
|
|
errno = res;
|
|
return -1;
|
|
}
|
|
|
|
// Check if file exists
|
|
if (SPIFFS_stat(&fs, path, &stat) == SPIFFS_OK) exists = 1;
|
|
|
|
// Make a copy of path
|
|
strlcpy(file->path, path, MAXNAMLEN);
|
|
|
|
// Open file
|
|
spiffs_flags spiffs_mode = 0;
|
|
|
|
// Translate flags to SPIFFS flags
|
|
if (flags == O_RDONLY)
|
|
spiffs_mode |= SPIFFS_RDONLY;
|
|
|
|
if (flags & O_WRONLY)
|
|
spiffs_mode |= SPIFFS_WRONLY;
|
|
|
|
if (flags & O_RDWR)
|
|
spiffs_mode = SPIFFS_RDWR;
|
|
|
|
if (flags & O_EXCL)
|
|
spiffs_mode |= SPIFFS_EXCL;
|
|
|
|
if (flags & O_CREAT)
|
|
spiffs_mode |= SPIFFS_CREAT;
|
|
|
|
if (flags & O_TRUNC)
|
|
spiffs_mode |= SPIFFS_TRUNC;
|
|
|
|
if (is_dir(path)) {
|
|
char npath[PATH_MAX + 1];
|
|
|
|
// Add /. to path
|
|
strlcpy(npath, path, PATH_MAX);
|
|
if (strcmp(path,"/") != 0) {
|
|
strlcat(npath,"/.", PATH_MAX);
|
|
} else {
|
|
strlcat(npath,".", PATH_MAX);
|
|
}
|
|
|
|
// Open SPIFFS file
|
|
file->spiffs_file = SPIFFS_open(&fs, npath, spiffs_mode, 0);
|
|
if (file->spiffs_file < 0) {
|
|
result = spiffs_result(fs.err_code);
|
|
}
|
|
|
|
file->is_dir = 1;
|
|
} else {
|
|
// Open SPIFFS file
|
|
file->spiffs_file = SPIFFS_open(&fs, path, spiffs_mode, 0);
|
|
if (file->spiffs_file < 0) {
|
|
result = spiffs_result(fs.err_code);
|
|
}
|
|
}
|
|
|
|
if (result != 0) {
|
|
list_remove(&files, fd, 1);
|
|
errno = result;
|
|
return -1;
|
|
}
|
|
|
|
res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);
|
|
if (res == SPIFFS_OK) {
|
|
// update file's time information
|
|
meta.atime = time(NULL); // Get the system time to access time
|
|
if (!exists) meta.ctime = meta.atime;
|
|
if (spiffs_mode != SPIFFS_RDONLY) meta.mtime = meta.atime;
|
|
SPIFFS_fupdate_meta(&fs, file->spiffs_file, &meta);
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------
|
|
static ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size) {
|
|
vfs_spiffs_file_t *file;
|
|
int res;
|
|
|
|
res = list_get(&files, fd, (void **)&file);
|
|
if (res) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
if (file->is_dir) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Write SPIFFS file
|
|
res = SPIFFS_write(&fs, file->spiffs_file, (void *)data, size);
|
|
if (res >= 0) {
|
|
return res;
|
|
} else {
|
|
res = spiffs_result(fs.err_code);
|
|
if (res != 0) {
|
|
errno = res;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size) {
|
|
vfs_spiffs_file_t *file;
|
|
int res;
|
|
|
|
res = list_get(&files, fd, (void **)&file);
|
|
if (res) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
if (file->is_dir) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Read SPIFFS file
|
|
res = SPIFFS_read(&fs, file->spiffs_file, dst, size);
|
|
if (res >= 0) {
|
|
return res;
|
|
} else {
|
|
res = spiffs_result(fs.err_code);
|
|
if (res != 0) {
|
|
errno = res;
|
|
return -1;
|
|
}
|
|
|
|
// EOF
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st) {
|
|
vfs_spiffs_file_t *file;
|
|
spiffs_stat stat;
|
|
int res;
|
|
spiffs_metadata_t meta;
|
|
|
|
res = list_get(&files, fd, (void **)&file);
|
|
if (res) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Set block size for this file system
|
|
st->st_blksize = CONFIG_SPIFFS_LOG_PAGE_SIZE;
|
|
|
|
// Get file/directory statistics
|
|
res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);
|
|
if (res == SPIFFS_OK) {
|
|
// Set file's time information from metadata
|
|
st->st_mtime = meta.mtime;
|
|
st->st_ctime = meta.ctime;
|
|
st->st_atime = meta.atime;
|
|
|
|
st->st_size = stat.size;
|
|
|
|
} else {
|
|
st->st_mtime = 0;
|
|
st->st_ctime = 0;
|
|
st->st_atime = 0;
|
|
st->st_size = 0;
|
|
errno = spiffs_result(fs.err_code);
|
|
//printf("SPIFFS_STAT: error %d\r\n", res);
|
|
return -1;
|
|
}
|
|
|
|
// Test if it's a directory entry
|
|
if (file->is_dir) st->st_mode = S_IFDIR;
|
|
else st->st_mode = S_IFREG;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_close(int fd) {
|
|
vfs_spiffs_file_t *file;
|
|
int res;
|
|
|
|
res = list_get(&files, fd, (void **)&file);
|
|
if (res) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
res = SPIFFS_close(&fs, file->spiffs_file);
|
|
if (res) {
|
|
res = spiffs_result(fs.err_code);
|
|
}
|
|
|
|
if (res < 0) {
|
|
errno = res;
|
|
return -1;
|
|
}
|
|
|
|
list_remove(&files, fd, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
static off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode) {
|
|
vfs_spiffs_file_t *file;
|
|
int res;
|
|
|
|
res = list_get(&files, fd, (void **)&file);
|
|
if (res) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
if (file->is_dir) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
int whence = SPIFFS_SEEK_CUR;
|
|
|
|
switch (mode) {
|
|
case SEEK_SET: whence = SPIFFS_SEEK_SET;break;
|
|
case SEEK_CUR: whence = SPIFFS_SEEK_CUR;break;
|
|
case SEEK_END: whence = SPIFFS_SEEK_END;break;
|
|
}
|
|
|
|
res = SPIFFS_lseek(&fs, file->spiffs_file, size, whence);
|
|
if (res < 0) {
|
|
res = spiffs_result(fs.err_code);
|
|
errno = res;
|
|
return -1;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_stat(const char * path, struct stat * st) {
|
|
int fd;
|
|
int res;
|
|
fd = vfs_spiffs_open(path, 0, 0);
|
|
res = vfs_spiffs_fstat(fd, st);
|
|
vfs_spiffs_close(fd);
|
|
|
|
return res;
|
|
}
|
|
|
|
//--------------------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_unlink(const char *path) {
|
|
char npath[PATH_MAX + 1];
|
|
|
|
strlcpy(npath, path, PATH_MAX);
|
|
|
|
if (is_dir(path)) {
|
|
// Check if directory is empty
|
|
int nument = 0;
|
|
sprintf(npath, "/spiffs");
|
|
strlcat(npath, path, PATH_MAX);
|
|
|
|
DIR *dir = opendir(npath);
|
|
if (dir) {
|
|
struct dirent *ent;
|
|
// Read directory entries
|
|
while ((ent = readdir(dir)) != NULL) {
|
|
nument++;
|
|
}
|
|
}
|
|
else {
|
|
errno = ENOTEMPTY;
|
|
return -1;
|
|
}
|
|
closedir(dir);
|
|
|
|
if (nument > 0) {
|
|
// Directory not empty, cannot remove
|
|
errno = ENOTEMPTY;
|
|
return -1;
|
|
}
|
|
|
|
strlcpy(npath, path, PATH_MAX);
|
|
// Add /. to path
|
|
if (strcmp(path,"/") != 0) {
|
|
strlcat(npath,"/.", PATH_MAX);
|
|
}
|
|
}
|
|
|
|
// Open SPIFFS file
|
|
spiffs_file FP = SPIFFS_open(&fs, npath, SPIFFS_RDWR, 0);
|
|
if (FP < 0) {
|
|
errno = spiffs_result(fs.err_code);
|
|
return -1;
|
|
}
|
|
|
|
// Remove SPIFSS file
|
|
if (SPIFFS_fremove(&fs, FP) < 0) {
|
|
errno = spiffs_result(fs.err_code);
|
|
SPIFFS_close(&fs, FP);
|
|
return -1;
|
|
}
|
|
|
|
SPIFFS_close(&fs, FP);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_rename(const char *src, const char *dst) {
|
|
if (SPIFFS_rename(&fs, src, dst) < 0) {
|
|
errno = spiffs_result(fs.err_code);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------
|
|
static DIR* vfs_spiffs_opendir(const char* name) {
|
|
struct stat st;
|
|
|
|
if (strcmp(name, "/") != 0) {
|
|
// Not on root
|
|
if (vfs_spiffs_stat(name, &st)) {
|
|
// Not found
|
|
errno = ENOENT;
|
|
return NULL;
|
|
}
|
|
if (!S_ISDIR(st.st_mode)) {
|
|
// Not a directory
|
|
errno = ENOTDIR;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
vfs_spiffs_dir_t *dir = calloc(1, sizeof(vfs_spiffs_dir_t));
|
|
|
|
if (!dir) {
|
|
errno = ENOMEM;
|
|
return NULL;
|
|
}
|
|
|
|
if (!SPIFFS_opendir(&fs, name, &dir->spiffs_dir)) {
|
|
free(dir);
|
|
errno = spiffs_result(fs.err_code);
|
|
return NULL;
|
|
}
|
|
|
|
strlcpy(dir->path, name, MAXNAMLEN);
|
|
|
|
return (DIR *)dir;
|
|
}
|
|
|
|
//---------------------------------------------------
|
|
static struct dirent* vfs_spiffs_readdir(DIR* pdir) {
|
|
int res = 0, len = 0, entries = 0;
|
|
vfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;
|
|
|
|
struct spiffs_dirent e;
|
|
struct spiffs_dirent *pe = &e;
|
|
|
|
struct dirent *ent = &dir->ent;
|
|
|
|
char *fn;
|
|
|
|
// Clear current dirent
|
|
memset(ent,0,sizeof(struct dirent));
|
|
|
|
// If this is the first call to readdir for pdir, and
|
|
// directory is the root path, return the mounted point if any
|
|
if (!dir->read_mount) {
|
|
if (strcmp(dir->path,"/") == 0) {
|
|
strlcpy(ent->d_name, "/spiffs", PATH_MAX);
|
|
ent->d_type = DT_DIR;
|
|
dir->read_mount = 1;
|
|
|
|
return ent;
|
|
}
|
|
|
|
dir->read_mount = 1;
|
|
}
|
|
|
|
// Search for next entry
|
|
for(;;) {
|
|
// Read directory
|
|
pe = SPIFFS_readdir(&dir->spiffs_dir, pe);
|
|
if (!pe) {
|
|
res = spiffs_result(fs.err_code);
|
|
errno = res;
|
|
break;
|
|
}
|
|
|
|
// Break condition
|
|
if (pe->name[0] == 0) break;
|
|
|
|
// Get name and length
|
|
fn = (char *)pe->name;
|
|
len = strlen(fn);
|
|
|
|
// Get entry type and size
|
|
ent->d_type = DT_REG;
|
|
|
|
if (len >= 2) {
|
|
if (fn[len - 1] == '.') {
|
|
if (fn[len - 2] == '/') {
|
|
ent->d_type = DT_DIR;
|
|
|
|
fn[len - 2] = '\0';
|
|
|
|
len = strlen(fn);
|
|
|
|
// Skip root dir
|
|
if (len == 0) {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Skip entries not belonged to path
|
|
if (strncmp(fn, dir->path, strlen(dir->path)) != 0) {
|
|
continue;
|
|
}
|
|
|
|
if (strlen(dir->path) > 1) {
|
|
if (*(fn + strlen(dir->path)) != '/') {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Skip root directory
|
|
fn = fn + strlen(dir->path);
|
|
len = strlen(fn);
|
|
if (len == 0) {
|
|
continue;
|
|
}
|
|
|
|
// Skip initial /
|
|
if (len > 1) {
|
|
if (*fn == '/') {
|
|
fn = fn + 1;
|
|
len--;
|
|
}
|
|
}
|
|
|
|
// Skip subdirectories
|
|
if (strchr(fn,'/')) {
|
|
continue;
|
|
}
|
|
|
|
//ent->d_fsize = pe->size;
|
|
|
|
strlcpy(ent->d_name, fn, MAXNAMLEN);
|
|
|
|
entries++;
|
|
|
|
break;
|
|
}
|
|
|
|
if (entries > 0) {
|
|
return ent;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
static int IRAM_ATTR vfs_piffs_closedir(DIR* pdir) {
|
|
vfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;
|
|
int res;
|
|
|
|
if (!pdir) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
if ((res = SPIFFS_closedir(&dir->spiffs_dir)) < 0) {
|
|
errno = spiffs_result(fs.err_code);;
|
|
return -1;
|
|
}
|
|
|
|
free(dir);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------
|
|
static int IRAM_ATTR vfs_spiffs_mkdir(const char *path, mode_t mode) {
|
|
char npath[PATH_MAX + 1];
|
|
int res;
|
|
|
|
// Add /. to path
|
|
strlcpy(npath, path, PATH_MAX);
|
|
if ((strcmp(path,"/") != 0) && (strcmp(path,"/.") != 0)) {
|
|
strlcat(npath,"/.", PATH_MAX);
|
|
}
|
|
|
|
spiffs_file fd = SPIFFS_open(&fs, npath, SPIFFS_CREAT, 0);
|
|
if (fd < 0) {
|
|
res = spiffs_result(fs.err_code);
|
|
errno = res;
|
|
return -1;
|
|
}
|
|
|
|
if (SPIFFS_close(&fs, fd) < 0) {
|
|
res = spiffs_result(fs.err_code);
|
|
errno = res;
|
|
return -1;
|
|
}
|
|
|
|
spiffs_metadata_t meta;
|
|
meta.atime = time(NULL); // Get the system time to access time
|
|
meta.ctime = meta.atime;
|
|
meta.mtime = meta.atime;
|
|
SPIFFS_update_meta(&fs, npath, &meta);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static const char tag[] = "[SPIFFS]";
|
|
|
|
//==================
|
|
int spiffs_mount() {
|
|
|
|
if (!spiffs_is_registered) return 0;
|
|
if (spiffs_is_mounted) return 1;
|
|
|
|
spiffs_config cfg;
|
|
int res = 0;
|
|
int retries = 0;
|
|
int err = 0;
|
|
|
|
ESP_LOGI(tag, "Mounting SPIFFS files system");
|
|
|
|
cfg.phys_addr = CONFIG_SPIFFS_BASE_ADDR;
|
|
cfg.phys_size = CONFIG_SPIFFS_SIZE;
|
|
cfg.phys_erase_block = SPIFFS_ERASE_SIZE;
|
|
cfg.log_page_size = CONFIG_SPIFFS_LOG_PAGE_SIZE;
|
|
cfg.log_block_size = CONFIG_SPIFFS_LOG_BLOCK_SIZE;
|
|
|
|
cfg.hal_read_f = (spiffs_read)low_spiffs_read;
|
|
cfg.hal_write_f = (spiffs_write)low_spiffs_write;
|
|
cfg.hal_erase_f = (spiffs_erase)low_spiffs_erase;
|
|
|
|
my_spiffs_work_buf = malloc(cfg.log_page_size * 8);
|
|
if (!my_spiffs_work_buf) {
|
|
err = 1;
|
|
goto err_exit;
|
|
}
|
|
|
|
int fds_len = sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
|
|
my_spiffs_fds = malloc(fds_len);
|
|
if (!my_spiffs_fds) {
|
|
free(my_spiffs_work_buf);
|
|
err = 2;
|
|
goto err_exit;
|
|
}
|
|
|
|
int cache_len = cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
|
|
my_spiffs_cache = malloc(cache_len);
|
|
if (!my_spiffs_cache) {
|
|
free(my_spiffs_work_buf);
|
|
free(my_spiffs_fds);
|
|
err = 3;
|
|
goto err_exit;
|
|
}
|
|
|
|
ESP_LOGI(tag, "Start address: 0x%x; Size %d KB", cfg.phys_addr, cfg.phys_size / 1024);
|
|
ESP_LOGI(tag, " Work buffer: %d B", cfg.log_page_size * 8);
|
|
ESP_LOGI(tag, " FDS buffer: %d B", sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);
|
|
ESP_LOGI(tag, " Cache size: %d B", cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);
|
|
while (retries < 2) {
|
|
res = SPIFFS_mount(
|
|
&fs, &cfg, my_spiffs_work_buf, my_spiffs_fds,
|
|
fds_len, my_spiffs_cache, cache_len, NULL
|
|
);
|
|
|
|
if (res < 0) {
|
|
if (fs.err_code == SPIFFS_ERR_NOT_A_FS) {
|
|
ESP_LOGW(tag, "No file system detected, formating...");
|
|
SPIFFS_unmount(&fs);
|
|
res = SPIFFS_format(&fs);
|
|
if (res < 0) {
|
|
free(my_spiffs_work_buf);
|
|
free(my_spiffs_fds);
|
|
free(my_spiffs_cache);
|
|
ESP_LOGE(tag, "Format error");
|
|
goto exit;
|
|
}
|
|
}
|
|
else {
|
|
free(my_spiffs_work_buf);
|
|
free(my_spiffs_fds);
|
|
free(my_spiffs_cache);
|
|
ESP_LOGE(tag, "Error mounting fs (%d)", res);
|
|
goto exit;
|
|
}
|
|
}
|
|
else break;
|
|
retries++;
|
|
}
|
|
|
|
if (retries > 1) {
|
|
free(my_spiffs_work_buf);
|
|
free(my_spiffs_fds);
|
|
free(my_spiffs_cache);
|
|
ESP_LOGE(tag, "Can't mount");
|
|
goto exit;
|
|
}
|
|
|
|
list_init(&files, 0);
|
|
|
|
ESP_LOGI(tag, "Mounted");
|
|
|
|
spiffs_is_mounted = 1;
|
|
return 1;
|
|
|
|
err_exit:
|
|
ESP_LOGE(tag, "Error allocating fs structures (%d)", err);
|
|
exit:
|
|
esp_vfs_unregister("/spiffs");
|
|
spiffs_is_registered = 0;
|
|
return 0;
|
|
}
|
|
|
|
//==========================
|
|
void vfs_spiffs_register() {
|
|
|
|
if (spiffs_is_registered) return;
|
|
|
|
if (spiffs_mutex == NULL) {
|
|
spiffs_mutex = xSemaphoreCreateMutex();
|
|
if (spiffs_mutex == NULL) {
|
|
ESP_LOGE(tag, "Error creating SPIFFS mutex");
|
|
return;
|
|
}
|
|
}
|
|
|
|
esp_vfs_t vfs = {
|
|
//.fd_offset = 0, // not available in latest esp-idf
|
|
.flags = ESP_VFS_FLAG_DEFAULT,
|
|
.write = &vfs_spiffs_write,
|
|
.open = &vfs_spiffs_open,
|
|
.fstat = &vfs_spiffs_fstat,
|
|
.close = &vfs_spiffs_close,
|
|
.read = &vfs_spiffs_read,
|
|
.lseek = &vfs_spiffs_lseek,
|
|
.stat = &vfs_spiffs_stat,
|
|
.link = NULL,
|
|
.unlink = &vfs_spiffs_unlink,
|
|
.rename = &vfs_spiffs_rename,
|
|
.mkdir = &vfs_spiffs_mkdir,
|
|
.opendir = &vfs_spiffs_opendir,
|
|
.readdir = &vfs_spiffs_readdir,
|
|
.closedir = &vfs_piffs_closedir,
|
|
};
|
|
|
|
ESP_LOGI(tag, "Registering SPIFFS file system");
|
|
esp_err_t res = esp_vfs_register(SPIFFS_BASE_PATH, &vfs, NULL);
|
|
if (res != ESP_OK) {
|
|
ESP_LOGE(tag, "Error, SPIFFS file system not registered");
|
|
return;
|
|
}
|
|
spiffs_is_registered = 1;
|
|
|
|
spiffs_mount();
|
|
}
|
|
|
|
//=============================
|
|
int spiffs_unmount(int unreg) {
|
|
|
|
if (!spiffs_is_mounted) return 0;
|
|
|
|
SPIFFS_unmount(&fs);
|
|
spiffs_is_mounted = 0;
|
|
|
|
if (unreg) {
|
|
esp_vfs_unregister("/spiffs");
|
|
spiffs_is_registered = 0;
|
|
}
|
|
return 1;
|
|
}
|