1 //-----------------------------------------------------------------------------
2 // Borrowed initially from https://github.com/pellepl/spiffs
3 // Copyright (c) 2013-2017 Peter Andersson (pelleplutt1976 at gmail.com)
4 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // See LICENSE.txt for the text of the license.
17 //-----------------------------------------------------------------------------
21 * spiffs is designed for following spi flash characteristics:
22 * - only big areas of data (blocks) can be erased
23 * - erasing resets all bits in a block to ones
24 * - writing pulls ones to zeroes
25 * - zeroes cannot be pulled to ones, without erase
28 * spiffs is also meant to be run on embedded, memory constraint devices.
30 * Entire area is divided in blocks. Entire area is also divided in pages.
31 * Each block contains same number of pages. A page cannot be erased, but a
32 * block can be erased.
34 * Entire area must be block_size * x
35 * page_size must be block_size / (2^y) where y > 2
37 * ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
39 * BLOCK 0 PAGE 0 object lookup 1
40 * PAGE 1 object lookup 2
42 * PAGE n-1 object lookup n
43 * PAGE n object data 1
44 * PAGE n+1 object data 2
46 * PAGE n+m-1 object data m
48 * BLOCK 1 PAGE n+m object lookup 1
49 * PAGE n+m+1 object lookup 2
51 * PAGE 2n+m-1 object lookup n
52 * PAGE 2n+m object data 1
53 * PAGE 2n+m object data 2
55 * PAGE 2n+2m-1 object data m
58 * n is number of object lookup pages, which is number of pages needed to index all pages
59 * in a block by object id
60 * : block_size / page_size * sizeof(obj_id) / page_size
61 * m is number data pages, which is number of pages in block minus number of lookup pages
62 * : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
63 * thus, n+m is total number of pages in a block
64 * : block_size / page_size
66 * ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
68 * Object lookup pages contain object id entries. Each entry represent the corresponding
70 * Assuming a 16 bit object id, an object id being 0xffff represents a free page.
71 * An object id being 0x0000 represents a deleted page.
73 * ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
74 * page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
75 * page 2 : data : data for object id 0008
76 * page 3 : data : data for object id 0001
77 * page 4 : data : data for object id 0aaa
81 * Object data pages can be either object index pages or object content.
82 * All object data pages contains a data page header, containing object id and span index.
83 * The span index denotes the object page ordering amongst data pages with same object id.
84 * This applies to both object index pages (when index spans more than one page of entries),
85 * and object data pages.
86 * An object index page contains page entries pointing to object content page. The entry index
87 * in a object index page correlates to the span index in the actual object data page.
88 * The first object index page (span index 0) is called object index header page, and also
89 * contains object flags (directory/file), size, object name etc.
93 * PAGE 256: objectl lookup page 1
94 * [*123] [ 123] [ 123] [ 123]
95 * [ 123] [*123] [ 123] [ 123]
96 * [free] [free] [free] [free] ...
97 * PAGE 257: objectl lookup page 2
98 * [free] [free] [free] [free] ...
99 * PAGE 258: object index page (header)
100 * obj.id:0123 span.ix:0000 flags:INDEX
101 * size:1600 name:ex.txt type:file
102 * [259] [260] [261] [262]
103 * PAGE 259: object data page
104 * obj.id:0123 span.ix:0000 flags:DATA
105 * PAGE 260: object data page
106 * obj.id:0123 span.ix:0001 flags:DATA
107 * PAGE 261: object data page
108 * obj.id:0123 span.ix:0002 flags:DATA
109 * PAGE 262: object data page
110 * obj.id:0123 span.ix:0003 flags:DATA
111 * PAGE 263: object index page
112 * obj.id:0123 span.ix:0001 flags:INDEX
113 * [264] [265] [fre] [fre]
114 * [fre] [fre] [fre] [fre]
115 * PAGE 264: object data page
116 * obj.id:0123 span.ix:0004 flags:DATA
117 * PAGE 265: object data page
118 * obj.id:0123 span.ix:0005 flags:DATA
121 #ifndef SPIFFS_NUCLEUS_H_
122 #define SPIFFS_NUCLEUS_H_
129 #define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1)
130 #define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1)
131 #define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2)
132 #define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
133 #define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
135 // visitor result, continue searching
136 #define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
137 // visitor result, continue searching after reloading lu buffer
138 #define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
139 // visitor result, stop searching
140 #define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
142 // updating an object index contents
143 #define SPIFFS_EV_IX_UPD (0)
144 // creating a new object index
145 #define SPIFFS_EV_IX_NEW (1)
146 // deleting an object index
147 #define SPIFFS_EV_IX_DEL (2)
148 // moving an object index without updating contents
149 #define SPIFFS_EV_IX_MOV (3)
150 // updating an object index header data only, not the table itself
151 #define SPIFFS_EV_IX_UPD_HDR (4)
153 #define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
155 #define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
157 #define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
158 #define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
162 #if defined(__GNUC__) || defined(__clang__) || defined(__TI_COMPILER_VERSION__)
163 /* For GCC, clang and TI compilers */
164 #define SPIFFS_PACKED __attribute__((packed))
165 #elif defined(__ICCARM__) || defined(__CC_ARM)
166 /* For IAR ARM and Keil MDK-ARM compilers */
167 #define SPIFFS_PACKED
170 /* Unknown compiler */
171 #define SPIFFS_PACKED
177 #if !SPIFFS_USE_MAGIC_LENGTH
178 #define SPIFFS_MAGIC(fs, bix) \
179 ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
180 #else // SPIFFS_USE_MAGIC_LENGTH
181 #define SPIFFS_MAGIC(fs, bix) \
182 ((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))
183 #endif // SPIFFS_USE_MAGIC_LENGTH
184 #endif // SPIFFS_USE_MAGIC
186 #define SPIFFS_CONFIG_MAGIC (0x20090315)
188 #if SPIFFS_SINGLETON == 0
189 #define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
190 ((fs)->cfg.log_page_size)
191 #define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
192 ((fs)->cfg.log_block_size)
193 #define SPIFFS_CFG_PHYS_SZ(fs) \
194 ((fs)->cfg.phys_size)
195 #define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
196 ((fs)->cfg.phys_erase_block)
197 #define SPIFFS_CFG_PHYS_ADDR(fs) \
198 ((fs)->cfg.phys_addr)
201 // total number of pages
202 #define SPIFFS_MAX_PAGES(fs) \
203 ( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
204 // total number of pages per block, including object lookup pages
205 #define SPIFFS_PAGES_PER_BLOCK(fs) \
206 ( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
207 // number of object lookup pages per block
208 #define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
209 (MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
210 // checks if page index belongs to object lookup
211 #define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
212 (((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
213 // number of object lookup entries in all object lookup pages
214 #define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
215 (SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
216 // converts a block to physical address
217 #define SPIFFS_BLOCK_TO_PADDR(fs, block) \
218 ( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
219 // converts a object lookup entry to page index
220 #define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
221 ((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
222 // converts a object lookup entry to physical address of corresponding page
223 #define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
224 (SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
225 // converts a page to physical address
226 #define SPIFFS_PAGE_TO_PADDR(fs, page) \
227 ( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
228 // converts a physical address to page
229 #define SPIFFS_PADDR_TO_PAGE(fs, addr) \
230 ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
231 // gives index in page for a physical address
232 #define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
233 ( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
234 // returns containing block for given page
235 #define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
236 ( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )
237 // returns starting page for block
238 #define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
239 ( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )
240 // converts page to entry in object lookup page
241 #define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
242 ( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )
243 // returns data size in a data page
244 #define SPIFFS_DATA_PAGE_SIZE(fs) \
245 ( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
246 // returns physical address for block's erase count,
247 // always in the physical last entry of the last object lookup page
248 #define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
249 ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
250 // returns physical address for block's magic,
251 // always in the physical second last entry of the last object lookup page
252 #define SPIFFS_MAGIC_PADDR(fs, bix) \
253 ( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
254 // checks if there is any room for magic in the object luts
255 #define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
256 ( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
257 <= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
259 // define helpers object
261 // entries in an object header page index
262 #define SPIFFS_OBJ_HDR_IX_LEN(fs) \
263 ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
264 // entries in an object page index
265 #define SPIFFS_OBJ_IX_LEN(fs) \
266 ((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
267 // object index entry for given data span index
268 #define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
269 ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
270 // object index span index number for given data span index or entry
271 #define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
272 ((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
273 // get data span index for object index span index
274 #define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \
275 ( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )
277 #if SPIFFS_FILEHDL_OFFSET
278 #define SPIFFS_FH_OFFS(fs, fh) ((fh) != 0 ? ((fh) + (fs)->cfg.fh_ix_offset) : 0)
279 #define SPIFFS_FH_UNOFFS(fs, fh) ((fh) != 0 ? ((fh) - (fs)->cfg.fh_ix_offset) : 0)
281 #define SPIFFS_FH_OFFS(fs, fh) (fh)
282 #define SPIFFS_FH_UNOFFS(fs, fh) (fh)
286 #define SPIFFS_OP_T_OBJ_LU (0<<0)
287 #define SPIFFS_OP_T_OBJ_LU2 (1<<0)
288 #define SPIFFS_OP_T_OBJ_IX (2<<0)
289 #define SPIFFS_OP_T_OBJ_DA (3<<0)
290 #define SPIFFS_OP_C_DELE (0<<2)
291 #define SPIFFS_OP_C_UPDT (1<<2)
292 #define SPIFFS_OP_C_MOVS (2<<2)
293 #define SPIFFS_OP_C_MOVD (3<<2)
294 #define SPIFFS_OP_C_FLSH (4<<2)
295 #define SPIFFS_OP_C_READ (5<<2)
296 #define SPIFFS_OP_C_WRTHRU (6<<2)
298 #define SPIFFS_OP_TYPE_MASK (3<<0)
299 #define SPIFFS_OP_COM_MASK (7<<2)
302 // if 0, this page is written to, else clean
303 #define SPIFFS_PH_FLAG_USED (1<<0)
304 // if 0, writing is finalized, else under modification
305 #define SPIFFS_PH_FLAG_FINAL (1<<1)
306 // if 0, this is an index page, else a data page
307 #define SPIFFS_PH_FLAG_INDEX (1<<2)
308 // if 0, page is deleted, else valid
309 #define SPIFFS_PH_FLAG_DELET (1<<7)
310 // if 0, this index header is being deleted
311 #define SPIFFS_PH_FLAG_IXDELE (1<<6)
314 #define SPIFFS_CHECK_MOUNT(fs) \
317 #define SPIFFS_CHECK_CFG(fs) \
318 ((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
320 #define SPIFFS_CHECK_RES(res) \
322 if ((res) < SPIFFS_OK) return (res); \
325 #define SPIFFS_API_CHECK_MOUNT(fs) \
326 if (!SPIFFS_CHECK_MOUNT((fs))) { \
327 (fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
328 return SPIFFS_ERR_NOT_MOUNTED; \
331 #define SPIFFS_API_CHECK_CFG(fs) \
332 if (!SPIFFS_CHECK_CFG((fs))) { \
333 (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
334 return SPIFFS_ERR_NOT_CONFIGURED; \
337 #define SPIFFS_API_CHECK_RES(fs, res) \
338 if ((res) < SPIFFS_OK) { \
339 (fs)->err_code = (res); \
343 #define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
344 if ((res) < SPIFFS_OK) { \
345 (fs)->err_code = (res); \
350 #define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
351 if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
352 if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
353 if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
354 if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
355 if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
356 if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
357 //if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
359 #define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
360 if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
361 if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
362 if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
363 if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
364 if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \
365 if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
368 // check id, only visit matching objec ids
369 #define SPIFFS_VIS_CHECK_ID (1<<0)
370 // report argument object id to visitor - else object lookup id is reported
371 #define SPIFFS_VIS_CHECK_PH (1<<1)
372 // stop searching at end of all look up pages
373 #define SPIFFS_VIS_NO_WRAP (1<<2)
375 #if SPIFFS_HAL_CALLBACK_EXTRA
377 #define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
378 (_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
379 #define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
380 (_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
381 #define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
382 (_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
384 #else // SPIFFS_HAL_CALLBACK_EXTRA
386 #define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
387 (_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
388 #define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
389 (_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
390 #define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
391 (_fs)->cfg.hal_erase_f((_paddr), (_len))
393 #endif // SPIFFS_HAL_CALLBACK_EXTRA
397 #define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
398 #define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
399 #define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
400 #define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
401 #define SPIFFS_CACHE_FLAG_DATA (1<<4)
402 #define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
404 #define SPIFFS_CACHE_PAGE_SIZE(fs) \
405 (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
407 #define spiffs_get_cache(fs) \
408 ((spiffs_cache *)((fs)->cache))
410 #define spiffs_get_cache_page_hdr(fs, c, ix) \
411 ((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
413 #define spiffs_get_cache_page(fs, c, ix) \
414 ((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
422 // last access of this cache page
427 // read cache page index
434 spiffs_obj_id obj_id
;
435 // offset in cache page
437 // size of cache page
449 u32_t cpage_use_mask
;
456 // spiffs nucleus file descriptor
458 // the filesystem of this descriptor
460 // number of file descriptor - if 0, the file descriptor is closed
461 spiffs_file file_nbr
;
462 // object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
463 spiffs_obj_id obj_id
;
466 // cached object index header page index
467 spiffs_page_ix objix_hdr_pix
;
468 // cached offset object index page index
469 spiffs_page_ix cursor_objix_pix
;
470 // cached offset object index span index
471 spiffs_span_ix cursor_objix_spix
;
472 // current absolute offset
474 // current file descriptor offset (cached)
479 spiffs_cache_page
*cache_page
;
481 #if SPIFFS_TEMPORAL_FD_CACHE
482 // djb2 hash of filename
484 // hit score (score == 0 indicates never used fd)
488 // spiffs index map, if 0 it means unmapped
489 spiffs_ix_map
*ix_map
;
496 // page header, part of each page except object lookup pages
497 // NB: this is always aligned when the data page is an object index,
498 // as in this case struct spiffs_page_object_ix is used
499 typedef struct SPIFFS_PACKED
{
501 spiffs_obj_id obj_id
;
503 spiffs_span_ix span_ix
;
506 } spiffs_page_header
;
508 // object index header page header
509 typedef struct SPIFFS_PACKED
510 #if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
511 __attribute((aligned(sizeof(spiffs_page_ix
))))
514 // common page header
515 spiffs_page_header p_hdr
;
517 u8_t _align
[4 - ((sizeof(spiffs_page_header
) & 3) == 0 ? 4 : (sizeof(spiffs_page_header
) & 3))];
521 spiffs_obj_type type
;
523 u8_t name
[SPIFFS_OBJ_NAME_LEN
];
524 #if SPIFFS_OBJ_META_LEN
525 // metadata. not interpreted by SPIFFS in any way.
526 u8_t meta
[SPIFFS_OBJ_META_LEN
];
529 spiffs_page_object_ix_header
;
531 // object index page header
532 typedef struct SPIFFS_PACKED
{
533 spiffs_page_header p_hdr
;
534 u8_t _align
[4 - ((sizeof(spiffs_page_header
) & 3) == 0 ? 4 : (sizeof(spiffs_page_header
) & 3))];
535 } spiffs_page_object_ix
;
537 // callback func for object lookup visitor
538 typedef s32_t (*spiffs_visitor_f
)(spiffs
*fs
, spiffs_obj_id id
, spiffs_block_ix bix
, int ix_entry
,
539 const void *user_const_p
, void *user_var_p
);
543 #define _spiffs_rd(fs, op, fh, addr, len, dst) \
544 spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
545 #define _spiffs_wr(fs, op, fh, addr, len, src) \
546 spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
548 #define _spiffs_rd(fs, op, fh, addr, len, dst) \
549 spiffs_phys_rd((fs), (addr), (len), (dst))
550 #define _spiffs_wr(fs, op, fh, addr, len, src) \
551 spiffs_phys_wr((fs), (addr), (len), (src))
555 #define MIN(a,b) ((a) < (b) ? (a) : (b))
558 #define MAX(a,b) ((a) > (b) ? (a) : (b))
563 s32_t
spiffs_phys_rd(
573 s32_t
spiffs_phys_wr(
583 s32_t
spiffs_phys_cpy(
590 s32_t
spiffs_phys_count_free_blocks(
593 s32_t
spiffs_obj_lu_find_entry_visitor(
595 spiffs_block_ix starting_block
,
596 int starting_lu_entry
,
598 spiffs_obj_id obj_id
,
600 const void *user_const_p
,
602 spiffs_block_ix
*block_ix
,
605 s32_t
spiffs_erase_block(
607 spiffs_block_ix bix
);
609 #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
612 #endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
616 s32_t
spiffs_obj_lu_scan(
619 s32_t
spiffs_obj_lu_find_free_obj_id(
621 spiffs_obj_id
*obj_id
,
622 const u8_t
*conflicting_name
);
624 s32_t
spiffs_obj_lu_find_free(
626 spiffs_block_ix starting_block
,
627 int starting_lu_entry
,
628 spiffs_block_ix
*block_ix
,
631 s32_t
spiffs_obj_lu_find_id(
633 spiffs_block_ix starting_block
,
634 int starting_lu_entry
,
635 spiffs_obj_id obj_id
,
636 spiffs_block_ix
*block_ix
,
639 s32_t
spiffs_obj_lu_find_id_and_span(
641 spiffs_obj_id obj_id
,
643 spiffs_page_ix exclusion_pix
,
644 spiffs_page_ix
*pix
);
646 s32_t
spiffs_obj_lu_find_id_and_span_by_phdr(
648 spiffs_obj_id obj_id
,
650 spiffs_page_ix exclusion_pix
,
651 spiffs_page_ix
*pix
);
655 s32_t
spiffs_page_allocate_data(
657 spiffs_obj_id obj_id
,
658 spiffs_page_header
*ph
,
663 spiffs_page_ix
*pix
);
665 s32_t
spiffs_page_move(
669 spiffs_obj_id obj_id
,
670 spiffs_page_header
*page_hdr
,
671 spiffs_page_ix src_pix
,
672 spiffs_page_ix
*dst_pix
);
674 s32_t
spiffs_page_delete(
680 s32_t
spiffs_object_create(
682 spiffs_obj_id obj_id
,
685 spiffs_obj_type type
,
686 spiffs_page_ix
*objix_hdr_pix
);
688 s32_t
spiffs_object_update_index_hdr(
691 spiffs_obj_id obj_id
,
692 spiffs_page_ix objix_hdr_pix
,
693 u8_t
*new_objix_hdr_data
,
697 spiffs_page_ix
*new_pix
);
701 s32_t
spiffs_populate_ix_map(
704 u32_t vec_entry_start
,
705 u32_t vec_entry_end
);
709 void spiffs_cb_object_event(
711 spiffs_page_object_ix
*objix
,
713 spiffs_obj_id obj_id_raw
,
715 spiffs_page_ix new_pix
,
718 s32_t
spiffs_object_open_by_id(
720 spiffs_obj_id obj_id
,
725 s32_t
spiffs_object_open_by_page(
732 s32_t
spiffs_object_append(
738 s32_t
spiffs_object_modify(
744 s32_t
spiffs_object_read(
750 s32_t
spiffs_object_truncate(
755 s32_t
spiffs_object_find_object_index_header_by_name(
757 const u8_t name
[SPIFFS_OBJ_NAME_LEN
],
758 spiffs_page_ix
*pix
);
762 s32_t
spiffs_gc_check(
766 s32_t
spiffs_gc_erase_page_stats(
768 spiffs_block_ix bix
);
770 s32_t
spiffs_gc_find_candidate(
772 spiffs_block_ix
**block_candidates
,
773 int *candidate_count
,
776 s32_t
spiffs_gc_clean(
778 spiffs_block_ix bix
);
780 s32_t
spiffs_gc_quick(
781 spiffs
*fs
, u16_t max_free_pages
);
785 s32_t
spiffs_fd_find_new(
790 s32_t
spiffs_fd_return(
799 #if SPIFFS_TEMPORAL_FD_CACHE
800 void spiffs_fd_temporal_cache_rehash(
802 const char *old_path
,
803 const char *new_path
);
807 void spiffs_cache_init(
810 void spiffs_cache_drop_page(
815 spiffs_cache_page
*spiffs_cache_page_allocate_by_fd(
819 void spiffs_cache_fd_release(
821 spiffs_cache_page
*cp
);
823 spiffs_cache_page
*spiffs_cache_page_get_by_fd(
829 s32_t
spiffs_lookup_consistency_check(
831 u8_t check_all_objects
);
833 s32_t
spiffs_page_consistency_check(
836 s32_t
spiffs_object_index_consistency_check(
840 // checked in test builds, otherwise plain memcpy (unless already defined)
842 #define _SPIFFS_MEMCPY(__d, __s, __l) do { \
843 intptr_t __a1 = (intptr_t)((u8_t*)(__s)); \
844 intptr_t __a2 = (intptr_t)((u8_t*)(__s)+(__l)); \
845 intptr_t __b1 = (intptr_t)((u8_t*)(__d)); \
846 intptr_t __b2 = (intptr_t)((u8_t*)(__d)+(__l)); \
847 if (__a1 <= __b2 && __b1 <= __a2) { \
848 printf("FATAL OVERLAP: memcpy from %lx..%lx to %lx..%lx\n", __a1, __a2, __b1, __b2); \
851 memcpy((__d),(__s),(__l)); \
854 #ifndef _SPIFFS_MEMCPY
855 #define _SPIFFS_MEMCPY(__d, __s, __l) do{memcpy((__d),(__s),(__l));}while(0)
857 #endif //_SPIFFS_TEST
859 #endif /* SPIFFS_NUCLEUS_H_ */