fix(spiffs): fix bugs of spiffs

1. fix debug macro and parameters error
2. fix data no-align load/store error
3. update other function for user to develop easily

Merges https://github.com/espressif/ESP8266_RTOS_SDK/pull/729
This commit is contained in:
Bernard Gautier
2019-10-09 11:37:25 +02:00
committed by dongheng
parent 36d8b6c0fb
commit cb772519aa
9 changed files with 2108 additions and 526 deletions

View File

@@ -5,8 +5,6 @@
* Author: petera
*/
#ifndef SPIFFS_H_
#define SPIFFS_H_
#if defined(__cplusplus)
@@ -49,6 +47,22 @@ 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_IX_MAP_UNMAPPED -10037
#define SPIFFS_ERR_IX_MAP_MAPPED -10038
#define SPIFFS_ERR_IX_MAP_BAD_RANGE -10039
#define SPIFFS_ERR_SEEK_BOUNDS -10040
#define SPIFFS_ERR_INTERNAL -10050
#define SPIFFS_ERR_TEST -10100
@@ -63,12 +77,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,16 +113,34 @@ 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(...) \
print(__VA_ARGS__)
printf(__VA_ARGS__)
#endif
#ifndef SPIFFS_GC_DBG
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
@@ -108,18 +154,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 +220,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 +283,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,7 +298,11 @@ 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];
#if SPIFFS_OBJ_META_LEN
u8_t meta[SPIFFS_OBJ_META_LEN];
#endif
} spiffs_stat;
struct spiffs_dirent {
@@ -243,6 +311,9 @@ struct spiffs_dirent {
spiffs_obj_type type;
u32_t size;
spiffs_page_ix pix;
#if SPIFFS_OBJ_META_LEN
u8_t meta[SPIFFS_OBJ_META_LEN];
#endif
};
typedef struct {
@@ -251,8 +322,57 @@ typedef struct {
int entry;
} spiffs_DIR;
#if SPIFFS_IX_MAP
typedef struct {
// buffer with looked up data pixes
spiffs_page_ix *map_buf;
// precise file byte offset
u32_t offset;
// start data span index of lookup buffer
spiffs_span_ix start_spix;
// end data span index of lookup buffer
spiffs_span_ix end_spix;
} spiffs_ix_map;
#endif
// 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 +406,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 +425,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 +434,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 +471,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 +487,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 +502,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 +524,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 +532,25 @@ 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);
#if SPIFFS_OBJ_META_LEN
/**
* Updates file's metadata
* @param fs the file system struct
* @param path path to the file
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
*/
s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);
/**
* Updates file's metadata
* @param fs the file system struct
* @param fh file handle of the file
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
*/
s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);
#endif
/**
* Returns last error of last file operation.
@@ -419,7 +573,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 +595,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 +674,115 @@ 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_IX_MAP
/**
* Maps the first level index lookup to a given memory map.
* This will make reading big files faster, as the memory map will be used for
* looking up data pages instead of searching for the indices on the physical
* medium. When mapping, all affected indicies are found and the information is
* copied to the array.
* Whole file or only parts of it may be mapped. The index map will cover file
* contents from argument offset until and including arguments (offset+len).
* It is valid to map a longer range than the current file size. The map will
* then be populated when the file grows.
* On garbage collections and file data page movements, the map array will be
* automatically updated. Do not tamper with the map array, as this contains
* the references to the data pages. Modifying it from outside will corrupt any
* future readings using this file descriptor.
* The map will no longer be used when the file descriptor closed or the file
* is unmapped.
* This can be useful to get faster and more deterministic timing when reading
* large files, or when seeking and reading a lot within a file.
* @param fs the file system struct
* @param fh the file handle of the file to map
* @param map a spiffs_ix_map struct, describing the index map
* @param offset absolute file offset where to start the index map
* @param len length of the mapping in actual file bytes
* @param map_buf the array buffer for the look up data - number of required
* elements in the array can be derived from function
* SPIFFS_bytes_to_ix_map_entries given the length
*/
s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
u32_t offset, u32_t len, spiffs_page_ix *map_buf);
/**
* Unmaps the index lookup from this filehandle. All future readings will
* proceed as normal, requiring reading of the first level indices from
* physical media.
* The map and map buffer given in function SPIFFS_ix_map will no longer be
* referenced by spiffs.
* It is not strictly necessary to unmap a file before closing it, as closing
* a file will automatically unmap it.
* @param fs the file system struct
* @param fh the file handle of the file to unmap
*/
s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);
/**
* Moves the offset for the index map given in function SPIFFS_ix_map. Parts or
* all of the map buffer will repopulated.
* @param fs the file system struct
* @param fh the mapped file handle of the file to remap
* @param offset new absolute file offset where to start the index map
*/
s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);
/**
* Utility function to get number of spiffs_page_ix entries a map buffer must
* contain on order to map given amount of file data in bytes.
* See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.
* @param fs the file system struct
* @param bytes number of file data bytes to map
* @return needed number of elements in a spiffs_page_ix array needed to
* map given amount of bytes in a file
*/
s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);
/**
* Utility function to amount of file data bytes that can be mapped when
* mapping a file with buffer having given number of spiffs_page_ix entries.
* See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.
* @param fs the file system struct
* @param map_page_ix_entries number of entries in a spiffs_page_ix array
* @return amount of file data in bytes that can be mapped given a map
* buffer having given amount of spiffs_page_ix entries
*/
s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
#endif // SPIFFS_IX_MAP
#if SPIFFS_TEST_VISUALISATION
/**
* Prints out a visualization of the filesystem.

View File

@@ -11,33 +11,78 @@
// ----------- 8< ------------
// Following includes are for the linux test build of spiffs
// These may/should/must be removed/altered/replaced in your target
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
//#include "params_test.h"
//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//#include <stddef.h>
//#include <unistd.h>
//#ifdef _SPIFFS_TEST
//#include "testrunner.h"
//#endif
// ----------- >8 ------------
#include "freertos/FreeRTOS.h"
// compile time switches
// Set generic spiffs debug output call.
#ifndef SPIFFS_DBG
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
#endif
// Set spiffs debug output call for garbage collecting.
#ifndef SPIFFS_GC_DBG
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_GC_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
#endif
// Set spiffs debug output call for caching.
#ifndef SPIFFS_CACHE_DBG
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_CACHE_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
#endif
// Set spiffs debug output call for system consistency checks.
#ifndef SPIFFS_CHECK_DBG
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
#define SPIFFS_CHECK_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
#endif
// Set spiffs debug output call for all api invocations.
#ifndef SPIFFS_API_DBG
#define SPIFFS_API_DBG(_f, ...) //printf(_f, ## __VA_ARGS__)
#endif
// Defines spiffs debug print formatters
// some general signed number
#ifndef _SPIPRIi
#define _SPIPRIi "%d"
#endif
// address
#ifndef _SPIPRIad
#define _SPIPRIad "%08x"
#endif
// block
#ifndef _SPIPRIbl
#define _SPIPRIbl "%04x"
#endif
// page
#ifndef _SPIPRIpg
#define _SPIPRIpg "%04x"
#endif
// span index
#ifndef _SPIPRIsp
#define _SPIPRIsp "%04x"
#endif
// file descriptor
#ifndef _SPIPRIfd
#define _SPIPRIfd "%d"
#endif
// file object id
#ifndef _SPIPRIid
#define _SPIPRIid "%04x"
#endif
// file flags
#ifndef _SPIPRIfl
#define _SPIPRIfl "%02x"
#endif
// Enable/disable API functions to determine exact number of bytes
// for filedescriptor and cache buffers. Once decided for a configuration,
@@ -51,7 +96,6 @@
#ifndef SPIFFS_CACHE
#define SPIFFS_CACHE 1
#endif
#if SPIFFS_CACHE
// Enables memory write caching for file descriptors in hydrogen
#ifndef SPIFFS_CACHE_WR
@@ -60,7 +104,7 @@
// Enable/disable statistics on caching. Debug/test purpose only.
#ifndef SPIFFS_CACHE_STATS
#define SPIFFS_CACHE_STATS 1
#define SPIFFS_CACHE_STATS 0
#endif
#endif
@@ -72,12 +116,12 @@
// Define maximum number of gc runs to perform to reach desired free pages.
#ifndef SPIFFS_GC_MAX_RUNS
#define SPIFFS_GC_MAX_RUNS 5
#define SPIFFS_GC_MAX_RUNS 10
#endif
// Enable/disable statistics on gc. Debug/test purpose only.
#ifndef SPIFFS_GC_STATS
#define SPIFFS_GC_STATS 1
#define SPIFFS_GC_STATS 0
#endif
// Garbage collecting examines all pages in a block which and sums up
@@ -102,11 +146,27 @@
#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 SPIFFS_OBJ_NAME_LEN - 1.
#ifndef SPIFFS_OBJ_NAME_LEN
#define SPIFFS_OBJ_NAME_LEN (32)
#endif
// Maximum length of the metadata associated with an object.
// Setting to non-zero value enables metadata-related API but also
// changes the on-disk format, so the change is not backward-compatible.
//
// Do note: the meta length must never exceed
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)
//
// This is derived from following:
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
// spiffs_object_ix_header fields + at least some LUT entries)
#ifndef SPIFFS_OBJ_META_LEN
#define SPIFFS_OBJ_META_LEN (0)
#endif
// Size of buffer allocated on stack used when copying data.
// Lower value generates more read/writes. No meaning having it bigger
// than logical page size.
@@ -122,6 +182,17 @@
#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 (1)
#endif
#endif
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
// These should be defined on a multithreaded system
@@ -134,7 +205,6 @@
#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.
@@ -167,11 +237,98 @@
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
#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
// Enable this to add a temporal file cache using the fd buffer.
// The effects of the cache is that SPIFFS_open will find the file faster in
// certain cases. It will make it a lot easier for spiffs to find files
// opened frequently, reducing number of readings from the spi flash for
// finding those files.
// This will grow each fd by 6 bytes. If your files are opened in patterns
// with a degree of temporal locality, the system is optimized.
// Examples can be letting spiffs serve web content, where one file is the css.
// The css is accessed for each html file that is opened, meaning it is
// accessed almost every second time a file is opened. Another example could be
// a log file that is often opened, written, and closed.
// The size of the cache is number of given file descriptors, as it piggybacks
// on the fd update mechanism. The cache lives in the closed file descriptors.
// When closed, the fd know the whereabouts of the file. Instead of forgetting
// this, the temporal cache will keep handling updates to that file even if the
// fd is closed. If the file is opened again, the location of the file is found
// directly. If all available descriptors become opened, all cache memory is
// lost.
#ifndef SPIFFS_TEMPORAL_FD_CACHE
#define SPIFFS_TEMPORAL_FD_CACHE 1
#endif
// Temporal file cache hit score. Each time a file is opened, all cached files
// will lose one point. If the opened file is found in cache, that entry will
// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this
// value for the specific access patterns of the application. However, it must
// be between 1 (no gain for hitting a cached entry often) and 255.
#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE
#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4
#endif
// Enable to be able to map object indices to memory.
// This allows for faster and more deterministic reading if cases of reading
// large files and when changing file offset by seeking around a lot.
// When mapping a file's index, the file system will be scanned for index pages
// and the info will be put in memory provided by user. When reading, the
// memory map can be looked up instead of searching for index pages on the
// medium. This way, user can trade memory against performance.
// Whole, parts of, or future parts not being written yet can be mapped. The
// memory array will be owned by spiffs and updated accordingly during garbage
// collecting or when modifying the indices. The latter is invoked by when the
// file is modified in some way. The index buffer is tied to the file
// descriptor.
#ifndef SPIFFS_IX_MAP
#define SPIFFS_IX_MAP 1
#endif
// By default SPIFFS in some cases relies on the property of NOR flash that bits
// cannot be set from 0 to 1 by writing and that controllers will ignore such
// bit changes. This results in fewer reads as SPIFFS can in some cases perform
// blind writes, with all bits set to 1 and only those it needs reset set to 0.
// Most of the chips and controllers allow this behavior, so the default is to
// use this technique. If your controller is one of the rare ones that don't,
// turn this option on and SPIFFS will perform a read-modify-write instead.
#ifndef SPIFFS_NO_BLIND_WRITES
#define SPIFFS_NO_BLIND_WRITES 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
#define SPIFFS_TEST_VISUALISATION 0
#define SPIFFS_TEST_VISUALISATION 1
#endif
#if SPIFFS_TEST_VISUALISATION
#ifndef spiffs_printf

View File

@@ -116,13 +116,23 @@
#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
// visitor result, continue searching
#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
// visitor result, continue searching after reloading lu buffer
#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
// visitor result, stop searching
#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
#define SPIFFS_EV_IX_UPD 0
#define SPIFFS_EV_IX_NEW 1
#define SPIFFS_EV_IX_DEL 2
// updating an object index contents
#define SPIFFS_EV_IX_UPD (0)
// creating a new object index
#define SPIFFS_EV_IX_NEW (1)
// deleting an object index
#define SPIFFS_EV_IX_DEL (2)
// moving an object index without updating contents
#define SPIFFS_EV_IX_MOV (3)
// updating an object index header data only, not the table itself
#define SPIFFS_EV_IX_UPD_HDR (4)
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
@@ -131,7 +141,31 @@
#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 defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
/* For GCC, clang and TI compilers */
#define SPIFFS_PACKED __attribute__((packed))
#elif defined(__ICCARM__) || defined(__CC_ARM)
/* For IAR ARM and Keil MDK-ARM compilers */
#define SPIFFS_PACKED
#else
/* Unknown compiler */
#define SPIFFS_PACKED
#endif
#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)
@@ -220,6 +254,17 @@
// object index span index number for given data span index or entry
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
// get data span index for object index span index
#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \
( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )
#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) ((spiffs_file)(fh))
#define SPIFFS_FH_UNOFFS(fs, fh) ((spiffs_file)(fh))
#endif
#define SPIFFS_OP_T_OBJ_LU (0<<0)
@@ -264,26 +309,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) \
@@ -304,13 +349,33 @@
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
// check id
// check id, only visit matching objec ids
#define SPIFFS_VIS_CHECK_ID (1<<0)
// report argument object id to visitor - else object lookup id is reported
#define SPIFFS_VIS_CHECK_PH (1<<1)
// 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)
@@ -390,13 +455,23 @@ typedef struct {
spiffs_span_ix cursor_objix_spix;
// current absolute offset
u32_t offset;
// current file descriptor offset
// current file descriptor offset (cached)
u32_t fdoffset;
// fd flags
spiffs_flags flags;
#if SPIFFS_CACHE_WR
spiffs_cache_page *cache_page;
#endif
#if SPIFFS_TEMPORAL_FD_CACHE
// djb2 hash of filename
u32_t name_hash;
// hit score (score == 0 indicates never used fd)
u16_t score;
#endif
#if SPIFFS_IX_MAP
// spiffs index map, if 0 it means unmapped
spiffs_ix_map *ix_map;
#endif
} spiffs_fd;
@@ -405,7 +480,7 @@ typedef struct {
// page header, part of each page except object lookup pages
// NB: this is always aligned when the data page is an object index,
// as in this case struct spiffs_page_object_ix is used
typedef struct __attribute(( packed )) {
typedef struct SPIFFS_PACKED {
// object id
spiffs_obj_id obj_id;
// object span index
@@ -415,7 +490,7 @@ typedef struct __attribute(( packed )) {
} spiffs_page_header;
// object index header page header
typedef struct __attribute(( packed ))
typedef struct SPIFFS_PACKED
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
#endif
@@ -423,24 +498,28 @@ typedef struct __attribute(( packed ))
// 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)];
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
spiffs_obj_type type;
// name of object
u8_t name[SPIFFS_OBJ_NAME_LEN];
#if SPIFFS_OBJ_META_LEN
// metadata. not interpreted by SPIFFS in any way.
u8_t meta[SPIFFS_OBJ_META_LEN];
#endif
} spiffs_page_object_ix_header;
// object index page header
typedef struct __attribute(( packed )) {
typedef struct SPIFFS_PACKED {
spiffs_page_header p_hdr;
u8_t _align[4 - (sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3)];
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
@@ -501,8 +580,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);
@@ -510,6 +589,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(
@@ -518,7 +602,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,
@@ -579,7 +663,8 @@ 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[],
const u8_t meta[],
spiffs_obj_type type,
spiffs_page_ix *objix_hdr_pix);
@@ -589,13 +674,24 @@ 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[],
const u8_t meta[],
u32_t size,
spiffs_page_ix *new_pix);
void spiffs_cb_object_event(
#if SPIFFS_IX_MAP
s32_t spiffs_populate_ix_map(
spiffs *fs,
spiffs_fd *fd,
u32_t vec_entry_start,
u32_t vec_entry_end);
#endif
void spiffs_cb_object_event(
spiffs *fs,
spiffs_page_object_ix *objix,
int ev,
spiffs_obj_id obj_id,
spiffs_span_ix spix,
@@ -641,7 +737,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);
// ---------------
@@ -671,7 +767,8 @@ s32_t spiffs_gc_quick(
s32_t spiffs_fd_find_new(
spiffs *fs,
spiffs_fd **fd);
spiffs_fd **fd,
const char *name);
s32_t spiffs_fd_return(
spiffs *fs,
@@ -682,6 +779,13 @@ s32_t spiffs_fd_get(
spiffs_file f,
spiffs_fd **fd);
#if SPIFFS_TEMPORAL_FD_CACHE
void spiffs_fd_temporal_cache_rehash(
spiffs *fs,
const char *old_path,
const char *new_path);
#endif
#if SPIFFS_CACHE
void spiffs_cache_init(
spiffs *fs);
@@ -715,4 +819,24 @@ s32_t spiffs_page_consistency_check(
s32_t spiffs_object_index_consistency_check(
spiffs *fs);
// memcpy macro,
// checked in test builds, otherwise plain memcpy (unless already defined)
#ifdef _SPIFFS_TEST
#define _SPIFFS_MEMCPY(__d, __s, __l) do { \
intptr_t __a1 = (intptr_t)((u8_t*)(__s)); \
intptr_t __a2 = (intptr_t)((u8_t*)(__s)+(__l)); \
intptr_t __b1 = (intptr_t)((u8_t*)(__d)); \
intptr_t __b2 = (intptr_t)((u8_t*)(__d)+(__l)); \
if (__a1 <= __b2 && __b1 <= __a2) { \
printf("FATAL OVERLAP: memcpy from %lx..%lx to %lx..%lx\n", __a1, __a2, __b1, __b2); \
ERREXIT(); \
} \
memcpy((__d),(__s),(__l)); \
} while (0)
#else
#ifndef _SPIFFS_MEMCPY
#define _SPIFFS_MEMCPY(__d, __s, __l) do{memcpy((__d),(__s),(__l));}while(0)
#endif
#endif //_SPIFFS_TEST
#endif /* SPIFFS_NUCLEUS_H_ */