From 4f1b33d52283fbf58a3de2027bc00e15e703f571 Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Wed, 21 Sep 2016 17:51:50 +1000 Subject: [PATCH] Grabbed latest spiffs + vfs layer from dev branch. Also included the recent LVM fix. Platform flash layer not yet functional. --- components/base_nodemcu/user_main.c | 34 +- components/lua/lauxlib.c | 30 +- components/lua/liolib.c | 52 +- components/lua/loadlib.c | 10 +- components/lua/lvm.c | 2 +- components/platform/Kconfig | 21 +- components/platform/include/platform.h | 2 + components/platform/include/vfs.h | 250 ++++++++++ components/platform/include/vfs_int.h | 136 ++++++ components/platform/platform_flash.c | 248 ++++++++++ components/platform/vfs.c | 469 ++++++++++++++++++ components/spiffs/LICENSE | 2 +- components/spiffs/component.mk | 3 + components/spiffs/docs/TODO | 16 +- components/spiffs/nodemcu_spiffs.h | 24 + components/spiffs/spiffs.c | 644 ++++++++++++++++++++----- components/spiffs/spiffs.h | 211 ++++++-- components/spiffs/spiffs_cache.c | 17 +- components/spiffs/spiffs_check.c | 105 ++-- components/spiffs/spiffs_config.h | 77 ++- components/spiffs/spiffs_gc.c | 14 +- components/spiffs/spiffs_hydrogen.c | 434 +++++++++++------ components/spiffs/spiffs_nucleus.c | 238 ++++++--- components/spiffs/spiffs_nucleus.h | 63 ++- 24 files changed, 2585 insertions(+), 517 deletions(-) create mode 100644 components/platform/include/vfs.h create mode 100644 components/platform/include/vfs_int.h create mode 100644 components/platform/platform_flash.c create mode 100644 components/platform/vfs.c create mode 100644 components/spiffs/nodemcu_spiffs.h diff --git a/components/base_nodemcu/user_main.c b/components/base_nodemcu/user_main.c index 5be4c111..c23ace2d 100644 --- a/components/base_nodemcu/user_main.c +++ b/components/base_nodemcu/user_main.c @@ -12,9 +12,9 @@ #include "platform.h" #include #include -#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); } diff --git a/components/lua/lauxlib.c b/components/lua/lauxlib.c index 596195d6..a22f69b7 100644 --- a/components/lua/lauxlib.c +++ b/components/lua/lauxlib.c @@ -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; } diff --git a/components/lua/liolib.c b/components/lua/liolib.c index 3bc396a5..2d3d56ba 100644 --- a/components/lua/liolib.c +++ b/components/lua/liolib.c @@ -9,7 +9,7 @@ #include #include #include -#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 diff --git a/components/lua/loadlib.c b/components/lua/loadlib.c index e6965141..63ceb595 100644 --- a/components/lua/loadlib.c +++ b/components/lua/loadlib.c @@ -19,8 +19,8 @@ #include #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 diff --git a/components/lua/lvm.c b/components/lua/lvm.c index 40b6c44e..c7e11de4 100644 --- a/components/lua/lvm.c +++ b/components/lua/lvm.c @@ -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; } diff --git a/components/platform/Kconfig b/components/platform/Kconfig index 132dd3bd..6b0be234 100644 --- a/components/platform/Kconfig +++ b/components/platform/Kconfig @@ -1,4 +1,4 @@ -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 diff --git a/components/platform/include/platform.h b/components/platform/include/platform.h index 85122f9a..a49df62e 100644 --- a/components/platform/include/platform.h +++ b/components/platform/include/platform.h @@ -2,6 +2,8 @@ #define _PLATFORM_H_ #include +#include +#include "sdkconfig.h" #include "cpu_esp32.h" #define PLATFORM_ALIGNMENT __attribute__((aligned(4))) diff --git a/components/platform/include/vfs.h b/components/platform/include/vfs.h new file mode 100644 index 00000000..69f5dec1 --- /dev/null +++ b/components/platform/include/vfs.h @@ -0,0 +1,250 @@ + +#ifndef __VFS_H__ +#define __VFS_H__ + +#include +#include +#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 diff --git a/components/platform/include/vfs_int.h b/components/platform/include/vfs_int.h new file mode 100644 index 00000000..c0725c79 --- /dev/null +++ b/components/platform/include/vfs_int.h @@ -0,0 +1,136 @@ +// internal definitions for vfs + +#ifndef __VFS_INT_H__ +#define __VFS_INT_H__ + +#include +#include + +#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 diff --git a/components/platform/platform_flash.c b/components/platform/platform_flash.c new file mode 100644 index 00000000..fdffbff2 --- /dev/null +++ b/components/platform/platform_flash.c @@ -0,0 +1,248 @@ +#include "platform.h" +#include "flash_api.h" +#include +#include +#include + +// **************************************************************************** +// 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; +} diff --git a/components/platform/vfs.c b/components/platform/vfs.c new file mode 100644 index 00000000..f4b7a09d --- /dev/null +++ b/components/platform/vfs.c @@ -0,0 +1,469 @@ +#include +#include +#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 ); +} diff --git a/components/spiffs/LICENSE b/components/spiffs/LICENSE index e9b0c677..c32f3f04 100644 --- a/components/spiffs/LICENSE +++ b/components/spiffs/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976gmail.com) +Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976gmail.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 diff --git a/components/spiffs/component.mk b/components/spiffs/component.mk index d6563b29..8ca59af4 100644 --- a/components/spiffs/component.mk +++ b/components/spiffs/component.mk @@ -1,3 +1,6 @@ COMPONENT_ADD_INCLUDEDIRS:=. +# TODO: clean up codebase to be sign clean... +EXTRA_CFLAGS+=-Wno-error=pointer-sign + include $(IDF_PATH)/make/component_common.mk diff --git a/components/spiffs/docs/TODO b/components/spiffs/docs/TODO index 88709f02..c947316a 100644 --- a/components/spiffs/docs/TODO +++ b/components/spiffs/docs/TODO @@ -1 +1,15 @@ -* When mending lost pages, also see if they fit into length specified in object index header \ No newline at end of file +* 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 diff --git a/components/spiffs/nodemcu_spiffs.h b/components/spiffs/nodemcu_spiffs.h new file mode 100644 index 00000000..25e6bb4d --- /dev/null +++ b/components/spiffs/nodemcu_spiffs.h @@ -0,0 +1,24 @@ +#ifndef _NODEMCU_SPIFFS_H +#define _NODEMCU_SPIFFS_H + +#ifndef NODEMCU_SPIFFS_NO_INCLUDE +#include +#include +#include +#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 diff --git a/components/spiffs/spiffs.c b/components/spiffs/spiffs.c index c7483791..ead8e42e 100644 --- a/components/spiffs/spiffs.c +++ b/components/spiffs/spiffs.c @@ -1,11 +1,15 @@ #include +#include #include "platform.h" #include "flash_api.h" #include "spiffs.h" - + spiffs fs; -#define LOG_PAGE_SIZE 256 +#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,25 +49,121 @@ 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; + 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 ); + 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 - 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); +#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; - cfg.hal_read_f = my_spiffs_read; - cfg.hal_write_f = my_spiffs_write; - cfg.hal_erase_f = my_spiffs_erase; + 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 + if (myspiffs_set_cfg(cfg, 0, 0, false)) { + return true; + } +#else + 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 + } + + // 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, spiffs_work_buf, @@ -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,105 +194,18 @@ 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 ) - return 0; - myspiffs_mount(); - return 1; -} + myspiffs_mount_internal(true); + SPIFFS_unmount(&fs); -int myspiffs_check( void ) -{ - // ets_wdt_disable(); - // int res = (int)SPIFFS_check(&fs); - // ets_wdt_enable(); - // return res; - return 0; -} + NODE_DBG("Formatting: size 0x%x, addr 0x%x\n", fs.cfg.phys_size, fs.cfg.phys_addr); -int myspiffs_open(const char *name, int flags){ - return (int)SPIFFS_open(&fs, (char *)name, (spiffs_flags)flags, 0); -} - -int myspiffs_close( int fd ){ - SPIFFS_close(&fs, (spiffs_file)fd); - return 0; -} -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; - } -#endif - int res = SPIFFS_write(&fs, (spiffs_file)fd, (void *)ptr, len); - if (res < 0) { - NODE_DBG("write errno %i\n", SPIFFS_errno(&fs)); + if (SPIFFS_format(&fs) < 0) { return 0; } - 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; - } - return res; -} -int myspiffs_lseek( int fd, int off, int whence ){ - return SPIFFS_lseek(&fs, (spiffs_file)fd, off, whence); -} -int myspiffs_eof( int fd ){ - return SPIFFS_eof(&fs, (spiffs_file)fd); -} -int myspiffs_tell( int fd ){ - return SPIFFS_tell(&fs, (spiffs_file)fd); -} -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; - } else { - return (int)c; - } - } - return (int)EOF; -} -int myspiffs_ungetc( int c, int fd ){ - return SPIFFS_lseek(&fs, (spiffs_file)fd, -1, SEEK_CUR); -} -int myspiffs_flush( int fd ){ - return SPIFFS_fflush(&fs, (spiffs_file)fd); -} -int myspiffs_error( int fd ){ - return SPIFFS_errno(&fs); -} -void myspiffs_clearerr( int fd ){ - SPIFFS_clearerr(&fs); -} -int myspiffs_rename( const char *old, const char *newname ){ - return SPIFFS_rename(&fs, (char *)old, (char *)newname); -} -size_t myspiffs_size( int fd ){ - return SPIFFS_size(&fs, (spiffs_file)fd); + + return myspiffs_mount(); } + #if 0 void test_spiffs() { char buf[12]; @@ -206,3 +223,406 @@ void test_spiffs() { NODE_DBG("--> %s <--\n", buf); } #endif + + +// *************************************************************************** +// vfs API +// *************************************************************************** + +#include +#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 ); + +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 ); +} + +static uint32_t myspiffs_vfs_isize( const struct vfs_item *di ) { + GET_STAT_S(di); + + return s->size; +} + +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 ); + } + } + + 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; +} + +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 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; +} + +static int32_t myspiffs_vfs_ferrno( const struct vfs_file *fd ) { + return SPIFFS_errno( &fs ); +} + + +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; + } +} + +// --------------------------------------------------------------------------- +// 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; +} + +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 { + free( dd ); + } + } + + return NULL; +} + +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; +} + +static int32_t myspiffs_vfs_remove( const char *name ) { + return SPIFFS_remove( &fs, name ); +} + +static int32_t myspiffs_vfs_rename( const char *oldname, const char *newname ) { + return SPIFFS_rename( &fs, oldname, newname ); +} + +static int32_t myspiffs_vfs_fsinfo( uint32_t *total, uint32_t *used ) { + return SPIFFS_info( &fs, total, used ); +} + +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; +} + +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; +} + +static int32_t myspiffs_vfs_format( void ) { + return myspiffs_format(); +} + +static int32_t myspiffs_vfs_errno( void ) { + return SPIFFS_errno( &fs ); +} + +static void myspiffs_vfs_clearerr( void ) { + SPIFFS_clearerr( &fs ); +} + + +// --------------------------------------------------------------------------- +// 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; +} diff --git a/components/spiffs/spiffs.h b/components/spiffs/spiffs.h index eecb8139..6711cd06 100644 --- a/components/spiffs/spiffs.h +++ b/components/spiffs/spiffs.h @@ -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 diff --git a/components/spiffs/spiffs_cache.c b/components/spiffs/spiffs_cache.c index 4fde4d36..4e68b9fc 100644 --- a/components/spiffs/spiffs_cache.c +++ b/components/spiffs/spiffs_cache.c @@ -7,6 +7,7 @@ #include "spiffs.h" #include "spiffs_nucleus.h" +#include #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); } } diff --git a/components/spiffs/spiffs_check.c b/components/spiffs/spiffs_check.c index 2180a2a1..0c6481b9 100644 --- a/components/spiffs/spiffs_check.c +++ b/components/spiffs/spiffs_check.c @@ -19,8 +19,24 @@ * Author: petera */ + #include "spiffs.h" #include "spiffs_nucleus.h" +#include + +#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); + 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 diff --git a/components/spiffs/spiffs_config.h b/components/spiffs/spiffs_config.h index 60e47e71..f69280b5 100644 --- a/components/spiffs/spiffs_config.h +++ b/components/spiffs/spiffs_config.h @@ -8,26 +8,25 @@ #ifndef SPIFFS_CONFIG_H_ #define SPIFFS_CONFIG_H_ -#include -#include -#include +#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 diff --git a/components/spiffs/spiffs_gc.c b/components/spiffs/spiffs_gc.c index e1fab368..92bd6657 100644 --- a/components/spiffs/spiffs_gc.c +++ b/components/spiffs/spiffs_gc.c @@ -1,5 +1,8 @@ #include "spiffs.h" #include "spiffs_nucleus.h" +#include + +#if !SPIFFS_READ_ONLY // Erases a logical block and updates the erase counter. // If cache is enabled, all pages that might be cached in this block @@ -36,7 +39,7 @@ s32_t spiffs_gc_quick( int cur_entry = 0; spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work; - SPIFFS_GC_DBG("gc_quick: running\n", cur_block); + SPIFFS_GC_DBG("gc_quick: running\n"); #if SPIFFS_GC_STATS fs->stats_gc_runs++; #endif @@ -249,14 +252,12 @@ s32_t spiffs_gc_find_candidate( memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs)); // divide up work area into block indices and scores - // todo alignment? - // YES DO PROPER ALIGNMENT !^@#%!@%! - if (max_candidates & 1) - ++max_candidates; // HACK WORKAROUND ICK for sizeof(spiffs_block_idx)==2 - spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work; s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix)); + // align cand_scores on s32_t boundary + cand_scores = (s32_t*)(((ptrdiff_t)cand_scores + sizeof(ptrdiff_t) - 1) & ~(sizeof(ptrdiff_t) - 1)); + *block_candidates = cand_blocks; int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)); @@ -570,3 +571,4 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) { return res; } +#endif // !SPIFFS_READ_ONLY diff --git a/components/spiffs/spiffs_hydrogen.c b/components/spiffs/spiffs_hydrogen.c index b0aa4d7c..d6719f06 100644 --- a/components/spiffs/spiffs_hydrogen.c +++ b/components/spiffs/spiffs_hydrogen.c @@ -7,8 +7,19 @@ #include "spiffs.h" #include "spiffs_nucleus.h" +#include +#if SPIFFS_FILEHDL_OFFSET +#define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0) +#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0) +#else +#define SPIFFS_FH_OFFS(fs, fh) (fh) +#define SPIFFS_FH_UNOFFS(fs, fh) (fh) +#endif + +#if SPIFFS_CACHE == 1 static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh); +#endif #if SPIFFS_BUFFER_HELP u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) { @@ -26,6 +37,10 @@ u8_t SPIFFS_mounted(spiffs *fs) { } s32_t SPIFFS_format(spiffs *fs) { +#if SPIFFS_READ_ONLY + (void)fs; + return SPIFFS_ERR_RO_NOT_IMPL; +#else SPIFFS_API_CHECK_CFG(fs); if (SPIFFS_CHECK_MOUNT(fs)) { fs->err_code = SPIFFS_ERR_MOUNTED; @@ -49,25 +64,35 @@ s32_t SPIFFS_format(spiffs *fs) { SPIFFS_UNLOCK(fs); return 0; +#endif // SPIFFS_READ_ONLY } +#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 + +s32_t SPIFFS_probe_fs(spiffs_config *config) { + s32_t res = spiffs_probe(config); + return res; +} + +#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 + s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, u8_t *fd_space, u32_t fd_space_size, void *cache, u32_t cache_size, spiffs_check_callback check_cb_f) { + void *user_data; SPIFFS_LOCK(fs); + user_data = fs->user_data; memset(fs, 0, sizeof(spiffs)); memcpy(&fs->cfg, config, sizeof(spiffs_config)); + fs->user_data = user_data; fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs); fs->work = &work[0]; fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)]; memset(fd_space, 0, fd_space_size); - // align fd_space pointer to pointer size byte boundary, below is safe + // align fd_space pointer to pointer size byte boundary u8_t ptr_size = sizeof(void*); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" - u8_t addr_lsb = ((u8_t)fd_space) & (ptr_size-1); -#pragma GCC diagnostic pop + u8_t addr_lsb = ((u8_t)(intptr_t)fd_space) & (ptr_size-1); if (addr_lsb) { fd_space += (ptr_size-addr_lsb); fd_space_size -= (ptr_size-addr_lsb); @@ -75,11 +100,8 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, fs->fd_space = fd_space; fs->fd_count = (fd_space_size/sizeof(spiffs_fd)); - // align cache pointer to 4 byte boundary, below is safe -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" - addr_lsb = ((u8_t)cache) & (ptr_size-1); -#pragma GCC diagnostic pop + // align cache pointer to 4 byte boundary + addr_lsb = ((u8_t)(intptr_t)cache) & (ptr_size-1); if (addr_lsb) { u8_t *cache_8 = (u8_t *)cache; cache_8 += (ptr_size-addr_lsb); @@ -89,9 +111,10 @@ s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work, if (cache_size & (ptr_size-1)) { cache_size -= (cache_size & (ptr_size-1)); } + #if SPIFFS_CACHE fs->cache = cache; - fs->cache_size = (cache_size > (config->log_page_size*32)) ? config->log_page_size*32 : cache_size; + fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs)*32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs)*32 : cache_size; spiffs_cache_init(fs); #endif @@ -152,43 +175,68 @@ void SPIFFS_clearerr(spiffs *fs) { fs->err_code = SPIFFS_OK; } -s32_t SPIFFS_creat(spiffs *fs, char *path, spiffs_mode mode) { +s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) { +#if SPIFFS_READ_ONLY + (void)fs; (void)path; (void)mode; + return SPIFFS_ERR_RO_NOT_IMPL; +#else (void)mode; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } SPIFFS_LOCK(fs); spiffs_obj_id obj_id; s32_t res; - res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (u8_t *)path); + res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t*)path); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_create(fs, obj_id, (u8_t *)path, SPIFFS_TYPE_FILE, 0); + res = spiffs_object_create(fs, obj_id, (const u8_t*)path, SPIFFS_TYPE_FILE, 0); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); SPIFFS_UNLOCK(fs); return 0; +#endif // SPIFFS_READ_ONLY } -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) { (void)mode; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } SPIFFS_LOCK(fs); spiffs_fd *fd; spiffs_page_ix pix; +#if SPIFFS_READ_ONLY + // not valid flags in read only mode + flags &= ~SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_TRUNC; +#endif // SPIFFS_READ_ONLY + s32_t res = spiffs_fd_find_new(fs, &fd); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)path, &pix); - if ((flags & SPIFFS_CREAT) == 0) { + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix); + if ((flags & SPIFFS_O_CREAT) == 0) { if (res < SPIFFS_OK) { spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } - if ((flags & SPIFFS_CREAT) && res == SPIFFS_ERR_NOT_FOUND) { + if (res == SPIFFS_OK && + (flags & (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) == (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) { + // creat and excl and file exists - fail + res = SPIFFS_ERR_FILE_EXISTS; + spiffs_fd_return(fs, fd->file_nbr); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + if ((flags & SPIFFS_O_CREAT) && res == SPIFFS_ERR_NOT_FOUND) { +#if !SPIFFS_READ_ONLY spiffs_obj_id obj_id; // no need to enter conflicting name here, already looked for it above res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0); @@ -196,12 +244,13 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_create(fs, obj_id, (u8_t*)path, SPIFFS_TYPE_FILE, &pix); + res = spiffs_object_create(fs, obj_id, (const u8_t*)path, SPIFFS_TYPE_FILE, &pix); if (res < SPIFFS_OK) { spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - flags &= ~SPIFFS_TRUNC; + flags &= ~SPIFFS_O_TRUNC; +#endif // !SPIFFS_READ_ONLY } else { if (res < SPIFFS_OK) { spiffs_fd_return(fs, fd->file_nbr); @@ -213,19 +262,21 @@ spiffs_file SPIFFS_open(spiffs *fs, char *path, spiffs_flags flags, spiffs_mode spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - if (flags & SPIFFS_TRUNC) { +#if !SPIFFS_READ_ONLY + if (flags & SPIFFS_O_TRUNC) { res = spiffs_object_truncate(fd, 0, 0); if (res < SPIFFS_OK) { spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } +#endif // !SPIFFS_READ_ONLY fd->fdoffset = 0; SPIFFS_UNLOCK(fs); - return fd->file_nbr; + return SPIFFS_FH_OFFS(fs, fd->file_nbr); } spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) { @@ -243,19 +294,67 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - if (flags & SPIFFS_TRUNC) { +#if !SPIFFS_READ_ONLY + if (flags & SPIFFS_O_TRUNC) { res = spiffs_object_truncate(fd, 0, 0); if (res < SPIFFS_OK) { spiffs_fd_return(fs, fd->file_nbr); } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } +#endif // !SPIFFS_READ_ONLY fd->fdoffset = 0; SPIFFS_UNLOCK(fs); - return fd->file_nbr; + return SPIFFS_FH_OFFS(fs, fd->file_nbr); +} + +spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) { + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + spiffs_fd *fd; + + s32_t res = spiffs_fd_find_new(fs, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + if (SPIFFS_IS_LOOKUP_PAGE(fs, page_ix)) { + res = SPIFFS_ERR_NOT_A_FILE; + spiffs_fd_return(fs, fd->file_nbr); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + + res = spiffs_object_open_by_page(fs, page_ix, fd, flags, mode); + if (res == SPIFFS_ERR_IS_FREE || + res == SPIFFS_ERR_DELETED || + res == SPIFFS_ERR_NOT_FINALIZED || + res == SPIFFS_ERR_NOT_INDEX || + res == SPIFFS_ERR_INDEX_SPAN_MISMATCH) { + res = SPIFFS_ERR_NOT_A_FILE; + } + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if !SPIFFS_READ_ONLY + if (flags & SPIFFS_O_TRUNC) { + res = spiffs_object_truncate(fd, 0, 0); + if (res < SPIFFS_OK) { + spiffs_fd_return(fs, fd->file_nbr); + } + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } +#endif // !SPIFFS_READ_ONLY + + fd->fdoffset = 0; + + SPIFFS_UNLOCK(fs); + + return SPIFFS_FH_OFFS(fs, fd->file_nbr); } s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { @@ -266,14 +365,21 @@ s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { spiffs_fd *fd; s32_t res; + fh = SPIFFS_FH_UNOFFS(fs, fh); res = spiffs_fd_get(fs, fh, &fd); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - if ((fd->flags & SPIFFS_RDONLY) == 0) { + if ((fd->flags & SPIFFS_O_RDONLY) == 0) { res = SPIFFS_ERR_NOT_READABLE; SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } + if (fd->size == SPIFFS_UNDEFINED_LEN && len > 0) { + // special case for zero sized files + res = SPIFFS_ERR_END_OF_OBJECT; + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + } + #if SPIFFS_CACHE_WR spiffs_fflush_cache(fs, fh); #endif @@ -305,6 +411,7 @@ s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { return len; } +#if !SPIFFS_READ_ONLY static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) { (void)fs; s32_t res = SPIFFS_OK; @@ -326,8 +433,13 @@ static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offs return len; } +#endif // !SPIFFS_READ_ONLY s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { +#if SPIFFS_READ_ONLY + (void)fs; (void)fh; (void)buf; (void)len; + return SPIFFS_ERR_RO_NOT_IMPL; +#else SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); @@ -336,14 +448,19 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { s32_t res; u32_t offset; + fh = SPIFFS_FH_UNOFFS(fs, fh); res = spiffs_fd_get(fs, fh, &fd); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - if ((fd->flags & SPIFFS_WRONLY) == 0) { + if ((fd->flags & SPIFFS_O_WRONLY) == 0) { res = SPIFFS_ERR_NOT_WRITABLE; SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } + if ((fd->flags & SPIFFS_O_APPEND)) { + fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size; + } + offset = fd->fdoffset; #if SPIFFS_CACHE_WR @@ -352,7 +469,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd); } #endif - if (fd->flags & SPIFFS_APPEND) { + if (fd->flags & SPIFFS_O_APPEND) { if (fd->size == SPIFFS_UNDEFINED_LEN) { offset = 0; } else { @@ -366,7 +483,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { } #if SPIFFS_CACHE_WR - if ((fd->flags & SPIFFS_DIRECT) == 0) { + if ((fd->flags & SPIFFS_O_DIRECT) == 0) { if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) { // small write, try to cache it u8_t alloc_cpage = 1; @@ -383,7 +500,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); spiffs_cache_fd_release(fs, fd->cache_page); - SPIFFS_API_CHECK_RES(fs, res); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } else { // writing within cache alloc_cpage = 0; @@ -414,7 +531,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { return len; } else { res = spiffs_hydro_write(fs, fd, buf, offset, len); - SPIFFS_API_CHECK_RES(fs, res); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); fd->fdoffset += len; SPIFFS_UNLOCK(fs); return res; @@ -429,21 +546,22 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) { spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix), fd->cache_page->offset, fd->cache_page->size); spiffs_cache_fd_release(fs, fd->cache_page); - SPIFFS_API_CHECK_RES(fs, res); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); res = spiffs_hydro_write(fs, fd, buf, offset, len); - SPIFFS_API_CHECK_RES(fs, res); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } } } #endif res = spiffs_hydro_write(fs, fd, buf, offset, len); - SPIFFS_API_CHECK_RES(fs, res); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); fd->fdoffset += len; SPIFFS_UNLOCK(fs); return res; +#endif // SPIFFS_READ_ONLY } s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { @@ -453,8 +571,9 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { spiffs_fd *fd; s32_t res; + fh = SPIFFS_FH_UNOFFS(fs, fh); res = spiffs_fd_get(fs, fh, &fd); - SPIFFS_API_CHECK_RES(fs, res); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); #if SPIFFS_CACHE_WR spiffs_fflush_cache(fs, fh); @@ -469,7 +588,7 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { break; } - if (offs > (s32_t)fd->size) { + if ((offs > (s32_t)fd->size) && (SPIFFS_UNDEFINED_LEN != fd->size)) { res = SPIFFS_ERR_END_OF_OBJECT; } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); @@ -491,9 +610,16 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) { return offs; } -s32_t SPIFFS_remove(spiffs *fs, char *path) { +s32_t SPIFFS_remove(spiffs *fs, const char *path) { +#if SPIFFS_READ_ONLY + (void)fs; (void)path; + return SPIFFS_ERR_RO_NOT_IMPL; +#else SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } SPIFFS_LOCK(fs); spiffs_fd *fd; @@ -503,7 +629,7 @@ s32_t SPIFFS_remove(spiffs *fs, char *path) { res = spiffs_fd_find_new(fs, &fd); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_find_object_index_header_by_name(fs, (u8_t *)path, &pix); + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix); if (res != SPIFFS_OK) { spiffs_fd_return(fs, fd->file_nbr); } @@ -523,19 +649,25 @@ s32_t SPIFFS_remove(spiffs *fs, char *path) { SPIFFS_UNLOCK(fs); return 0; +#endif // SPIFFS_READ_ONLY } s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { +#if SPIFFS_READ_ONLY + (void)fs; (void)fh; + return SPIFFS_ERR_RO_NOT_IMPL; +#else SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); SPIFFS_LOCK(fs); spiffs_fd *fd; s32_t res; + fh = SPIFFS_FH_UNOFFS(fs, fh); res = spiffs_fd_get(fs, fh, &fd); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - if ((fd->flags & SPIFFS_WRONLY) == 0) { + if ((fd->flags & SPIFFS_O_WRONLY) == 0) { res = SPIFFS_ERR_NOT_WRITABLE; SPIFFS_API_CHECK_RES_UNLOCK(fs, res); } @@ -551,9 +683,11 @@ s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) { SPIFFS_UNLOCK(fs); return 0; +#endif // SPIFFS_READ_ONLY } static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) { + (void)fh; spiffs_page_object_ix_header objix_hdr; spiffs_obj_id obj_id; s32_t res =_spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh, @@ -566,23 +700,27 @@ static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spi obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id); SPIFFS_API_CHECK_RES(fs, res); - s->obj_id = obj_id; + s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG; s->type = objix_hdr.type; s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; + s->pix = pix; strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN); return res; } -s32_t SPIFFS_stat(spiffs *fs, char *path, spiffs_stat *s) { +s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) { SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } SPIFFS_LOCK(fs); s32_t res; spiffs_page_ix pix; - res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)path, &pix); + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)path, &pix); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); res = spiffs_stat_pix(fs, pix, 0, s); @@ -600,6 +738,7 @@ s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) { spiffs_fd *fd; s32_t res; + fh = SPIFFS_FH_UNOFFS(fs, fh); res = spiffs_fd_get(fs, fh, &fd); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); @@ -616,15 +755,18 @@ s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) { // Checks if there are any cached writes for the object id associated with // given filehandle. If so, these writes are flushed. +#if SPIFFS_CACHE == 1 static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { + (void)fs; + (void)fh; s32_t res = SPIFFS_OK; -#if SPIFFS_CACHE_WR +#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR spiffs_fd *fd; res = spiffs_fd_get(fs, fh, &fd); SPIFFS_API_CHECK_RES(fs, res); - if ((fd->flags & SPIFFS_DIRECT) == 0) { + if ((fd->flags & SPIFFS_O_DIRECT) == 0) { if (fd->cache_page == 0) { // see if object id is associated with cache already fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd); @@ -645,13 +787,16 @@ static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) { return res; } +#endif s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { + (void)fh; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); s32_t res = SPIFFS_OK; -#if SPIFFS_CACHE_WR +#if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR SPIFFS_LOCK(fs); + fh = SPIFFS_FH_UNOFFS(fs, fh); res = spiffs_fflush_cache(fs, fh); SPIFFS_API_CHECK_RES_UNLOCK(fs,res); SPIFFS_UNLOCK(fs); @@ -660,38 +805,46 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) { return res; } -void SPIFFS_close(spiffs *fs, spiffs_file fh) { - if (!SPIFFS_CHECK_CFG((fs))) { - (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; - return; - } - - if (!SPIFFS_CHECK_MOUNT(fs)) { - fs->err_code = SPIFFS_ERR_NOT_MOUNTED; - return; - } - SPIFFS_LOCK(fs); - -#if SPIFFS_CACHE - spiffs_fflush_cache(fs, fh); -#endif - spiffs_fd_return(fs, fh); - - SPIFFS_UNLOCK(fs); -} - -s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { +s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) { SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); + + s32_t res = SPIFFS_OK; + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); +#if SPIFFS_CACHE + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + res = spiffs_fd_return(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + + SPIFFS_UNLOCK(fs); + + return res; +} + +s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) { +#if SPIFFS_READ_ONLY + (void)fs; (void)old_path; (void)new_path; + return SPIFFS_ERR_RO_NOT_IMPL; +#else + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + if (strlen(new_path) > SPIFFS_OBJ_NAME_LEN - 1 || + strlen(old_path) > SPIFFS_OBJ_NAME_LEN - 1) { + SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG); + } SPIFFS_LOCK(fs); spiffs_page_ix pix_old, pix_dummy; spiffs_fd *fd; - s32_t res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)old, &pix_old); + s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)old_path, &pix_old); SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_find_object_index_header_by_name(fs, (u8_t*)new, &pix_dummy); + res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t*)new_path, &pix_dummy); if (res == SPIFFS_ERR_NOT_FOUND) { res = SPIFFS_OK; } else if (res == SPIFFS_OK) { @@ -708,7 +861,7 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { } SPIFFS_API_CHECK_RES_UNLOCK(fs, res); - res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (u8_t*)new, + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t*)new_path, 0, &pix_dummy); spiffs_fd_return(fs, fd->file_nbr); @@ -718,9 +871,10 @@ s32_t SPIFFS_rename(spiffs *fs, char *old, char *new) { SPIFFS_UNLOCK(fs); return res; +#endif // SPIFFS_READ_ONLY } -spiffs_DIR *SPIFFS_opendir(spiffs *fs, char *name, spiffs_DIR *d) { +spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) { (void)name; if (!SPIFFS_CHECK_CFG((fs))) { @@ -744,9 +898,9 @@ static s32_t spiffs_read_dir_v( spiffs_obj_id obj_id, spiffs_block_ix bix, int ix_entry, - u32_t user_data, - void *user_p) { - (void)user_data; + const void *user_const_p, + void *user_var_p) { + (void)user_const_p; s32_t res; spiffs_page_object_ix_header objix_hdr; if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED || @@ -762,10 +916,9 @@ static s32_t spiffs_read_dir_v( objix_hdr.p_hdr.span_ix == 0 && (objix_hdr.p_hdr.flags& (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { - struct spiffs_dirent *e = (struct spiffs_dirent *)user_p; + struct spiffs_dirent *e = (struct spiffs_dirent*)user_var_p; e->obj_id = obj_id; - strncpy((char *)e->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN); - + strcpy((char *)e->name, (char *)objix_hdr.name); e->type = objix_hdr.type; e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size; e->pix = pix; @@ -780,7 +933,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED; return 0; } - SPIFFS_LOCK(fs); + SPIFFS_LOCK(d->fs); spiffs_block_ix bix; int entry; @@ -804,7 +957,7 @@ struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) { } else { d->fs->err_code = res; } - SPIFFS_UNLOCK(fs); + SPIFFS_UNLOCK(d->fs); return ret; } @@ -815,6 +968,10 @@ s32_t SPIFFS_closedir(spiffs_DIR *d) { } s32_t SPIFFS_check(spiffs *fs) { +#if SPIFFS_READ_ONLY + (void)fs; + return SPIFFS_ERR_RO_NOT_IMPL; +#else s32_t res; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -830,6 +987,7 @@ s32_t SPIFFS_check(spiffs *fs) { SPIFFS_UNLOCK(fs); return res; +#endif // SPIFFS_READ_ONLY } s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { @@ -856,64 +1014,11 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) { return res; } -s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { - SPIFFS_API_CHECK_MOUNT(fs); - SPIFFS_LOCK(fs); - - spiffs_fd *fd; - s32_t res; - res = spiffs_fd_get(fs, fh, &fd); - SPIFFS_API_CHECK_RES(fs, res); - -#if SPIFFS_CACHE_WR - spiffs_fflush_cache(fs, fh); -#endif - - res = fd->fdoffset; - - SPIFFS_UNLOCK(fs); - return res; -} - -s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { - SPIFFS_API_CHECK_MOUNT(fs); - SPIFFS_LOCK(fs); - - spiffs_fd *fd; - s32_t res; - res = spiffs_fd_get(fs, fh, &fd); - SPIFFS_API_CHECK_RES(fs, res); - -#if SPIFFS_CACHE_WR - spiffs_fflush_cache(fs, fh); -#endif - - res = (fd->fdoffset == fd->size); - - SPIFFS_UNLOCK(fs); - return res; -} - -s32_t SPIFFS_size(spiffs *fs, spiffs_file fh) { - SPIFFS_API_CHECK_MOUNT(fs); - SPIFFS_LOCK(fs); - - spiffs_fd *fd; - s32_t res; - res = spiffs_fd_get(fs, fh, &fd); - SPIFFS_API_CHECK_RES(fs, res); - -#if SPIFFS_CACHE_WR - spiffs_fflush_cache(fs, fh); -#endif - - res = fd->size; - - SPIFFS_UNLOCK(fs); - return res; -} - s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) { +#if SPIFFS_READ_ONLY + (void)fs; (void)max_free_pages; + return SPIFFS_ERR_RO_NOT_IMPL; +#else s32_t res; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -924,10 +1029,15 @@ s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) { SPIFFS_API_CHECK_RES_UNLOCK(fs, res); SPIFFS_UNLOCK(fs); return 0; +#endif // SPIFFS_READ_ONLY } s32_t SPIFFS_gc(spiffs *fs, u32_t size) { +#if SPIFFS_READ_ONLY + (void)fs; (void)size; + return SPIFFS_ERR_RO_NOT_IMPL; +#else s32_t res; SPIFFS_API_CHECK_CFG(fs); SPIFFS_API_CHECK_MOUNT(fs); @@ -938,8 +1048,61 @@ s32_t SPIFFS_gc(spiffs *fs, u32_t size) { SPIFFS_API_CHECK_RES_UNLOCK(fs, res); SPIFFS_UNLOCK(fs); return 0; +#endif // SPIFFS_READ_ONLY } +s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) { + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if SPIFFS_CACHE_WR + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size)); + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) { + s32_t res; + SPIFFS_API_CHECK_CFG(fs); + SPIFFS_API_CHECK_MOUNT(fs); + SPIFFS_LOCK(fs); + + fh = SPIFFS_FH_UNOFFS(fs, fh); + + spiffs_fd *fd; + res = spiffs_fd_get(fs, fh, &fd); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); + +#if SPIFFS_CACHE_WR + res = spiffs_fflush_cache(fs, fh); + SPIFFS_API_CHECK_RES_UNLOCK(fs, res); +#endif + + res = fd->fdoffset; + + SPIFFS_UNLOCK(fs); + return res; +} + +s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) { + SPIFFS_LOCK(fs); + fs->file_cb_f = cb_func; + SPIFFS_UNLOCK(fs); + return 0; +} #if SPIFFS_TEST_VISUALISATION s32_t SPIFFS_vis(spiffs *fs) { @@ -1008,11 +1171,10 @@ s32_t SPIFFS_vis(spiffs *fs) { spiffs_printf("free_blocks: %i\n", fs->free_blocks); spiffs_printf("page_alloc: %i\n", fs->stats_p_allocated); spiffs_printf("page_delet: %i\n", fs->stats_p_deleted); + SPIFFS_UNLOCK(fs); u32_t total, used; SPIFFS_info(fs, &total, &used); spiffs_printf("used: %i of %i\n", used, total); - - SPIFFS_UNLOCK(fs); return res; } #endif diff --git a/components/spiffs/spiffs_nucleus.c b/components/spiffs/spiffs_nucleus.c index fc525e78..6737b573 100644 --- a/components/spiffs/spiffs_nucleus.c +++ b/components/spiffs/spiffs_nucleus.c @@ -1,5 +1,6 @@ #include "spiffs.h" #include "spiffs_nucleus.h" +#include static s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) { s32_t res = SPIFFS_OK; @@ -29,6 +30,7 @@ static s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pi return res; } +#if !SPIFFS_READ_ONLY static s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) { s32_t res = SPIFFS_OK; if (pix == (spiffs_page_ix)-1) { @@ -56,6 +58,7 @@ static s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix p #endif return res; } +#endif // !SPIFFS_READ_ONLY #if !SPIFFS_CACHE @@ -64,7 +67,7 @@ s32_t spiffs_phys_rd( u32_t addr, u32_t len, u8_t *dst) { - return fs->cfg.hal_read_f(addr, len, dst); + return SPIFFS_HAL_READ(fs, addr, len, dst); } s32_t spiffs_phys_wr( @@ -72,17 +75,19 @@ s32_t spiffs_phys_wr( u32_t addr, u32_t len, u8_t *src) { - return fs->cfg.hal_write_f(addr, len, src); + return SPIFFS_HAL_WRITE(fs, addr, len, src); } #endif +#if !SPIFFS_READ_ONLY s32_t spiffs_phys_cpy( spiffs *fs, spiffs_file fh, u32_t dst, u32_t src, u32_t len) { + (void)fh; s32_t res; u8_t b[SPIFFS_COPY_BUFFER_STACK]; while (len > 0) { @@ -97,10 +102,11 @@ s32_t spiffs_phys_cpy( } return SPIFFS_OK; } +#endif // !SPIFFS_READ_ONLY // Find object lookup entry containing given id with visitor. // Iterate over object lookup pages in each block until a given object id entry is found. -// When found, the visitor function is called with block index, entry index and user_data. +// When found, the visitor function is called with block index, entry index and user data. // If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be // ended and visitor's return code is returned to caller. // If no visitor is given (0) the search returns on first entry with matching object id. @@ -112,8 +118,8 @@ s32_t spiffs_phys_cpy( // SPIFFS_VIS_NO_WRAP // @param obj_id argument object id // @param v visitor callback function -// @param user_data any data, passed to the callback visitor function -// @param user_p any pointer, passed to the callback visitor function +// @param user_const_p any const pointer, passed to the callback visitor function +// @param user_var_p any pointer, passed to the callback visitor function // @param block_ix reported block index where match was found // @param lu_entry reported look up index where match was found s32_t spiffs_obj_lu_find_entry_visitor( @@ -123,8 +129,8 @@ s32_t spiffs_obj_lu_find_entry_visitor( u8_t flags, spiffs_obj_id obj_id, spiffs_visitor_f v, - u32_t user_data, - void *user_p, + const void *user_const_p, + void *user_var_p, spiffs_block_ix *block_ix, int *lu_entry) { s32_t res = SPIFFS_OK; @@ -174,8 +180,8 @@ s32_t spiffs_obj_lu_find_entry_visitor( (flags & SPIFFS_VIS_CHECK_PH) ? obj_id : obj_lu_buf[cur_entry-entry_offset], cur_block, cur_entry, - user_data, - user_p); + user_const_p, + user_var_p); if (res == SPIFFS_VIS_COUNTINUE || res == SPIFFS_VIS_COUNTINUE_RELOAD) { if (res == SPIFFS_VIS_COUNTINUE_RELOAD) { res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, @@ -217,6 +223,7 @@ s32_t spiffs_obj_lu_find_entry_visitor( return SPIFFS_VIS_END; } +#if !SPIFFS_READ_ONLY s32_t spiffs_erase_block( spiffs *fs, spiffs_block_ix bix) { @@ -227,7 +234,8 @@ s32_t spiffs_erase_block( // here we ignore res, just try erasing the block while (size > 0) { SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); - (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs)); + addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs); size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs); } @@ -241,7 +249,7 @@ s32_t spiffs_erase_block( #if SPIFFS_USE_MAGIC // finally, write magic - spiffs_obj_id magic = SPIFFS_MAGIC(fs); + spiffs_obj_id magic = SPIFFS_MAGIC(fs, bix); res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0, SPIFFS_MAGIC_PADDR(fs, bix), sizeof(spiffs_obj_id), (u8_t *)&magic); @@ -255,6 +263,59 @@ s32_t spiffs_erase_block( return res; } +#endif // !SPIFFS_READ_ONLY + +#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 +s32_t spiffs_probe( + spiffs_config *cfg) { + s32_t res; + u32_t paddr; + spiffs dummy_fs; // create a dummy fs struct just to be able to use macros + memcpy(&dummy_fs.cfg, cfg, sizeof(spiffs_config)); + dummy_fs.block_count = 0; + + // Read three magics, as one block may be in an aborted erase state. + // At least two of these must contain magic and be in decreasing order. + spiffs_obj_id magic[3]; + spiffs_obj_id bix_count[3]; + + spiffs_block_ix bix; + for (bix = 0; bix < 3; bix++) { + paddr = SPIFFS_MAGIC_PADDR(&dummy_fs, bix); +#if SPIFFS_HAL_CALLBACK_EXTRA + // not any proper fs to report here, so callback with null + // (cross fingers that no-one gets angry) + res = cfg->hal_read_f((void *)0, paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]); +#else + res = cfg->hal_read_f(paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]); +#endif + bix_count[bix] = magic[bix] ^ SPIFFS_MAGIC(&dummy_fs, 0); + SPIFFS_CHECK_RES(res); + } + + // check that we have sane number of blocks + if (bix_count[0] < 3) return SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS; + // check that the order is correct, take aborted erases in calculation + // first block aborted erase + if (magic[0] == (spiffs_obj_id)(-1) && bix_count[1] - bix_count[2] == 1) { + return (bix_count[1]+1) * cfg->log_block_size; + } + // second block aborted erase + if (magic[1] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[2] == 2) { + return bix_count[0] * cfg->log_block_size; + } + // third block aborted erase + if (magic[2] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[1] == 1) { + return bix_count[0] * cfg->log_block_size; + } + // no block has aborted erase + if (bix_count[0] - bix_count[1] == 1 && bix_count[1] - bix_count[2] == 1) { + return bix_count[0] * cfg->log_block_size; + } + + return SPIFFS_ERR_PROBE_NOT_A_FS; +} +#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0 static s32_t spiffs_obj_lu_scan_v( @@ -262,11 +323,11 @@ static s32_t spiffs_obj_lu_scan_v( spiffs_obj_id obj_id, spiffs_block_ix bix, int ix_entry, - u32_t user_data, - void *user_p) { + const void *user_const_p, + void *user_var_p) { (void)bix; - (void)user_data; - (void)user_p; + (void)user_const_p; + (void)user_var_p; if (obj_id == SPIFFS_OBJ_ID_FREE) { if (ix_entry == 0) { fs->free_blocks++; @@ -309,7 +370,7 @@ s32_t spiffs_obj_lu_scan( sizeof(spiffs_obj_id), (u8_t *)&magic); SPIFFS_CHECK_RES(res); - if (magic != SPIFFS_MAGIC(fs)) { + if (magic != SPIFFS_MAGIC(fs, bix)) { if (unerased_bix == (spiffs_block_ix)-1) { // allow one unerased block as it might be powered down during an erase unerased_bix = bix; @@ -348,7 +409,11 @@ s32_t spiffs_obj_lu_scan( if (unerased_bix != (spiffs_block_ix)-1) { // found one unerased block, remedy SPIFFS_DBG("mount: erase block %i\n", bix); +#if SPIFFS_READ_ONLY + res = SPIFFS_ERR_RO_ABORTED_OPERATION; +#else res = spiffs_erase_block(fs, unerased_bix); +#endif // SPIFFS_READ_ONLY SPIFFS_CHECK_RES(res); } #endif @@ -379,6 +444,7 @@ s32_t spiffs_obj_lu_scan( return res; } +#if !SPIFFS_READ_ONLY // Find free object lookup entry // Iterate over object lookup pages in each block until a free object id entry is found s32_t spiffs_obj_lu_find_free( @@ -407,12 +473,13 @@ s32_t spiffs_obj_lu_find_free( fs->free_blocks--; } } - if (res == SPIFFS_VIS_END) { + if (res == SPIFFS_ERR_FULL) { SPIFFS_DBG("fs full\n"); } - return res == SPIFFS_VIS_END ? SPIFFS_ERR_FULL : res; + return res; } +#endif // !SPIFFS_READ_ONLY // Find object lookup entry containing given id // Iterate over object lookup pages in each block until a given object id entry is found @@ -437,8 +504,8 @@ static s32_t spiffs_obj_lu_find_id_and_span_v( spiffs_obj_id obj_id, spiffs_block_ix bix, int ix_entry, - u32_t user_data, - void *user_p) { + const void *user_const_p, + void *user_var_p) { s32_t res; spiffs_page_header ph; spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); @@ -446,10 +513,10 @@ static s32_t spiffs_obj_lu_find_id_and_span_v( SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph); SPIFFS_CHECK_RES(res); if (ph.obj_id == obj_id && - ph.span_ix == (spiffs_span_ix)user_data && + ph.span_ix == *((spiffs_span_ix*)user_var_p) && (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET && !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) && - (user_p == 0 || *((spiffs_page_ix *)user_p) != pix)) { + (user_const_p == 0 || *((const spiffs_page_ix*)user_const_p) != pix)) { return SPIFFS_OK; } else { return SPIFFS_VIS_COUNTINUE; @@ -474,8 +541,8 @@ s32_t spiffs_obj_lu_find_id_and_span( SPIFFS_VIS_CHECK_ID, obj_id, spiffs_obj_lu_find_id_and_span_v, - (u32_t)spix, exclusion_pix ? &exclusion_pix : 0, + &spix, &bix, &entry); @@ -513,8 +580,8 @@ s32_t spiffs_obj_lu_find_id_and_span_by_phdr( SPIFFS_VIS_CHECK_PH, obj_id, spiffs_obj_lu_find_id_and_span_v, - (u32_t)spix, exclusion_pix ? &exclusion_pix : 0, + &spix, &bix, &entry); @@ -534,6 +601,7 @@ s32_t spiffs_obj_lu_find_id_and_span_by_phdr( return res; } +#if !SPIFFS_READ_ONLY // Allocates a free defined page with given obj_id // Occupies object lookup entry and page // data may be NULL; where only page header is stored, len and page_offs is ignored @@ -591,7 +659,9 @@ s32_t spiffs_page_allocate_data( return res; } +#endif // !SPIFFS_READ_ONLY +#if !SPIFFS_READ_ONLY // Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page. // If page data is null, provided header is used for metainfo and page data is physically copied. s32_t spiffs_page_move( @@ -654,7 +724,9 @@ s32_t spiffs_page_move( res = spiffs_page_delete(fs, src_pix); return res; } +#endif // !SPIFFS_READ_ONLY +#if !SPIFFS_READ_ONLY // Deletes a page and removes it from object lookup. s32_t spiffs_page_delete( spiffs *fs, @@ -683,12 +755,14 @@ s32_t spiffs_page_delete( return res; } +#endif // !SPIFFS_READ_ONLY +#if !SPIFFS_READ_ONLY // Create an object index header page with empty index and undefined length s32_t spiffs_object_create( spiffs *fs, spiffs_obj_id obj_id, - u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[SPIFFS_OBJ_NAME_LEN], spiffs_obj_type type, spiffs_page_ix *objix_hdr_pix) { s32_t res = SPIFFS_OK; @@ -719,7 +793,7 @@ s32_t spiffs_object_create( oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED); oix_hdr.type = type; oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page - strncpy((char *)&oix_hdr.name, (char *)name, SPIFFS_OBJ_NAME_LEN); + strncpy((char*)&oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN); // update page @@ -735,7 +809,9 @@ s32_t spiffs_object_create( return res; } +#endif // !SPIFFS_READ_ONLY +#if !SPIFFS_READ_ONLY // update object index header with any combination of name/size/index // new_objix_hdr_data may be null, if so the object index header page is loaded // name may be null, if so name is not changed @@ -746,7 +822,7 @@ s32_t spiffs_object_update_index_hdr( spiffs_obj_id obj_id, spiffs_page_ix objix_hdr_pix, u8_t *new_objix_hdr_data, - u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[SPIFFS_OBJ_NAME_LEN], u32_t size, spiffs_page_ix *new_pix) { s32_t res = SPIFFS_OK; @@ -770,7 +846,7 @@ s32_t spiffs_object_update_index_hdr( // change name if (name) { - strncpy((char *)objix_hdr->name, (char *)name, SPIFFS_OBJ_NAME_LEN); + strncpy((char*)objix_hdr->name, (const char*)name, SPIFFS_OBJ_NAME_LEN); } if (size) { objix_hdr->size = size; @@ -790,18 +866,19 @@ s32_t spiffs_object_update_index_hdr( return res; } +#endif // !SPIFFS_READ_ONLY void spiffs_cb_object_event( spiffs *fs, spiffs_fd *fd, int ev, - spiffs_obj_id obj_id, + spiffs_obj_id obj_id_raw, spiffs_span_ix spix, spiffs_page_ix new_pix, u32_t new_size) { (void)fd; // update index caches in all file descriptors - obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG; + spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG; u32_t i; spiffs_fd *fds = (spiffs_fd *)fs->fd_space; for (i = 0; i < fs->fd_count; i++) { @@ -828,6 +905,22 @@ void spiffs_cb_object_event( } } } + + // callback to user if object index header + if (fs->file_cb_f && spix == 0 && (obj_id_raw & SPIFFS_OBJ_ID_IX_FLAG)) { + spiffs_fileop_type op; + if (ev == SPIFFS_EV_IX_NEW) { + op = SPIFFS_CB_CREATED; + } else if (ev == SPIFFS_EV_IX_UPD) { + op = SPIFFS_CB_UPDATED; + } else if (ev == SPIFFS_EV_IX_DEL) { + op = SPIFFS_CB_DELETED; + } else { + SPIFFS_DBG(" callback: WARNING unknown callback event %02x\n", ev); + return; // bail out + } + fs->file_cb_f(fs, op, obj_id, new_pix); + } } // Open object by id @@ -886,6 +979,7 @@ s32_t spiffs_object_open_by_page( return res; } +#if !SPIFFS_READ_ONLY // Append to object // keep current object index (header) page in fs->work buffer s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { @@ -1125,8 +1219,10 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { } return res; -} +} // spiffs_object_append +#endif // !SPIFFS_READ_ONLY +#if !SPIFFS_READ_ONLY // Modify object // keep current object index (header) page in fs->work buffer s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { @@ -1326,16 +1422,17 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) { } return res; -} +} // spiffs_object_modify +#endif // !SPIFFS_READ_ONLY static s32_t spiffs_object_find_object_index_header_by_name_v( spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix bix, int ix_entry, - u32_t user_data, - void *user_p) { - (void)user_data; + const void *user_const_p, + void *user_var_p) { + (void)user_var_p; s32_t res; spiffs_page_object_ix_header objix_hdr; spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry); @@ -1349,7 +1446,7 @@ static s32_t spiffs_object_find_object_index_header_by_name_v( if (objix_hdr.p_hdr.span_ix == 0 && (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { - if (strncmp((char *)user_p, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN) == 0) { + if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) { return SPIFFS_OK; } } @@ -1360,7 +1457,7 @@ static s32_t spiffs_object_find_object_index_header_by_name_v( // Finds object index header page by name s32_t spiffs_object_find_object_index_header_by_name( spiffs *fs, - u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[SPIFFS_OBJ_NAME_LEN], spiffs_page_ix *pix) { s32_t res; spiffs_block_ix bix; @@ -1372,8 +1469,8 @@ s32_t spiffs_object_find_object_index_header_by_name( 0, 0, spiffs_object_find_object_index_header_by_name_v, - 0, name, + 0, &bix, &entry); @@ -1392,6 +1489,7 @@ s32_t spiffs_object_find_object_index_header_by_name( return res; } +#if !SPIFFS_READ_ONLY // Truncates object to new size. If new size is null, object may be removed totally s32_t spiffs_object_truncate( spiffs_fd *fd, @@ -1400,8 +1498,16 @@ s32_t spiffs_object_truncate( s32_t res = SPIFFS_OK; spiffs *fs = fd->fs; - res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs)); - SPIFFS_CHECK_RES(res); + if ((fd->size == SPIFFS_UNDEFINED_LEN || fd->size == 0) && !remove) { + // no op + return res; + } + + // need 2 pages if not removing: object index page + possibly chopped data page + if (remove == 0) { + res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs) * 2); + SPIFFS_CHECK_RES(res); + } spiffs_page_ix objix_pix = fd->objix_hdr_pix; spiffs_span_ix data_spix = (fd->size > 0 ? fd->size-1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs); @@ -1440,11 +1546,18 @@ s32_t spiffs_object_truncate( SPIFFS_CHECK_RES(res); spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0); if (prev_objix_spix > 0) { - // update object index header page - SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %i\n", fd->objix_hdr_pix, prev_objix_spix, cur_size); - res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, - fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix); - SPIFFS_CHECK_RES(res); + // Update object index header page, unless we totally want to remove the file. + // If fully removing, we're not keeping consistency as good as when storing the header between chunks, + // would we be aborted. But when removing full files, a crammed system may otherwise + // report ERR_FULL a la windows. We cannot have that. + // Hence, take the risk - if aborted, a file check would free the lost pages and mend things + // as the file is marked as fully deleted in the beginning. + if (remove == 0) { + SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %i\n", fd->objix_hdr_pix, prev_objix_spix, cur_size); + res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, + fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix); + SPIFFS_CHECK_RES(res); + } fd->size = cur_size; } } @@ -1480,7 +1593,7 @@ s32_t spiffs_object_truncate( SPIFFS_DBG("truncate: got data pix %04x\n", data_pix); - if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) { + if (new_size == 0 || remove || cur_size - new_size >= SPIFFS_DATA_PAGE_SIZE(fs)) { // delete full data page res = spiffs_page_data_check(fs, fd, data_pix, data_spix); if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) { @@ -1611,7 +1724,8 @@ s32_t spiffs_object_truncate( fd->size = cur_size; return res; -} +} // spiffs_object_truncate +#endif // !SPIFFS_READ_ONLY s32_t spiffs_object_read( spiffs_fd *fd, @@ -1691,6 +1805,7 @@ s32_t spiffs_object_read( return res; } +#if !SPIFFS_READ_ONLY typedef struct { spiffs_obj_id min_obj_id; spiffs_obj_id max_obj_id; @@ -1699,10 +1814,10 @@ typedef struct { } spiffs_free_obj_id_state; static s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, - u32_t user_data, void *user_p) { + const void *user_const_p, void *user_var_p) { if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) { - spiffs_obj_id min_obj_id = user_data; - u8_t *conflicting_name = (u8_t *)user_p; + spiffs_obj_id min_obj_id = *((spiffs_obj_id*)user_var_p); + const u8_t *conflicting_name = (const u8_t*)user_const_p; // if conflicting name parameter is given, also check if this name is found in object index hdrs if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) { @@ -1715,7 +1830,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id i if (objix_hdr.p_hdr.span_ix == 0 && (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) == (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) { - if (strncmp((char *)user_p, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN) == 0) { + if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) { return SPIFFS_ERR_CONFLICTING_NAME; } } @@ -1732,11 +1847,11 @@ static s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id i } static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, - u32_t user_data, void *user_p) { - (void)user_data; + const void *user_const_p, void *user_var_p) { + (void)user_var_p; if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED && (id & SPIFFS_OBJ_ID_IX_FLAG)) { s32_t res; - spiffs_free_obj_id_state *state = (spiffs_free_obj_id_state *)user_p; + const spiffs_free_obj_id_state *state = (const spiffs_free_obj_id_state*)user_const_p; spiffs_page_object_ix_header objix_hdr; res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, @@ -1745,7 +1860,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id ((objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) == (SPIFFS_PH_FLAG_DELET))) { // ok object look up entry - if (state->conflicting_name && strncmp((const char *)state->conflicting_name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN) == 0) { + if (state->conflicting_name && strcmp((const char *)state->conflicting_name, (char *)objix_hdr.name) == 0) { return SPIFFS_ERR_CONFLICTING_NAME; } @@ -1764,10 +1879,10 @@ static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id // Scans thru all object lookup for object index header pages. If total possible number of // object ids cannot fit into a work buffer, these are grouped. When a group containing free // object ids is found, the object lu is again scanned for object ids within group and bitmasked. -// Finally, the bitmasked is searched for a free id -s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *conflicting_name) { +// Finally, the bitmask is searched for a free id +s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8_t *conflicting_name) { s32_t res = SPIFFS_OK; - u32_t max_objects = (SPIFFS_CFG_PHYS_SZ(fs) / (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) / 2; + u32_t max_objects = (fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) / 2; spiffs_free_obj_id_state state; spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE; state.min_obj_id = 1; @@ -1784,8 +1899,8 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co SPIFFS_DBG("free_obj_id: BITM min:%04x max:%04x\n", state.min_obj_id, state.max_obj_id); memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); - res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, state.min_obj_id, - conflicting_name, 0, 0); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, + conflicting_name, &state.min_obj_id, 0, 0); if (res == SPIFFS_VIS_END) res = SPIFFS_OK; SPIFFS_CHECK_RES(res); // traverse bitmask until found free obj_id @@ -1849,7 +1964,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%i\n", state.min_obj_id, state.max_obj_id, state.compaction); memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs)); - res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, 0, &state, 0, 0); + res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, &state, 0, 0, 0); if (res == SPIFFS_VIS_END) res = SPIFFS_OK; SPIFFS_CHECK_RES(res); state.conflicting_name = 0; // searched for conflicting name once, no need to do it again @@ -1858,6 +1973,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *co return res; } +#endif // !SPIFFS_READ_ONLY s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd) { u32_t i; diff --git a/components/spiffs/spiffs_nucleus.h b/components/spiffs/spiffs_nucleus.h index c5c3b9e4..df7a9d8e 100644 --- a/components/spiffs/spiffs_nucleus.h +++ b/components/spiffs/spiffs_nucleus.h @@ -131,7 +131,15 @@ #define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0) #define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1) -#define SPIFFS_MAGIC(fs) ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) +#if SPIFFS_USE_MAGIC +#if !SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_MAGIC(fs, bix) \ + ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) +#else // SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_MAGIC(fs, bix) \ + ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix)))) +#endif // SPIFFS_USE_MAGIC_LENGTH +#endif // SPIFFS_USE_MAGIC #define SPIFFS_CONFIG_MAGIC (0x20090315) @@ -264,26 +272,26 @@ #define SPIFFS_API_CHECK_MOUNT(fs) \ if (!SPIFFS_CHECK_MOUNT((fs))) { \ (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \ - return -1; \ + return SPIFFS_ERR_NOT_MOUNTED; \ } #define SPIFFS_API_CHECK_CFG(fs) \ if (!SPIFFS_CHECK_CFG((fs))) { \ (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \ - return -1; \ + return SPIFFS_ERR_NOT_CONFIGURED; \ } #define SPIFFS_API_CHECK_RES(fs, res) \ if ((res) < SPIFFS_OK) { \ (fs)->err_code = (res); \ - return -1; \ + return (res); \ } #define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \ if ((res) < SPIFFS_OK) { \ (fs)->err_code = (res); \ SPIFFS_UNLOCK(fs); \ - return -1; \ + return (res); \ } #define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \ @@ -311,6 +319,26 @@ // stop searching at end of all look up pages #define SPIFFS_VIS_NO_WRAP (1<<2) +#if SPIFFS_HAL_CALLBACK_EXTRA + +#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \ + (_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src)) +#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \ + (_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst)) +#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \ + (_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len)) + +#else // SPIFFS_HAL_CALLBACK_EXTRA + +#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \ + (_fs)->cfg.hal_write_f((_paddr), (_len), (_src)) +#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \ + (_fs)->cfg.hal_read_f((_paddr), (_len), (_dst)) +#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \ + (_fs)->cfg.hal_erase_f((_paddr), (_len)) + +#endif // SPIFFS_HAL_CALLBACK_EXTRA + #if SPIFFS_CACHE #define SPIFFS_CACHE_FLAG_DIRTY (1<<0) @@ -416,9 +444,14 @@ typedef struct __attribute(( packed )) { // object index header page header typedef struct __attribute(( packed )) +#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES + __attribute(( aligned(sizeof(spiffs_page_ix)) )) +#endif { // common page header spiffs_page_header p_hdr; + // alignment + u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))]; // size of object u32_t size; // type of object @@ -430,11 +463,12 @@ typedef struct __attribute(( packed )) // object index page header typedef struct __attribute(( packed )) { spiffs_page_header p_hdr; + u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))]; } spiffs_page_object_ix; // callback func for object lookup visitor typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry, - u32_t user_data, void *user_p); + const void *user_const_p, void *user_var_p); #if SPIFFS_CACHE @@ -495,8 +529,8 @@ s32_t spiffs_obj_lu_find_entry_visitor( u8_t flags, spiffs_obj_id obj_id, spiffs_visitor_f v, - u32_t user_data, - void *user_p, + const void *user_const_p, + void *user_var_p, spiffs_block_ix *block_ix, int *lu_entry); @@ -504,6 +538,11 @@ s32_t spiffs_erase_block( spiffs *fs, spiffs_block_ix bix); +#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH +s32_t spiffs_probe( + spiffs_config *cfg); +#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH + // --------------- s32_t spiffs_obj_lu_scan( @@ -512,7 +551,7 @@ s32_t spiffs_obj_lu_scan( s32_t spiffs_obj_lu_find_free_obj_id( spiffs *fs, spiffs_obj_id *obj_id, - u8_t *conflicting_name); + const u8_t *conflicting_name); s32_t spiffs_obj_lu_find_free( spiffs *fs, @@ -573,7 +612,7 @@ s32_t spiffs_page_delete( s32_t spiffs_object_create( spiffs *fs, spiffs_obj_id obj_id, - u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[SPIFFS_OBJ_NAME_LEN], spiffs_obj_type type, spiffs_page_ix *objix_hdr_pix); @@ -583,7 +622,7 @@ s32_t spiffs_object_update_index_hdr( spiffs_obj_id obj_id, spiffs_page_ix objix_hdr_pix, u8_t *new_objix_hdr_data, - u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[SPIFFS_OBJ_NAME_LEN], u32_t size, spiffs_page_ix *new_pix); @@ -635,7 +674,7 @@ s32_t spiffs_object_truncate( s32_t spiffs_object_find_object_index_header_by_name( spiffs *fs, - u8_t name[SPIFFS_OBJ_NAME_LEN], + const u8_t name[SPIFFS_OBJ_NAME_LEN], spiffs_page_ix *pix); // ---------------