1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-25 20:02:37 +03:00

Update SPIFFS to 82aeac6

Fixes duplicate files issue (#1685)
This commit is contained in:
Ivan Grokhotkov 2016-03-10 13:00:38 +03:00
parent d7078ed9b5
commit 6a7551e1f0
10 changed files with 529 additions and 466 deletions

View File

@ -1,306 +0,0 @@
* QUICK AND DIRTY INTEGRATION EXAMPLE
So, assume you're running a Cortex-M3 board with a 2 MB SPI flash on it. The
SPI flash has 64kB blocks. Your project is built using gnumake, and now you
want to try things out.
First, you simply copy the files in src/ to your own source folder. Exclude
all files in test folder. Then you point out these files in your make script
for compilation.
Also copy the spiffs_config.h over from the src/default/ folder.
Try building. This fails, nagging about inclusions and u32_t and whatnot. Open
the spiffs_config.h and delete the bad inclusions. Also, add following
typedefs:
typedef signed int s32_t;
typedef unsigned int u32_t;
typedef signed short s16_t;
typedef unsigned short u16_t;
typedef signed char s8_t;
typedef unsigned char u8_t;
Now it should build. Over to the mounting business. Assume you already
implemented the read, write and erase functions to your SPI flash:
void my_spi_read(int addr, int size, char *buf)
void my_spi_write(int addr, int size, char *buf)
void my_spi_erase(int addr, int size)
In your main.c or similar, include the spiffs.h and do that spiffs struct:
#include <spiffs.h>
static spiffs fs;
Also, toss up some of the needed buffers:
#define LOG_PAGE_SIZE 256
static u8_t spiffs_work_buf[LOG_PAGE_SIZE*2];
static u8_t spiffs_fds[32*4];
static u8_t spiffs_cache_buf[(LOG_PAGE_SIZE+32)*4];
Now, write the my_spiffs_mount function:
void my_spiffs_mount() {
spiffs_config cfg;
cfg.phys_size = 2*1024*1024; // use all spi flash
cfg.phys_addr = 0; // start spiffs at start of spi flash
cfg.phys_erase_block = 65536; // according to datasheet
cfg.log_block_size = 65536; // let us not complicate things
cfg.log_page_size = LOG_PAGE_SIZE; // as we said
cfg.hal_read_f = my_spi_read;
cfg.hal_write_f = my_spi_write;
cfg.hal_erase_f = my_spi_erase;
int res = SPIFFS_mount(&fs,
&cfg,
spiffs_work_buf,
spiffs_fds,
sizeof(spiffs_fds),
spiffs_cache_buf,
sizeof(spiffs_cache_buf),
0);
printf("mount res: %i\n", res);
}
Now, build warns about the my_spi_read, write and erase functions. Wrong
signatures, so go wrap them:
static s32_t my_spiffs_read(u32_t addr, u32_t size, u8_t *dst) {
my_spi_read(addr, size, dst);
return SPIFFS_OK;
}
static s32_t my_spiffs_write(u32_t addr, u32_t size, u8_t *src) {
my_spi_write(addr, size, dst);
return SPIFFS_OK;
}
static s32_t my_spiffs_erase(u32_t addr, u32_t size) {
my_spi_erase(addr, size);
return SPIFFS_OK;
}
Redirect the config in my_spiffs_mount to the wrappers instead:
cfg.hal_read_f = my_spiffs_read;
cfg.hal_write_f = my_spiffs_write;
cfg.hal_erase_f = my_spiffs_erase;
Ok, now you should be able to build and run. However, you get this output:
mount res: -1
but you wanted
mount res: 0
This is probably due to you having experimented with your SPI flash, so it
contains rubbish from spiffs's point of view. Do a mass erase and run again.
If all is ok now, you're good to go. Try creating a file and read it back:
static void test_spiffs() {
char buf[12];
// Surely, I've mounted spiffs before entering here
spiffs_file fd = SPIFFS_open(&fs, "my_file", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
if (SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
SPIFFS_close(&fs, fd);
fd = SPIFFS_open(&fs, "my_file", SPIFFS_RDWR, 0);
if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) printf("errno %i\n", SPIFFS_errno(&fs));
SPIFFS_close(&fs, fd);
printf("--> %s <--\n", buf);
}
Compile, run, cross fingers hard, and you'll get the output:
--> Hello world <--
Got errors? Check spiffs.h for error definitions to get a clue what went voodoo.
* THINGS TO CHECK
When you alter the spiffs_config values, make sure you also check the typedefs
in spiffs_config.h:
- spiffs_block_ix
- spiffs_page_ix
- spiffs_obj_id
- spiffs_span_ix
The sizes of these typedefs must not underflow, else spiffs might end up in
eternal loops. Each typedef is commented what check for.
Also, if you alter the code or just want to verify your configuration, you can
run
> make test
in the spiffs folder. This will run all testcases using the configuration in
default/spiffs_config.h and test/params_test.h. The tests are written for linux
but should run under cygwin also.
* INTEGRATING SPIFFS
In order to integrate spiffs to your embedded target, you will basically need:
- A SPI flash device which your processor can communicate with
- An implementation for reading, writing and erasing the flash
- Memory (flash or ram) for the code
- Memory (ram) for the stack
Other stuff may be needed, threaded systems might need mutexes and so on.
** Logical structure
First and foremost, one must decide how to divide up the SPI flash for spiffs.
Having the datasheet for the actual SPI flash in hand will help. Spiffs can be
defined to use all or only parts of the SPI flash.
If following seems arcane, read the "HOW TO CONFIG" chapter first.
- Decide the logical size of blocks. This must be a multiple of the biggest
physical SPI flash block size. To go safe, use the physical block size -
which in many cases is 65536 bytes.
- Decide the logical size of pages. This must be a 2nd logarithm part of the
logical block size. To go safe, use 256 bytes to start with.
- Decide how much of the SPI flash memory to be used for spiffs. This must be
on logical block boundary. If unsafe, use 1 megabyte to start with.
- Decide where on the SPI flash memory the spiffs area should start. This must
be on physical block/sector boundary. If unsafe, use address 0.
** SPI flash API
The target must provide three functions to spiffs:
- s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst)
- s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src)
- s32_t (*spiffs_erase)(u32_t addr, u32_t size)
These functions define the only communication between the SPI flash and the
spiffs stack.
On success these must return 0 (or SPIFFS_OK). Anything else will be considered
an error.
The size for read and write requests will never exceed the logical page size,
but it may be less.
The address and size on erase requests will always be on physical block size
boundaries.
** Mount specification
In spiffs.h, there is a SPIFFS_mount function defined, used to mount spiffs on
the SPI flash.
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)
- fs Points to a spiffs struct. This may be totally uninitialized.
- config Points to a spiffs_config struct. This struct must be
initialized when mounting. See below.
- work A ram memory buffer being double the size of the logical page
size. This buffer is used excessively by the spiffs stack. If
logical page size is 256, this buffer must be 512 bytes.
- fd_space A ram memory buffer used for file descriptors.
- fd_space_size The size of the file descriptor buffer. A file descriptor
normally is around 32 bytes depending on the build config -
the bigger the buffer, the more file descriptors are
available.
- cache A ram memory buffer used for cache. Ignored if cache is
disabled in build config.
- cache_size The size of the cache buffer. Ignored if cache is disabled in
build config. One cache page will be slightly larger than the
logical page size. The more ram, the more cache pages, the
quicker the system.
- check_cb_f Callback function for monitoring spiffs consistency checks and
mending operations. May be null.
The config struct must be initialized prior to mounting. One must always
define the SPI flash access functions:
spiffs_config.hal_read_f - pointing to the function reading the SPI flash
spiffs_config.hal_write_f - pointing to the function writing the SPI flash
spiffs_config.hal_erase_f - pointing to the function erasing the SPI flash
Depending on the build config - if SPIFFS_SINGLETON is set to zero - following
parameters must be defined:
spiffs_config.phys_size - the physical number of bytes accounted for
spiffs on the SPI flash
spiffs_config.phys_addr - the physical starting address on the SPI flash
spiffs_config.phys_erase_block - the physical size of the largest block/sector
on the SPI flash found within the spiffs
usage address space
spiffs_config.log_block_size - the logical size of a spiffs block
spiffs_config.log_page_size - the logical size of a spiffs page
If SPIFFS_SINGLETON is set to one, above parameters must be set ny defines in
the config header file, spiffs_config.h.
** Build config
makefile: The files needed to be compiled to your target resides in files.mk to
be included in your makefile, either by cut and paste or by inclusion.
Types: spiffs uses the types u8_t, s8_t, u16_t, s16_t, u32_t, s32_t; these must
be typedeffed.
spiffs_config.h: you also need to define a spiffs_config.h header. Example of
this is found in the default/ directory.
** RAM
Spiffs needs ram. It needs a working buffer being double the size of the
logical page size. It also needs at least one file descriptor. If cache is
enabled (highly recommended), it will also need a bunch of cache pages.
Say you have a logical page size of 256 bytes. You want to be able to have four
files open simultaneously, and you can give spiffs four cache pages. This
roughly sums up to:
256*2 (work buffer) +
32*4 (file descriptors) +
(256+32)*4 (cache pages) + 40 (cache metadata)
i.e. 1832 bytes.
This is apart from call stack usage.
To get the exact amount of bytes needed on your specific target, enable
SPIFFS_BUFFER_HELP in spiffs_config.h, rebuild and call:
SPIFFS_buffer_bytes_for_filedescs
SPIFFS_buffer_bytes_for_cache
Having these figures you can disable SPIFFS_BUFFER_HELP again to save flash.
* HOW TO CONFIG
TODO

0
cores/esp8266/spiffs/LICENSE Executable file → Normal file
View File

View File

@ -1,110 +0,0 @@
SPIFFS (SPI Flash File System)
V0.3.2
Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976<at>gmail.com)
For legal stuff, see LICENCE in this directory. Basically, you may do whatever
you want with the source. Use, modify, sell, print it out, roll it and smoke it
- as long as I won't be held responsible.
Love to hear feedback though!
* INTRODUCTION
Spiffs is a file system intended for SPI NOR flash devices on embedded targets.
Spiffs is designed with following characteristics in mind:
- Small (embedded) targets, sparse RAM without heap
- Only big areas of data (blocks) can be erased
- An erase will reset all bits in block to ones
- Writing pulls one to zeroes
- Zeroes can only be pulled to ones by erase
- Wear leveling
* FEATURES
What spiffs does:
- Specifically designed for low ram usage
- Uses statically sized ram buffers, independent of number of files
- Posix-like api: open, close, read, write, seek, stat, etc
- It can be run on any NOR flash, not only SPI flash - theoretically also on
embedded flash of an microprocessor
- Multiple spiffs configurations can be run on same target - and even on same
SPI flash device
- Implements static wear leveling
- Built in file system consistency checks
What spiffs does not:
- Presently, spiffs does not support directories. It produces a flat
structure. Creating a file with path "tmp/myfile.txt" will create a file
called "tmp/myfile.txt" instead of a "myfile.txt" under directory "tmp".
- It is not a realtime stack. One write operation might take much longer than
another.
- Poor scalability. Spiffs is intended for small memory devices - the normal
sizes for SPI flashes. Going beyond ~128MB is probably a bad idea. This is
a side effect of the design goal to use as little ram as possible.
- Presently, it does not detect or handle bad blocks.
* MORE INFO
For integration, see the docs/INTEGRATION file.
For use and design, see the docs/TECH_SPEC file.
For testing and contributions, see the docs/IMPLEMENTING file.
* HISTORY
0.3.2
Limit cache size if too much cache is given (thanks pgeiem)
New feature - Controlled erase. #23
SPIFFS_rename leaks file descriptors #28 (thanks benpicco)
moved dbg print defines in test framework to params_test.h
lseek should return the resulting offset (thanks hefloryd)
fixed type on dbg ifdefs
silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco)
Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela)
Cache might writethrough too often #16
even moar testrunner updates
Test framework update and some added tests
Some thoughts for next gen
Test sigsevs when having too many sectors #13 (thanks alonewolfx2)
GC might be suboptimal #11
Fix eternal readdir when objheader at last block, last entry
New API functions:
SPIFFS_gc_quick - call a nonintrusive gc
SPIFFS_gc - call a full-scale intrusive gc
0.3.1
Removed two return warnings, was too triggerhappy on release
0.3.0
Added existing namecheck when creating files
Lots of static analysis bugs #6
Added rename func
Fix SPIFFS_read length when reading beyond file size
Added reading beyond file length testcase
Made build a bit more configurable
Changed name in spiffs from "errno" to "err_code" due to conflicts compiling
in mingw
Improved GC checks, fixed an append bug, more robust truncate for very special
case
GC checks preempts GC, truncate even less picky
Struct alignment needed for some targets, define in spiffs config #10
Spiffs filesystem magic, definable in config
New config defines:
SPIFFS_USE_MAGIC - enable or disable magic check upon mount
SPIFFS_ALIGNED_OBJECT_INDEX_TABLES - alignment for certain targets
New API functions:
SPIFFS_rename - rename files
SPIFFS_clearerr - clears last errno
SPIFFS_info - returns info on used and total bytes in fs
SPIFFS_format - formats the filesystem
SPIFFS_mounted - checks if filesystem is mounted

View File

@ -0,0 +1,146 @@
# SPIFFS (SPI Flash File System)
**V0.3.4**
Copyright (c) 2013-2016 Peter Andersson (pelleplutt1976 at gmail.com)
For legal stuff, see [LICENSE](https://github.com/pellepl/spiffs/blob/master/LICENSE). Basically, you may do whatever you want with the source. Use, modify, sell, print it out, roll it and smoke it - as long as I won't be held responsible.
Love to hear feedback though!
## INTRODUCTION
Spiffs is a file system intended for SPI NOR flash devices on embedded targets.
Spiffs is designed with following characteristics in mind:
- Small (embedded) targets, sparse RAM without heap
- Only big areas of data (blocks) can be erased
- An erase will reset all bits in block to ones
- Writing pulls one to zeroes
- Zeroes can only be pulled to ones by erase
- Wear leveling
## FEATURES
What spiffs does:
- Specifically designed for low ram usage
- Uses statically sized ram buffers, independent of number of files
- Posix-like api: open, close, read, write, seek, stat, etc
- It can be run on any NOR flash, not only SPI flash - theoretically also on embedded flash of an microprocessor
- Multiple spiffs configurations can be run on same target - and even on same SPI flash device
- Implements static wear leveling
- Built in file system consistency checks
What spiffs does not:
- Presently, spiffs does not support directories. It produces a flat structure. Creating a file with path *tmp/myfile.txt* will create a file called *tmp/myfile.txt* instead of a *myfile.txt* under directory *tmp*.
- It is not a realtime stack. One write operation might take much longer than another.
- Poor scalability. Spiffs is intended for small memory devices - the normal sizes for SPI flashes. Going beyond ~128MB is probably a bad idea. This is a side effect of the design goal to use as little ram as possible.
- Presently, it does not detect or handle bad blocks.
## MORE INFO
See the [wiki](https://github.com/pellepl/spiffs/wiki) for configuring, integrating and using spiffs.
For design, see [docs/TECH_SPEC](https://github.com/pellepl/spiffs/blob/master/docs/TECH_SPEC).
For a generic spi flash driver, see [this](https://github.com/pellepl/spiflash_driver).
## HISTORY
### 0.3.4
- Added user callback file func.
- Fixed a stat bug with obj id.
- SPIFFS_probe_fs added
- Add possibility to compile a read-only version of spiffs
- Make magic dependent on fs length, if needed (see #59 & #66) (thanks @hreintke)
- Exposed SPIFFS_open_by_page_function
- Zero-size file cannot be seek #57 (thanks @lishen2)
- Add tell and eof functions #54 (thanks @raburton)
- Make api string params const #53 (thanks @raburton)
- Preserve user_data during mount() #51 (thanks @rojer)
New API functions:
- `SPIFFS_set_file_callback_func` - register a callback informing about file events
- `SPIFFS_probe_fs` - probe a spi flash trying to figure out size of fs
- `SPIFFS_open_by_page` - open a file by page index
- `SPIFFS_eof` - checks if end of file is reached
- `SPIFFS_tell` - returns current file offset
New config defines:
- `SPIFFS_READ_ONLY`
- `SPIFFS_USE_MAGIC_LENGTH`
### 0.3.3
**Might not be compatible with 0.3.2 structures. See issue #40**
- Possibility to add integer offset to file handles
- Truncate function presumes too few free pages #49
- Bug in truncate function #48 (thanks @PawelDefee)
- Update spiffs_gc.c - remove unnecessary parameter (thanks @PawelDefee)
- Update INTEGRATION docs (thanks @PawelDefee)
- Fix pointer truncation in 64-bit platforms (thanks @igrr)
- Zero-sized files cannot be read #44 (thanks @rojer)
- (More) correct calculation of max_id in obj_lu_find #42 #41 (thanks @lishen2)
- Check correct error code in obj_lu_find_free #41 (thanks @lishen2)
- Moar comments for SPIFFS_lseek (thanks @igrr)
- Fixed padding in spiffs_page_object_ix #40 (thanks @jmattsson @lishen2)
- Fixed gc_quick test (thanks @jmattsson)
- Add SPIFFS_EXCL flag #36
- SPIFFS_close may fail silently if cache is enabled #37
- User data in callbacks #34
- Ignoring SINGLETON build in cache setup (thanks Luca)
- Compilation error fixed #32 (thanks @chotasanjiv)
- Align cand_scores (thanks @hefloryd)
- Fix build warnings when SPIFFS_CACHE is 0 (thanks @ajaybhargav)
New config defines:
- `SPIFFS_FILEHDL_OFFSET`
### 0.3.2
- Limit cache size if too much cache is given (thanks pgeiem)
- New feature - Controlled erase. #23
- SPIFFS_rename leaks file descriptors #28 (thanks benpicco)
- moved dbg print defines in test framework to params_test.h
- lseek should return the resulting offset (thanks hefloryd)
- fixed type on dbg ifdefs
- silence warning about signed/unsigned comparison when spiffs_obj_id is 32 bit (thanks benpicco)
- Possible error in test_spiffs.c #21 (thanks yihcdaso-yeskela)
- Cache might writethrough too often #16
- even moar testrunner updates
- Test framework update and some added tests
- Some thoughts for next gen
- Test sigsevs when having too many sectors #13 (thanks alonewolfx2)
- GC might be suboptimal #11
- Fix eternal readdir when objheader at last block, last entry
New API functions:
- `SPIFFS_gc_quick` - call a nonintrusive gc
- `SPIFFS_gc` - call a full-scale intrusive gc
### 0.3.1
- Removed two return warnings, was too triggerhappy on release
### 0.3.0
- Added existing namecheck when creating files
- Lots of static analysis bugs #6
- Added rename func
- Fix SPIFFS_read length when reading beyond file size
- Added reading beyond file length testcase
- Made build a bit more configurable
- Changed name in spiffs from "errno" to "err_code" due to conflicts compiling in mingw
- Improved GC checks, fixed an append bug, more robust truncate for very special case
- GC checks preempts GC, truncate even less picky
- Struct alignment needed for some targets, define in spiffs config #10
- Spiffs filesystem magic, definable in config
New config defines:
- `SPIFFS_USE_MAGIC` - enable or disable magic check upon mount
- `SPIFFS_ALIGNED_OBJECT_INDEX_TABLES` - alignment for certain targets
New API functions:
- `SPIFFS_rename` - rename files
- `SPIFFS_clearerr` - clears last errno
- `SPIFFS_info` - returns info on used and total bytes in fs
- `SPIFFS_format` - formats the filesystem
- `SPIFFS_mounted` - checks if filesystem is mounted

View File

@ -49,6 +49,11 @@ extern "C" {
#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_INTERNAL -10050
#define SPIFFS_ERR_TEST -10100
@ -63,9 +68,10 @@ typedef u16_t spiffs_mode;
// object type
typedef u8_t spiffs_obj_type;
#if SPIFFS_HAL_CALLBACK_EXTRA
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 */
@ -110,6 +116,19 @@ typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_repor
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__)
@ -247,7 +266,8 @@ typedef struct spiffs_t {
// 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
@ -261,6 +281,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;
@ -280,6 +301,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
@ -326,14 +381,13 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, 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.
* Optimization purposes, when traversing a file system with SPIFFS_readdir
* 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.
@ -342,6 +396,22 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs
*/
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
@ -562,6 +632,22 @@ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
*/
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.

View File

@ -19,9 +19,11 @@
* Author: petera
*/
#include "spiffs.h"
#include "spiffs_nucleus.h"
#if !SPIFFS_READ_ONLY
#if SPIFFS_HAL_CALLBACK_EXTRA
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
@ -106,6 +108,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,
@ -989,3 +992,4 @@ s32_t spiffs_object_index_consistency_check(spiffs *fs) {
return res;
}
#endif // !SPIFFS_READ_ONLY

View File

@ -1,6 +1,8 @@
#include "spiffs.h"
#include "spiffs_nucleus.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
// is dropped.
@ -571,3 +573,4 @@ s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
return res;
}
#endif // !SPIFFS_READ_ONLY

View File

@ -36,6 +36,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;
@ -59,8 +63,18 @@ 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,
@ -167,6 +181,10 @@ void SPIFFS_clearerr(spiffs *fs) {
}
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);
@ -180,6 +198,7 @@ s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
SPIFFS_UNLOCK(fs);
return 0;
#endif // SPIFFS_READ_ONLY
}
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {
@ -191,6 +210,11 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs
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);
@ -211,6 +235,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs
}
if ((flags & SPIFFS_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);
@ -224,6 +249,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs
}
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
flags &= ~SPIFFS_TRUNC;
#endif // !SPIFFS_READ_ONLY
} else {
if (res < SPIFFS_OK) {
spiffs_fd_return(fs, fd->file_nbr);
@ -235,6 +261,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs
spiffs_fd_return(fs, fd->file_nbr);
}
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
#if !SPIFFS_READ_ONLY
if (flags & SPIFFS_TRUNC) {
res = spiffs_object_truncate(fd, 0, 0);
if (res < SPIFFS_OK) {
@ -242,6 +269,7 @@ spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs
}
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
}
#endif // !SPIFFS_READ_ONLY
fd->fdoffset = 0;
@ -265,6 +293,7 @@ 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 !SPIFFS_READ_ONLY
if (flags & SPIFFS_TRUNC) {
res = spiffs_object_truncate(fd, 0, 0);
if (res < SPIFFS_OK) {
@ -272,6 +301,53 @@ spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_fl
}
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);
}
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_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;
@ -334,6 +410,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;
@ -355,8 +432,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);
@ -374,6 +456,10 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
}
if ((fd->flags & SPIFFS_APPEND)) {
fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
}
offset = fd->fdoffset;
#if SPIFFS_CACHE_WR
@ -474,6 +560,7 @@ s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
SPIFFS_UNLOCK(fs);
return res;
#endif // SPIFFS_READ_ONLY
}
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
@ -500,7 +587,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);
@ -523,6 +610,10 @@ s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
}
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);
SPIFFS_LOCK(fs);
@ -554,9 +645,14 @@ s32_t SPIFFS_remove(spiffs *fs, const 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);
@ -583,6 +679,7 @@ 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) {
@ -599,9 +696,10 @@ 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;
@ -655,7 +753,7 @@ 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);
@ -689,7 +787,7 @@ s32_t SPIFFS_fflush(spiffs *fs, spiffs_file 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);
@ -721,6 +819,10 @@ s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
}
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *new) {
#if SPIFFS_READ_ONLY
(void)fs; (void)old; (void)new;
return SPIFFS_ERR_RO_NOT_IMPL;
#else
SPIFFS_API_CHECK_CFG(fs);
SPIFFS_API_CHECK_MOUNT(fs);
SPIFFS_LOCK(fs);
@ -758,6 +860,7 @@ s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *new) {
SPIFFS_UNLOCK(fs);
return res;
#endif // SPIFFS_READ_ONLY
}
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {
@ -854,6 +957,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);
@ -869,6 +976,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) {
@ -896,6 +1004,10 @@ s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
}
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);
@ -906,10 +1018,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);
@ -920,6 +1037,7 @@ 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) {
@ -939,7 +1057,7 @@ s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
#endif
res = (fd->fdoffset == fd->size);
res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size));
SPIFFS_UNLOCK(fs);
return res;
@ -968,6 +1086,12 @@ s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
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) {

View File

@ -29,6 +29,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 +57,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
@ -77,6 +79,7 @@ s32_t spiffs_phys_wr(
#endif
#if !SPIFFS_READ_ONLY
s32_t spiffs_phys_cpy(
spiffs *fs,
spiffs_file fh,
@ -98,6 +101,7 @@ 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.
@ -218,6 +222,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) {
@ -243,7 +248,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);
@ -257,6 +262,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(
@ -311,7 +369,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;
@ -349,8 +407,12 @@ s32_t spiffs_obj_lu_scan(
#if SPIFFS_USE_MAGIC
if (unerased_bix != (spiffs_block_ix)-1) {
// found one unerased block, remedy
SPIFFS_DBG("mount: erase block %d\n", bix);
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
@ -381,6 +443,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(
@ -415,6 +478,7 @@ s32_t spiffs_obj_lu_find_free(
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
@ -536,6 +600,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
@ -593,7 +658,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(
@ -656,7 +723,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,
@ -685,7 +754,9 @@ 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,
@ -706,7 +777,7 @@ s32_t spiffs_object_create(
// find free entry
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("create: found free page @ %04x bix:%d entry:%d\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
SPIFFS_DBG("create: found free page @ %04x bix:%i entry:%i\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
// occupy page in object lookup
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
@ -737,7 +808,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
@ -792,18 +865,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++) {
@ -811,7 +885,7 @@ void spiffs_cb_object_event(
if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
if (spix == 0) {
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
SPIFFS_DBG(" callback: setting fd %d:%04x objix_hdr_pix to %04x, size:%d\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
SPIFFS_DBG(" callback: setting fd %i:%04x objix_hdr_pix to %04x, size:%i\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
cur_fd->objix_hdr_pix = new_pix;
if (new_size != 0) {
cur_fd->size = new_size;
@ -823,13 +897,29 @@ void spiffs_cb_object_event(
}
if (cur_fd->cursor_objix_spix == spix) {
if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
SPIFFS_DBG(" callback: setting fd %d:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
SPIFFS_DBG(" callback: setting fd %i:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
cur_fd->cursor_objix_pix = new_pix;
} else {
cur_fd->cursor_objix_pix = 0;
}
}
}
// 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
@ -883,11 +973,12 @@ s32_t spiffs_object_open_by_page(
SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
SPIFFS_DBG("open: fd %d is obj id %04x\n", fd->file_nbr, fd->obj_id);
SPIFFS_DBG("open: fd %i is obj id %04x\n", fd->file_nbr, fd->obj_id);
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) {
@ -895,7 +986,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
s32_t res = SPIFFS_OK;
u32_t written = 0;
SPIFFS_DBG("append: %d bytes @ offs %d of size %d\n", len, offset, fd->size);
SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size);
if (offset > fd->size) {
SPIFFS_DBG("append: offset reversed to size\n");
@ -904,7 +995,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
if (res != SPIFFS_OK) {
SPIFFS_DBG("append: gc check fail %d\n", res);
SPIFFS_DBG("append: gc check fail %i\n", res);
}
SPIFFS_CHECK_RES(res);
@ -932,7 +1023,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// within this clause we return directly if something fails, object index mess-up
if (written > 0) {
// store previous object index page, unless first pass
SPIFFS_DBG("append: %04x store objix %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store objix %04x:%04x, written %i\n", fd->obj_id,
cur_objix_pix, prev_objix_spix, written);
if (prev_objix_spix == 0) {
// this is an update to object index header page
@ -949,7 +1040,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
new_objix_hdr_page, 0, written);
}
} else {
@ -965,7 +1056,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
SPIFFS_CHECK_RES(res);
SPIFFS_DBG("append: %04x store new size I %d in objix_hdr, %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store new size I %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
offset+written, new_objix_hdr_page, 0, written);
}
fd->size = offset+written;
@ -994,7 +1085,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// quick "load" of new object index page
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %d\n", fd->obj_id
SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %i\n", fd->obj_id
, cur_objix_pix, cur_objix_spix, written);
} else {
// on first pass, we load existing object index page
@ -1006,7 +1097,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
SPIFFS_CHECK_RES(res);
}
SPIFFS_DBG("append: %04x found object index at page %04x [fd size %d]\n", fd->obj_id, pix, fd->size);
SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\n", fd->obj_id, pix, fd->size);
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
SPIFFS_CHECK_RES(res);
@ -1030,7 +1121,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
&p_hdr, &data[written], to_write, page_offs, 1, &data_page);
SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%d, len %d, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id,
data_page, data_spix, page_offs, to_write, written);
} else {
// append to existing page, fill out free data in existing page
@ -1047,7 +1138,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%d, len %d, written %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id
, data_page, data_spix, page_offs, to_write, written);
}
@ -1083,7 +1174,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
if (cur_objix_spix != 0) {
// wrote beyond object index header page
// write last modified object index page, unless object header index page
SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %d\n", fd->obj_id,
SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %i\n", fd->obj_id,
cur_objix_pix, cur_objix_spix, written);
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
@ -1097,7 +1188,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// update size in object header index page
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
SPIFFS_DBG("append: %04x store new size II %d in objix_hdr, %04x:%04x, written %d, res %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id
, offset+written, new_objix_hdr_page, 0, written, res2);
SPIFFS_CHECK_RES(res2);
} else {
@ -1105,7 +1196,7 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
if (offset == 0) {
// wrote to empty object - simply update size and write whole page
objix_hdr->size = offset+written;
SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
, cur_objix_pix, cur_objix_spix, written);
res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
@ -1120,15 +1211,17 @@ s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// modifying object index header page, update size and make new copy
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %d\n", fd->obj_id
SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
, new_objix_hdr_page, 0, written);
SPIFFS_CHECK_RES(res2);
}
}
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) {
@ -1168,7 +1261,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// store previous object index header page
res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %d\n", new_objix_hdr_pix, 0, written);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
SPIFFS_CHECK_RES(res);
} else {
// store new version of previous object index page
@ -1178,7 +1271,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
SPIFFS_CHECK_RES(res);
res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %d\n", new_objix_pix, objix->p_hdr.span_ix, written);
SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %i\n", new_objix_pix, objix->p_hdr.span_ix, written);
SPIFFS_CHECK_RES(res);
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
}
@ -1233,7 +1326,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// a full page, allocate and write a new page of data
res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
&p_hdr, &data[written], to_write, page_offs, 1, &data_pix);
SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%d, len %d, written %d\n", data_pix, data_spix, page_offs, to_write, written);
SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%i, len %i, written %i\n", data_pix, data_spix, page_offs, to_write, written);
} else {
// write to existing page, allocate new and copy unmodified data
@ -1274,7 +1367,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
(u8_t *)&p_hdr.flags);
if (res != SPIFFS_OK) break;
SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%d, len %d, written %d\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%i, len %i, written %i\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
}
// delete original data page
@ -1313,7 +1406,7 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
SPIFFS_CHECK_RES(res2);
res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %d\n", new_objix_pix, cur_objix_spix, written);
SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %i\n", new_objix_pix, cur_objix_spix, written);
fd->cursor_objix_pix = new_objix_pix;
fd->cursor_objix_spix = cur_objix_spix;
SPIFFS_CHECK_RES(res2);
@ -1323,12 +1416,13 @@ s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
// wrote within object index header page
res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %d\n", new_objix_hdr_pix, 0, written);
SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
SPIFFS_CHECK_RES(res2);
}
return res;
}
} // spiffs_object_modify
#endif // !SPIFFS_READ_ONLY
static s32_t spiffs_object_find_object_index_header_by_name_v(
spiffs *fs,
@ -1394,6 +1488,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,
@ -1402,6 +1497,11 @@ s32_t spiffs_object_truncate(
s32_t res = SPIFFS_OK;
spiffs *fs = fd->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
res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs) * 2);
SPIFFS_CHECK_RES(res);
@ -1444,7 +1544,7 @@ s32_t spiffs_object_truncate(
spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);
if (prev_objix_spix > 0) {
// update object index header page
SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %d\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
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);
@ -1487,14 +1587,14 @@ s32_t spiffs_object_truncate(
// 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) {
SPIFFS_DBG("truncate: err validating data pix %d\n", res);
SPIFFS_DBG("truncate: err validating data pix %i\n", res);
break;
}
if (res == SPIFFS_OK) {
res = spiffs_page_delete(fs, data_pix);
if (res != SPIFFS_OK) {
SPIFFS_DBG("truncate: err deleting data pix %d\n", res);
SPIFFS_DBG("truncate: err deleting data pix %i\n", res);
break;
}
} else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
@ -1509,13 +1609,13 @@ s32_t spiffs_object_truncate(
}
fd->size = cur_size;
fd->offset = cur_size;
SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%d\n", data_pix, data_spix, cur_size);
SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%i\n", data_pix, data_spix, cur_size);
} else {
// delete last page, partially
spiffs_page_header p_hdr;
spiffs_page_ix new_data_pix;
u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));
SPIFFS_DBG("truncate: delete %d bytes from data page %04x for data spix:%04x, cur_size:%d\n", bytes_to_remove, data_pix, data_spix, cur_size);
SPIFFS_DBG("truncate: delete %i bytes from data page %04x for data spix:%04x, cur_size:%i\n", bytes_to_remove, data_pix, data_spix, cur_size);
res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
if (res != SPIFFS_OK) break;
@ -1614,7 +1714,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,
@ -1670,7 +1771,7 @@ s32_t spiffs_object_read(
len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
// remaining data in file
len_to_read = MIN(len_to_read, fd->size);
SPIFFS_DBG("read: offset:%d rd:%d data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix,
SPIFFS_DBG("read: offset:%i rd:%i data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix,
SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
if (len_to_read <= 0) {
res = SPIFFS_ERR_END_OF_OBJECT;
@ -1694,6 +1795,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;
@ -1756,7 +1858,7 @@ static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id
if (id >= state->min_obj_id && id <= state->max_obj_id) {
u8_t *map = (u8_t *)fs->work;
int ix = (id - state->min_obj_id) / state->compaction;
//SPIFFS_DBG("free_obj_id: add ix %d for id %04x min:%04x max%04x comp:%d\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
//SPIFFS_DBG("free_obj_id: add ix %i for id %04x min:%04x max%04x comp:%i\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
map[ix]++;
}
}
@ -1829,7 +1931,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8
return SPIFFS_ERR_FULL;
}
SPIFFS_DBG("free_obj_id: COMP select index:%d min_count:%d min:%04x max:%04x compact:%d\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
SPIFFS_DBG("free_obj_id: COMP select index:%i min_count:%i min:%04x max:%04x compact:%i\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
if (min_count == 0) {
// no id in this range, skip compacting and use directly
@ -1849,7 +1951,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8
// in a work memory of log_page_size bytes, we may fit in log_page_size ids
// todo what if compaction is > 255 - then we cannot fit it in a byte
state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));
SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%d\n", state.min_obj_id, state.max_obj_id, state.compaction);
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, &state, 0, 0, 0);
@ -1861,6 +1963,7 @@ s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8
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)
@ -530,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(