From 6a7551e1f02e17df62e7e5c3efeee7818f4ba33b Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 10 Mar 2016 13:00:38 +0300 Subject: [PATCH] Update SPIFFS to 82aeac6 Fixes duplicate files issue (#1685) --- cores/esp8266/spiffs/INTEGRATION | 306 ------------------------- cores/esp8266/spiffs/LICENSE | 0 cores/esp8266/spiffs/README | 110 --------- cores/esp8266/spiffs/README.md | 146 ++++++++++++ cores/esp8266/spiffs/spiffs.h | 94 +++++++- cores/esp8266/spiffs/spiffs_check.c | 4 + cores/esp8266/spiffs/spiffs_gc.c | 3 + cores/esp8266/spiffs/spiffs_hydrogen.c | 134 ++++++++++- cores/esp8266/spiffs/spiffs_nucleus.c | 183 +++++++++++---- cores/esp8266/spiffs/spiffs_nucleus.h | 15 +- 10 files changed, 529 insertions(+), 466 deletions(-) delete mode 100644 cores/esp8266/spiffs/INTEGRATION mode change 100755 => 100644 cores/esp8266/spiffs/LICENSE delete mode 100644 cores/esp8266/spiffs/README create mode 100644 cores/esp8266/spiffs/README.md diff --git a/cores/esp8266/spiffs/INTEGRATION b/cores/esp8266/spiffs/INTEGRATION deleted file mode 100644 index 20ff70d05..000000000 --- a/cores/esp8266/spiffs/INTEGRATION +++ /dev/null @@ -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 - - 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 diff --git a/cores/esp8266/spiffs/LICENSE b/cores/esp8266/spiffs/LICENSE old mode 100755 new mode 100644 diff --git a/cores/esp8266/spiffs/README b/cores/esp8266/spiffs/README deleted file mode 100644 index 673049d57..000000000 --- a/cores/esp8266/spiffs/README +++ /dev/null @@ -1,110 +0,0 @@ -SPIFFS (SPI Flash File System) -V0.3.2 - -Copyright (c) 2013-2015 Peter Andersson (pelleplutt1976gmail.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 - - diff --git a/cores/esp8266/spiffs/README.md b/cores/esp8266/spiffs/README.md new file mode 100644 index 000000000..5f8efd8da --- /dev/null +++ b/cores/esp8266/spiffs/README.md @@ -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 diff --git a/cores/esp8266/spiffs/spiffs.h b/cores/esp8266/spiffs/spiffs.h index 0a8d0220f..c625d9315 100644 --- a/cores/esp8266/spiffs/spiffs.h +++ b/cores/esp8266/spiffs/spiffs.h @@ -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. diff --git a/cores/esp8266/spiffs/spiffs_check.c b/cores/esp8266/spiffs/spiffs_check.c index 0576843e3..8dd6665bd 100644 --- a/cores/esp8266/spiffs/spiffs_check.c +++ b/cores/esp8266/spiffs/spiffs_check.c @@ -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 diff --git a/cores/esp8266/spiffs/spiffs_gc.c b/cores/esp8266/spiffs/spiffs_gc.c index 91d7e54a1..8abb8dfc3 100644 --- a/cores/esp8266/spiffs/spiffs_gc.c +++ b/cores/esp8266/spiffs/spiffs_gc.c @@ -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 diff --git a/cores/esp8266/spiffs/spiffs_hydrogen.c b/cores/esp8266/spiffs/spiffs_hydrogen.c index 6c31da2de..c43ddcdc3 100644 --- a/cores/esp8266/spiffs/spiffs_hydrogen.c +++ b/cores/esp8266/spiffs/spiffs_hydrogen.c @@ -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) { diff --git a/cores/esp8266/spiffs/spiffs_nucleus.c b/cores/esp8266/spiffs/spiffs_nucleus.c index 96ff4c92a..8a3c72530 100644 --- a/cores/esp8266/spiffs/spiffs_nucleus.c +++ b/cores/esp8266/spiffs/spiffs_nucleus.c @@ -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; diff --git a/cores/esp8266/spiffs/spiffs_nucleus.h b/cores/esp8266/spiffs/spiffs_nucleus.h index b64d10cac..6e4e8ac33 100644 --- a/cores/esp8266/spiffs/spiffs_nucleus.h +++ b/cores/esp8266/spiffs/spiffs_nucleus.h @@ -131,7 +131,15 @@ #define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0) #define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1) -#define SPIFFS_MAGIC(fs) ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) +#if SPIFFS_USE_MAGIC +#if !SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_MAGIC(fs, bix) \ + ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs))) +#else // SPIFFS_USE_MAGIC_LENGTH +#define SPIFFS_MAGIC(fs, bix) \ + ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix)))) +#endif // SPIFFS_USE_MAGIC_LENGTH +#endif // SPIFFS_USE_MAGIC #define SPIFFS_CONFIG_MAGIC (0x20090315) @@ -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(