Commit 4f1b33d5 authored by Johny Mattsson's avatar Johny Mattsson
Browse files

Grabbed latest spiffs + vfs layer from dev branch.

Also included the recent LVM fix.

Platform flash layer not yet functional.
parent fe602d2d
......@@ -12,9 +12,9 @@
#include "platform.h"
#include <string.h>
#include <stdlib.h>
#include "flash_fs.h"
#include "flash_api.h"
#include "vfs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "driver/console.h"
#include "task/task.h"
......@@ -62,23 +62,12 @@ void nodemcu_init(void)
return;
}
// FIXME: this breaks horribly on the ESP32 at the moment; possibly all flash writes?
#if defined(FLASH_SAFE_API) && defined(__ESP8266__)
if( flash_safe_get_size_byte() != flash_rom_get_size_byte()) {
#if defined(FLASH_SAFE_API)
if (flash_safe_get_size_byte() != flash_rom_get_size_byte()) {
NODE_ERR("Self adjust flash size.\n");
// Fit hardware real flash size.
flash_rom_set_size_byte(flash_safe_get_size_byte());
if( !fs_format() )
{
NODE_ERR( "\ni*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
}
else{
NODE_ERR( "format done.\n" );
}
fs_unmount(); // mounted by format.
// Reboot to get SDK to use (or write) init data at new location
system_restart ();
......@@ -87,9 +76,16 @@ void nodemcu_init(void)
}
#endif // defined(FLASH_SAFE_API)
#if defined ( BUILD_SPIFFS )
fs_mount();
// test_spiffs();
#if defined ( CONFIG_BUILD_SPIFFS )
if (!vfs_mount("/FLASH", 0)) {
// Failed to mount -- try reformat
NODE_ERR("Formatting file system. Please wait...\n");
if (1 || !vfs_format()) { // FIXME
NODE_ERR( "*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
}
// Note that fs_format leaves the file system mounted
}
#endif
task_post_low(task_get_id(start_lua), 0);
......@@ -120,5 +116,5 @@ void app_main (void)
console_init (&cfg, input_task);
xTaskCreate (
nodemcu_main, "nodemcu", 2048, 0, configTIMER_TASK_PRIORITY +1, NULL);
nodemcu_main, "nodemcu", 2560, 0, tskIDLE_PRIORITY +1, NULL);
}
......@@ -13,7 +13,7 @@
#include C_HEADER_STDLIB
#include C_HEADER_STRING
#ifndef LUA_CROSS_COMPILER
#include "flash_fs.h"
#include "vfs.h"
#else
#endif
......@@ -671,8 +671,8 @@ static const char *getFSF (lua_State *L, void *ud, size_t *size) {
return "\n";
}
if (fs_eof(lf->f)) return NULL;
*size = fs_read(lf->f, lf->buff, sizeof(lf->buff));
if (vfs_eof(lf->f)) return NULL;
*size = vfs_read(lf->f, lf->buff, sizeof(lf->buff));
return (*size > 0) ? lf->buff : NULL;
}
......@@ -697,29 +697,29 @@ LUALIB_API int luaL_loadfsfile (lua_State *L, const char *filename) {
}
else {
lua_pushfstring(L, "@%s", filename);
lf.f = fs_open(filename, FS_RDONLY);
if (lf.f < FS_OPEN_OK) return errfsfile(L, "open", fnameindex);
lf.f = vfs_open(filename, "r");
if (!lf.f) return errfsfile(L, "open", fnameindex);
}
// if(fs_size(lf.f)>LUAL_BUFFERSIZE)
// if(vfs_size(lf.f)>LUAL_BUFFERSIZE)
// return luaL_error(L, "file is too big");
c = fs_getc(lf.f);
c = vfs_getc(lf.f);
if (c == '#') { /* Unix exec. file? */
lf.extraline = 1;
while ((c = fs_getc(lf.f)) != EOF && c != '\n') ; /* skip first line */
if (c == '\n') c = fs_getc(lf.f);
while ((c = vfs_getc(lf.f)) != EOF && c != '\n') ; /* skip first line */
if (c == '\n') c = vfs_getc(lf.f);
}
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
fs_close(lf.f);
lf.f = fs_open(filename, FS_RDONLY); /* reopen in binary mode */
if (lf.f < FS_OPEN_OK) return errfsfile(L, "reopen", fnameindex);
vfs_close(lf.f);
lf.f = vfs_open(filename, "r"); /* reopen in binary mode */
if (!lf.f) return errfsfile(L, "reopen", fnameindex);
/* skip eventual `#!...' */
while ((c = fs_getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
while ((c = vfs_getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) ;
lf.extraline = 0;
}
fs_ungetc(c, lf.f);
vfs_ungetc(c, lf.f);
status = lua_load(L, getFSF, &lf, lua_tostring(L, -1));
if (filename) fs_close(lf.f); /* close file (even in case of errors) */
if (filename) vfs_close(lf.f); /* close file (even in case of errors) */
lua_remove(L, fnameindex);
return status;
}
......
......@@ -9,7 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "flash_fs.h"
#include "vfs.h"
#define liolib_c
#define LUA_LIB
......@@ -39,7 +39,7 @@ static const int liolib_keys[] = {(int)&luaL_callmeta, (int)&luaL_typerror, (int
static const char *const fnames[] = {"input", "output"};
static int pushresult (lua_State *L, int i, const char *filename) {
int en = fs_error(0); /* calls to Lua API may change this value */
int en = vfs_ferrno(0); /* calls to Lua API may change this value */
if (i) {
lua_pushboolean(L, 1);
return 1;
......@@ -57,7 +57,7 @@ static int pushresult (lua_State *L, int i, const char *filename) {
static void fileerror (lua_State *L, int arg, const char *filename) {
lua_pushfstring(L, "%s: err(%d)", filename, fs_error(0));
lua_pushfstring(L, "%s: err(%d)", filename, vfs_ferrno(0));
luaL_argerror(L, arg, lua_tostring(L, -1));
}
......@@ -130,7 +130,7 @@ static int io_pclose (lua_State *L) {
*/
static int io_fclose (lua_State *L) {
int *p = tofilep(L);
int ok = (fs_close(*p) == 0);
int ok = (vfs_close(*p) == 0);
*p = FS_OPEN_OK - 1;
return pushresult(L, ok, NULL);
}
......@@ -149,7 +149,7 @@ static int aux_close (lua_State *L) {
lua_pushliteral(L, "cannot close standard file");
return 2;
}
int ok = (fs_close(*p) == 0);
int ok = (vfs_close(*p) == 0);
*p = FS_OPEN_OK - 1;
return pushresult(L, ok, NULL);
#endif
......@@ -187,7 +187,7 @@ static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
int *pf = newfile(L);
*pf = fs_open(filename, fs_mode2flag(mode));
*pf = vfs_open(filename, mode);
return (*pf == FS_OPEN_OK - 1) ? pushresult(L, 0, filename) : 1;
}
......@@ -201,7 +201,7 @@ static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
int *pf = newfile(L);
*pf = lua_popen(L, filename, fs_mode2flag(mode));
*pf = lua_popen(L, filename, mode);
return (*pf == FS_OPEN_OK - 1) ? pushresult(L, 0, filename) : 1;
}
......@@ -230,7 +230,7 @@ static int g_iofile (lua_State *L, int f, const char *mode) {
const char *filename = lua_tostring(L, 1);
if (filename) {
int *pf = newfile(L);
*pf = fs_open(filename, fs_mode2flag(mode));
*pf = vfs_open(filename, mode);
if (*pf == FS_OPEN_OK - 1)
fileerror(L, 1, filename);
}
......@@ -282,7 +282,7 @@ static int io_lines (lua_State *L) {
else {
const char *filename = luaL_checkstring(L, 1);
int *pf = newfile(L);
*pf = fs_open(filename, FS_RDONLY);
*pf = vfs_open(filename, "r");
if (*pf == FS_OPEN_OK - 1)
fileerror(L, 1, filename);
aux_lines(L, lua_gettop(L), 1);
......@@ -300,7 +300,7 @@ static int io_lines (lua_State *L) {
#if 0
static int read_number (lua_State *L, int f) {
lua_Number d;
if (fs_scanf(f, LUA_NUMBER_SCAN, &d) == 1) {
if (vfs_scanf(f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d);
return 1;
}
......@@ -312,8 +312,8 @@ static int read_number (lua_State *L, int f) {
#endif
static int test_eof (lua_State *L, int f) {
int c = fs_getc(f);
fs_ungetc(c, f);
int c = vfs_getc(f);
vfs_ungetc(c, f);
lua_pushlstring(L, NULL, 0);
return (c != EOF);
}
......@@ -325,7 +325,7 @@ static int read_line (lua_State *L, int f) {
for (;;) {
size_t l;
char *p = luaL_prepbuffer(&b);
if (fs_gets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
if (vfs_gets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
luaL_pushresult(&b); /* close buffer */
return (lua_objlen(L, -1) > 0); /* check whether read something */
}
......@@ -347,7 +347,7 @@ static int read_line (lua_State *L, int f) {
signed char c = EOF;
int i = 0;
do{
c = (signed char)fs_getc(f);
c = (signed char)vfs_getc(f);
if(c==EOF){
break;
}
......@@ -377,7 +377,7 @@ static int read_chars (lua_State *L, int f, size_t n) {
do {
char *p = luaL_prepbuffer(&b);
if (rlen > n) rlen = n; /* cannot read more than asked */
nr = fs_read(f, p, rlen);
nr = vfs_read(f, p, rlen);
luaL_addsize(&b, nr);
n -= nr; /* still have to read `n' chars */
} while (n > 0 && nr == rlen); /* until end of count or eof */
......@@ -390,7 +390,7 @@ static int g_read (lua_State *L, int f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
fs_clearerr(f);
//vfs_clearerr(f);
if (nargs == 0) { /* no arguments? */
success = read_line(L, f);
n = first+1; /* to return 1 result */
......@@ -425,7 +425,7 @@ static int g_read (lua_State *L, int f, int first) {
}
}
}
if (fs_error(f))
if (vfs_ferrno(f))
return pushresult(L, 0, NULL);
if (!success) {
lua_pop(L, 1); /* remove last result */
......@@ -453,8 +453,8 @@ static int io_readline (lua_State *L) {
return 0;
}
sucess = read_line(L, *pf);
if (fs_error(*pf))
return luaL_error(L, "err(%d)", fs_error(*pf));
if (vfs_ferrno(*pf))
return luaL_error(L, "err(%d)", vfs_ferrno(*pf));
if (sucess) return 1;
else { /* EOF */
if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */
......@@ -477,14 +477,14 @@ static int g_write (lua_State *L, int f, int arg) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
fs_printf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
vfs_printf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
}
else
#endif
{
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
status = status && (fs_write(f, s, l) == l);
status = status && (vfs_write(f, s, l) == l);
}
}
return pushresult(L, status, NULL);
......@@ -502,16 +502,16 @@ static int f_write (lua_State *L) {
static int f_seek (lua_State *L) {
static const int mode[] = {FS_SEEK_SET, FS_SEEK_CUR, FS_SEEK_END};
static const int mode[] = {VFS_SEEK_SET, VFS_SEEK_CUR, VFS_SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
int f = tofile(L);
int op = luaL_checkoption(L, 2, "cur", modenames);
long offset = luaL_optlong(L, 3, 0);
op = fs_seek(f, offset, mode[op]);
op = vfs_lseek(f, offset, mode[op]);
if (op)
return pushresult(L, 0, NULL); /* error */
else {
lua_pushinteger(L, fs_tell(f));
lua_pushinteger(L, vfs_tell(f));
return 1;
}
}
......@@ -530,12 +530,12 @@ static int f_setvbuf (lua_State *L) {
static int io_flush (lua_State *L) {
return pushresult(L, fs_flush(getiofile(L, IO_OUTPUT)) == 0, NULL);
return pushresult(L, vfs_flush(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static int f_flush (lua_State *L) {
return pushresult(L, fs_flush(tofile(L)) == 0, NULL);
return pushresult(L, vfs_flush(tofile(L)) == 0, NULL);
}
#undef MIN_OPT_LEVEL
......
......@@ -19,8 +19,8 @@
#include <fcntl.h>
#ifndef LUA_CROSS_COMPILER
#include "flash_fs.h"
#include "c_stdlib.h"
#include "vfs.h"
#include "c_stdlib.h" // for c_getenv
#endif
#include "lauxlib.h"
......@@ -341,9 +341,9 @@ static int readable (const char *filename) {
}
#else
static int readable (const char *filename) {
int f = fs_open(filename, FS_RDONLY); /* try to open file */
if (f < FS_OPEN_OK) return 0; /* open failed */
fs_close(f);
int f = vfs_open(filename, "r"); /* try to open file */
if (!f) return 0; /* open failed */
vfs_close(f);
return 1;
}
#endif
......
......@@ -759,7 +759,6 @@ void luaV_execute (lua_State *L, int nexeccalls) {
fixedstack(L);
if (n == 0) {
n = cast_int(L->top - ra) - 1;
L->top = L->ci->top;
}
if (c == 0) c = cast_int(*pc++);
runtime_check(L, ttistable(ra));
......@@ -772,6 +771,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
setobj2t(L, luaH_setnum(L, h, last--), val);
luaC_barriert(L, h, val);
}
L->top = L->ci->top;
unfixedstack(L);
continue;
}
......
menu "Platform hardware config"
menu "Platform config"
choice FLASH_SIZE
bool "Platform SPI flash size"
......@@ -105,7 +105,7 @@ config NODE_DEBUG
Enable debugging output via NODE_DBG(). This is VERY chatty.
For development/debugging use only.
config NODE_ERROR
config NODE_ERR
bool "Enable NODE_ERR() output"
default "y"
help
......@@ -115,4 +115,21 @@ config NODE_ERROR
something has gone seriously wrong and you probably want to know about
it.
config FS_OBJ_NAME_LEN
int "Make filesystem object name length"
default 31
help
Maximum name of filesystem objects (files, directories).
# I don't think we can deal without SPIFFS at this point, so always on for now
config BUILD_SPIFFS
bool
default "y"
config BUILD_FATFS
bool "Support for FAT filesystems"
default "n"
help
Include support for accessing FAT filesystems on SD cards.
endmenu
......@@ -2,6 +2,8 @@
#define _PLATFORM_H_
#include <stdint.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "cpu_esp32.h"
#define PLATFORM_ALIGNMENT __attribute__((aligned(4)))
......
#ifndef __VFS_H__
#define __VFS_H__
#include <stdint.h>
#include <stdbool.h>
#include "vfs_int.h"
// DEPRECATED, DON'T USE
// Check for fd != 0 instead
#define FS_OPEN_OK 1
// ---------------------------------------------------------------------------
// file functions
//
// vfs_close - close file descriptor and free memory
// fd: file descriptor
// Returns: VFS_RES_OK or negative value in case of error
inline int32_t vfs_close( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->close( f ) : VFS_RES_ERR;
}
// vfs_read - read data from file
// fd: file descriptor
// ptr: destination data buffer
// len: requested length
// Returns: Number of bytes read, or VFS_RES_ERR in case of error
inline int32_t vfs_read( int fd, void *ptr, size_t len ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->read( f, ptr, len ) : VFS_RES_ERR;
}
// vfs_write - write data to file
// fd: file descriptor
// ptr: source data buffer
// len: requested length
// Returns: Number of bytes written, or VFS_RES_ERR in case of error
inline int32_t vfs_write( int fd, const void *ptr, size_t len ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->write( f, ptr, len ) : VFS_RES_ERR;
}
int vfs_getc( int fd );
int vfs_ungetc( int c, int fd );
// vfs_lseek - move read/write pointer
// fd: file descriptor
// off: offset
// whence: VFS_SEEK_SET - set pointer to off
// VFS_SEEK_CUR - set pointer to current position + off
// VFS_SEEK_END - set pointer to end of file + off
// Returns: New position, or VFS_RES_ERR in case of error
inline int32_t vfs_lseek( int fd, int32_t off, int whence ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->lseek( f, off, whence ) : VFS_RES_ERR;
}
// vfs_eof - test for end-of-file
// fd: file descriptor
// Returns: 0 if not at end, != 0 if end of file
inline int32_t vfs_eof( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->eof( f ) : VFS_RES_ERR;
}
// vfs_tell - get read/write position
// fd: file descriptor
// Returns: Current position
inline int32_t vfs_tell( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->tell( f ) : VFS_RES_ERR;
}
// vfs_flush - flush write cache to file
// fd: file descriptor
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
inline int32_t vfs_flush( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->flush( f ) : VFS_RES_ERR;
}
// vfs_size - get current file size
// fd: file descriptor
// Returns: File size
inline uint32_t vfs_size( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f && f->fns->size ? f->fns->size( f ) : 0;
}
// vfs_ferrno - get file system specific errno
// fd: file descriptor
// Returns: errno
int32_t vfs_ferrno( int fd );
// ---------------------------------------------------------------------------
// dir functions
//
// vfs_closedir - close directory descriptor and free memory
// dd: dir descriptor
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
inline int32_t vfs_closedir( vfs_dir *dd ) { return dd->fns->close( dd ); }
// vfs_readdir - read next directory item
// dd: dir descriptor
// Returns: item object, or NULL in case of error
inline vfs_item *vfs_readdir( vfs_dir *dd ) { return dd->fns->readdir( dd ); }
// ---------------------------------------------------------------------------
// dir item functions
//
// vfs_closeitem - close directory item and free memory
// di: item descriptor
// Returns: nothing
inline void vfs_closeitem( vfs_item *di ) { return di->fns->close( di ); }
// vfs_item_size - get item's size
// di: item descriptor
// Returns: Item size
inline uint32_t vfs_item_size( vfs_item *di ) { return di->fns->size( di ); }
// vfs_item_time - get item's modification time
// di: item descriptor
// Returns: Item modification time
inline int32_t vfs_item_time( vfs_item *di, struct vfs_time *tm ) { return di->fns->time ? di->fns->time( di, tm ) : VFS_RES_ERR; }
// vfs_item_name - get item's name
// di: item descriptor
// Returns: Item name
inline const char *vfs_item_name( vfs_item *di ) { return di->fns->name( di ); }
// vfs_item_is_dir - check for directory
// di: item descriptor
// Returns: >0 if item is a directory, 0 if not
inline int32_t vfs_item_is_dir( vfs_item *di ) { return di->fns->is_dir ? di->fns->is_dir( di ) : 0; }
// vfs_item_is_rdonly - check for read-only
// di: item descriptor
// Returns: >0 if item is read only, 0 if not
inline int32_t vfs_item_is_rdonly( vfs_item *di ) { return di->fns->is_rdonly ? di->fns->is_rdonly( di ) : 0; }
// vfs_item_is_hidden - check for hidden attribute
// di: item descriptor
// Returns: >0 if item is hidden, 0 if not
inline int32_t vfs_item_is_hidden( vfs_item *di ) { return di->fns->is_hidden ? di->fns->is_hidden( di ) : 0; }
// vfs_item_is_sys - check for sys attribute
// di: item descriptor
// Returns: >0 if item is sys, 0 if not
inline int32_t vfs_item_is_sys( vfs_item *di ) { return di->fns->is_sys ? di->fns->is_sys( di ) : 0; }
// vfs_item_is_arch - check for archive attribute
// di: item descriptor
// Returns: >0 if item is archive, 0 if not
inline int32_t vfs_item_is_arch( vfs_item *di ) { return di->fns->is_arch ? di->fns->is_arch( di ) : 0; }
// ---------------------------------------------------------------------------
// volume functions
//
// vfs_umount - unmount logical drive and free memory
// vol: volume object
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
inline int32_t vfs_umount( vfs_vol *vol ) { return vol->fns->umount( vol ); }
// ---------------------------------------------------------------------------
// file system functions
//
// vfs_mount - unmount logical drive
// name: name of logical drive
// num: drive's physical number (eg. SS/CS pin), negative values are ignored
// Returns: Volume object, or NULL in case of error
vfs_vol *vfs_mount( const char *name, int num );
// vfs_open - open file
// name: file name
// mode: open mode
// Returns: File descriptor, or NULL in case of error
int vfs_open( const char *name, const char *mode );
// vfs_opendir - open directory
// name: dir name
// Returns: Directory descriptor, or NULL in case of error
vfs_dir *vfs_opendir( const char *name );
// vfs_stat - stat file or directory
// name: file or directory name
// Returns: Item object, or NULL in case of error
vfs_item *vfs_stat( const char *name );
// vfs_remove - remove file or directory
// name: file or directory name
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_remove( const char *name );
// vfs_rename - rename file or directory
// name: file or directory name
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_rename( const char *oldname, const char *newname );
// vfs_mkdir - create directory
// name: directory name
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_mkdir( const char *name );
// vfs_fsinfo - get file system info
// name: logical drive identifier
// total: receives total amount
// used: received used amount
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_fsinfo( const char *name, uint32_t *total, uint32_t *used );
// vfs_format - format file system
// Returns: 1, or 0 in case of error
int32_t vfs_format( void );
// vfs_chdir - change default directory
// path: new default directory
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_chdir( const char *path );
// vfs_fscfg - query configuration settings of file system
// phys_addr: pointer to store physical address information
// phys_size: pointer to store physical size information
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_fscfg( const char *name, uint32_t *phys_addr, uint32_t *phys_size);
// vfs_errno - get file system specific errno
// name: logical drive identifier
// Returns: errno
int32_t vfs_errno( const char *name );
// vfs_clearerr - cleaer file system specific errno
void vfs_clearerr( const char *name );
// vfs_register_rtc_cb - register callback function for RTC query
// cb: pointer to callback function
void vfs_register_rtc_cb( int32_t (*cb)( vfs_time *tm ) );
// vfs_basename - identify basename (incl. extension)
// path: full file system path
// Returns: pointer to basename within path string
const char *vfs_basename( const char *path );
#endif
// internal definitions for vfs
#ifndef __VFS_INT_H__
#define __VFS_INT_H__
#include <string.h>
#include <stdint.h>
#if 0
#include "spiffs.h"
#include "fatfs_prefix_lib.h"
#include "ff.h"
#endif
#define VFS_EOF -1
enum vfs_filesystems {
VFS_FS_NONE = 0,
VFS_FS_SPIFFS,
VFS_FS_FATFS
};
enum vfs_seek {
VFS_SEEK_SET = 0,
VFS_SEEK_CUR,
VFS_SEEK_END
};
enum vfs_result {
VFS_RES_OK = 0,
VFS_RES_ERR = -1
};
struct vfs_time {
int year, mon, day;
int hour, min, sec;
};
typedef struct vfs_time vfs_time;
// generic file descriptor
struct vfs_file {
int fs_type;
const struct vfs_file_fns *fns;
};
typedef const struct vfs_file vfs_file;
// file descriptor functions
struct vfs_file_fns {
int32_t (*close)( const struct vfs_file *fd );
int32_t (*read)( const struct vfs_file *fd, void *ptr, size_t len );
int32_t (*write)( const struct vfs_file *fd, const void *ptr, size_t len );
int32_t (*lseek)( const struct vfs_file *fd, int32_t off, int whence );
int32_t (*eof)( const struct vfs_file *fd );
int32_t (*tell)( const struct vfs_file *fd );
int32_t (*flush)( const struct vfs_file *fd );
uint32_t (*size)( const struct vfs_file *fd );
int32_t (*ferrno)( const struct vfs_file *fd );
};
typedef const struct vfs_file_fns vfs_file_fns;
// generic dir item descriptor
struct vfs_item {
int fs_type;
const struct vfs_item_fns *fns;
};
typedef const struct vfs_item vfs_item;
// directory item functions
struct vfs_item_fns {
void (*close)( const struct vfs_item *di );
uint32_t (*size)( const struct vfs_item *di );
int32_t (*time)( const struct vfs_item *di, struct vfs_time *tm );
const char *(*name)( const struct vfs_item *di );
int32_t (*is_dir)( const struct vfs_item *di );
int32_t (*is_rdonly)( const struct vfs_item *di );
int32_t (*is_hidden)( const struct vfs_item *di );
int32_t (*is_sys)( const struct vfs_item *di );
int32_t (*is_arch)( const struct vfs_item *di );
};
typedef const struct vfs_item_fns vfs_item_fns;
// generic dir descriptor
struct vfs_dir {
int fs_type;
const struct vfs_dir_fns *fns;
};
typedef const struct vfs_dir vfs_dir;
// dir descriptor functions
struct vfs_dir_fns {
int32_t (*close)( const struct vfs_dir *dd );
vfs_item *(*readdir)( const struct vfs_dir *dd );
};
typedef const struct vfs_dir_fns vfs_dir_fns;
// generic volume descriptor
struct vfs_vol {
int fs_type;
const struct vfs_vol_fns *fns;
};
typedef const struct vfs_vol vfs_vol;
// volume functions
struct vfs_vol_fns {
int32_t (*umount)( const struct vfs_vol *vol );
};
typedef const struct vfs_vol_fns vfs_vol_fns;
struct vfs_fs_fns {
vfs_vol *(*mount)( const char *name, int num );
vfs_file *(*open)( const char *name, const char *mode );
vfs_dir *(*opendir)( const char *name );
vfs_item *(*stat)( const char *name );
int32_t (*remove)( const char *name );
int32_t (*rename)( const char *oldname, const char *newname );
int32_t (*mkdir)( const char *name );
int32_t (*fsinfo)( uint32_t *total, uint32_t *used );
int32_t (*fscfg)( uint32_t *phys_addr, uint32_t *phys_size );
int32_t (*format)( void );
int32_t (*chdrive)( const char * );
int32_t (*chdir)( const char * );
int32_t (*ferrno)( void );
void (*clearerr)( void );
};
typedef const struct vfs_fs_fns vfs_fs_fns;
vfs_fs_fns *myspiffs_realm( const char *inname, char **outname, int set_current_drive );
vfs_fs_fns *myfatfs_realm( const char *inname, char **outname, int set_current_drive );
int32_t vfs_get_rtc( vfs_time *tm );
#endif
#include "platform.h"
#include "flash_api.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
// ****************************************************************************
// Internal flash support functions
/* This symbol must be exported by the linker command file and contain the
* size of all the sections packed into the irom0_flash.bin file, in order
* for us to find the end of used flash.
*/
extern char _irom0_bin_min_sz[];
// Helper function: find the flash sector in which an address resides
// Return the sector number, as well as the start and end address of the sector
static uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend )
{
#ifdef INTERNAL_FLASH_SECTOR_SIZE
// All the sectors in the flash have the same size, so just align the address
uint32_t sect_id = address / INTERNAL_FLASH_SECTOR_SIZE;
if( pstart )
*pstart = sect_id * INTERNAL_FLASH_SECTOR_SIZE ;
if( pend )
*pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE - 1;
return sect_id;
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
// The flash has blocks of different size
// Their size is decribed in the INTERNAL_FLASH_SECTOR_ARRAY macro
const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
uint32_t total = 0, i = 0;
while( ( total <= address ) && ( i < sizeof( flash_sect_size ) / sizeof( uint32_t ) ) )
total += flash_sect_size[ i ++ ];
if( pstart )
*pstart = ( total - flash_sect_size[ i - 1 ] );
if( pend )
*pend = total - 1;
return i - 1;
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
}
uint32_t platform_flash_get_sector_of_address( uint32_t addr )
{
return flashh_find_sector( addr, NULL, NULL );
}
uint32_t platform_flash_get_num_sectors(void)
{
#ifdef INTERNAL_FLASH_SECTOR_SIZE
return INTERNAL_FLASH_SIZE / INTERNAL_FLASH_SECTOR_SIZE;
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
return sizeof( flash_sect_size ) / sizeof( uint32_t );
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
}
uint32_t platform_flash_get_first_free_block_address( uint32_t *psect )
{
uint32_t flash_offs = IROM0_START_FLASH_ADDR + (uint32_t)_irom0_bin_min_sz;
uint32_t sect =
(flash_offs + INTERNAL_FLASH_SECTOR_SIZE-1)/INTERNAL_FLASH_SECTOR_SIZE;
++sect; /* compensate for various headers not counted in _irom0_bin_min_sz */
if (psect)
*psect = sect;
return sect * INTERNAL_FLASH_SECTOR_SIZE;
}
uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size )
{
#ifndef INTERNAL_FLASH_WRITE_UNIT_SIZE
return platform_s_flash_write( from, toaddr, size );
#else // #ifindef INTERNAL_FLASH_WRITE_UNIT_SIZE
uint32_t temp, rest, ssize = size;
unsigned i;
char tmpdata[ INTERNAL_FLASH_WRITE_UNIT_SIZE ];
const uint8_t *pfrom = ( const uint8_t* )from;
const uint32_t blksize = INTERNAL_FLASH_WRITE_UNIT_SIZE;
const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;
// Align the start
if( toaddr & blkmask )
{
rest = toaddr & blkmask;
temp = toaddr & ~blkmask; // this is the actual aligned address
// memcpy( tmpdata, ( const void* )temp, blksize );
platform_s_flash_read( tmpdata, temp, blksize );
for( i = rest; size && ( i < blksize ); i ++, size --, pfrom ++ )
tmpdata[ i ] = *pfrom;
platform_s_flash_write( tmpdata, temp, blksize );
if( size == 0 )
return ssize;
toaddr = temp + blksize;
}
// The start address is now a multiple of blksize
// Compute how many bytes we can write as multiples of blksize
rest = size & blkmask;
temp = size & ~blkmask;
// Program the blocks now
if( temp )
{
platform_s_flash_write( pfrom, toaddr, temp );
toaddr += temp;
pfrom += temp;
}
// And the final part of a block if needed
if( rest )
{
// memcpy( tmpdata, ( const void* )toaddr, blksize );
platform_s_flash_read( tmpdata, toaddr, blksize );
for( i = 0; size && ( i < rest ); i ++, size --, pfrom ++ )
tmpdata[ i ] = *pfrom;
platform_s_flash_write( tmpdata, toaddr, blksize );
}
return ssize;
#endif // #ifndef INTERNAL_FLASH_WRITE_UNIT_SIZE
}
uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size )
{
#ifndef INTERNAL_FLASH_READ_UNIT_SIZE
return platform_s_flash_read( to, fromaddr, size );
#else // #ifindef INTERNAL_FLASH_READ_UNIT_SIZE
uint32_t temp, rest, ssize = size;
unsigned i;
char tmpdata[ INTERNAL_FLASH_READ_UNIT_SIZE ] __attribute__ ((aligned(INTERNAL_FLASH_READ_UNIT_SIZE)));
uint8_t *pto = ( uint8_t* )to;
const uint32_t blksize = INTERNAL_FLASH_READ_UNIT_SIZE;
const uint32_t blkmask = INTERNAL_FLASH_READ_UNIT_SIZE - 1;
// Align the start
if( fromaddr & blkmask )
{
rest = fromaddr & blkmask;
temp = fromaddr & ~blkmask; // this is the actual aligned address
platform_s_flash_read( tmpdata, temp, blksize );
for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ )
*pto = tmpdata[ i ];
if( size == 0 )
return ssize;
fromaddr = temp + blksize;
}
// The start address is now a multiple of blksize
// Compute how many bytes we can read as multiples of blksize
rest = size & blkmask;
temp = size & ~blkmask;
// Program the blocks now
if( temp )
{
platform_s_flash_read( pto, fromaddr, temp );
fromaddr += temp;
pto += temp;
}
// And the final part of a block if needed
if( rest )
{
platform_s_flash_read( tmpdata, fromaddr, blksize );
for( i = 0; size && ( i < rest ); i ++, size --, pto ++ )
*pto = tmpdata[ i ];
}
return ssize;
#endif // #ifndef INTERNAL_FLASH_READ_UNIT_SIZE
}
/*
* Assumptions:
* > toaddr is INTERNAL_FLASH_WRITE_UNIT_SIZE aligned
* > size is a multiple of INTERNAL_FLASH_WRITE_UNIT_SIZE
*/
uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t size )
{
SpiFlashOpResult r;
const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;
uint32_t *apbuf = NULL;
uint32_t fromaddr = (uint32_t)from;
if( (fromaddr & blkmask ) || (fromaddr >= INTERNAL_FLASH_MAPPED_ADDRESS)) {
apbuf = (uint32_t *)malloc(size);
if(!apbuf)
return 0;
memcpy(apbuf, from, size);
}
r = flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size);
if(apbuf)
free(apbuf);
if(SPI_FLASH_RESULT_OK == r)
return size;
else{
NODE_ERR( "ERROR in flash_write: r=%d at %08X\n", ( int )r, ( unsigned )toaddr);
return 0;
}
}
/*
* Assumptions:
* > fromaddr is INTERNAL_FLASH_READ_UNIT_SIZE aligned
* > size is a multiple of INTERNAL_FLASH_READ_UNIT_SIZE
*/
uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size )
{
if (size==0)
return 0;
SpiFlashOpResult r;
const uint32_t blkmask = (INTERNAL_FLASH_READ_UNIT_SIZE - 1);
if( ((uint32_t)to) & blkmask )
{
uint32_t size2=size-INTERNAL_FLASH_READ_UNIT_SIZE;
uint32* to2=(uint32*)((((uint32_t)to)&(~blkmask))+INTERNAL_FLASH_READ_UNIT_SIZE);
r = flash_read(fromaddr, to2, size2);
if(SPI_FLASH_RESULT_OK == r)
{
memmove(to,to2,size2);
char back[ INTERNAL_FLASH_READ_UNIT_SIZE ] __attribute__ ((aligned(INTERNAL_FLASH_READ_UNIT_SIZE)));
r=flash_read(fromaddr+size2,(uint32*)back,INTERNAL_FLASH_READ_UNIT_SIZE);
memcpy((uint8_t*)to+size2,back,INTERNAL_FLASH_READ_UNIT_SIZE);
}
}
else
r = flash_read(fromaddr, (uint32 *)to, size);
if(SPI_FLASH_RESULT_OK == r)
return size;
else{
NODE_ERR( "ERROR in flash_read: r=%d at %08X\n", ( int )r, ( unsigned )fromaddr);
return 0;
}
}
int platform_flash_erase_sector( uint32_t sector_id )
{
return flash_erase( sector_id ) == SPI_FLASH_RESULT_OK ? PLATFORM_OK : PLATFORM_ERR;
}
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr)
{
// FIXME: need to take actual memory maps into account!
return mapped_addr - IROM0_START_MAPPED_ADDR + IROM0_START_FLASH_ADDR;
}
#include <stdlib.h>
#include <stdio.h>
#include "vfs.h"
#include "platform.h"
#define LDRV_TRAVERSAL 0
// ---------------------------------------------------------------------------
// RTC system interface
//
static int32_t (*rtc_cb)( vfs_time *tm ) = NULL;
// called by operating system
void vfs_register_rtc_cb( int32_t (*cb)( vfs_time *tm ) )
{
// allow NULL pointer to unregister callback function
rtc_cb = cb;
}
// called by file system drivers
int32_t vfs_get_rtc( vfs_time *tm )
{
if (rtc_cb) {
return rtc_cb( tm );
}
return VFS_RES_ERR;
}
static int dir_level = 1;
static const char *normalize_path( const char *path )
{
#if ! LDRV_TRAVERSAL
return path;
#else
const char *temp = path;
size_t len;
while ((len = strlen( temp )) >= 2) {
if (temp[0] == '.' && temp[1] == '.') {
--dir_level;
if (len >= 4 && dir_level > 0) {
// prepare next step
temp = &(temp[4]);
} else {
// we're at top, the remainder is expected be an absolute path
temp = &(temp[3]);
}
} else {
break;
}
}
if (dir_level > 0) {
// no traversal on root level
return path;
} else {
// path traverses via root
return temp;
}
#endif
}
// ---------------------------------------------------------------------------
// file system functions
//
vfs_vol *vfs_mount( const char *name, int num )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->mount( outname, num );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
vfs_vol *r = fs_fns->mount( outname, num );
free( outname );
return r;
}
#endif
return NULL;
}
int vfs_open( const char *name, const char *mode )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return (int)fs_fns->open( outname, mode );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int r = (int)fs_fns->open( outname, mode );
free( outname );
return r;
}
#endif
return 0;
}
vfs_dir *vfs_opendir( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->opendir( outname );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
vfs_dir *r = fs_fns->opendir( outname );
free( outname );
return r;
}
#endif
return NULL;
}
vfs_item *vfs_stat( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->stat( outname );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
vfs_item *r = fs_fns->stat( outname );
free( outname );
return r;
}
#endif
return NULL;
}
int32_t vfs_remove( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->remove( outname );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int32_t r = fs_fns->remove( outname );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_rename( const char *oldname, const char *newname )
{
vfs_fs_fns *fs_fns;
const char *normoldname = normalize_path( oldname );
const char *normnewname = normalize_path( newname );
char *oldoutname, *newoutname;
#ifdef CONFIG_BUILD_SPIFFS
if (myspiffs_realm( normoldname, &oldoutname, false )) {
if ((fs_fns = myspiffs_realm( normnewname, &newoutname, false ))) {
return fs_fns->rename( oldoutname, newoutname );
}
}
#endif
#ifdef CONFIG_BUILD_FATFS
if (myfatfs_realm( normoldname, &oldoutname, false )) {
if ((fs_fns = myfatfs_realm( normnewname, &newoutname, false ))) {
int32_t r = fs_fns->rename( oldoutname, newoutname );
free( oldoutname );
free( newoutname );
return r;
}
free( oldoutname );
}
#endif
return -1;
}
int32_t vfs_mkdir( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
// not supported
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int32_t r = fs_fns->mkdir( outname );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_fsinfo( const char *name, uint32_t *total, uint32_t *used )
{
vfs_fs_fns *fs_fns;
char *outname;
if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->fsinfo( total, used );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
free( outname );
return fs_fns->fsinfo( total, used );
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_fscfg( const char *name, uint32_t *phys_addr, uint32_t *phys_size)
{
vfs_fs_fns *fs_fns;
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( "/FLASH", &outname, false ))) {
return fs_fns->fscfg( phys_addr, phys_size );
}
#endif
#ifdef CONFIG_BUILD_FATFS
// not supported
#endif
// Error
return VFS_RES_ERR;
}
int32_t vfs_format( void )
{
vfs_fs_fns *fs_fns;
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( "/FLASH", &outname, false ))) {
return fs_fns->format();
}
#endif
#ifdef CONFIG_BUILD_FATFS
// not supported
#endif
// Error
return 0;
}
int32_t vfs_chdir( const char *path )
{
vfs_fs_fns *fs_fns;
const char *normpath = normalize_path( path );
const char *level;
char *outname;
int ok = VFS_RES_ERR;
#if LDRV_TRAVERSAL
// track dir level
if (normpath[0] == '/') {
dir_level = 0;
level = &(normpath[1]);
} else {
level = normpath;
}
while (strlen( level ) > 0) {
dir_level++;
if (level = strchr( level, '/' )) {
level++;
} else {
break;
}
}
#endif
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normpath, &outname, true ))) {
// our SPIFFS integration doesn't support directories
if (strlen( outname ) == 0) {
ok = VFS_RES_OK;
}
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normpath, &outname, true ))) {
if (strchr( outname, ':' )) {
// need to set FatFS' default drive
fs_fns->chdrive( outname );
// and force chdir to root in case path points only to root
fs_fns->chdir( "/" );
}
if (fs_fns->chdir( outname ) == VFS_RES_OK) {
ok = VFS_RES_OK;
}
free( outname );
}
#endif
return ok == VFS_RES_OK ? VFS_RES_OK : VFS_RES_ERR;
}
int32_t vfs_errno( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
if (!name) name = ""; // current drive
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->ferrno( );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int32_t r = fs_fns->ferrno( );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_ferrno( int fd )
{
vfs_file *f = (vfs_file *)fd;
if (f) {
return f->fns->ferrno ? f->fns->ferrno( f ) : 0;
} else {
vfs_fs_fns *fs_fns;
const char *name = ""; // current drive
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( name, &outname, false ))) {
return fs_fns->ferrno( );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( name, &outname, false ))) {
int32_t r = fs_fns->ferrno( );
free( outname );
return r;
}
#endif
}
return 0;
}
void vfs_clearerr( const char *name )
{
vfs_fs_fns *fs_fns;
char *outname;
if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
fs_fns->clearerr( );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
fs_fns->clearerr( );
free( outname );
}
#endif
}
const char *vfs_basename( const char *path )
{
const char *basename;
// deduce basename (incl. extension) for length check
if ((basename = strrchr( path, '/' ))) {
basename++;
} else if ((basename = strrchr( path, ':' ))) {
basename++;
} else {
basename = path;
}
return basename;
}
// ---------------------------------------------------------------------------
// supplementary functions
//
int vfs_getc( int fd )
{
unsigned char c = 0xFF;
int32_t res;
if(!vfs_eof( fd )) {
if (1 != vfs_read( fd, &c, 1 )) {
NODE_DBG("getc errno %i\n", vfs_ferrno( fd ));
return VFS_EOF;
} else {
return (int)c;
}
}
return VFS_EOF;
}
int vfs_ungetc( int c, int fd )
{
return vfs_lseek( fd, -1, VFS_SEEK_CUR );
}
The MIT License (MIT)
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976<at>gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
......
COMPONENT_ADD_INCLUDEDIRS:=.
# TODO: clean up codebase to be sign clean...
EXTRA_CFLAGS+=-Wno-error=pointer-sign
include $(IDF_PATH)/make/component_common.mk
* When mending lost pages, also see if they fit into length specified in object index header
SPIFFS2 thoughts
* Instead of exact object id:s in the object lookup tables, use a hash of span index and object id.
Eg. object id xor:ed with bit-reversed span index.
This should decrease number of actual pages that needs to be visited when looking thru the obj lut.
* Logical number of each block. When moving stuff in a garbage collected page, the free
page is assigned the same number as the garbage collected. Thus, object index pages do not have to
be rewritten.
* Steal one page, use as a bit parity page. When starting an fs modification operation, write one bit
as zero. When ending, write another bit as zero. On mount, if number of zeroes in page is uneven, a
check is automatically run.
\ No newline at end of file
#ifndef _NODEMCU_SPIFFS_H
#define _NODEMCU_SPIFFS_H
#ifndef NODEMCU_SPIFFS_NO_INCLUDE
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#endif
// Turn off stats
#define SPIFFS_CACHE_STATS 0
#define SPIFFS_GC_STATS 0
// Needs to align stuff
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
// Enable magic so we can find the file system (but not yet)
#define SPIFFS_USE_MAGIC 1
#define SPIFFS_USE_MAGIC_LENGTH 1
// Reduce the chance of returning disk full
#define SPIFFS_GC_MAX_RUNS 256
#endif
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "flash_api.h"
#include "spiffs.h"
......@@ -6,6 +7,9 @@
spiffs fs;
#define LOG_PAGE_SIZE 256
#define LOG_BLOCK_SIZE (INTERNAL_FLASH_SECTOR_SIZE * 2)
#define LOG_BLOCK_SIZE_SMALL_FS (INTERNAL_FLASH_SECTOR_SIZE)
#define MIN_BLOCKS_FS 4
static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
static u8_t spiffs_fds[32*4];
......@@ -45,24 +49,120 @@ The small 4KB sectors allow for greater flexibility in applications th
********************/
void myspiffs_mount() {
spiffs_config cfg;
static bool myspiffs_set_location(spiffs_config *cfg, int align, int offset, int block_size) {
#ifdef SPIFFS_FIXED_LOCATION
cfg->phys_addr = (SPIFFS_FIXED_LOCATION + block_size - 1) & ~(block_size-1);
#else
cfg->phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL ) + offset;
cfg->phys_addr = (cfg->phys_addr + align - 1) & ~(align - 1);
#endif
#ifdef SPIFFS_SIZE_1M_BOUNDARY
cfg->phys_size = ((0x100000 - (SYS_PARAM_SEC_NUM * INTERNAL_FLASH_SECTOR_SIZE) - ( ( u32_t )cfg->phys_addr )) & ~(block_size - 1)) & 0xfffff;
#else
cfg->phys_size = (INTERNAL_FLASH_SIZE - ( ( u32_t )cfg->phys_addr )) & ~(block_size - 1);
#endif
if ((int) cfg->phys_size < 0) {
return false;
}
cfg->log_block_size = block_size;
return (cfg->phys_size / block_size) >= MIN_BLOCKS_FS;
}
/*
* Returns true if FS was found
* align must be a power of two
*/
static bool myspiffs_set_cfg(spiffs_config *cfg, int align, int offset, bool force_create) {
cfg->phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet
cfg->log_page_size = LOG_PAGE_SIZE; // as we said
cfg->hal_read_f = my_spiffs_read;
cfg->hal_write_f = my_spiffs_write;
cfg->hal_erase_f = my_spiffs_erase;
if (!myspiffs_set_location(cfg, align, offset, LOG_BLOCK_SIZE)) {
if (!myspiffs_set_location(cfg, align, offset, LOG_BLOCK_SIZE_SMALL_FS)) {
return false;
}
}
NODE_DBG("fs.start:%x,max:%x\n",cfg->phys_addr,cfg->phys_size);
#ifdef SPIFFS_USE_MAGIC_LENGTH
if (force_create) {
return true;
}
int size = SPIFFS_probe_fs(cfg);
if (size > 0 && size < cfg->phys_size) {
NODE_DBG("Overriding size:%x\n",size);
cfg->phys_size = size;
}
if (size > 0) {
return true;
}
return false;
#else
return true;
#endif
}
static bool myspiffs_find_cfg(spiffs_config *cfg, bool force_create) {
int i;
if (!force_create) {
#ifdef SPIFFS_FIXED_LOCATION
cfg.phys_addr = SPIFFS_FIXED_LOCATION;
if (myspiffs_set_cfg(cfg, 0, 0, false)) {
return true;
}
#else
cfg.phys_addr = ( u32_t )platform_flash_get_first_free_block_address( NULL );
if (INTERNAL_FLASH_SIZE >= 700000) {
for (i = 0; i < 8; i++) {
if (myspiffs_set_cfg(cfg, 0x10000, 0x10000 * i, false)) {
return true;
}
}
}
for (i = 0; i < 8; i++) {
if (myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, LOG_BLOCK_SIZE * i, false)) {
return true;
}
}
#endif
cfg.phys_addr += 0x3FFF;
cfg.phys_addr &= 0xFFFFC000; // align to 4 sector.
cfg.phys_size = INTERNAL_FLASH_SIZE - ( ( u32_t )cfg.phys_addr );
cfg.phys_erase_block = INTERNAL_FLASH_SECTOR_SIZE; // according to datasheet
cfg.log_block_size = INTERNAL_FLASH_SECTOR_SIZE; // let us not complicate things
cfg.log_page_size = LOG_PAGE_SIZE; // as we said
NODE_DBG("fs.start:%x,max:%x\n",cfg.phys_addr,cfg.phys_size);
cfg.hal_read_f = my_spiffs_read;
cfg.hal_write_f = my_spiffs_write;
cfg.hal_erase_f = my_spiffs_erase;
}
// No existing file system -- set up for a format
if (INTERNAL_FLASH_SIZE >= 700000) {
myspiffs_set_cfg(cfg, 0x10000, 0x10000, true);
#ifndef SPIFFS_MAX_FILESYSTEM_SIZE
if (cfg->phys_size < 400000) {
// Don't waste so much in alignment
myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, LOG_BLOCK_SIZE * 4, true);
}
#endif
} else {
myspiffs_set_cfg(cfg, LOG_BLOCK_SIZE, 0, true);
}
#ifdef SPIFFS_MAX_FILESYSTEM_SIZE
if (cfg->phys_size > SPIFFS_MAX_FILESYSTEM_SIZE) {
cfg->phys_size = (SPIFFS_MAX_FILESYSTEM_SIZE) & ~(cfg->log_block_size - 1);
}
#endif
return false;
}
static bool myspiffs_mount_internal(bool force_mount) {
spiffs_config cfg;
if (!myspiffs_find_cfg(&cfg, force_mount) && !force_mount) {
return false;
}
fs.err_code = 0;
int res = SPIFFS_mount(&fs,
&cfg,
......@@ -77,8 +177,12 @@ void myspiffs_mount() {
#endif
// myspiffs_check_callback);
0);
NODE_DBG("mount res: %i\n", res);
(void)res;
NODE_DBG("mount res: %d, %d\n", res, fs.err_code);
return res == SPIFFS_OK;
}
bool myspiffs_mount() {
return myspiffs_mount_internal(false);
}
void myspiffs_unmount() {
......@@ -90,119 +194,435 @@ void myspiffs_unmount() {
int myspiffs_format( void )
{
SPIFFS_unmount(&fs);
u32_t sect_first, sect_last;
#ifdef SPIFFS_FIXED_LOCATION
sect_first = SPIFFS_FIXED_LOCATION;
#else
sect_first = ( u32_t )platform_flash_get_first_free_block_address( NULL );
#endif
sect_first += 0x3FFF;
sect_first &= 0xFFFFC000; // align to 4 sector.
sect_first = platform_flash_get_sector_of_address(sect_first);
sect_last = INTERNAL_FLASH_SIZE - SYS_PARAM_SEC_NUM;
sect_last = platform_flash_get_sector_of_address(sect_last);
NODE_DBG("sect_first: %x, sect_last: %x\n", sect_first, sect_last);
while( sect_first <= sect_last )
if( platform_flash_erase_sector( sect_first ++ ) == PLATFORM_ERR )
myspiffs_mount_internal(true);
SPIFFS_unmount(&fs);
NODE_DBG("Formatting: size 0x%x, addr 0x%x\n", fs.cfg.phys_size, fs.cfg.phys_addr);
if (SPIFFS_format(&fs) < 0) {
return 0;
myspiffs_mount();
return 1;
}
return myspiffs_mount();
}
int myspiffs_check( void )
{
// ets_wdt_disable();
// int res = (int)SPIFFS_check(&fs);
// ets_wdt_enable();
// return res;
return 0;
#if 0
void test_spiffs() {
char buf[12];
// Surely, I've mounted spiffs before entering here
spiffs_file fd = SPIFFS_open(&fs, "my_file", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
if (SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12) < 0) NODE_DBG("errno %i\n", SPIFFS_errno(&fs));
SPIFFS_close(&fs, fd);
fd = SPIFFS_open(&fs, "my_file", SPIFFS_RDWR, 0);
if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) NODE_DBG("errno %i\n", SPIFFS_errno(&fs));
SPIFFS_close(&fs, fd);
NODE_DBG("--> %s <--\n", buf);
}
#endif
// ***************************************************************************
// vfs API
// ***************************************************************************
#include <stdlib.h>
#include "vfs_int.h"
#define MY_LDRV_ID "FLASH"
// default current drive
static int is_current_drive = true;
// forward declarations
static int32_t myspiffs_vfs_close( const struct vfs_file *fd );
static int32_t myspiffs_vfs_read( const struct vfs_file *fd, void *ptr, size_t len );
static int32_t myspiffs_vfs_write( const struct vfs_file *fd, const void *ptr, size_t len );
static int32_t myspiffs_vfs_lseek( const struct vfs_file *fd, int32_t off, int whence );
static int32_t myspiffs_vfs_eof( const struct vfs_file *fd );
static int32_t myspiffs_vfs_tell( const struct vfs_file *fd );
static int32_t myspiffs_vfs_flush( const struct vfs_file *fd );
static int32_t myspiffs_vfs_ferrno( const struct vfs_file *fd );
static int32_t myspiffs_vfs_closedir( const struct vfs_dir *dd );
static vfs_item *myspiffs_vfs_readdir( const struct vfs_dir *dd );
static void myspiffs_vfs_iclose( const struct vfs_item *di );
static uint32_t myspiffs_vfs_isize( const struct vfs_item *di );
//static const struct tm *myspiffs_vfs_time( const struct vfs_item *di );
static const char *myspiffs_vfs_name( const struct vfs_item *di );
static vfs_vol *myspiffs_vfs_mount( const char *name, int num );
static vfs_file *myspiffs_vfs_open( const char *name, const char *mode );
static vfs_dir *myspiffs_vfs_opendir( const char *name );
static vfs_item *myspiffs_vfs_stat( const char *name );
static int32_t myspiffs_vfs_remove( const char *name );
static int32_t myspiffs_vfs_rename( const char *oldname, const char *newname );
static int32_t myspiffs_vfs_fsinfo( uint32_t *total, uint32_t *used );
static int32_t myspiffs_vfs_fscfg( uint32_t *phys_addr, uint32_t *phys_size );
static int32_t myspiffs_vfs_format( void );
static int32_t myspiffs_vfs_errno( void );
static void myspiffs_vfs_clearerr( void );
int myspiffs_open(const char *name, int flags){
return (int)SPIFFS_open(&fs, (char *)name, (spiffs_flags)flags, 0);
static int32_t myspiffs_vfs_umount( const struct vfs_vol *vol );
// ---------------------------------------------------------------------------
// function tables
//
static vfs_fs_fns myspiffs_fs_fns = {
.mount = myspiffs_vfs_mount,
.open = myspiffs_vfs_open,
.opendir = myspiffs_vfs_opendir,
.stat = myspiffs_vfs_stat,
.remove = myspiffs_vfs_remove,
.rename = myspiffs_vfs_rename,
.mkdir = NULL,
.fsinfo = myspiffs_vfs_fsinfo,
.fscfg = myspiffs_vfs_fscfg,
.format = myspiffs_vfs_format,
.chdrive = NULL,
.chdir = NULL,
.ferrno = myspiffs_vfs_errno,
.clearerr = myspiffs_vfs_clearerr
};
static vfs_file_fns myspiffs_file_fns = {
.close = myspiffs_vfs_close,
.read = myspiffs_vfs_read,
.write = myspiffs_vfs_write,
.lseek = myspiffs_vfs_lseek,
.eof = myspiffs_vfs_eof,
.tell = myspiffs_vfs_tell,
.flush = myspiffs_vfs_flush,
.size = NULL,
.ferrno = myspiffs_vfs_ferrno
};
static vfs_item_fns myspiffs_item_fns = {
.close = myspiffs_vfs_iclose,
.size = myspiffs_vfs_isize,
.time = NULL,
.name = myspiffs_vfs_name,
.is_dir = NULL,
.is_rdonly = NULL,
.is_hidden = NULL,
.is_sys = NULL,
.is_arch = NULL
};
static vfs_dir_fns myspiffs_dd_fns = {
.close = myspiffs_vfs_closedir,
.readdir = myspiffs_vfs_readdir
};
// ---------------------------------------------------------------------------
// specific struct extensions
//
struct myvfs_file {
struct vfs_file vfs_file;
spiffs_file fh;
};
struct myvfs_dir {
struct vfs_dir vfs_dir;
spiffs_DIR d;
};
struct myvfs_stat {
struct vfs_item vfs_item;
spiffs_stat s;
};
// ---------------------------------------------------------------------------
// stat functions
//
#define GET_STAT_S(descr) \
const struct myvfs_stat *mystat = (const struct myvfs_stat *)descr; \
spiffs_stat *s = (spiffs_stat *)&(mystat->s);
static void myspiffs_vfs_iclose( const struct vfs_item *di ) {
// free descriptor memory
free( (void *)di );
}
int myspiffs_close( int fd ){
SPIFFS_close(&fs, (spiffs_file)fd);
return 0;
static uint32_t myspiffs_vfs_isize( const struct vfs_item *di ) {
GET_STAT_S(di);
return s->size;
}
size_t myspiffs_write( int fd, const void* ptr, size_t len ){
#if 0
if(fd==c_stdout || fd==c_stderr){
uart0_tx_buffer((u8_t*)ptr, len);
return len;
static const char *myspiffs_vfs_name( const struct vfs_item *di ) {
GET_STAT_S(di);
return s->name;
}
// ---------------------------------------------------------------------------
// volume functions
//
static int32_t myspiffs_vfs_umount( const struct vfs_vol *vol ) {
// not implemented
return VFS_RES_ERR;
}
// ---------------------------------------------------------------------------
// dir functions
//
#define GET_DIR_D(descr) \
const struct myvfs_dir *mydd = (const struct myvfs_dir *)descr; \
spiffs_DIR *d = (spiffs_DIR *)&(mydd->d);
static int32_t myspiffs_vfs_closedir( const struct vfs_dir *dd ) {
GET_DIR_D(dd);
int32_t res = SPIFFS_closedir( d );
// free descriptor memory
free( (void *)dd );
return res;
}
static vfs_item *myspiffs_vfs_readdir( const struct vfs_dir *dd ) {
GET_DIR_D(dd);
struct myvfs_stat *stat;
struct spiffs_dirent dirent;
if ((stat = malloc( sizeof( struct myvfs_stat ) ))) {
if (SPIFFS_readdir( d, &dirent )) {
stat->vfs_item.fs_type = VFS_FS_FATFS;
stat->vfs_item.fns = &myspiffs_item_fns;
// copy entries to vfs' directory item
stat->s.size = dirent.size;
strncpy( stat->s.name, dirent.name, SPIFFS_OBJ_NAME_LEN );
return (vfs_item *)stat;
} else {
free( stat );
}
#endif
int res = SPIFFS_write(&fs, (spiffs_file)fd, (void *)ptr, len);
if (res < 0) {
NODE_DBG("write errno %i\n", SPIFFS_errno(&fs));
return 0;
}
return NULL;
}
// ---------------------------------------------------------------------------
// file functions
//
#define GET_FILE_FH(descr) \
const struct myvfs_file *myfd = (const struct myvfs_file *)descr; \
spiffs_file fh = myfd->fh;
static int32_t myspiffs_vfs_close( const struct vfs_file *fd ) {
GET_FILE_FH(fd);
int32_t res = SPIFFS_close( &fs, fh );
// free descriptor memory
free( (void *)fd );
return res;
}
size_t myspiffs_read( int fd, void* ptr, size_t len){
int res = SPIFFS_read(&fs, (spiffs_file)fd, ptr, len);
if (res < 0) {
NODE_DBG("read errno %i\n", SPIFFS_errno(&fs));
return 0;
static int32_t myspiffs_vfs_read( const struct vfs_file *fd, void *ptr, size_t len ) {
GET_FILE_FH(fd);
return SPIFFS_read( &fs, fh, ptr, len );
}
static int32_t myspiffs_vfs_write( const struct vfs_file *fd, const void *ptr, size_t len ) {
GET_FILE_FH(fd);
return SPIFFS_write( &fs, fh, (void *)ptr, len );
}
static int32_t myspiffs_vfs_lseek( const struct vfs_file *fd, int32_t off, int whence ) {
GET_FILE_FH(fd);
int spiffs_whence;
switch (whence) {
default:
case VFS_SEEK_SET:
spiffs_whence = SPIFFS_SEEK_SET;
break;
case VFS_SEEK_CUR:
spiffs_whence = SPIFFS_SEEK_CUR;
break;
case VFS_SEEK_END:
spiffs_whence = SPIFFS_SEEK_END;
break;
}
return res;
return SPIFFS_lseek( &fs, fh, off, spiffs_whence );
}
static int32_t myspiffs_vfs_eof( const struct vfs_file *fd ) {
GET_FILE_FH(fd);
return SPIFFS_eof( &fs, fh );
}
static int32_t myspiffs_vfs_tell( const struct vfs_file *fd ) {
GET_FILE_FH(fd);
return SPIFFS_tell( &fs, fh );
}
static int32_t myspiffs_vfs_flush( const struct vfs_file *fd ) {
GET_FILE_FH(fd);
return SPIFFS_fflush( &fs, fh ) >= 0 ? VFS_RES_OK : VFS_RES_ERR;
}
int myspiffs_lseek( int fd, int off, int whence ){
return SPIFFS_lseek(&fs, (spiffs_file)fd, off, whence);
static int32_t myspiffs_vfs_ferrno( const struct vfs_file *fd ) {
return SPIFFS_errno( &fs );
}
int myspiffs_eof( int fd ){
return SPIFFS_eof(&fs, (spiffs_file)fd);
static int fs_mode2flag(const char *mode){
if(strlen(mode)==1){
if(strcmp(mode,"w")==0)
return SPIFFS_WRONLY|SPIFFS_CREAT|SPIFFS_TRUNC;
else if(strcmp(mode, "r")==0)
return SPIFFS_RDONLY;
else if(strcmp(mode, "a")==0)
return SPIFFS_WRONLY|SPIFFS_CREAT|SPIFFS_APPEND;
else
return SPIFFS_RDONLY;
} else if (strlen(mode)==2){
if(strcmp(mode,"r+")==0)
return SPIFFS_RDWR;
else if(strcmp(mode, "w+")==0)
return SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_TRUNC;
else if(strcmp(mode, "a+")==0)
return SPIFFS_RDWR|SPIFFS_CREAT|SPIFFS_APPEND;
else
return SPIFFS_RDONLY;
} else {
return SPIFFS_RDONLY;
}
}
int myspiffs_tell( int fd ){
return SPIFFS_tell(&fs, (spiffs_file)fd);
// ---------------------------------------------------------------------------
// filesystem functions
//
static vfs_file *myspiffs_vfs_open( const char *name, const char *mode ) {
struct myvfs_file *fd;
int flags = fs_mode2flag( mode );
if ((fd = (struct myvfs_file *)malloc( sizeof( struct myvfs_file ) ))) {
if (0 < (fd->fh = SPIFFS_open( &fs, name, flags, 0 ))) {
fd->vfs_file.fs_type = VFS_FS_SPIFFS;
fd->vfs_file.fns = &myspiffs_file_fns;
return (vfs_file *)fd;
} else {
free( fd );
}
}
return NULL;
}
int myspiffs_getc( int fd ){
unsigned char c = 0xFF;
int res;
if(!myspiffs_eof(fd)){
res = SPIFFS_read(&fs, (spiffs_file)fd, &c, 1);
if (res != 1) {
NODE_DBG("getc errno %i\n", SPIFFS_errno(&fs));
return (int)EOF;
static vfs_dir *myspiffs_vfs_opendir( const char *name ){
struct myvfs_dir *dd;
if ((dd = (struct myvfs_dir *)malloc( sizeof( struct myvfs_dir ) ))) {
if (SPIFFS_opendir( &fs, name, &(dd->d) )) {
dd->vfs_dir.fs_type = VFS_FS_SPIFFS;
dd->vfs_dir.fns = &myspiffs_dd_fns;
return (vfs_dir *)dd;
} else {
return (int)c;
free( dd );
}
}
return (int)EOF;
return NULL;
}
int myspiffs_ungetc( int c, int fd ){
return SPIFFS_lseek(&fs, (spiffs_file)fd, -1, SEEK_CUR);
static vfs_item *myspiffs_vfs_stat( const char *name ) {
struct myvfs_stat *s;
if ((s = (struct myvfs_stat *)malloc( sizeof( struct myvfs_stat ) ))) {
if (0 <= SPIFFS_stat( &fs, name, &(s->s) )) {
s->vfs_item.fs_type = VFS_FS_SPIFFS;
s->vfs_item.fns = &myspiffs_item_fns;
return (vfs_item *)s;
} else {
free( s );
}
}
return NULL;
}
int myspiffs_flush( int fd ){
return SPIFFS_fflush(&fs, (spiffs_file)fd);
static int32_t myspiffs_vfs_remove( const char *name ) {
return SPIFFS_remove( &fs, name );
}
int myspiffs_error( int fd ){
return SPIFFS_errno(&fs);
static int32_t myspiffs_vfs_rename( const char *oldname, const char *newname ) {
return SPIFFS_rename( &fs, oldname, newname );
}
void myspiffs_clearerr( int fd ){
SPIFFS_clearerr(&fs);
static int32_t myspiffs_vfs_fsinfo( uint32_t *total, uint32_t *used ) {
return SPIFFS_info( &fs, total, used );
}
int myspiffs_rename( const char *old, const char *newname ){
return SPIFFS_rename(&fs, (char *)old, (char *)newname);
static int32_t myspiffs_vfs_fscfg( uint32_t *phys_addr, uint32_t *phys_size ) {
*phys_addr = fs.cfg.phys_addr;
*phys_size = fs.cfg.phys_size;
return VFS_RES_OK;
}
size_t myspiffs_size( int fd ){
return SPIFFS_size(&fs, (spiffs_file)fd);
static vfs_vol *myspiffs_vfs_mount( const char *name, int num ) {
// volume descriptor not supported, just return true / false
return myspiffs_mount() ? (vfs_vol *)1 : NULL;
}
#if 0
void test_spiffs() {
char buf[12];
// Surely, I've mounted spiffs before entering here
static int32_t myspiffs_vfs_format( void ) {
return myspiffs_format();
}
spiffs_file fd = SPIFFS_open(&fs, "my_file", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
if (SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12) < 0) NODE_DBG("errno %i\n", SPIFFS_errno(&fs));
SPIFFS_close(&fs, fd);
static int32_t myspiffs_vfs_errno( void ) {
return SPIFFS_errno( &fs );
}
fd = SPIFFS_open(&fs, "my_file", SPIFFS_RDWR, 0);
if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) NODE_DBG("errno %i\n", SPIFFS_errno(&fs));
SPIFFS_close(&fs, fd);
static void myspiffs_vfs_clearerr( void ) {
SPIFFS_clearerr( &fs );
}
NODE_DBG("--> %s <--\n", buf);
// ---------------------------------------------------------------------------
// VFS interface functions
//
vfs_fs_fns *myspiffs_realm( const char *inname, char **outname, int set_current_drive ) {
if (inname[0] == '/') {
size_t idstr_len = strlen( MY_LDRV_ID );
// logical drive is specified, check if it's our id
if (0 == strncmp( &(inname[1]), MY_LDRV_ID, idstr_len )) {
*outname = (char *)&(inname[1 + idstr_len]);
if (*outname[0] == '/') {
// skip leading /
(*outname)++;
}
if (set_current_drive) is_current_drive = true;
return &myspiffs_fs_fns;
}
} else {
// no logical drive in patchspec, are we current drive?
if (is_current_drive) {
*outname = (char *)inname;
return &myspiffs_fs_fns;
}
}
if (set_current_drive) is_current_drive = false;
return NULL;
}
#endif
......@@ -5,8 +5,6 @@
* Author: petera
*/
#ifndef SPIFFS_H_
#define SPIFFS_H_
#if defined(__cplusplus)
......@@ -49,6 +47,15 @@ extern "C" {
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
#define SPIFFS_ERR_FILE_EXISTS -10030
#define SPIFFS_ERR_NOT_A_FILE -10031
#define SPIFFS_ERR_RO_NOT_IMPL -10032
#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033
#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034
#define SPIFFS_ERR_PROBE_NOT_A_FS -10035
#define SPIFFS_ERR_NAME_TOO_LONG -10036
#define SPIFFS_ERR_INTERNAL -10050
#define SPIFFS_ERR_TEST -10100
......@@ -63,12 +70,26 @@ typedef u16_t spiffs_mode;
// object type
typedef u8_t spiffs_obj_type;
struct spiffs_t;
#if SPIFFS_HAL_CALLBACK_EXTRA
/* spi read call function type */
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
/* spi write call function type */
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
/* spi erase call function type */
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
#else // SPIFFS_HAL_CALLBACK_EXTRA
/* spi read call function type */
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
/* spi write call function type */
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
/* spi erase call function type */
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
#endif // SPIFFS_HAL_CALLBACK_EXTRA
/* file system check callback report operation */
typedef enum {
......@@ -85,12 +106,30 @@ typedef enum {
SPIFFS_CHECK_FIX_LOOKUP,
SPIFFS_CHECK_DELETE_ORPHANED_INDEX,
SPIFFS_CHECK_DELETE_PAGE,
SPIFFS_CHECK_DELETE_BAD_FILE,
SPIFFS_CHECK_DELETE_BAD_FILE
} spiffs_check_report;
/* file system check callback function */
#if SPIFFS_HAL_CALLBACK_EXTRA
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
u32_t arg1, u32_t arg2);
#else // SPIFFS_HAL_CALLBACK_EXTRA
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
u32_t arg1, u32_t arg2);
#endif // SPIFFS_HAL_CALLBACK_EXTRA
/* file system listener callback operation */
typedef enum {
/* the file has been created */
SPIFFS_CB_CREATED = 0,
/* the file has been updated or moved to another page */
SPIFFS_CB_UPDATED,
/* the file has been deleted */
SPIFFS_CB_DELETED
} spiffs_fileop_type;
/* file system listener callback function */
typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);
#ifndef SPIFFS_DBG
#define SPIFFS_DBG(...) \
......@@ -108,18 +147,28 @@ typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_repor
/* Any write to the filehandle is appended to end of the file */
#define SPIFFS_APPEND (1<<0)
#define SPIFFS_O_APPEND SPIFFS_APPEND
/* If the opened file exists, it will be truncated to zero length before opened */
#define SPIFFS_TRUNC (1<<1)
#define SPIFFS_O_TRUNC SPIFFS_TRUNC
/* If the opened file does not exist, it will be created before opened */
#define SPIFFS_CREAT (1<<2)
#define SPIFFS_O_CREAT SPIFFS_CREAT
/* The opened file may only be read */
#define SPIFFS_RDONLY (1<<3)
/* The opened file may only be writted */
#define SPIFFS_O_RDONLY SPIFFS_RDONLY
/* The opened file may only be written */
#define SPIFFS_WRONLY (1<<4)
/* The opened file may be both read and writted */
#define SPIFFS_O_WRONLY SPIFFS_WRONLY
/* The opened file may be both read and written */
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
/* Any writes to the filehandle will never be cached */
#define SPIFFS_O_RDWR SPIFFS_RDWR
/* Any writes to the filehandle will never be cached but flushed directly */
#define SPIFFS_DIRECT (1<<5)
#define SPIFFS_O_DIRECT SPIFFS_DIRECT
/* If SPIFFS_O_CREAT and SPIFFS_O_EXCL are set, SPIFFS_open() shall fail if the file exists */
#define SPIFFS_EXCL (1<<6)
#define SPIFFS_O_EXCL SPIFFS_EXCL
#define SPIFFS_SEEK_SET (0)
#define SPIFFS_SEEK_CUR (1)
......@@ -164,10 +213,15 @@ typedef struct {
// logical size of a page, must be at least
// log_block_size / 8
u32_t log_page_size;
#endif
#if SPIFFS_FILEHDL_OFFSET
// an integer offset added to each file handle
u16_t fh_ix_offset;
#endif
} spiffs_config;
typedef struct {
typedef struct spiffs_t {
// file system configuration
spiffs_config cfg;
// number of logical blocks
......@@ -222,9 +276,12 @@ typedef struct {
// check callback function
spiffs_check_callback check_cb_f;
// file callback function
spiffs_file_callback file_cb_f;
// mounted flag
u8_t mounted;
// user data
void *user_data;
// config magic
u32_t config_magic;
} spiffs;
......@@ -234,6 +291,7 @@ typedef struct {
spiffs_obj_id obj_id;
u32_t size;
spiffs_obj_type type;
spiffs_page_ix pix;
u8_t name[SPIFFS_OBJ_NAME_LEN];
} spiffs_stat;
......@@ -253,6 +311,40 @@ typedef struct {
// functions
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
/**
* Special function. This takes a spiffs config struct and returns the number
* of blocks this file system was formatted with. This function relies on
* that following info is set correctly in given config struct:
*
* phys_addr, log_page_size, and log_block_size.
*
* Also, hal_read_f must be set in the config struct.
*
* One must be sure of the correct page size and that the physical address is
* correct in the probed file system when calling this function. It is not
* checked if the phys_addr actually points to the start of the file system,
* so one might get a false positive if entering a phys_addr somewhere in the
* middle of the file system at block boundary. In addition, it is not checked
* if the page size is actually correct. If it is not, weird file system sizes
* will be returned.
*
* If this function detects a file system it returns the assumed file system
* size, which can be used to set the phys_size.
*
* Otherwise, it returns an error indicating why it is not regarded as a file
* system.
*
* Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
* macros. It returns the error code directly, instead of as read by
* SPIFFS_errno.
*
* @param config essential parts of the physical and logical
* configuration of the file system.
*/
s32_t SPIFFS_probe_fs(spiffs_config *config);
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
/**
* Initializes the file system dynamic parameters and mounts the filesystem.
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
......@@ -286,19 +378,18 @@ void SPIFFS_unmount(spiffs *fs);
* @param path the path of the new file
* @param mode ignored, for posix compliance
*/
s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode);
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
/**
* Opens/creates a file.
* @param fs the file system struct
* @param path the path of the new file
* @param flags the flags for the open command, can be combinations of
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT
* SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,
* SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL
* @param mode ignored, for posix compliance
*/
spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode mode);
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
/**
* Opens a file by given dir entry.
......@@ -306,7 +397,7 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode
* a normal SPIFFS_open would need to traverse the filesystem again to find
* the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
* @param fs the file system struct
* @param path the dir entry to the file
* @param e the dir entry to the file
* @param flags the flags for the open command, can be combinations of
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
......@@ -315,6 +406,22 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode
*/
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
/**
* Opens a file by given page index.
* Optimization purposes, opens a file by directly pointing to the page
* index in the spi flash.
* If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
* is returned.
* @param fs the file system struct
* @param page_ix the page index
* @param flags the flags for the open command, can be combinations of
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
* SPIFFS_CREAT will have no effect in this case.
* @param mode ignored, for posix compliance
*/
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
/**
* Reads from given filehandle.
* @param fs the file system struct
......@@ -336,13 +443,14 @@ s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
/**
* Moves the read/write file offset
* Moves the read/write file offset. Resulting offset is returned or negative if error.
* lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
* @param fs the file system struct
* @param fh the filehandle
* @param offs how much/where to move the offset
* @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
* if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offset
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
*/
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
......@@ -351,7 +459,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
* @param fs the file system struct
* @param path the path of the file to remove
*/
s32_t SPIFFS_remove(spiffs *fs, char *path);
s32_t SPIFFS_remove(spiffs *fs, const char *path);
/**
* Removes a file by filehandle
......@@ -366,7 +474,7 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
* @param path the path of the file to stat
* @param s the stat struct to populate
*/
s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s);
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
/**
* Gets file status by filehandle
......@@ -388,7 +496,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
* @param fs the file system struct
* @param fh the filehandle of the file to close
*/
void SPIFFS_close(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
/**
* Renames a file
......@@ -396,7 +504,7 @@ void SPIFFS_close(spiffs *fs, spiffs_file fh);
* @param old path of file to rename
* @param newPath new path of file
*/
s32_t SPIFFS_rename(spiffs *fs, char *old, char *newPath);
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
/**
* Returns last error of last file operation.
......@@ -419,7 +527,7 @@ void SPIFFS_clearerr(spiffs *fs);
* @param name the name of the directory
* @param d pointer the directory stream to be populated
*/
spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d);
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
/**
* Closes a directory stream
......@@ -441,13 +549,6 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
*/
s32_t SPIFFS_check(spiffs *fs);
/**
* Searches for a block with only deleted entries. If found, it is erased.
* @param fs the file system struct
*/
s32_t SPIFFS_erase_deleted_block(spiffs *fs);
/**
* Returns number of total bytes available and number of used bytes.
* This is an estimation, and depends on if there a many files with little
......@@ -527,6 +628,36 @@ s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
*/
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
/**
* Check if EOF reached.
* @param fs the file system struct
* @param fh the filehandle of the file to check
*/
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
/**
* Get position in file.
* @param fs the file system struct
* @param fh the filehandle of the file to check
*/
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
/**
* Registers a callback function that keeps track on operations on file
* headers. Do note, that this callback is called from within internal spiffs
* mechanisms. Any operations on the actual file system being callbacked from
* in this callback will mess things up for sure - do not do this.
* This can be used to track where files are and move around during garbage
* collection, which in turn can be used to build location tables in ram.
* Used in conjuction with SPIFFS_open_by_page this may improve performance
* when opening a lot of files.
* Must be invoked after mount.
*
* @param fs the file system struct
* @param cb_func the callback on file operations
*/
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
#if SPIFFS_TEST_VISUALISATION
/**
* Prints out a visualization of the filesystem.
......@@ -553,30 +684,6 @@ u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
#if SPIFFS_CACHE
#endif
void myspiffs_mount();
void myspiffs_unmount();
int myspiffs_open(const char *name, int flags);
int myspiffs_close( int fd );
size_t myspiffs_write( int fd, const void* ptr, size_t len );
size_t myspiffs_read( int fd, void* ptr, size_t len);
int myspiffs_lseek( int fd, int off, int whence );
int myspiffs_eof( int fd );
int myspiffs_tell( int fd );
int myspiffs_getc( int fd );
int myspiffs_ungetc( int c, int fd );
int myspiffs_flush( int fd );
int myspiffs_error( int fd );
void myspiffs_clearerr( int fd );
int myspiffs_check( void );
int myspiffs_rename( const char *old, const char *newname );
size_t myspiffs_size( int fd );
int myspiffs_format (void);
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
s32_t SPIFFS_size(spiffs *fs, spiffs_file fh);
#if defined(__cplusplus)
}
#endif
......
......@@ -7,6 +7,7 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include <string.h>
#if SPIFFS_CACHE
......@@ -39,7 +40,7 @@ static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
res = fs->cfg.hal_write_f(SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
}
cp->flags = 0;
......@@ -137,10 +138,7 @@ s32_t spiffs_phys_rd(
} else {
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
// for second layer lookup functions, we do not cache in order to prevent shredding
return fs->cfg.hal_read_f(
addr ,
len,
dst);
return SPIFFS_HAL_READ(fs, addr, len, dst);
}
#if SPIFFS_CACHE_STATS
fs->cache_misses++;
......@@ -151,8 +149,7 @@ s32_t spiffs_phys_rd(
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
}
s32_t res2 = fs->cfg.hal_read_f(
s32_t res2 = SPIFFS_HAL_READ(fs,
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
SPIFFS_CFG_LOG_PAGE_SZ(fs),
spiffs_get_cache_page(fs, cache, cp->ix));
......@@ -186,7 +183,7 @@ s32_t spiffs_phys_wr(
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
// page is being deleted, wipe from cache - unless it is a lookup page
spiffs_cache_page_free(fs, cp->ix, 0);
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
}
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
......@@ -197,13 +194,13 @@ s32_t spiffs_phys_wr(
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
// page is being updated, no write-cache, just pass thru
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
} else {
return SPIFFS_OK;
}
} else {
// no cache page, no write cache - just write thru
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
}
}
......
......@@ -19,8 +19,24 @@
* Author: petera
*/
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include <string.h>
#if !SPIFFS_READ_ONLY
#if SPIFFS_HAL_CALLBACK_EXTRA
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
do { \
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
} while (0)
#else
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
do { \
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
} while (0)
#endif
//---------------------------------------
// Look up consistency
......@@ -93,6 +109,7 @@ static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_
} else {
// calc entry in index
entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
}
// load index
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
......@@ -194,9 +211,9 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
res = spiffs_page_delete(fs, new_pix);
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
}
SPIFFS_CHECK_RES(res);
}
......@@ -216,7 +233,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
}
} else {
SPIFFS_CHECK_RES(res);
......@@ -254,7 +271,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
*reload_lu = 1;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
}
SPIFFS_CHECK_RES(res);
}
......@@ -306,7 +323,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
......@@ -315,7 +332,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// rewrite as obj_id_lu
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
......@@ -353,7 +370,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// if only data page exists, make this page index
if (data_pix && objix_pix_d == 0) {
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
spiffs_page_header new_ph;
spiffs_page_ix new_pix;
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
......@@ -369,7 +386,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// if only index exists, make data page
if (data_pix == 0 && objix_pix_d) {
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
spiffs_page_header new_ph;
spiffs_page_ix new_pix;
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
......@@ -406,7 +423,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// page referenced by object index but not final
// just finalize
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
......@@ -418,7 +435,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
if (delete_page) {
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
}
......@@ -427,14 +444,14 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
}
static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
u32_t user_data, void *user_p) {
(void)user_data;
(void)user_p;
const void *user_const_p, void *user_var_p) {
(void)user_const_p;
(void)user_var_p;
s32_t res = SPIFFS_OK;
spiffs_page_header p_hdr;
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
(cur_block * 256)/fs->block_count, 0);
// load header
......@@ -460,7 +477,7 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
(void)check_all_objects;
s32_t res = SPIFFS_OK;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
......@@ -469,10 +486,10 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
}
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
......@@ -506,14 +523,17 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
spiffs_block_ix cur_block = 0;
// build consistency bitmap for id range traversing all blocks
while (!restart && cur_block < fs->block_count) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
0);
// traverse each page except for lookup pages
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
//if ((cur_pix & 0xff) == 0)
// SPIFFS_CHECK_DBG("PA: processing pix %08x, block %08x of pix %08x, block %08x\n",
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
// read header
spiffs_page_header p_hdr;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
......@@ -598,11 +618,11 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
// delete file
res = spiffs_page_delete(fs, cur_pix);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
......@@ -636,7 +656,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (data_pix == 0) {
// not found, this index is badly borked
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
SPIFFS_CHECK_RES(res);
break;
......@@ -648,10 +668,10 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
......@@ -669,7 +689,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
// the object which is referring to this page
SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n",
p_hdr.obj_id, cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
SPIFFS_CHECK_RES(res);
// extra precaution, delete this page also
......@@ -764,19 +784,19 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
continue;
} else if (delete_page) {
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
res = spiffs_page_delete(fs, cur_pix);
}
SPIFFS_CHECK_RES(res);
......@@ -818,6 +838,8 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
}
}
}
SPIFFS_CHECK_DBG("PA: processed %04x, restart %i\n", pix_offset, restart);
// next page range
if (!restart) {
pix_offset += pages_per_scan;
......@@ -828,12 +850,12 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
// Checks consistency amongst all pages and fixes irregularities
s32_t spiffs_page_consistency_check(spiffs *fs) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
s32_t res = spiffs_page_consistency_check_i(fs);
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
......@@ -855,14 +877,14 @@ static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
}
static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
int cur_entry, u32_t user_data, void *user_p) {
(void)user_data;
int cur_entry, const void *user_const_p, void *user_var_p) {
(void)user_const_p;
s32_t res_c = SPIFFS_VIS_COUNTINUE;
s32_t res = SPIFFS_OK;
u32_t *log_ix = (u32_t *)user_p;
u32_t *log_ix = (u32_t*)user_var_p;
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
(cur_block * 256)/fs->block_count, 0);
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
......@@ -879,7 +901,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
(SPIFFS_PH_FLAG_DELET)) {
SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n",
cur_pix, obj_id, p_hdr.span_ix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
return res_c;
......@@ -935,7 +957,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
if (delete) {
SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n",
cur_pix, obj_id, p_hdr.span_ix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
}
......@@ -958,16 +980,17 @@ s32_t spiffs_object_index_consistency_check(spiffs *fs) {
// a reachable/unreachable object id.
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
u32_t obj_id_log_ix = 0;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
0, 0);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_OK;
}
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
#endif // !SPIFFS_READ_ONLY
......@@ -8,26 +8,25 @@
#ifndef SPIFFS_CONFIG_H_
#define SPIFFS_CONFIG_H_
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "nodemcu_spiffs.h"
#include "sdkconfig.h"
// compile time switches
// Set generic spiffs debug output call.
#ifndef SPIFFS_DGB
#ifndef SPIFFS_DBG
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for garbage collecting.
#ifndef SPIFFS_GC_DGB
#ifndef SPIFFS_GC_DBG
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for caching.
#ifndef SPIFFS_CACHE_DGB
#ifndef SPIFFS_CACHE_DBG
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for system consistency checks.
#ifndef SPIFFS_CHECK_DGB
#ifndef SPIFFS_CHECK_DBG
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
#endif
......@@ -51,10 +50,8 @@
// Enable/disable statistics on caching. Debug/test purpose only.
#ifndef SPIFFS_CACHE_STATS
#define SPIFFS_CACHE_STATS 0
#define SPIFFS_CACHE_STATS 1
#endif
#else
#define SPIFFS_CACHE_WR 0
#endif
// Always check header of each accessed page to ensure consistent state.
......@@ -70,7 +67,7 @@
// Enable/disable statistics on gc. Debug/test purpose only.
#ifndef SPIFFS_GC_STATS
#define SPIFFS_GC_STATS 0
#define SPIFFS_GC_STATS 1
#endif
// Garbage collecting examines all pages in a block which and sums up
......@@ -95,9 +92,11 @@
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
#endif
// Object name maximum length.
// Object name maximum length. Note that this length include the
// zero-termination character, meaning maximum string of characters
// can at most be CONFIG_SPIFFS_OBJ_NAME_LEN - 1.
#ifndef SPIFFS_OBJ_NAME_LEN
#define SPIFFS_OBJ_NAME_LEN (32)
#define SPIFFS_OBJ_NAME_LEN (CONFIG_FS_OBJ_NAME_LEN+1)
#endif
// Size of buffer allocated on stack used when copying data.
......@@ -115,19 +114,29 @@
#define SPIFFS_USE_MAGIC (0)
#endif
#if SPIFFS_USE_MAGIC
// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
// enabled, the magic will also be dependent on the length of the filesystem.
// For example, a filesystem configured and formatted for 4 megabytes will not
// be accepted for mounting with a configuration defining the filesystem as 2
// megabytes.
#ifndef SPIFFS_USE_MAGIC_LENGTH
#define SPIFFS_USE_MAGIC_LENGTH (0)
#endif
#endif
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
// These should be defined on a multithreaded system
// define this to entering a mutex if you're running on a multithreaded system
// define this to enter a mutex if you're running on a multithreaded system
#ifndef SPIFFS_LOCK
#define SPIFFS_LOCK(fs)
#endif
// define this to exiting a mutex if you're running on a multithreaded system
// define this to exit a mutex if you're running on a multithreaded system
#ifndef SPIFFS_UNLOCK
#define SPIFFS_UNLOCK(fs)
#endif
// Enable if only one spiffs instance with constant configuration will exist
// on the target. This will reduce calculations, flash and memory accesses.
// Parts of configuration must be defined below instead of at time of mount.
......@@ -155,7 +164,41 @@
#endif
#endif
// Set SPFIFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
// Enable this if your target needs aligned data for index tables
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0
#endif
// Enable this if you want the HAL callbacks to be called with the spiffs struct
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
#define SPIFFS_HAL_CALLBACK_EXTRA 0
#endif
// Enable this if you want to add an integer offset to all file handles
// (spiffs_file). This is useful if running multiple instances of spiffs on
// same target, in order to recognise to what spiffs instance a file handle
// belongs.
// NB: This adds config field fh_ix_offset in the configuration struct when
// mounting, which must be defined.
#ifndef SPIFFS_FILEHDL_OFFSET
#define SPIFFS_FILEHDL_OFFSET 0
#endif
// Enable this to compile a read only version of spiffs.
// This will reduce binary size of spiffs. All code comprising modification
// of the file system will not be compiled. Some config will be ignored.
// HAL functions for erasing and writing to spi-flash may be null. Cache
// can be disabled for even further binary size reduction (and ram savings).
// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.
// If the file system cannot be mounted due to aborted erase operation and
// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be
// returned.
// Might be useful for e.g. bootloaders and such.
#ifndef SPIFFS_READ_ONLY
#define SPIFFS_READ_ONLY 0
#endif
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
// in the api. This function will visualize all filesystem using given printf
// function.
#ifndef SPIFFS_TEST_VISUALISATION
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment