847 lines
25 KiB
C
847 lines
25 KiB
C
|
/*
|
||
|
* spiffs_nucleus.h
|
||
|
*
|
||
|
* Created on: Jun 15, 2013
|
||
|
* Author: petera
|
||
|
*/
|
||
|
|
||
|
/* SPIFFS layout
|
||
|
*
|
||
|
* spiffs is designed for following spi flash characteristics:
|
||
|
* - only big areas of data (blocks) can be erased
|
||
|
* - erasing resets all bits in a block to ones
|
||
|
* - writing pulls ones to zeroes
|
||
|
* - zeroes cannot be pulled to ones, without erase
|
||
|
* - wear leveling
|
||
|
*
|
||
|
* spiffs is also meant to be run on embedded, memory constraint devices.
|
||
|
*
|
||
|
* Entire area is divided in blocks. Entire area is also divided in pages.
|
||
|
* Each block contains same number of pages. A page cannot be erased, but a
|
||
|
* block can be erased.
|
||
|
*
|
||
|
* Entire area must be block_size * x
|
||
|
* page_size must be block_size / (2^y) where y > 2
|
||
|
*
|
||
|
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||
|
*
|
||
|
* BLOCK 0 PAGE 0 object lookup 1
|
||
|
* PAGE 1 object lookup 2
|
||
|
* ...
|
||
|
* PAGE n-1 object lookup n
|
||
|
* PAGE n object data 1
|
||
|
* PAGE n+1 object data 2
|
||
|
* ...
|
||
|
* PAGE n+m-1 object data m
|
||
|
*
|
||
|
* BLOCK 1 PAGE n+m object lookup 1
|
||
|
* PAGE n+m+1 object lookup 2
|
||
|
* ...
|
||
|
* PAGE 2n+m-1 object lookup n
|
||
|
* PAGE 2n+m object data 1
|
||
|
* PAGE 2n+m object data 2
|
||
|
* ...
|
||
|
* PAGE 2n+2m-1 object data m
|
||
|
* ...
|
||
|
*
|
||
|
* n is number of object lookup pages, which is number of pages needed to index all pages
|
||
|
* in a block by object id
|
||
|
* : block_size / page_size * sizeof(obj_id) / page_size
|
||
|
* m is number data pages, which is number of pages in block minus number of lookup pages
|
||
|
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||
|
* thus, n+m is total number of pages in a block
|
||
|
* : block_size / page_size
|
||
|
*
|
||
|
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||
|
*
|
||
|
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
||
|
* data page.
|
||
|
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||
|
* An object id being 0x0000 represents a deleted page.
|
||
|
*
|
||
|
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||
|
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||
|
* page 2 : data : data for object id 0008
|
||
|
* page 3 : data : data for object id 0001
|
||
|
* page 4 : data : data for object id 0aaa
|
||
|
* ...
|
||
|
*
|
||
|
*
|
||
|
* Object data pages can be either object index pages or object content.
|
||
|
* All object data pages contains a data page header, containing object id and span index.
|
||
|
* The span index denotes the object page ordering amongst data pages with same object id.
|
||
|
* This applies to both object index pages (when index spans more than one page of entries),
|
||
|
* and object data pages.
|
||
|
* An object index page contains page entries pointing to object content page. The entry index
|
||
|
* in a object index page correlates to the span index in the actual object data page.
|
||
|
* The first object index page (span index 0) is called object index header page, and also
|
||
|
* contains object flags (directory/file), size, object name etc.
|
||
|
*
|
||
|
* ex:
|
||
|
* BLOCK 1
|
||
|
* PAGE 256: objectl lookup page 1
|
||
|
* [*123] [ 123] [ 123] [ 123]
|
||
|
* [ 123] [*123] [ 123] [ 123]
|
||
|
* [free] [free] [free] [free] ...
|
||
|
* PAGE 257: objectl lookup page 2
|
||
|
* [free] [free] [free] [free] ...
|
||
|
* PAGE 258: object index page (header)
|
||
|
* obj.id:0123 span.ix:0000 flags:INDEX
|
||
|
* size:1600 name:ex.txt type:file
|
||
|
* [259] [260] [261] [262]
|
||
|
* PAGE 259: object data page
|
||
|
* obj.id:0123 span.ix:0000 flags:DATA
|
||
|
* PAGE 260: object data page
|
||
|
* obj.id:0123 span.ix:0001 flags:DATA
|
||
|
* PAGE 261: object data page
|
||
|
* obj.id:0123 span.ix:0002 flags:DATA
|
||
|
* PAGE 262: object data page
|
||
|
* obj.id:0123 span.ix:0003 flags:DATA
|
||
|
* PAGE 263: object index page
|
||
|
* obj.id:0123 span.ix:0001 flags:INDEX
|
||
|
* [264] [265] [fre] [fre]
|
||
|
* [fre] [fre] [fre] [fre]
|
||
|
* PAGE 264: object data page
|
||
|
* obj.id:0123 span.ix:0004 flags:DATA
|
||
|
* PAGE 265: object data page
|
||
|
* obj.id:0123 span.ix:0005 flags:DATA
|
||
|
*
|
||
|
*/
|
||
|
#ifndef SPIFFS_NUCLEUS_H_
|
||
|
#define SPIFFS_NUCLEUS_H_
|
||
|
|
||
|
#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1)
|
||
|
#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1)
|
||
|
#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2)
|
||
|
#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
|
||
|
#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
|
||
|
|
||
|
// visitor result, continue searching
|
||
|
#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
|
||
|
// visitor result, continue searching after reloading lu buffer
|
||
|
#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
|
||
|
// visitor result, stop searching
|
||
|
#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
|
||
|
|
||
|
// updating an object index contents
|
||
|
#define SPIFFS_EV_IX_UPD (0)
|
||
|
// creating a new object index
|
||
|
#define SPIFFS_EV_IX_NEW (1)
|
||
|
// deleting an object index
|
||
|
#define SPIFFS_EV_IX_DEL (2)
|
||
|
// moving an object index without updating contents
|
||
|
#define SPIFFS_EV_IX_MOV (3)
|
||
|
// updating an object index header data only, not the table itself
|
||
|
#define SPIFFS_EV_IX_UPD_HDR (4)
|
||
|
|
||
|
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
|
||
|
|
||
|
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
||
|
|
||
|
#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
|
||
|
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
|
||
|
|
||
|
|
||
|
|
||
|
#if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
|
||
|
/* For GCC, clang and TI compilers */
|
||
|
#define SPIFFS_PACKED __attribute__((packed))
|
||
|
#elif defined(__ICCARM__) || defined(__CC_ARM)
|
||
|
/* For IAR ARM and Keil MDK-ARM compilers */
|
||
|
#define SPIFFS_PACKED
|
||
|
|
||
|
#else
|
||
|
/* Unknown compiler */
|
||
|
#define SPIFFS_PACKED
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
#if SPIFFS_USE_MAGIC
|
||
|
#if !SPIFFS_USE_MAGIC_LENGTH
|
||
|
#define SPIFFS_MAGIC(fs, bix) \
|
||
|
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
|
||
|
#else // SPIFFS_USE_MAGIC_LENGTH
|
||
|
#define SPIFFS_MAGIC(fs, bix) \
|
||
|
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))
|
||
|
#endif // SPIFFS_USE_MAGIC_LENGTH
|
||
|
#endif // SPIFFS_USE_MAGIC
|
||
|
|
||
|
#define SPIFFS_CONFIG_MAGIC (0x20090315)
|
||
|
|
||
|
#if SPIFFS_SINGLETON == 0
|
||
|
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
|
||
|
((fs)->cfg.log_page_size)
|
||
|
#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
|
||
|
((fs)->cfg.log_block_size)
|
||
|
#define SPIFFS_CFG_PHYS_SZ(fs) \
|
||
|
((fs)->cfg.phys_size)
|
||
|
#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
|
||
|
((fs)->cfg.phys_erase_block)
|
||
|
#define SPIFFS_CFG_PHYS_ADDR(fs) \
|
||
|
((fs)->cfg.phys_addr)
|
||
|
#endif
|
||
|
|
||
|
// total number of pages
|
||
|
#define SPIFFS_MAX_PAGES(fs) \
|
||
|
( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||
|
// total number of pages per block, including object lookup pages
|
||
|
#define SPIFFS_PAGES_PER_BLOCK(fs) \
|
||
|
( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||
|
// number of object lookup pages per block
|
||
|
#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
|
||
|
(MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
|
||
|
// checks if page index belongs to object lookup
|
||
|
#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
|
||
|
(((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||
|
// number of object lookup entries in all object lookup pages
|
||
|
#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
|
||
|
(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||
|
// converts a block to physical address
|
||
|
#define SPIFFS_BLOCK_TO_PADDR(fs, block) \
|
||
|
( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
|
||
|
// converts a object lookup entry to page index
|
||
|
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
|
||
|
((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
|
||
|
// converts a object lookup entry to physical address of corresponding page
|
||
|
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
|
||
|
(SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||
|
// converts a page to physical address
|
||
|
#define SPIFFS_PAGE_TO_PADDR(fs, page) \
|
||
|
( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||
|
// converts a physical address to page
|
||
|
#define SPIFFS_PADDR_TO_PAGE(fs, addr) \
|
||
|
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||
|
// gives index in page for a physical address
|
||
|
#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
|
||
|
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||
|
// returns containing block for given page
|
||
|
#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
|
||
|
( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )
|
||
|
// returns starting page for block
|
||
|
#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
|
||
|
( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )
|
||
|
// converts page to entry in object lookup page
|
||
|
#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
|
||
|
( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )
|
||
|
// returns data size in a data page
|
||
|
#define SPIFFS_DATA_PAGE_SIZE(fs) \
|
||
|
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
|
||
|
// returns physical address for block's erase count,
|
||
|
// always in the physical last entry of the last object lookup page
|
||
|
#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
|
||
|
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
|
||
|
// returns physical address for block's magic,
|
||
|
// always in the physical second last entry of the last object lookup page
|
||
|
#define SPIFFS_MAGIC_PADDR(fs, bix) \
|
||
|
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
|
||
|
// checks if there is any room for magic in the object luts
|
||
|
#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
|
||
|
( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
|
||
|
<= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
|
||
|
|
||
|
// define helpers object
|
||
|
|
||
|
// entries in an object header page index
|
||
|
#define SPIFFS_OBJ_HDR_IX_LEN(fs) \
|
||
|
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
|
||
|
// entries in an object page index
|
||
|
#define SPIFFS_OBJ_IX_LEN(fs) \
|
||
|
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
|
||
|
// object index entry for given data span index
|
||
|
#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
|
||
|
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
|
||
|
// object index span index number for given data span index or entry
|
||
|
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
|
||
|
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
|
||
|
// get data span index for object index span index
|
||
|
#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \
|
||
|
( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )
|
||
|
|
||
|
#if SPIFFS_FILEHDL_OFFSET
|
||
|
#define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)
|
||
|
#define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)
|
||
|
#else
|
||
|
#define SPIFFS_FH_OFFS(fs, fh) ((spiffs_file)(fh))
|
||
|
#define SPIFFS_FH_UNOFFS(fs, fh) ((spiffs_file)(fh))
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define SPIFFS_OP_T_OBJ_LU (0<<0)
|
||
|
#define SPIFFS_OP_T_OBJ_LU2 (1<<0)
|
||
|
#define SPIFFS_OP_T_OBJ_IX (2<<0)
|
||
|
#define SPIFFS_OP_T_OBJ_DA (3<<0)
|
||
|
#define SPIFFS_OP_C_DELE (0<<2)
|
||
|
#define SPIFFS_OP_C_UPDT (1<<2)
|
||
|
#define SPIFFS_OP_C_MOVS (2<<2)
|
||
|
#define SPIFFS_OP_C_MOVD (3<<2)
|
||
|
#define SPIFFS_OP_C_FLSH (4<<2)
|
||
|
#define SPIFFS_OP_C_READ (5<<2)
|
||
|
#define SPIFFS_OP_C_WRTHRU (6<<2)
|
||
|
|
||
|
#define SPIFFS_OP_TYPE_MASK (3<<0)
|
||
|
#define SPIFFS_OP_COM_MASK (7<<2)
|
||
|
|
||
|
|
||
|
// if 0, this page is written to, else clean
|
||
|
#define SPIFFS_PH_FLAG_USED (1<<0)
|
||
|
// if 0, writing is finalized, else under modification
|
||
|
#define SPIFFS_PH_FLAG_FINAL (1<<1)
|
||
|
// if 0, this is an index page, else a data page
|
||
|
#define SPIFFS_PH_FLAG_INDEX (1<<2)
|
||
|
// if 0, page is deleted, else valid
|
||
|
#define SPIFFS_PH_FLAG_DELET (1<<7)
|
||
|
// if 0, this index header is being deleted
|
||
|
#define SPIFFS_PH_FLAG_IXDELE (1<<6)
|
||
|
|
||
|
|
||
|
#define SPIFFS_CHECK_MOUNT(fs) \
|
||
|
((fs)->mounted != 0)
|
||
|
|
||
|
#define SPIFFS_CHECK_CFG(fs) \
|
||
|
((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
|
||
|
|
||
|
#define SPIFFS_CHECK_RES(res) \
|
||
|
do { \
|
||
|
if ((res) < SPIFFS_OK) return (res); \
|
||
|
} while (0);
|
||
|
|
||
|
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
||
|
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
||
|
(fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
|
||
|
return SPIFFS_ERR_NOT_MOUNTED; \
|
||
|
}
|
||
|
|
||
|
#define SPIFFS_API_CHECK_CFG(fs) \
|
||
|
if (!SPIFFS_CHECK_CFG((fs))) { \
|
||
|
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
|
||
|
return SPIFFS_ERR_NOT_CONFIGURED; \
|
||
|
}
|
||
|
|
||
|
#define SPIFFS_API_CHECK_RES(fs, res) \
|
||
|
if ((res) < SPIFFS_OK) { \
|
||
|
(fs)->err_code = (res); \
|
||
|
return (res); \
|
||
|
}
|
||
|
|
||
|
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
||
|
if ((res) < SPIFFS_OK) { \
|
||
|
(fs)->err_code = (res); \
|
||
|
SPIFFS_UNLOCK(fs); \
|
||
|
return (res); \
|
||
|
}
|
||
|
|
||
|
#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
||
|
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
||
|
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
||
|
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
||
|
|
||
|
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||
|
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
|
||
|
if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \
|
||
|
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
|
||
|
|
||
|
|
||
|
// check id, only visit matching objec ids
|
||
|
#define SPIFFS_VIS_CHECK_ID (1<<0)
|
||
|
// report argument object id to visitor - else object lookup id is reported
|
||
|
#define SPIFFS_VIS_CHECK_PH (1<<1)
|
||
|
// stop searching at end of all look up pages
|
||
|
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
||
|
|
||
|
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||
|
|
||
|
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||
|
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
|
||
|
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||
|
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
|
||
|
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||
|
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
|
||
|
|
||
|
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||
|
|
||
|
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||
|
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
|
||
|
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||
|
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
|
||
|
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||
|
(_fs)->cfg.hal_erase_f((_paddr), (_len))
|
||
|
|
||
|
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||
|
|
||
|
#if SPIFFS_CACHE
|
||
|
|
||
|
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
||
|
#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
|
||
|
#define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
|
||
|
#define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
|
||
|
#define SPIFFS_CACHE_FLAG_DATA (1<<4)
|
||
|
#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
|
||
|
|
||
|
#define SPIFFS_CACHE_PAGE_SIZE(fs) \
|
||
|
(sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
|
||
|
|
||
|
#define spiffs_get_cache(fs) \
|
||
|
((spiffs_cache *)((fs)->cache))
|
||
|
|
||
|
#define spiffs_get_cache_page_hdr(fs, c, ix) \
|
||
|
((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
|
||
|
|
||
|
#define spiffs_get_cache_page(fs, c, ix) \
|
||
|
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||
|
|
||
|
// cache page struct
|
||
|
typedef struct {
|
||
|
// cache flags
|
||
|
u8_t flags;
|
||
|
// cache page index
|
||
|
u8_t ix;
|
||
|
// last access of this cache page
|
||
|
u32_t last_access;
|
||
|
union {
|
||
|
// type read cache
|
||
|
struct {
|
||
|
// read cache page index
|
||
|
spiffs_page_ix pix;
|
||
|
};
|
||
|
#if SPIFFS_CACHE_WR
|
||
|
// type write cache
|
||
|
struct {
|
||
|
// write cache
|
||
|
spiffs_obj_id obj_id;
|
||
|
// offset in cache page
|
||
|
u32_t offset;
|
||
|
// size of cache page
|
||
|
u16_t size;
|
||
|
};
|
||
|
#endif
|
||
|
};
|
||
|
} spiffs_cache_page;
|
||
|
|
||
|
// cache struct
|
||
|
typedef struct {
|
||
|
u8_t cpage_count;
|
||
|
u32_t last_access;
|
||
|
u32_t cpage_use_map;
|
||
|
u32_t cpage_use_mask;
|
||
|
u8_t *cpages;
|
||
|
} spiffs_cache;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// spiffs nucleus file descriptor
|
||
|
typedef struct {
|
||
|
// the filesystem of this descriptor
|
||
|
spiffs *fs;
|
||
|
// number of file descriptor - if 0, the file descriptor is closed
|
||
|
spiffs_file file_nbr;
|
||
|
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
||
|
spiffs_obj_id obj_id;
|
||
|
// size of the file
|
||
|
u32_t size;
|
||
|
// cached object index header page index
|
||
|
spiffs_page_ix objix_hdr_pix;
|
||
|
// cached offset object index page index
|
||
|
spiffs_page_ix cursor_objix_pix;
|
||
|
// cached offset object index span index
|
||
|
spiffs_span_ix cursor_objix_spix;
|
||
|
// current absolute offset
|
||
|
u32_t offset;
|
||
|
// current file descriptor offset (cached)
|
||
|
u32_t fdoffset;
|
||
|
// fd flags
|
||
|
spiffs_flags flags;
|
||
|
#if SPIFFS_CACHE_WR
|
||
|
spiffs_cache_page *cache_page;
|
||
|
#endif
|
||
|
#if SPIFFS_TEMPORAL_FD_CACHE
|
||
|
// djb2 hash of filename
|
||
|
u32_t name_hash;
|
||
|
// hit score (score == 0 indicates never used fd)
|
||
|
u16_t score;
|
||
|
#endif
|
||
|
#if SPIFFS_IX_MAP
|
||
|
// spiffs index map, if 0 it means unmapped
|
||
|
spiffs_ix_map *ix_map;
|
||
|
#endif
|
||
|
} spiffs_fd;
|
||
|
|
||
|
|
||
|
// object structs
|
||
|
|
||
|
// page header, part of each page except object lookup pages
|
||
|
// NB: this is always aligned when the data page is an object index,
|
||
|
// as in this case struct spiffs_page_object_ix is used
|
||
|
typedef struct SPIFFS_PACKED {
|
||
|
// object id
|
||
|
spiffs_obj_id obj_id;
|
||
|
// object span index
|
||
|
spiffs_span_ix span_ix;
|
||
|
// flags
|
||
|
u8_t flags;
|
||
|
} spiffs_page_header;
|
||
|
|
||
|
// object index header page header
|
||
|
typedef struct SPIFFS_PACKED
|
||
|
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||
|
#ifdef _MSC_VER
|
||
|
__declspec( align( 2 ) ) // must track sizeof(spiffs_page_ix) in spiffs_config.h
|
||
|
#else
|
||
|
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
|
||
|
#endif
|
||
|
#endif
|
||
|
{
|
||
|
// common page header
|
||
|
spiffs_page_header p_hdr;
|
||
|
// alignment
|
||
|
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||
|
// size of object
|
||
|
u32_t size;
|
||
|
// type of object
|
||
|
spiffs_obj_type type;
|
||
|
// name of object
|
||
|
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||
|
#if SPIFFS_OBJ_META_LEN
|
||
|
// metadata. not interpreted by SPIFFS in any way.
|
||
|
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||
|
#endif
|
||
|
} spiffs_page_object_ix_header;
|
||
|
|
||
|
// object index page header
|
||
|
typedef struct SPIFFS_PACKED {
|
||
|
spiffs_page_header p_hdr;
|
||
|
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||
|
} spiffs_page_object_ix;
|
||
|
|
||
|
// callback func for object lookup visitor
|
||
|
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
||
|
const void *user_const_p, void *user_var_p);
|
||
|
|
||
|
|
||
|
#if SPIFFS_CACHE
|
||
|
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||
|
spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
|
||
|
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||
|
spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
|
||
|
#else
|
||
|
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||
|
spiffs_phys_rd((fs), (addr), (len), (dst))
|
||
|
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||
|
spiffs_phys_wr((fs), (addr), (len), (src))
|
||
|
#endif
|
||
|
|
||
|
#ifndef MIN
|
||
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||
|
#endif
|
||
|
#ifndef MAX
|
||
|
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||
|
#endif
|
||
|
|
||
|
// ---------------
|
||
|
|
||
|
s32_t spiffs_phys_rd(
|
||
|
spiffs *fs,
|
||
|
#if SPIFFS_CACHE
|
||
|
u8_t op,
|
||
|
spiffs_file fh,
|
||
|
#endif
|
||
|
u32_t addr,
|
||
|
u32_t len,
|
||
|
u8_t *dst);
|
||
|
|
||
|
s32_t spiffs_phys_wr(
|
||
|
spiffs *fs,
|
||
|
#if SPIFFS_CACHE
|
||
|
u8_t op,
|
||
|
spiffs_file fh,
|
||
|
#endif
|
||
|
u32_t addr,
|
||
|
u32_t len,
|
||
|
u8_t *src);
|
||
|
|
||
|
s32_t spiffs_phys_cpy(
|
||
|
spiffs *fs,
|
||
|
spiffs_file fh,
|
||
|
u32_t dst,
|
||
|
u32_t src,
|
||
|
u32_t len);
|
||
|
|
||
|
s32_t spiffs_phys_count_free_blocks(
|
||
|
spiffs *fs);
|
||
|
|
||
|
s32_t spiffs_obj_lu_find_entry_visitor(
|
||
|
spiffs *fs,
|
||
|
spiffs_block_ix starting_block,
|
||
|
int starting_lu_entry,
|
||
|
u8_t flags,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_visitor_f v,
|
||
|
const void *user_const_p,
|
||
|
void *user_var_p,
|
||
|
spiffs_block_ix *block_ix,
|
||
|
int *lu_entry);
|
||
|
|
||
|
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(
|
||
|
spiffs *fs);
|
||
|
|
||
|
s32_t spiffs_obj_lu_find_free_obj_id(
|
||
|
spiffs *fs,
|
||
|
spiffs_obj_id *obj_id,
|
||
|
const u8_t *conflicting_name);
|
||
|
|
||
|
s32_t spiffs_obj_lu_find_free(
|
||
|
spiffs *fs,
|
||
|
spiffs_block_ix starting_block,
|
||
|
int starting_lu_entry,
|
||
|
spiffs_block_ix *block_ix,
|
||
|
int *lu_entry);
|
||
|
|
||
|
s32_t spiffs_obj_lu_find_id(
|
||
|
spiffs *fs,
|
||
|
spiffs_block_ix starting_block,
|
||
|
int starting_lu_entry,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_block_ix *block_ix,
|
||
|
int *lu_entry);
|
||
|
|
||
|
s32_t spiffs_obj_lu_find_id_and_span(
|
||
|
spiffs *fs,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_span_ix spix,
|
||
|
spiffs_page_ix exclusion_pix,
|
||
|
spiffs_page_ix *pix);
|
||
|
|
||
|
s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
|
||
|
spiffs *fs,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_span_ix spix,
|
||
|
spiffs_page_ix exclusion_pix,
|
||
|
spiffs_page_ix *pix);
|
||
|
|
||
|
// ---------------
|
||
|
|
||
|
s32_t spiffs_page_allocate_data(
|
||
|
spiffs *fs,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_page_header *ph,
|
||
|
u8_t *data,
|
||
|
u32_t len,
|
||
|
u32_t page_offs,
|
||
|
u8_t finalize,
|
||
|
spiffs_page_ix *pix);
|
||
|
|
||
|
s32_t spiffs_page_move(
|
||
|
spiffs *fs,
|
||
|
spiffs_file fh,
|
||
|
u8_t *page_data,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_page_header *page_hdr,
|
||
|
spiffs_page_ix src_pix,
|
||
|
spiffs_page_ix *dst_pix);
|
||
|
|
||
|
s32_t spiffs_page_delete(
|
||
|
spiffs *fs,
|
||
|
spiffs_page_ix pix);
|
||
|
|
||
|
// ---------------
|
||
|
|
||
|
s32_t spiffs_object_create(
|
||
|
spiffs *fs,
|
||
|
spiffs_obj_id obj_id,
|
||
|
const u8_t name[],
|
||
|
const u8_t meta[],
|
||
|
spiffs_obj_type type,
|
||
|
spiffs_page_ix *objix_hdr_pix);
|
||
|
|
||
|
s32_t spiffs_object_update_index_hdr(
|
||
|
spiffs *fs,
|
||
|
spiffs_fd *fd,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_page_ix objix_hdr_pix,
|
||
|
u8_t *new_objix_hdr_data,
|
||
|
const u8_t name[],
|
||
|
const u8_t meta[],
|
||
|
u32_t size,
|
||
|
spiffs_page_ix *new_pix);
|
||
|
|
||
|
#if SPIFFS_IX_MAP
|
||
|
|
||
|
s32_t spiffs_populate_ix_map(
|
||
|
spiffs *fs,
|
||
|
spiffs_fd *fd,
|
||
|
u32_t vec_entry_start,
|
||
|
u32_t vec_entry_end);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
void spiffs_cb_object_event(
|
||
|
spiffs *fs,
|
||
|
spiffs_page_object_ix *objix,
|
||
|
int ev,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_span_ix spix,
|
||
|
spiffs_page_ix new_pix,
|
||
|
u32_t new_size);
|
||
|
|
||
|
s32_t spiffs_object_open_by_id(
|
||
|
spiffs *fs,
|
||
|
spiffs_obj_id obj_id,
|
||
|
spiffs_fd *f,
|
||
|
spiffs_flags flags,
|
||
|
spiffs_mode mode);
|
||
|
|
||
|
s32_t spiffs_object_open_by_page(
|
||
|
spiffs *fs,
|
||
|
spiffs_page_ix pix,
|
||
|
spiffs_fd *f,
|
||
|
spiffs_flags flags,
|
||
|
spiffs_mode mode);
|
||
|
|
||
|
s32_t spiffs_object_append(
|
||
|
spiffs_fd *fd,
|
||
|
u32_t offset,
|
||
|
u8_t *data,
|
||
|
u32_t len);
|
||
|
|
||
|
s32_t spiffs_object_modify(
|
||
|
spiffs_fd *fd,
|
||
|
u32_t offset,
|
||
|
u8_t *data,
|
||
|
u32_t len);
|
||
|
|
||
|
s32_t spiffs_object_read(
|
||
|
spiffs_fd *fd,
|
||
|
u32_t offset,
|
||
|
u32_t len,
|
||
|
u8_t *dst);
|
||
|
|
||
|
s32_t spiffs_object_truncate(
|
||
|
spiffs_fd *fd,
|
||
|
u32_t new_len,
|
||
|
u8_t remove_object);
|
||
|
|
||
|
s32_t spiffs_object_find_object_index_header_by_name(
|
||
|
spiffs *fs,
|
||
|
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||
|
spiffs_page_ix *pix);
|
||
|
|
||
|
// ---------------
|
||
|
|
||
|
s32_t spiffs_gc_check(
|
||
|
spiffs *fs,
|
||
|
u32_t len);
|
||
|
|
||
|
s32_t spiffs_gc_erase_page_stats(
|
||
|
spiffs *fs,
|
||
|
spiffs_block_ix bix);
|
||
|
|
||
|
s32_t spiffs_gc_find_candidate(
|
||
|
spiffs *fs,
|
||
|
spiffs_block_ix **block_candidate,
|
||
|
int *candidate_count,
|
||
|
char fs_crammed);
|
||
|
|
||
|
s32_t spiffs_gc_clean(
|
||
|
spiffs *fs,
|
||
|
spiffs_block_ix bix);
|
||
|
|
||
|
s32_t spiffs_gc_quick(
|
||
|
spiffs *fs, u16_t max_free_pages);
|
||
|
|
||
|
// ---------------
|
||
|
|
||
|
s32_t spiffs_fd_find_new(
|
||
|
spiffs *fs,
|
||
|
spiffs_fd **fd,
|
||
|
const char *name);
|
||
|
|
||
|
s32_t spiffs_fd_return(
|
||
|
spiffs *fs,
|
||
|
spiffs_file f);
|
||
|
|
||
|
s32_t spiffs_fd_get(
|
||
|
spiffs *fs,
|
||
|
spiffs_file f,
|
||
|
spiffs_fd **fd);
|
||
|
|
||
|
#if SPIFFS_TEMPORAL_FD_CACHE
|
||
|
void spiffs_fd_temporal_cache_rehash(
|
||
|
spiffs *fs,
|
||
|
const char *old_path,
|
||
|
const char *new_path);
|
||
|
#endif
|
||
|
|
||
|
#if SPIFFS_CACHE
|
||
|
void spiffs_cache_init(
|
||
|
spiffs *fs);
|
||
|
|
||
|
void spiffs_cache_drop_page(
|
||
|
spiffs *fs,
|
||
|
spiffs_page_ix pix);
|
||
|
|
||
|
#if SPIFFS_CACHE_WR
|
||
|
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(
|
||
|
spiffs *fs,
|
||
|
spiffs_fd *fd);
|
||
|
|
||
|
void spiffs_cache_fd_release(
|
||
|
spiffs *fs,
|
||
|
spiffs_cache_page *cp);
|
||
|
|
||
|
spiffs_cache_page *spiffs_cache_page_get_by_fd(
|
||
|
spiffs *fs,
|
||
|
spiffs_fd *fd);
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
s32_t spiffs_lookup_consistency_check(
|
||
|
spiffs *fs,
|
||
|
u8_t check_all_objects);
|
||
|
|
||
|
s32_t spiffs_page_consistency_check(
|
||
|
spiffs *fs);
|
||
|
|
||
|
s32_t spiffs_object_index_consistency_check(
|
||
|
spiffs *fs);
|
||
|
|
||
|
// memcpy macro,
|
||
|
// checked in test builds, otherwise plain memcpy (unless already defined)
|
||
|
#ifdef _SPIFFS_TEST
|
||
|
#define _SPIFFS_MEMCPY(__d, __s, __l) do { \
|
||
|
intptr_t __a1 = (intptr_t)((u8_t*)(__s)); \
|
||
|
intptr_t __a2 = (intptr_t)((u8_t*)(__s)+(__l)); \
|
||
|
intptr_t __b1 = (intptr_t)((u8_t*)(__d)); \
|
||
|
intptr_t __b2 = (intptr_t)((u8_t*)(__d)+(__l)); \
|
||
|
if (__a1 <= __b2 && __b1 <= __a2) { \
|
||
|
printf("FATAL OVERLAP: memcpy from %lx..%lx to %lx..%lx\n", __a1, __a2, __b1, __b2); \
|
||
|
ERREXIT(); \
|
||
|
} \
|
||
|
memcpy((__d),(__s),(__l)); \
|
||
|
} while (0)
|
||
|
#else
|
||
|
#ifndef _SPIFFS_MEMCPY
|
||
|
#define _SPIFFS_MEMCPY(__d, __s, __l) do{memcpy((__d),(__s),(__l));}while(0)
|
||
|
#endif
|
||
|
#endif //_SPIFFS_TEST
|
||
|
|
||
|
#endif /* SPIFFS_NUCLEUS_H_ */
|