Grabbed latest spiffs + vfs layer from dev branch.

Also included the recent LVM fix.

Platform flash layer not yet functional.
This commit is contained in:
Johny Mattsson 2016-09-21 17:51:50 +10:00
parent fe602d2d7e
commit 4f1b33d522
24 changed files with 2585 additions and 517 deletions

View File

@ -12,9 +12,9 @@
#include "platform.h"
#include <string.h>
#include <stdlib.h>
#include "flash_fs.h"
#include "flash_api.h"
#include "vfs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "driver/console.h"
#include "task/task.h"
@ -62,23 +62,12 @@ void nodemcu_init(void)
return;
}
// FIXME: this breaks horribly on the ESP32 at the moment; possibly all flash writes?
#if defined(FLASH_SAFE_API) && defined(__ESP8266__)
if( flash_safe_get_size_byte() != flash_rom_get_size_byte()) {
#if defined(FLASH_SAFE_API)
if (flash_safe_get_size_byte() != flash_rom_get_size_byte()) {
NODE_ERR("Self adjust flash size.\n");
// Fit hardware real flash size.
flash_rom_set_size_byte(flash_safe_get_size_byte());
if( !fs_format() )
{
NODE_ERR( "\ni*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
}
else{
NODE_ERR( "format done.\n" );
}
fs_unmount(); // mounted by format.
// Reboot to get SDK to use (or write) init data at new location
system_restart ();
@ -87,9 +76,16 @@ void nodemcu_init(void)
}
#endif // defined(FLASH_SAFE_API)
#if defined ( BUILD_SPIFFS )
fs_mount();
// test_spiffs();
#if defined ( CONFIG_BUILD_SPIFFS )
if (!vfs_mount("/FLASH", 0)) {
// Failed to mount -- try reformat
NODE_ERR("Formatting file system. Please wait...\n");
if (1 || !vfs_format()) { // FIXME
NODE_ERR( "*** ERROR ***: unable to format. FS might be compromised.\n" );
NODE_ERR( "It is advised to re-flash the NodeMCU image.\n" );
}
// Note that fs_format leaves the file system mounted
}
#endif
task_post_low(task_get_id(start_lua), 0);
@ -120,5 +116,5 @@ void app_main (void)
console_init (&cfg, input_task);
xTaskCreate (
nodemcu_main, "nodemcu", 2048, 0, configTIMER_TASK_PRIORITY +1, NULL);
nodemcu_main, "nodemcu", 2560, 0, tskIDLE_PRIORITY +1, NULL);
}

View File

@ -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;
}

View File

@ -9,7 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "flash_fs.h"
#include "vfs.h"
#define liolib_c
#define LUA_LIB
@ -39,7 +39,7 @@ static const int liolib_keys[] = {(int)&luaL_callmeta, (int)&luaL_typerror, (int
static const char *const fnames[] = {"input", "output"};
static int pushresult (lua_State *L, int i, const char *filename) {
int en = fs_error(0); /* calls to Lua API may change this value */
int en = vfs_ferrno(0); /* calls to Lua API may change this value */
if (i) {
lua_pushboolean(L, 1);
return 1;
@ -57,7 +57,7 @@ static int pushresult (lua_State *L, int i, const char *filename) {
static void fileerror (lua_State *L, int arg, const char *filename) {
lua_pushfstring(L, "%s: err(%d)", filename, fs_error(0));
lua_pushfstring(L, "%s: err(%d)", filename, vfs_ferrno(0));
luaL_argerror(L, arg, lua_tostring(L, -1));
}
@ -130,7 +130,7 @@ static int io_pclose (lua_State *L) {
*/
static int io_fclose (lua_State *L) {
int *p = tofilep(L);
int ok = (fs_close(*p) == 0);
int ok = (vfs_close(*p) == 0);
*p = FS_OPEN_OK - 1;
return pushresult(L, ok, NULL);
}
@ -149,7 +149,7 @@ static int aux_close (lua_State *L) {
lua_pushliteral(L, "cannot close standard file");
return 2;
}
int ok = (fs_close(*p) == 0);
int ok = (vfs_close(*p) == 0);
*p = FS_OPEN_OK - 1;
return pushresult(L, ok, NULL);
#endif
@ -187,7 +187,7 @@ static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
int *pf = newfile(L);
*pf = fs_open(filename, fs_mode2flag(mode));
*pf = vfs_open(filename, mode);
return (*pf == FS_OPEN_OK - 1) ? pushresult(L, 0, filename) : 1;
}
@ -201,7 +201,7 @@ static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
int *pf = newfile(L);
*pf = lua_popen(L, filename, fs_mode2flag(mode));
*pf = lua_popen(L, filename, mode);
return (*pf == FS_OPEN_OK - 1) ? pushresult(L, 0, filename) : 1;
}
@ -230,7 +230,7 @@ static int g_iofile (lua_State *L, int f, const char *mode) {
const char *filename = lua_tostring(L, 1);
if (filename) {
int *pf = newfile(L);
*pf = fs_open(filename, fs_mode2flag(mode));
*pf = vfs_open(filename, mode);
if (*pf == FS_OPEN_OK - 1)
fileerror(L, 1, filename);
}
@ -282,7 +282,7 @@ static int io_lines (lua_State *L) {
else {
const char *filename = luaL_checkstring(L, 1);
int *pf = newfile(L);
*pf = fs_open(filename, FS_RDONLY);
*pf = vfs_open(filename, "r");
if (*pf == FS_OPEN_OK - 1)
fileerror(L, 1, filename);
aux_lines(L, lua_gettop(L), 1);
@ -300,7 +300,7 @@ static int io_lines (lua_State *L) {
#if 0
static int read_number (lua_State *L, int f) {
lua_Number d;
if (fs_scanf(f, LUA_NUMBER_SCAN, &d) == 1) {
if (vfs_scanf(f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d);
return 1;
}
@ -312,8 +312,8 @@ static int read_number (lua_State *L, int f) {
#endif
static int test_eof (lua_State *L, int f) {
int c = fs_getc(f);
fs_ungetc(c, f);
int c = vfs_getc(f);
vfs_ungetc(c, f);
lua_pushlstring(L, NULL, 0);
return (c != EOF);
}
@ -325,7 +325,7 @@ static int read_line (lua_State *L, int f) {
for (;;) {
size_t l;
char *p = luaL_prepbuffer(&b);
if (fs_gets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
if (vfs_gets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
luaL_pushresult(&b); /* close buffer */
return (lua_objlen(L, -1) > 0); /* check whether read something */
}
@ -347,7 +347,7 @@ static int read_line (lua_State *L, int f) {
signed char c = EOF;
int i = 0;
do{
c = (signed char)fs_getc(f);
c = (signed char)vfs_getc(f);
if(c==EOF){
break;
}
@ -377,7 +377,7 @@ static int read_chars (lua_State *L, int f, size_t n) {
do {
char *p = luaL_prepbuffer(&b);
if (rlen > n) rlen = n; /* cannot read more than asked */
nr = fs_read(f, p, rlen);
nr = vfs_read(f, p, rlen);
luaL_addsize(&b, nr);
n -= nr; /* still have to read `n' chars */
} while (n > 0 && nr == rlen); /* until end of count or eof */
@ -390,7 +390,7 @@ static int g_read (lua_State *L, int f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
fs_clearerr(f);
//vfs_clearerr(f);
if (nargs == 0) { /* no arguments? */
success = read_line(L, f);
n = first+1; /* to return 1 result */
@ -425,7 +425,7 @@ static int g_read (lua_State *L, int f, int first) {
}
}
}
if (fs_error(f))
if (vfs_ferrno(f))
return pushresult(L, 0, NULL);
if (!success) {
lua_pop(L, 1); /* remove last result */
@ -453,8 +453,8 @@ static int io_readline (lua_State *L) {
return 0;
}
sucess = read_line(L, *pf);
if (fs_error(*pf))
return luaL_error(L, "err(%d)", fs_error(*pf));
if (vfs_ferrno(*pf))
return luaL_error(L, "err(%d)", vfs_ferrno(*pf));
if (sucess) return 1;
else { /* EOF */
if (lua_toboolean(L, lua_upvalueindex(2))) { /* generator created file? */
@ -477,14 +477,14 @@ static int g_write (lua_State *L, int f, int arg) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
fs_printf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
vfs_printf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
}
else
#endif
{
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
status = status && (fs_write(f, s, l) == l);
status = status && (vfs_write(f, s, l) == l);
}
}
return pushresult(L, status, NULL);
@ -502,16 +502,16 @@ static int f_write (lua_State *L) {
static int f_seek (lua_State *L) {
static const int mode[] = {FS_SEEK_SET, FS_SEEK_CUR, FS_SEEK_END};
static const int mode[] = {VFS_SEEK_SET, VFS_SEEK_CUR, VFS_SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
int f = tofile(L);
int op = luaL_checkoption(L, 2, "cur", modenames);
long offset = luaL_optlong(L, 3, 0);
op = fs_seek(f, offset, mode[op]);
op = vfs_lseek(f, offset, mode[op]);
if (op)
return pushresult(L, 0, NULL); /* error */
else {
lua_pushinteger(L, fs_tell(f));
lua_pushinteger(L, vfs_tell(f));
return 1;
}
}
@ -530,12 +530,12 @@ static int f_setvbuf (lua_State *L) {
static int io_flush (lua_State *L) {
return pushresult(L, fs_flush(getiofile(L, IO_OUTPUT)) == 0, NULL);
return pushresult(L, vfs_flush(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static int f_flush (lua_State *L) {
return pushresult(L, fs_flush(tofile(L)) == 0, NULL);
return pushresult(L, vfs_flush(tofile(L)) == 0, NULL);
}
#undef MIN_OPT_LEVEL

View File

@ -19,8 +19,8 @@
#include <fcntl.h>
#ifndef LUA_CROSS_COMPILER
#include "flash_fs.h"
#include "c_stdlib.h"
#include "vfs.h"
#include "c_stdlib.h" // for c_getenv
#endif
#include "lauxlib.h"
@ -341,9 +341,9 @@ static int readable (const char *filename) {
}
#else
static int readable (const char *filename) {
int f = fs_open(filename, FS_RDONLY); /* try to open file */
if (f < FS_OPEN_OK) return 0; /* open failed */
fs_close(f);
int f = vfs_open(filename, "r"); /* try to open file */
if (!f) return 0; /* open failed */
vfs_close(f);
return 1;
}
#endif

View File

@ -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;
}

View File

@ -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

View File

@ -2,6 +2,8 @@
#define _PLATFORM_H_
#include <stdint.h>
#include <stdio.h>
#include "sdkconfig.h"
#include "cpu_esp32.h"
#define PLATFORM_ALIGNMENT __attribute__((aligned(4)))

View File

@ -0,0 +1,250 @@
#ifndef __VFS_H__
#define __VFS_H__
#include <stdint.h>
#include <stdbool.h>
#include "vfs_int.h"
// DEPRECATED, DON'T USE
// Check for fd != 0 instead
#define FS_OPEN_OK 1
// ---------------------------------------------------------------------------
// file functions
//
// vfs_close - close file descriptor and free memory
// fd: file descriptor
// Returns: VFS_RES_OK or negative value in case of error
inline int32_t vfs_close( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->close( f ) : VFS_RES_ERR;
}
// vfs_read - read data from file
// fd: file descriptor
// ptr: destination data buffer
// len: requested length
// Returns: Number of bytes read, or VFS_RES_ERR in case of error
inline int32_t vfs_read( int fd, void *ptr, size_t len ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->read( f, ptr, len ) : VFS_RES_ERR;
}
// vfs_write - write data to file
// fd: file descriptor
// ptr: source data buffer
// len: requested length
// Returns: Number of bytes written, or VFS_RES_ERR in case of error
inline int32_t vfs_write( int fd, const void *ptr, size_t len ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->write( f, ptr, len ) : VFS_RES_ERR;
}
int vfs_getc( int fd );
int vfs_ungetc( int c, int fd );
// vfs_lseek - move read/write pointer
// fd: file descriptor
// off: offset
// whence: VFS_SEEK_SET - set pointer to off
// VFS_SEEK_CUR - set pointer to current position + off
// VFS_SEEK_END - set pointer to end of file + off
// Returns: New position, or VFS_RES_ERR in case of error
inline int32_t vfs_lseek( int fd, int32_t off, int whence ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->lseek( f, off, whence ) : VFS_RES_ERR;
}
// vfs_eof - test for end-of-file
// fd: file descriptor
// Returns: 0 if not at end, != 0 if end of file
inline int32_t vfs_eof( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->eof( f ) : VFS_RES_ERR;
}
// vfs_tell - get read/write position
// fd: file descriptor
// Returns: Current position
inline int32_t vfs_tell( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->tell( f ) : VFS_RES_ERR;
}
// vfs_flush - flush write cache to file
// fd: file descriptor
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
inline int32_t vfs_flush( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f ? f->fns->flush( f ) : VFS_RES_ERR;
}
// vfs_size - get current file size
// fd: file descriptor
// Returns: File size
inline uint32_t vfs_size( int fd ) {
vfs_file *f = (vfs_file *)fd;
return f && f->fns->size ? f->fns->size( f ) : 0;
}
// vfs_ferrno - get file system specific errno
// fd: file descriptor
// Returns: errno
int32_t vfs_ferrno( int fd );
// ---------------------------------------------------------------------------
// dir functions
//
// vfs_closedir - close directory descriptor and free memory
// dd: dir descriptor
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
inline int32_t vfs_closedir( vfs_dir *dd ) { return dd->fns->close( dd ); }
// vfs_readdir - read next directory item
// dd: dir descriptor
// Returns: item object, or NULL in case of error
inline vfs_item *vfs_readdir( vfs_dir *dd ) { return dd->fns->readdir( dd ); }
// ---------------------------------------------------------------------------
// dir item functions
//
// vfs_closeitem - close directory item and free memory
// di: item descriptor
// Returns: nothing
inline void vfs_closeitem( vfs_item *di ) { return di->fns->close( di ); }
// vfs_item_size - get item's size
// di: item descriptor
// Returns: Item size
inline uint32_t vfs_item_size( vfs_item *di ) { return di->fns->size( di ); }
// vfs_item_time - get item's modification time
// di: item descriptor
// Returns: Item modification time
inline int32_t vfs_item_time( vfs_item *di, struct vfs_time *tm ) { return di->fns->time ? di->fns->time( di, tm ) : VFS_RES_ERR; }
// vfs_item_name - get item's name
// di: item descriptor
// Returns: Item name
inline const char *vfs_item_name( vfs_item *di ) { return di->fns->name( di ); }
// vfs_item_is_dir - check for directory
// di: item descriptor
// Returns: >0 if item is a directory, 0 if not
inline int32_t vfs_item_is_dir( vfs_item *di ) { return di->fns->is_dir ? di->fns->is_dir( di ) : 0; }
// vfs_item_is_rdonly - check for read-only
// di: item descriptor
// Returns: >0 if item is read only, 0 if not
inline int32_t vfs_item_is_rdonly( vfs_item *di ) { return di->fns->is_rdonly ? di->fns->is_rdonly( di ) : 0; }
// vfs_item_is_hidden - check for hidden attribute
// di: item descriptor
// Returns: >0 if item is hidden, 0 if not
inline int32_t vfs_item_is_hidden( vfs_item *di ) { return di->fns->is_hidden ? di->fns->is_hidden( di ) : 0; }
// vfs_item_is_sys - check for sys attribute
// di: item descriptor
// Returns: >0 if item is sys, 0 if not
inline int32_t vfs_item_is_sys( vfs_item *di ) { return di->fns->is_sys ? di->fns->is_sys( di ) : 0; }
// vfs_item_is_arch - check for archive attribute
// di: item descriptor
// Returns: >0 if item is archive, 0 if not
inline int32_t vfs_item_is_arch( vfs_item *di ) { return di->fns->is_arch ? di->fns->is_arch( di ) : 0; }
// ---------------------------------------------------------------------------
// volume functions
//
// vfs_umount - unmount logical drive and free memory
// vol: volume object
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
inline int32_t vfs_umount( vfs_vol *vol ) { return vol->fns->umount( vol ); }
// ---------------------------------------------------------------------------
// file system functions
//
// vfs_mount - unmount logical drive
// name: name of logical drive
// num: drive's physical number (eg. SS/CS pin), negative values are ignored
// Returns: Volume object, or NULL in case of error
vfs_vol *vfs_mount( const char *name, int num );
// vfs_open - open file
// name: file name
// mode: open mode
// Returns: File descriptor, or NULL in case of error
int vfs_open( const char *name, const char *mode );
// vfs_opendir - open directory
// name: dir name
// Returns: Directory descriptor, or NULL in case of error
vfs_dir *vfs_opendir( const char *name );
// vfs_stat - stat file or directory
// name: file or directory name
// Returns: Item object, or NULL in case of error
vfs_item *vfs_stat( const char *name );
// vfs_remove - remove file or directory
// name: file or directory name
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_remove( const char *name );
// vfs_rename - rename file or directory
// name: file or directory name
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_rename( const char *oldname, const char *newname );
// vfs_mkdir - create directory
// name: directory name
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_mkdir( const char *name );
// vfs_fsinfo - get file system info
// name: logical drive identifier
// total: receives total amount
// used: received used amount
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_fsinfo( const char *name, uint32_t *total, uint32_t *used );
// vfs_format - format file system
// Returns: 1, or 0 in case of error
int32_t vfs_format( void );
// vfs_chdir - change default directory
// path: new default directory
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_chdir( const char *path );
// vfs_fscfg - query configuration settings of file system
// phys_addr: pointer to store physical address information
// phys_size: pointer to store physical size information
// Returns: VFS_RES_OK, or VFS_RES_ERR in case of error
int32_t vfs_fscfg( const char *name, uint32_t *phys_addr, uint32_t *phys_size);
// vfs_errno - get file system specific errno
// name: logical drive identifier
// Returns: errno
int32_t vfs_errno( const char *name );
// vfs_clearerr - cleaer file system specific errno
void vfs_clearerr( const char *name );
// vfs_register_rtc_cb - register callback function for RTC query
// cb: pointer to callback function
void vfs_register_rtc_cb( int32_t (*cb)( vfs_time *tm ) );
// vfs_basename - identify basename (incl. extension)
// path: full file system path
// Returns: pointer to basename within path string
const char *vfs_basename( const char *path );
#endif

View File

@ -0,0 +1,136 @@
// internal definitions for vfs
#ifndef __VFS_INT_H__
#define __VFS_INT_H__
#include <string.h>
#include <stdint.h>
#if 0
#include "spiffs.h"
#include "fatfs_prefix_lib.h"
#include "ff.h"
#endif
#define VFS_EOF -1
enum vfs_filesystems {
VFS_FS_NONE = 0,
VFS_FS_SPIFFS,
VFS_FS_FATFS
};
enum vfs_seek {
VFS_SEEK_SET = 0,
VFS_SEEK_CUR,
VFS_SEEK_END
};
enum vfs_result {
VFS_RES_OK = 0,
VFS_RES_ERR = -1
};
struct vfs_time {
int year, mon, day;
int hour, min, sec;
};
typedef struct vfs_time vfs_time;
// generic file descriptor
struct vfs_file {
int fs_type;
const struct vfs_file_fns *fns;
};
typedef const struct vfs_file vfs_file;
// file descriptor functions
struct vfs_file_fns {
int32_t (*close)( const struct vfs_file *fd );
int32_t (*read)( const struct vfs_file *fd, void *ptr, size_t len );
int32_t (*write)( const struct vfs_file *fd, const void *ptr, size_t len );
int32_t (*lseek)( const struct vfs_file *fd, int32_t off, int whence );
int32_t (*eof)( const struct vfs_file *fd );
int32_t (*tell)( const struct vfs_file *fd );
int32_t (*flush)( const struct vfs_file *fd );
uint32_t (*size)( const struct vfs_file *fd );
int32_t (*ferrno)( const struct vfs_file *fd );
};
typedef const struct vfs_file_fns vfs_file_fns;
// generic dir item descriptor
struct vfs_item {
int fs_type;
const struct vfs_item_fns *fns;
};
typedef const struct vfs_item vfs_item;
// directory item functions
struct vfs_item_fns {
void (*close)( const struct vfs_item *di );
uint32_t (*size)( const struct vfs_item *di );
int32_t (*time)( const struct vfs_item *di, struct vfs_time *tm );
const char *(*name)( const struct vfs_item *di );
int32_t (*is_dir)( const struct vfs_item *di );
int32_t (*is_rdonly)( const struct vfs_item *di );
int32_t (*is_hidden)( const struct vfs_item *di );
int32_t (*is_sys)( const struct vfs_item *di );
int32_t (*is_arch)( const struct vfs_item *di );
};
typedef const struct vfs_item_fns vfs_item_fns;
// generic dir descriptor
struct vfs_dir {
int fs_type;
const struct vfs_dir_fns *fns;
};
typedef const struct vfs_dir vfs_dir;
// dir descriptor functions
struct vfs_dir_fns {
int32_t (*close)( const struct vfs_dir *dd );
vfs_item *(*readdir)( const struct vfs_dir *dd );
};
typedef const struct vfs_dir_fns vfs_dir_fns;
// generic volume descriptor
struct vfs_vol {
int fs_type;
const struct vfs_vol_fns *fns;
};
typedef const struct vfs_vol vfs_vol;
// volume functions
struct vfs_vol_fns {
int32_t (*umount)( const struct vfs_vol *vol );
};
typedef const struct vfs_vol_fns vfs_vol_fns;
struct vfs_fs_fns {
vfs_vol *(*mount)( const char *name, int num );
vfs_file *(*open)( const char *name, const char *mode );
vfs_dir *(*opendir)( const char *name );
vfs_item *(*stat)( const char *name );
int32_t (*remove)( const char *name );
int32_t (*rename)( const char *oldname, const char *newname );
int32_t (*mkdir)( const char *name );
int32_t (*fsinfo)( uint32_t *total, uint32_t *used );
int32_t (*fscfg)( uint32_t *phys_addr, uint32_t *phys_size );
int32_t (*format)( void );
int32_t (*chdrive)( const char * );
int32_t (*chdir)( const char * );
int32_t (*ferrno)( void );
void (*clearerr)( void );
};
typedef const struct vfs_fs_fns vfs_fs_fns;
vfs_fs_fns *myspiffs_realm( const char *inname, char **outname, int set_current_drive );
vfs_fs_fns *myfatfs_realm( const char *inname, char **outname, int set_current_drive );
int32_t vfs_get_rtc( vfs_time *tm );
#endif

View File

@ -0,0 +1,248 @@
#include "platform.h"
#include "flash_api.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
// ****************************************************************************
// Internal flash support functions
/* This symbol must be exported by the linker command file and contain the
* size of all the sections packed into the irom0_flash.bin file, in order
* for us to find the end of used flash.
*/
extern char _irom0_bin_min_sz[];
// Helper function: find the flash sector in which an address resides
// Return the sector number, as well as the start and end address of the sector
static uint32_t flashh_find_sector( uint32_t address, uint32_t *pstart, uint32_t *pend )
{
#ifdef INTERNAL_FLASH_SECTOR_SIZE
// All the sectors in the flash have the same size, so just align the address
uint32_t sect_id = address / INTERNAL_FLASH_SECTOR_SIZE;
if( pstart )
*pstart = sect_id * INTERNAL_FLASH_SECTOR_SIZE ;
if( pend )
*pend = ( sect_id + 1 ) * INTERNAL_FLASH_SECTOR_SIZE - 1;
return sect_id;
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
// The flash has blocks of different size
// Their size is decribed in the INTERNAL_FLASH_SECTOR_ARRAY macro
const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
uint32_t total = 0, i = 0;
while( ( total <= address ) && ( i < sizeof( flash_sect_size ) / sizeof( uint32_t ) ) )
total += flash_sect_size[ i ++ ];
if( pstart )
*pstart = ( total - flash_sect_size[ i - 1 ] );
if( pend )
*pend = total - 1;
return i - 1;
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
}
uint32_t platform_flash_get_sector_of_address( uint32_t addr )
{
return flashh_find_sector( addr, NULL, NULL );
}
uint32_t platform_flash_get_num_sectors(void)
{
#ifdef INTERNAL_FLASH_SECTOR_SIZE
return INTERNAL_FLASH_SIZE / INTERNAL_FLASH_SECTOR_SIZE;
#else // #ifdef INTERNAL_FLASH_SECTOR_SIZE
const uint32_t flash_sect_size[] = INTERNAL_FLASH_SECTOR_ARRAY;
return sizeof( flash_sect_size ) / sizeof( uint32_t );
#endif // #ifdef INTERNAL_FLASH_SECTOR_SIZE
}
uint32_t platform_flash_get_first_free_block_address( uint32_t *psect )
{
uint32_t flash_offs = IROM0_START_FLASH_ADDR + (uint32_t)_irom0_bin_min_sz;
uint32_t sect =
(flash_offs + INTERNAL_FLASH_SECTOR_SIZE-1)/INTERNAL_FLASH_SECTOR_SIZE;
++sect; /* compensate for various headers not counted in _irom0_bin_min_sz */
if (psect)
*psect = sect;
return sect * INTERNAL_FLASH_SECTOR_SIZE;
}
uint32_t platform_flash_write( const void *from, uint32_t toaddr, uint32_t size )
{
#ifndef INTERNAL_FLASH_WRITE_UNIT_SIZE
return platform_s_flash_write( from, toaddr, size );
#else // #ifindef INTERNAL_FLASH_WRITE_UNIT_SIZE
uint32_t temp, rest, ssize = size;
unsigned i;
char tmpdata[ INTERNAL_FLASH_WRITE_UNIT_SIZE ];
const uint8_t *pfrom = ( const uint8_t* )from;
const uint32_t blksize = INTERNAL_FLASH_WRITE_UNIT_SIZE;
const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;
// Align the start
if( toaddr & blkmask )
{
rest = toaddr & blkmask;
temp = toaddr & ~blkmask; // this is the actual aligned address
// memcpy( tmpdata, ( const void* )temp, blksize );
platform_s_flash_read( tmpdata, temp, blksize );
for( i = rest; size && ( i < blksize ); i ++, size --, pfrom ++ )
tmpdata[ i ] = *pfrom;
platform_s_flash_write( tmpdata, temp, blksize );
if( size == 0 )
return ssize;
toaddr = temp + blksize;
}
// The start address is now a multiple of blksize
// Compute how many bytes we can write as multiples of blksize
rest = size & blkmask;
temp = size & ~blkmask;
// Program the blocks now
if( temp )
{
platform_s_flash_write( pfrom, toaddr, temp );
toaddr += temp;
pfrom += temp;
}
// And the final part of a block if needed
if( rest )
{
// memcpy( tmpdata, ( const void* )toaddr, blksize );
platform_s_flash_read( tmpdata, toaddr, blksize );
for( i = 0; size && ( i < rest ); i ++, size --, pfrom ++ )
tmpdata[ i ] = *pfrom;
platform_s_flash_write( tmpdata, toaddr, blksize );
}
return ssize;
#endif // #ifndef INTERNAL_FLASH_WRITE_UNIT_SIZE
}
uint32_t platform_flash_read( void *to, uint32_t fromaddr, uint32_t size )
{
#ifndef INTERNAL_FLASH_READ_UNIT_SIZE
return platform_s_flash_read( to, fromaddr, size );
#else // #ifindef INTERNAL_FLASH_READ_UNIT_SIZE
uint32_t temp, rest, ssize = size;
unsigned i;
char tmpdata[ INTERNAL_FLASH_READ_UNIT_SIZE ] __attribute__ ((aligned(INTERNAL_FLASH_READ_UNIT_SIZE)));
uint8_t *pto = ( uint8_t* )to;
const uint32_t blksize = INTERNAL_FLASH_READ_UNIT_SIZE;
const uint32_t blkmask = INTERNAL_FLASH_READ_UNIT_SIZE - 1;
// Align the start
if( fromaddr & blkmask )
{
rest = fromaddr & blkmask;
temp = fromaddr & ~blkmask; // this is the actual aligned address
platform_s_flash_read( tmpdata, temp, blksize );
for( i = rest; size && ( i < blksize ); i ++, size --, pto ++ )
*pto = tmpdata[ i ];
if( size == 0 )
return ssize;
fromaddr = temp + blksize;
}
// The start address is now a multiple of blksize
// Compute how many bytes we can read as multiples of blksize
rest = size & blkmask;
temp = size & ~blkmask;
// Program the blocks now
if( temp )
{
platform_s_flash_read( pto, fromaddr, temp );
fromaddr += temp;
pto += temp;
}
// And the final part of a block if needed
if( rest )
{
platform_s_flash_read( tmpdata, fromaddr, blksize );
for( i = 0; size && ( i < rest ); i ++, size --, pto ++ )
*pto = tmpdata[ i ];
}
return ssize;
#endif // #ifndef INTERNAL_FLASH_READ_UNIT_SIZE
}
/*
* Assumptions:
* > toaddr is INTERNAL_FLASH_WRITE_UNIT_SIZE aligned
* > size is a multiple of INTERNAL_FLASH_WRITE_UNIT_SIZE
*/
uint32_t platform_s_flash_write( const void *from, uint32_t toaddr, uint32_t size )
{
SpiFlashOpResult r;
const uint32_t blkmask = INTERNAL_FLASH_WRITE_UNIT_SIZE - 1;
uint32_t *apbuf = NULL;
uint32_t fromaddr = (uint32_t)from;
if( (fromaddr & blkmask ) || (fromaddr >= INTERNAL_FLASH_MAPPED_ADDRESS)) {
apbuf = (uint32_t *)malloc(size);
if(!apbuf)
return 0;
memcpy(apbuf, from, size);
}
r = flash_write(toaddr, apbuf?(uint32 *)apbuf:(uint32 *)from, size);
if(apbuf)
free(apbuf);
if(SPI_FLASH_RESULT_OK == r)
return size;
else{
NODE_ERR( "ERROR in flash_write: r=%d at %08X\n", ( int )r, ( unsigned )toaddr);
return 0;
}
}
/*
* Assumptions:
* > fromaddr is INTERNAL_FLASH_READ_UNIT_SIZE aligned
* > size is a multiple of INTERNAL_FLASH_READ_UNIT_SIZE
*/
uint32_t platform_s_flash_read( void *to, uint32_t fromaddr, uint32_t size )
{
if (size==0)
return 0;
SpiFlashOpResult r;
const uint32_t blkmask = (INTERNAL_FLASH_READ_UNIT_SIZE - 1);
if( ((uint32_t)to) & blkmask )
{
uint32_t size2=size-INTERNAL_FLASH_READ_UNIT_SIZE;
uint32* to2=(uint32*)((((uint32_t)to)&(~blkmask))+INTERNAL_FLASH_READ_UNIT_SIZE);
r = flash_read(fromaddr, to2, size2);
if(SPI_FLASH_RESULT_OK == r)
{
memmove(to,to2,size2);
char back[ INTERNAL_FLASH_READ_UNIT_SIZE ] __attribute__ ((aligned(INTERNAL_FLASH_READ_UNIT_SIZE)));
r=flash_read(fromaddr+size2,(uint32*)back,INTERNAL_FLASH_READ_UNIT_SIZE);
memcpy((uint8_t*)to+size2,back,INTERNAL_FLASH_READ_UNIT_SIZE);
}
}
else
r = flash_read(fromaddr, (uint32 *)to, size);
if(SPI_FLASH_RESULT_OK == r)
return size;
else{
NODE_ERR( "ERROR in flash_read: r=%d at %08X\n", ( int )r, ( unsigned )fromaddr);
return 0;
}
}
int platform_flash_erase_sector( uint32_t sector_id )
{
return flash_erase( sector_id ) == SPI_FLASH_RESULT_OK ? PLATFORM_OK : PLATFORM_ERR;
}
uint32_t platform_flash_mapped2phys (uint32_t mapped_addr)
{
// FIXME: need to take actual memory maps into account!
return mapped_addr - IROM0_START_MAPPED_ADDR + IROM0_START_FLASH_ADDR;
}

469
components/platform/vfs.c Normal file
View File

@ -0,0 +1,469 @@
#include <stdlib.h>
#include <stdio.h>
#include "vfs.h"
#include "platform.h"
#define LDRV_TRAVERSAL 0
// ---------------------------------------------------------------------------
// RTC system interface
//
static int32_t (*rtc_cb)( vfs_time *tm ) = NULL;
// called by operating system
void vfs_register_rtc_cb( int32_t (*cb)( vfs_time *tm ) )
{
// allow NULL pointer to unregister callback function
rtc_cb = cb;
}
// called by file system drivers
int32_t vfs_get_rtc( vfs_time *tm )
{
if (rtc_cb) {
return rtc_cb( tm );
}
return VFS_RES_ERR;
}
static int dir_level = 1;
static const char *normalize_path( const char *path )
{
#if ! LDRV_TRAVERSAL
return path;
#else
const char *temp = path;
size_t len;
while ((len = strlen( temp )) >= 2) {
if (temp[0] == '.' && temp[1] == '.') {
--dir_level;
if (len >= 4 && dir_level > 0) {
// prepare next step
temp = &(temp[4]);
} else {
// we're at top, the remainder is expected be an absolute path
temp = &(temp[3]);
}
} else {
break;
}
}
if (dir_level > 0) {
// no traversal on root level
return path;
} else {
// path traverses via root
return temp;
}
#endif
}
// ---------------------------------------------------------------------------
// file system functions
//
vfs_vol *vfs_mount( const char *name, int num )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->mount( outname, num );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
vfs_vol *r = fs_fns->mount( outname, num );
free( outname );
return r;
}
#endif
return NULL;
}
int vfs_open( const char *name, const char *mode )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return (int)fs_fns->open( outname, mode );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int r = (int)fs_fns->open( outname, mode );
free( outname );
return r;
}
#endif
return 0;
}
vfs_dir *vfs_opendir( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->opendir( outname );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
vfs_dir *r = fs_fns->opendir( outname );
free( outname );
return r;
}
#endif
return NULL;
}
vfs_item *vfs_stat( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->stat( outname );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
vfs_item *r = fs_fns->stat( outname );
free( outname );
return r;
}
#endif
return NULL;
}
int32_t vfs_remove( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->remove( outname );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int32_t r = fs_fns->remove( outname );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_rename( const char *oldname, const char *newname )
{
vfs_fs_fns *fs_fns;
const char *normoldname = normalize_path( oldname );
const char *normnewname = normalize_path( newname );
char *oldoutname, *newoutname;
#ifdef CONFIG_BUILD_SPIFFS
if (myspiffs_realm( normoldname, &oldoutname, false )) {
if ((fs_fns = myspiffs_realm( normnewname, &newoutname, false ))) {
return fs_fns->rename( oldoutname, newoutname );
}
}
#endif
#ifdef CONFIG_BUILD_FATFS
if (myfatfs_realm( normoldname, &oldoutname, false )) {
if ((fs_fns = myfatfs_realm( normnewname, &newoutname, false ))) {
int32_t r = fs_fns->rename( oldoutname, newoutname );
free( oldoutname );
free( newoutname );
return r;
}
free( oldoutname );
}
#endif
return -1;
}
int32_t vfs_mkdir( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
// not supported
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int32_t r = fs_fns->mkdir( outname );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_fsinfo( const char *name, uint32_t *total, uint32_t *used )
{
vfs_fs_fns *fs_fns;
char *outname;
if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->fsinfo( total, used );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
free( outname );
return fs_fns->fsinfo( total, used );
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_fscfg( const char *name, uint32_t *phys_addr, uint32_t *phys_size)
{
vfs_fs_fns *fs_fns;
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( "/FLASH", &outname, false ))) {
return fs_fns->fscfg( phys_addr, phys_size );
}
#endif
#ifdef CONFIG_BUILD_FATFS
// not supported
#endif
// Error
return VFS_RES_ERR;
}
int32_t vfs_format( void )
{
vfs_fs_fns *fs_fns;
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( "/FLASH", &outname, false ))) {
return fs_fns->format();
}
#endif
#ifdef CONFIG_BUILD_FATFS
// not supported
#endif
// Error
return 0;
}
int32_t vfs_chdir( const char *path )
{
vfs_fs_fns *fs_fns;
const char *normpath = normalize_path( path );
const char *level;
char *outname;
int ok = VFS_RES_ERR;
#if LDRV_TRAVERSAL
// track dir level
if (normpath[0] == '/') {
dir_level = 0;
level = &(normpath[1]);
} else {
level = normpath;
}
while (strlen( level ) > 0) {
dir_level++;
if (level = strchr( level, '/' )) {
level++;
} else {
break;
}
}
#endif
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normpath, &outname, true ))) {
// our SPIFFS integration doesn't support directories
if (strlen( outname ) == 0) {
ok = VFS_RES_OK;
}
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normpath, &outname, true ))) {
if (strchr( outname, ':' )) {
// need to set FatFS' default drive
fs_fns->chdrive( outname );
// and force chdir to root in case path points only to root
fs_fns->chdir( "/" );
}
if (fs_fns->chdir( outname ) == VFS_RES_OK) {
ok = VFS_RES_OK;
}
free( outname );
}
#endif
return ok == VFS_RES_OK ? VFS_RES_OK : VFS_RES_ERR;
}
int32_t vfs_errno( const char *name )
{
vfs_fs_fns *fs_fns;
const char *normname = normalize_path( name );
char *outname;
if (!name) name = ""; // current drive
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
return fs_fns->ferrno( );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
int32_t r = fs_fns->ferrno( );
free( outname );
return r;
}
#endif
return VFS_RES_ERR;
}
int32_t vfs_ferrno( int fd )
{
vfs_file *f = (vfs_file *)fd;
if (f) {
return f->fns->ferrno ? f->fns->ferrno( f ) : 0;
} else {
vfs_fs_fns *fs_fns;
const char *name = ""; // current drive
char *outname;
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( name, &outname, false ))) {
return fs_fns->ferrno( );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( name, &outname, false ))) {
int32_t r = fs_fns->ferrno( );
free( outname );
return r;
}
#endif
}
return 0;
}
void vfs_clearerr( const char *name )
{
vfs_fs_fns *fs_fns;
char *outname;
if (!name) name = ""; // current drive
const char *normname = normalize_path( name );
#ifdef CONFIG_BUILD_SPIFFS
if ((fs_fns = myspiffs_realm( normname, &outname, false ))) {
fs_fns->clearerr( );
}
#endif
#ifdef CONFIG_BUILD_FATFS
if ((fs_fns = myfatfs_realm( normname, &outname, false ))) {
fs_fns->clearerr( );
free( outname );
}
#endif
}
const char *vfs_basename( const char *path )
{
const char *basename;
// deduce basename (incl. extension) for length check
if ((basename = strrchr( path, '/' ))) {
basename++;
} else if ((basename = strrchr( path, ':' ))) {
basename++;
} else {
basename = path;
}
return basename;
}
// ---------------------------------------------------------------------------
// supplementary functions
//
int vfs_getc( int fd )
{
unsigned char c = 0xFF;
int32_t res;
if(!vfs_eof( fd )) {
if (1 != vfs_read( fd, &c, 1 )) {
NODE_DBG("getc errno %i\n", vfs_ferrno( fd ));
return VFS_EOF;
} else {
return (int)c;
}
}
return VFS_EOF;
}
int vfs_ungetc( int c, int fd )
{
return vfs_lseek( fd, -1, VFS_SEEK_CUR );
}

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976<at>gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@ -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

View File

@ -1 +1,15 @@
* 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.

View File

@ -0,0 +1,24 @@
#ifndef _NODEMCU_SPIFFS_H
#define _NODEMCU_SPIFFS_H
#ifndef NODEMCU_SPIFFS_NO_INCLUDE
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#endif
// Turn off stats
#define SPIFFS_CACHE_STATS 0
#define SPIFFS_GC_STATS 0
// Needs to align stuff
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
// Enable magic so we can find the file system (but not yet)
#define SPIFFS_USE_MAGIC 1
#define SPIFFS_USE_MAGIC_LENGTH 1
// Reduce the chance of returning disk full
#define SPIFFS_GC_MAX_RUNS 256
#endif

View File

@ -1,4 +1,5 @@
#include <stdio.h>
#include <stdbool.h>
#include "platform.h"
#include "flash_api.h"
#include "spiffs.h"
@ -6,6 +7,9 @@
spiffs fs;
#define LOG_PAGE_SIZE 256
#define LOG_BLOCK_SIZE (INTERNAL_FLASH_SECTOR_SIZE * 2)
#define LOG_BLOCK_SIZE_SMALL_FS (INTERNAL_FLASH_SECTOR_SIZE)
#define MIN_BLOCKS_FS 4
static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
static u8_t spiffs_fds[32*4];
@ -45,24 +49,120 @@ The small 4KB sectors allow for greater flexibility in applications th
********************/
void myspiffs_mount() {
spiffs_config cfg;
static bool myspiffs_set_location(spiffs_config *cfg, int align, int offset, int block_size) {
#ifdef SPIFFS_FIXED_LOCATION
cfg.phys_addr = SPIFFS_FIXED_LOCATION;
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,
@ -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 )
myspiffs_mount_internal(true);
SPIFFS_unmount(&fs);
NODE_DBG("Formatting: size 0x%x, addr 0x%x\n", fs.cfg.phys_size, fs.cfg.phys_addr);
if (SPIFFS_format(&fs) < 0) {
return 0;
myspiffs_mount();
return 1;
}
return myspiffs_mount();
}
int myspiffs_check( void )
{
// ets_wdt_disable();
// int res = (int)SPIFFS_check(&fs);
// ets_wdt_enable();
// return res;
return 0;
}
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));
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);
}
#if 0
void test_spiffs() {
char buf[12];
@ -206,3 +223,406 @@ void test_spiffs() {
NODE_DBG("--> %s <--\n", buf);
}
#endif
// ***************************************************************************
// vfs API
// ***************************************************************************
#include <stdlib.h>
#include "vfs_int.h"
#define MY_LDRV_ID "FLASH"
// default current drive
static int is_current_drive = true;
// forward declarations
static int32_t myspiffs_vfs_close( const struct vfs_file *fd );
static int32_t myspiffs_vfs_read( const struct vfs_file *fd, void *ptr, size_t len );
static int32_t myspiffs_vfs_write( const struct vfs_file *fd, const void *ptr, size_t len );
static int32_t myspiffs_vfs_lseek( const struct vfs_file *fd, int32_t off, int whence );
static int32_t myspiffs_vfs_eof( const struct vfs_file *fd );
static int32_t myspiffs_vfs_tell( const struct vfs_file *fd );
static int32_t myspiffs_vfs_flush( const struct vfs_file *fd );
static int32_t myspiffs_vfs_ferrno( const struct vfs_file *fd );
static int32_t myspiffs_vfs_closedir( const struct vfs_dir *dd );
static vfs_item *myspiffs_vfs_readdir( const struct vfs_dir *dd );
static void myspiffs_vfs_iclose( const struct vfs_item *di );
static uint32_t myspiffs_vfs_isize( const struct vfs_item *di );
//static const struct tm *myspiffs_vfs_time( const struct vfs_item *di );
static const char *myspiffs_vfs_name( const struct vfs_item *di );
static vfs_vol *myspiffs_vfs_mount( const char *name, int num );
static vfs_file *myspiffs_vfs_open( const char *name, const char *mode );
static vfs_dir *myspiffs_vfs_opendir( const char *name );
static vfs_item *myspiffs_vfs_stat( const char *name );
static int32_t myspiffs_vfs_remove( const char *name );
static int32_t myspiffs_vfs_rename( const char *oldname, const char *newname );
static int32_t myspiffs_vfs_fsinfo( uint32_t *total, uint32_t *used );
static int32_t myspiffs_vfs_fscfg( uint32_t *phys_addr, uint32_t *phys_size );
static int32_t myspiffs_vfs_format( void );
static int32_t myspiffs_vfs_errno( void );
static void myspiffs_vfs_clearerr( void );
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;
}

View File

@ -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

View File

@ -7,6 +7,7 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include <string.h>
#if SPIFFS_CACHE
@ -39,7 +40,7 @@ static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
res = fs->cfg.hal_write_f(SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
}
cp->flags = 0;
@ -137,10 +138,7 @@ s32_t spiffs_phys_rd(
} else {
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
// for second layer lookup functions, we do not cache in order to prevent shredding
return fs->cfg.hal_read_f(
addr ,
len,
dst);
return SPIFFS_HAL_READ(fs, addr, len, dst);
}
#if SPIFFS_CACHE_STATS
fs->cache_misses++;
@ -151,8 +149,7 @@ s32_t spiffs_phys_rd(
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
}
s32_t res2 = fs->cfg.hal_read_f(
s32_t res2 = SPIFFS_HAL_READ(fs,
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
SPIFFS_CFG_LOG_PAGE_SZ(fs),
spiffs_get_cache_page(fs, cache, cp->ix));
@ -186,7 +183,7 @@ s32_t spiffs_phys_wr(
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
// page is being deleted, wipe from cache - unless it is a lookup page
spiffs_cache_page_free(fs, cp->ix, 0);
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
}
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
@ -197,13 +194,13 @@ s32_t spiffs_phys_wr(
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
// page is being updated, no write-cache, just pass thru
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
} else {
return SPIFFS_OK;
}
} else {
// no cache page, no write cache - just write thru
return fs->cfg.hal_write_f(addr, len, src);
return SPIFFS_HAL_WRITE(fs, addr, len, src);
}
}

View File

@ -19,8 +19,24 @@
* Author: petera
*/
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include <string.h>
#if !SPIFFS_READ_ONLY
#if SPIFFS_HAL_CALLBACK_EXTRA
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
do { \
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
} while (0)
#else
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
do { \
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
} while (0)
#endif
//---------------------------------------
// Look up consistency
@ -93,6 +109,7 @@ static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_
} else {
// calc entry in index
entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
}
// load index
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
@ -194,9 +211,9 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
res = spiffs_page_delete(fs, new_pix);
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
}
SPIFFS_CHECK_RES(res);
}
@ -216,7 +233,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting %04x to new page %04x\n", cur_pix, new_pix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
}
} else {
SPIFFS_CHECK_RES(res);
@ -254,7 +271,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
*reload_lu = 1;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
}
SPIFFS_CHECK_RES(res);
}
@ -306,7 +323,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x to pix %04x\n", cur_pix, new_ph.obj_id, new_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
@ -315,7 +332,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// rewrite as obj_id_lu
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page %04x as %04x\n", cur_pix, new_ph.obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
SPIFFS_CHECK_RES(res);
*reload_lu = 1;
@ -353,7 +370,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// if only data page exists, make this page index
if (data_pix && objix_pix_d == 0) {
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
spiffs_page_header new_ph;
spiffs_page_ix new_pix;
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
@ -369,7 +386,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// if only index exists, make data page
if (data_pix == 0 && objix_pix_d) {
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
spiffs_page_header new_ph;
spiffs_page_ix new_pix;
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
@ -406,7 +423,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
// page referenced by object index but not final
// just finalize
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
@ -418,7 +435,7 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
if (delete_page) {
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page %04x\n", cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
}
@ -427,14 +444,14 @@ static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, s
}
static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
u32_t user_data, void *user_p) {
(void)user_data;
(void)user_p;
const void *user_const_p, void *user_var_p) {
(void)user_const_p;
(void)user_var_p;
s32_t res = SPIFFS_OK;
spiffs_page_header p_hdr;
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
(cur_block * 256)/fs->block_count, 0);
// load header
@ -460,7 +477,7 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
(void)check_all_objects;
s32_t res = SPIFFS_OK;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
@ -469,10 +486,10 @@ s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
}
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
@ -506,14 +523,17 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
spiffs_block_ix cur_block = 0;
// build consistency bitmap for id range traversing all blocks
while (!restart && cur_block < fs->block_count) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
0);
// traverse each page except for lookup pages
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
//if ((cur_pix & 0xff) == 0)
// SPIFFS_CHECK_DBG("PA: processing pix %08x, block %08x of pix %08x, block %08x\n",
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
// read header
spiffs_page_header p_hdr;
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
@ -598,11 +618,11 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend - delete object\n", res);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
// delete file
res = spiffs_page_delete(fs, cur_pix);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
@ -636,7 +656,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (data_pix == 0) {
// not found, this index is badly borked
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id %04x\n", p_hdr.obj_id);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
SPIFFS_CHECK_RES(res);
break;
@ -648,10 +668,10 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
@ -669,7 +689,7 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
// the object which is referring to this page
SPIFFS_CHECK_DBG("PA: FIXUP: removing object %04x and page %04x\n",
p_hdr.obj_id, cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
SPIFFS_CHECK_RES(res);
// extra precaution, delete this page also
@ -764,19 +784,19 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
// index bad also, cannot mend this file
SPIFFS_CHECK_DBG("PA: FIXUP: index bad %i, cannot mend!\n", res);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
} else {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
}
SPIFFS_CHECK_RES(res);
restart = 1;
continue;
} else if (delete_page) {
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page %04x\n", cur_pix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
res = spiffs_page_delete(fs, cur_pix);
}
SPIFFS_CHECK_RES(res);
@ -818,6 +838,8 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
}
}
}
SPIFFS_CHECK_DBG("PA: processed %04x, restart %i\n", pix_offset, restart);
// next page range
if (!restart) {
pix_offset += pages_per_scan;
@ -828,12 +850,12 @@ static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
// Checks consistency amongst all pages and fixes irregularities
s32_t spiffs_page_consistency_check(spiffs *fs) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
s32_t res = spiffs_page_consistency_check_i(fs);
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
@ -855,14 +877,14 @@ static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
}
static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
int cur_entry, u32_t user_data, void *user_p) {
(void)user_data;
int cur_entry, const void *user_const_p, void *user_var_p) {
(void)user_const_p;
s32_t res_c = SPIFFS_VIS_COUNTINUE;
s32_t res = SPIFFS_OK;
u32_t *log_ix = (u32_t *)user_p;
u32_t *log_ix = (u32_t*)user_var_p;
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
(cur_block * 256)/fs->block_count, 0);
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
@ -879,7 +901,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
(SPIFFS_PH_FLAG_DELET)) {
SPIFFS_CHECK_DBG("IX: pix %04x, obj id:%04x spix:%04x header not fully deleted - deleting\n",
cur_pix, obj_id, p_hdr.span_ix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
return res_c;
@ -935,7 +957,7 @@ static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id o
if (delete) {
SPIFFS_CHECK_DBG("IX: FIXUP: pix %04x, obj id:%04x spix:%04x is orphan index - deleting\n",
cur_pix, obj_id, p_hdr.span_ix);
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
res = spiffs_page_delete(fs, cur_pix);
SPIFFS_CHECK_RES(res);
}
@ -958,16 +980,17 @@ s32_t spiffs_object_index_consistency_check(spiffs *fs) {
// a reachable/unreachable object id.
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
u32_t obj_id_log_ix = 0;
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
0, 0);
if (res == SPIFFS_VIS_END) {
res = SPIFFS_OK;
}
if (res != SPIFFS_OK) {
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
}
if (fs->check_cb_f) fs->check_cb_f(SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
return res;
}
#endif // !SPIFFS_READ_ONLY

View File

@ -8,26 +8,25 @@
#ifndef SPIFFS_CONFIG_H_
#define SPIFFS_CONFIG_H_
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "nodemcu_spiffs.h"
#include "sdkconfig.h"
// compile time switches
// Set generic spiffs debug output call.
#ifndef SPIFFS_DGB
#ifndef SPIFFS_DBG
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for garbage collecting.
#ifndef SPIFFS_GC_DGB
#ifndef SPIFFS_GC_DBG
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for caching.
#ifndef SPIFFS_CACHE_DGB
#ifndef SPIFFS_CACHE_DBG
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
#endif
// Set spiffs debug output call for system consistency checks.
#ifndef SPIFFS_CHECK_DGB
#ifndef SPIFFS_CHECK_DBG
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
#endif
@ -51,10 +50,8 @@
// Enable/disable statistics on caching. Debug/test purpose only.
#ifndef SPIFFS_CACHE_STATS
#define SPIFFS_CACHE_STATS 0
#define SPIFFS_CACHE_STATS 1
#endif
#else
#define SPIFFS_CACHE_WR 0
#endif
// Always check header of each accessed page to ensure consistent state.
@ -70,7 +67,7 @@
// Enable/disable statistics on gc. Debug/test purpose only.
#ifndef SPIFFS_GC_STATS
#define SPIFFS_GC_STATS 0
#define SPIFFS_GC_STATS 1
#endif
// Garbage collecting examines all pages in a block which and sums up
@ -95,9 +92,11 @@
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
#endif
// Object name maximum length.
// Object name maximum length. Note that this length include the
// zero-termination character, meaning maximum string of characters
// can at most be CONFIG_SPIFFS_OBJ_NAME_LEN - 1.
#ifndef SPIFFS_OBJ_NAME_LEN
#define SPIFFS_OBJ_NAME_LEN (32)
#define SPIFFS_OBJ_NAME_LEN (CONFIG_FS_OBJ_NAME_LEN+1)
#endif
// Size of buffer allocated on stack used when copying data.
@ -115,19 +114,29 @@
#define SPIFFS_USE_MAGIC (0)
#endif
#if SPIFFS_USE_MAGIC
// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
// enabled, the magic will also be dependent on the length of the filesystem.
// For example, a filesystem configured and formatted for 4 megabytes will not
// be accepted for mounting with a configuration defining the filesystem as 2
// megabytes.
#ifndef SPIFFS_USE_MAGIC_LENGTH
#define SPIFFS_USE_MAGIC_LENGTH (0)
#endif
#endif
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
// These should be defined on a multithreaded system
// define this to entering a mutex if you're running on a multithreaded system
// define this to enter a mutex if you're running on a multithreaded system
#ifndef SPIFFS_LOCK
#define SPIFFS_LOCK(fs)
#endif
// define this to exiting a mutex if you're running on a multithreaded system
// define this to exit a mutex if you're running on a multithreaded system
#ifndef SPIFFS_UNLOCK
#define SPIFFS_UNLOCK(fs)
#endif
// Enable if only one spiffs instance with constant configuration will exist
// on the target. This will reduce calculations, flash and memory accesses.
// Parts of configuration must be defined below instead of at time of mount.
@ -155,7 +164,41 @@
#endif
#endif
// Set SPFIFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
// Enable this if your target needs aligned data for index tables
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0
#endif
// Enable this if you want the HAL callbacks to be called with the spiffs struct
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
#define SPIFFS_HAL_CALLBACK_EXTRA 0
#endif
// Enable this if you want to add an integer offset to all file handles
// (spiffs_file). This is useful if running multiple instances of spiffs on
// same target, in order to recognise to what spiffs instance a file handle
// belongs.
// NB: This adds config field fh_ix_offset in the configuration struct when
// mounting, which must be defined.
#ifndef SPIFFS_FILEHDL_OFFSET
#define SPIFFS_FILEHDL_OFFSET 0
#endif
// Enable this to compile a read only version of spiffs.
// This will reduce binary size of spiffs. All code comprising modification
// of the file system will not be compiled. Some config will be ignored.
// HAL functions for erasing and writing to spi-flash may be null. Cache
// can be disabled for even further binary size reduction (and ram savings).
// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.
// If the file system cannot be mounted due to aborted erase operation and
// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be
// returned.
// Might be useful for e.g. bootloaders and such.
#ifndef SPIFFS_READ_ONLY
#define SPIFFS_READ_ONLY 0
#endif
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
// in the api. This function will visualize all filesystem using given printf
// function.
#ifndef SPIFFS_TEST_VISUALISATION

View File

@ -1,5 +1,8 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include <string.h>
#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

View File

@ -7,8 +7,19 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include <string.h>
#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

View File

@ -1,5 +1,6 @@
#include "spiffs.h"
#include "spiffs_nucleus.h"
#include <string.h>
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));
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
// 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;

View File

@ -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);
// ---------------