2 #include "spiffs_nucleus.h"
5 static s32_t
spiffs_page_data_check(spiffs
*fs
, spiffs_fd
*fd
, spiffs_page_ix pix
, spiffs_span_ix spix
) {
7 if (pix
== (spiffs_page_ix
) - 1) {
8 // referring to page 0xffff...., bad object index
9 return SPIFFS_ERR_INDEX_REF_FREE
;
11 if (pix
% SPIFFS_PAGES_PER_BLOCK(fs
) < SPIFFS_OBJ_LOOKUP_PAGES(fs
)) {
12 // referring to an object lookup page, bad object index
13 return SPIFFS_ERR_INDEX_REF_LU
;
15 if (pix
> SPIFFS_MAX_PAGES(fs
)) {
16 // referring to a bad page
17 return SPIFFS_ERR_INDEX_REF_INVALID
;
20 spiffs_page_header ph
;
22 fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_READ
,
24 SPIFFS_PAGE_TO_PADDR(fs
, pix
),
25 sizeof(spiffs_page_header
),
27 SPIFFS_CHECK_RES(res
);
28 SPIFFS_VALIDATE_DATA(ph
, fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, spix
);
34 static s32_t
spiffs_page_index_check(spiffs
*fs
, spiffs_fd
*fd
, spiffs_page_ix pix
, spiffs_span_ix spix
) {
35 s32_t res
= SPIFFS_OK
;
36 if (pix
== (spiffs_page_ix
) - 1) {
37 // referring to page 0xffff...., bad object index
38 return SPIFFS_ERR_INDEX_FREE
;
40 if (pix
% SPIFFS_PAGES_PER_BLOCK(fs
) < SPIFFS_OBJ_LOOKUP_PAGES(fs
)) {
41 // referring to an object lookup page, bad object index
42 return SPIFFS_ERR_INDEX_LU
;
44 if (pix
> SPIFFS_MAX_PAGES(fs
)) {
45 // referring to a bad page
46 return SPIFFS_ERR_INDEX_INVALID
;
49 spiffs_page_header ph
;
51 fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
53 SPIFFS_PAGE_TO_PADDR(fs
, pix
),
54 sizeof(spiffs_page_header
),
56 SPIFFS_CHECK_RES(res
);
57 SPIFFS_VALIDATE_OBJIX(ph
, fd
->obj_id
, spix
);
61 #endif // !SPIFFS_READ_ONLY
70 return SPIFFS_HAL_READ(fs
, addr
, len
, dst
);
78 return SPIFFS_HAL_WRITE(fs
, addr
, len
, src
);
84 s32_t
spiffs_phys_cpy(
92 u8_t b
[SPIFFS_COPY_BUFFER_STACK
];
94 u32_t chunk_size
= MIN(SPIFFS_COPY_BUFFER_STACK
, len
);
95 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_MOVS
, fh
, src
, chunk_size
, b
);
96 SPIFFS_CHECK_RES(res
);
97 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_MOVD
, fh
, dst
, chunk_size
, b
);
98 SPIFFS_CHECK_RES(res
);
105 #endif // !SPIFFS_READ_ONLY
107 // Find object lookup entry containing given id with visitor.
108 // Iterate over object lookup pages in each block until a given object id entry is found.
109 // When found, the visitor function is called with block index, entry index and user data.
110 // If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be
111 // ended and visitor's return code is returned to caller.
112 // If no visitor is given (0) the search returns on first entry with matching object id.
113 // If no match is found in all look up, SPIFFS_VIS_END is returned.
114 // @param fs the file system
115 // @param starting_block the starting block to start search in
116 // @param starting_lu_entry the look up index entry to start search in
117 // @param flags ored combination of SPIFFS_VIS_CHECK_ID, SPIFFS_VIS_CHECK_PH,
118 // SPIFFS_VIS_NO_WRAP
119 // @param obj_id argument object id
120 // @param v visitor callback function
121 // @param user_const_p any const pointer, passed to the callback visitor function
122 // @param user_var_p any pointer, passed to the callback visitor function
123 // @param block_ix reported block index where match was found
124 // @param lu_entry reported look up index where match was found
125 s32_t
spiffs_obj_lu_find_entry_visitor(
127 spiffs_block_ix starting_block
,
128 int starting_lu_entry
,
130 spiffs_obj_id obj_id
,
132 const void *user_const_p
,
134 spiffs_block_ix
*block_ix
,
136 s32_t res
= SPIFFS_OK
;
137 s32_t entry_count
= fs
->block_count
* SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs
);
138 spiffs_block_ix cur_block
= starting_block
;
139 u32_t cur_block_addr
= starting_block
* SPIFFS_CFG_LOG_BLOCK_SZ(fs
);
141 spiffs_obj_id
*obj_lu_buf
= (spiffs_obj_id
*)fs
->lu_work
;
142 int cur_entry
= starting_lu_entry
;
143 int entries_per_page
= (SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(spiffs_obj_id
));
146 if (cur_entry
> (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs
) - 1) {
149 cur_block_addr
= cur_block
* SPIFFS_CFG_LOG_BLOCK_SZ(fs
);
150 if (cur_block
>= fs
->block_count
) {
151 if (flags
& SPIFFS_VIS_NO_WRAP
) {
152 return SPIFFS_VIS_END
;
162 while (res
== SPIFFS_OK
&& entry_count
> 0) {
163 int obj_lookup_page
= cur_entry
/ entries_per_page
;
164 // check each object lookup page
165 while (res
== SPIFFS_OK
&& obj_lookup_page
< (int)SPIFFS_OBJ_LOOKUP_PAGES(fs
)) {
166 int entry_offset
= obj_lookup_page
* entries_per_page
;
167 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_READ
,
168 0, cur_block_addr
+ SPIFFS_PAGE_TO_PADDR(fs
, obj_lookup_page
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
170 while (res
== SPIFFS_OK
&&
171 cur_entry
- entry_offset
< entries_per_page
&& // for non-last obj lookup pages
172 cur_entry
< (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs
)) { // for last obj lookup page
173 if ((flags
& SPIFFS_VIS_CHECK_ID
) == 0 || obj_lu_buf
[cur_entry
- entry_offset
] == obj_id
) {
174 if (block_ix
) *block_ix
= cur_block
;
175 if (lu_entry
) *lu_entry
= cur_entry
;
179 (flags
& SPIFFS_VIS_CHECK_PH
) ? obj_id
: obj_lu_buf
[cur_entry
- entry_offset
],
184 if (res
== SPIFFS_VIS_COUNTINUE
|| res
== SPIFFS_VIS_COUNTINUE_RELOAD
) {
185 if (res
== SPIFFS_VIS_COUNTINUE_RELOAD
) {
186 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_READ
,
187 0, cur_block_addr
+ SPIFFS_PAGE_TO_PADDR(fs
, obj_lookup_page
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
188 SPIFFS_CHECK_RES(res
);
205 } // per object lookup page
208 cur_block_addr
+= SPIFFS_CFG_LOG_BLOCK_SZ(fs
);
209 if (cur_block
>= fs
->block_count
) {
210 if (flags
& SPIFFS_VIS_NO_WRAP
) {
211 return SPIFFS_VIS_END
;
220 SPIFFS_CHECK_RES(res
);
222 return SPIFFS_VIS_END
;
225 #if !SPIFFS_READ_ONLY
226 s32_t
spiffs_erase_block(
228 spiffs_block_ix bix
) {
230 u32_t addr
= SPIFFS_BLOCK_TO_PADDR(fs
, bix
);
231 s32_t size
= SPIFFS_CFG_LOG_BLOCK_SZ(fs
);
233 // here we ignore res, just try erasing the block
235 SPIFFS_DBG("erase "_SPIPRIad
":"_SPIPRIi
"\n", addr
, SPIFFS_CFG_PHYS_ERASE_SZ(fs
));
236 SPIFFS_HAL_ERASE(fs
, addr
, SPIFFS_CFG_PHYS_ERASE_SZ(fs
));
238 addr
+= SPIFFS_CFG_PHYS_ERASE_SZ(fs
);
239 size
-= SPIFFS_CFG_PHYS_ERASE_SZ(fs
);
243 // register erase count for this block
244 res
= _spiffs_wr(fs
, SPIFFS_OP_C_WRTHRU
| SPIFFS_OP_T_OBJ_LU2
, 0,
245 SPIFFS_ERASE_COUNT_PADDR(fs
, bix
),
246 sizeof(spiffs_obj_id
), (u8_t
*)&fs
->max_erase_count
);
247 SPIFFS_CHECK_RES(res
);
250 // finally, write magic
251 spiffs_obj_id magic
= SPIFFS_MAGIC(fs
, bix
);
252 res
= _spiffs_wr(fs
, SPIFFS_OP_C_WRTHRU
| SPIFFS_OP_T_OBJ_LU2
, 0,
253 SPIFFS_MAGIC_PADDR(fs
, bix
),
254 sizeof(spiffs_obj_id
), (u8_t
*)&magic
);
255 SPIFFS_CHECK_RES(res
);
258 fs
->max_erase_count
++;
259 if (fs
->max_erase_count
== SPIFFS_OBJ_ID_IX_FLAG
) {
260 fs
->max_erase_count
= 0;
265 #endif // !SPIFFS_READ_ONLY
267 #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
269 spiffs_config
*cfg
) {
272 spiffs dummy_fs
; // create a dummy fs struct just to be able to use macros
273 _SPIFFS_MEMCPY(&dummy_fs
.cfg
, cfg
, sizeof(spiffs_config
));
274 dummy_fs
.block_count
= 0;
276 // Read three magics, as one block may be in an aborted erase state.
277 // At least two of these must contain magic and be in decreasing order.
278 spiffs_obj_id magic
[3];
279 spiffs_obj_id bix_count
[3];
282 for (bix
= 0; bix
< 3; bix
++) {
283 paddr
= SPIFFS_MAGIC_PADDR(&dummy_fs
, bix
);
284 #if SPIFFS_HAL_CALLBACK_EXTRA
285 // not any proper fs to report here, so callback with null
286 // (cross fingers that no-one gets angry)
287 res
= cfg
->hal_read_f((void *)0, paddr
, sizeof(spiffs_obj_id
), (u8_t
*)&magic
[bix
]);
289 res
= cfg
->hal_read_f(paddr
, sizeof(spiffs_obj_id
), (u8_t
*)&magic
[bix
]);
291 bix_count
[bix
] = magic
[bix
] ^ SPIFFS_MAGIC(&dummy_fs
, 0);
292 SPIFFS_CHECK_RES(res
);
295 // check that we have sane number of blocks
296 if (bix_count
[0] < 3) return SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS
;
297 // check that the order is correct, take aborted erases in calculation
298 // first block aborted erase
299 if (magic
[0] == (spiffs_obj_id
)(-1) && bix_count
[1] - bix_count
[2] == 1) {
300 return (bix_count
[1] + 1) * cfg
->log_block_size
;
302 // second block aborted erase
303 if (magic
[1] == (spiffs_obj_id
)(-1) && bix_count
[0] - bix_count
[2] == 2) {
304 return bix_count
[0] * cfg
->log_block_size
;
306 // third block aborted erase
307 if (magic
[2] == (spiffs_obj_id
)(-1) && bix_count
[0] - bix_count
[1] == 1) {
308 return bix_count
[0] * cfg
->log_block_size
;
310 // no block has aborted erase
311 if (bix_count
[0] - bix_count
[1] == 1 && bix_count
[1] - bix_count
[2] == 1) {
312 return bix_count
[0] * cfg
->log_block_size
;
315 return SPIFFS_ERR_PROBE_NOT_A_FS
;
317 #endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
320 static s32_t
spiffs_obj_lu_scan_v(
322 spiffs_obj_id obj_id
,
325 const void *user_const_p
,
330 if (obj_id
== SPIFFS_OBJ_ID_FREE
) {
333 // todo optimize further, return SPIFFS_NEXT_BLOCK
335 } else if (obj_id
== SPIFFS_OBJ_ID_DELETED
) {
336 fs
->stats_p_deleted
++;
338 fs
->stats_p_allocated
++;
341 return SPIFFS_VIS_COUNTINUE
;
345 // Scans thru all obj lu and counts free, deleted and used pages
346 // Find the maximum block erase count
347 // Checks magic if enabled
348 s32_t
spiffs_obj_lu_scan(
354 spiffs_block_ix unerased_bix
= (spiffs_block_ix
) - 1;
357 // find out erase count
358 // if enabled, check magic
360 spiffs_obj_id erase_count_final
;
361 spiffs_obj_id erase_count_min
= SPIFFS_OBJ_ID_FREE
;
362 spiffs_obj_id erase_count_max
= 0;
363 while (bix
< fs
->block_count
) {
367 SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
368 0, SPIFFS_MAGIC_PADDR(fs
, bix
),
369 sizeof(spiffs_obj_id
), (u8_t
*)&magic
);
371 SPIFFS_CHECK_RES(res
);
372 if (magic
!= SPIFFS_MAGIC(fs
, bix
)) {
373 if (unerased_bix
== (spiffs_block_ix
) - 1) {
374 // allow one unerased block as it might be powered down during an erase
377 // more than one unerased block, bail out
378 SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS
);
382 spiffs_obj_id erase_count
;
384 SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
385 0, SPIFFS_ERASE_COUNT_PADDR(fs
, bix
),
386 sizeof(spiffs_obj_id
), (u8_t
*)&erase_count
);
387 SPIFFS_CHECK_RES(res
);
388 if (erase_count
!= SPIFFS_OBJ_ID_FREE
) {
389 erase_count_min
= MIN(erase_count_min
, erase_count
);
390 erase_count_max
= MAX(erase_count_max
, erase_count
);
395 if (erase_count_min
== 0 && erase_count_max
== SPIFFS_OBJ_ID_FREE
) {
396 // clean system, set counter to zero
397 erase_count_final
= 0;
398 } else if (erase_count_max
- erase_count_min
> (SPIFFS_OBJ_ID_FREE
) / 2) {
400 erase_count_final
= erase_count_min
+ 1;
402 erase_count_final
= erase_count_max
+ 1;
405 fs
->max_erase_count
= erase_count_final
;
408 if (unerased_bix
!= (spiffs_block_ix
) - 1) {
409 // found one unerased block, remedy
410 SPIFFS_DBG("mount: erase block "_SPIPRIbl
"\n", bix
);
412 res
= SPIFFS_ERR_RO_ABORTED_OPERATION
;
414 res
= spiffs_erase_block(fs
, unerased_bix
);
415 #endif // SPIFFS_READ_ONLY
416 SPIFFS_CHECK_RES(res
);
423 fs
->stats_p_allocated
= 0;
424 fs
->stats_p_deleted
= 0;
426 res
= spiffs_obj_lu_find_entry_visitor(fs
,
431 spiffs_obj_lu_scan_v
,
437 if (res
== SPIFFS_VIS_END
) {
441 SPIFFS_CHECK_RES(res
);
446 #if !SPIFFS_READ_ONLY
447 // Find free object lookup entry
448 // Iterate over object lookup pages in each block until a free object id entry is found
449 s32_t
spiffs_obj_lu_find_free(
451 spiffs_block_ix starting_block
,
452 int starting_lu_entry
,
453 spiffs_block_ix
*block_ix
,
456 if (!fs
->cleaning
&& fs
->free_blocks
< 2) {
457 res
= spiffs_gc_quick(fs
, 0);
458 if (res
== SPIFFS_ERR_NO_DELETED_BLOCKS
) {
461 SPIFFS_CHECK_RES(res
);
462 if (fs
->free_blocks
< 2) {
463 return SPIFFS_ERR_FULL
;
466 res
= spiffs_obj_lu_find_id(fs
, starting_block
, starting_lu_entry
,
467 SPIFFS_OBJ_ID_FREE
, block_ix
, lu_entry
);
468 if (res
== SPIFFS_OK
) {
469 fs
->free_cursor_block_ix
= *block_ix
;
470 fs
->free_cursor_obj_lu_entry
= (*lu_entry
) + 1;
471 if (*lu_entry
== 0) {
475 if (res
== SPIFFS_ERR_FULL
) {
476 SPIFFS_DBGF("fs full\n");
481 #endif // !SPIFFS_READ_ONLY
483 // Find object lookup entry containing given id
484 // Iterate over object lookup pages in each block until a given object id entry is found
485 s32_t
spiffs_obj_lu_find_id(
487 spiffs_block_ix starting_block
,
488 int starting_lu_entry
,
489 spiffs_obj_id obj_id
,
490 spiffs_block_ix
*block_ix
,
492 s32_t res
= spiffs_obj_lu_find_entry_visitor(
493 fs
, starting_block
, starting_lu_entry
, SPIFFS_VIS_CHECK_ID
, obj_id
, 0, 0, 0, block_ix
, lu_entry
);
494 if (res
== SPIFFS_VIS_END
) {
495 res
= SPIFFS_ERR_NOT_FOUND
;
501 static s32_t
spiffs_obj_lu_find_id_and_span_v(
503 spiffs_obj_id obj_id
,
506 const void *user_const_p
,
509 spiffs_page_header ph
;
510 spiffs_page_ix pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, ix_entry
);
511 res
= _spiffs_rd(fs
, 0, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
512 SPIFFS_PAGE_TO_PADDR(fs
, pix
), sizeof(spiffs_page_header
), (u8_t
*)&ph
);
513 SPIFFS_CHECK_RES(res
);
514 if (ph
.obj_id
== obj_id
&&
515 ph
.span_ix
== *((spiffs_span_ix
*)user_var_p
) &&
516 (ph
.flags
& (SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_USED
)) == SPIFFS_PH_FLAG_DELET
&&
517 !((obj_id
& SPIFFS_OBJ_ID_IX_FLAG
) && (ph
.flags
& SPIFFS_PH_FLAG_IXDELE
) == 0 && ph
.span_ix
== 0) &&
518 (user_const_p
== 0 || *((const spiffs_page_ix
*)user_const_p
) != pix
)) {
521 return SPIFFS_VIS_COUNTINUE
;
525 // Find object lookup entry containing given id and span index
526 // Iterate over object lookup pages in each block until a given object id entry is found
527 s32_t
spiffs_obj_lu_find_id_and_span(
529 spiffs_obj_id obj_id
,
531 spiffs_page_ix exclusion_pix
,
532 spiffs_page_ix
*pix
) {
537 res
= spiffs_obj_lu_find_entry_visitor(fs
,
539 fs
->cursor_obj_lu_entry
,
542 spiffs_obj_lu_find_id_and_span_v
,
543 exclusion_pix
? &exclusion_pix
: 0,
548 if (res
== SPIFFS_VIS_END
) {
549 res
= SPIFFS_ERR_NOT_FOUND
;
552 SPIFFS_CHECK_RES(res
);
555 *pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
558 fs
->cursor_block_ix
= bix
;
559 fs
->cursor_obj_lu_entry
= entry
;
564 // Find object lookup entry containing given id and span index in page headers only
565 // Iterate over object lookup pages in each block until a given object id entry is found
566 s32_t
spiffs_obj_lu_find_id_and_span_by_phdr(
568 spiffs_obj_id obj_id
,
570 spiffs_page_ix exclusion_pix
,
571 spiffs_page_ix
*pix
) {
576 res
= spiffs_obj_lu_find_entry_visitor(fs
,
578 fs
->cursor_obj_lu_entry
,
581 spiffs_obj_lu_find_id_and_span_v
,
582 exclusion_pix
? &exclusion_pix
: 0,
587 if (res
== SPIFFS_VIS_END
) {
588 res
= SPIFFS_ERR_NOT_FOUND
;
591 SPIFFS_CHECK_RES(res
);
594 *pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
597 fs
->cursor_block_ix
= bix
;
598 fs
->cursor_obj_lu_entry
= entry
;
605 // update index map of given fd with given object index data
606 static void spiffs_update_ix_map(spiffs
*fs
,
607 spiffs_fd
*fd
, spiffs_span_ix objix_spix
, spiffs_page_object_ix
*objix
) {
611 spiffs_ix_map
*map
= fd
->ix_map
;
612 spiffs_span_ix map_objix_start_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, map
->start_spix
);
613 spiffs_span_ix map_objix_end_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, map
->end_spix
);
615 // check if updated ix is within map range
616 if (objix_spix
< map_objix_start_spix
|| objix_spix
> map_objix_end_spix
) {
620 // update memory mapped page index buffer to new pages
622 // get range of updated object index map data span indices
623 spiffs_span_ix objix_data_spix_start
=
624 SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs
, objix_spix
);
625 spiffs_span_ix objix_data_spix_end
= objix_data_spix_start
+
626 (objix_spix
== 0 ? SPIFFS_OBJ_HDR_IX_LEN(fs
) : SPIFFS_OBJ_IX_LEN(fs
));
628 // calc union of object index range and index map range array
629 spiffs_span_ix map_spix
= MAX(map
->start_spix
, objix_data_spix_start
);
630 spiffs_span_ix map_spix_end
= MIN(map
->end_spix
+ 1, objix_data_spix_end
);
632 while (map_spix
< map_spix_end
) {
633 spiffs_page_ix objix_data_pix
;
634 if (objix_spix
== 0) {
635 // get data page from object index header page
636 objix_data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix_header
)))[map_spix
];
638 // get data page from object index page
639 objix_data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, map_spix
)];
642 if (objix_data_pix
== (spiffs_page_ix
) - 1) {
643 // reached end of object, abort
647 map
->map_buf
[map_spix
- map
->start_spix
] = objix_data_pix
;
648 SPIFFS_DBG("map "_SPIPRIid
":"_SPIPRIsp
" ("_SPIPRIsp
"--"_SPIPRIsp
") objix.spix:"_SPIPRIsp
" to pix "_SPIPRIpg
"\n",
649 fd
->obj_id
, map_spix
- map
->start_spix
,
650 map
->start_spix
, map
->end_spix
,
651 objix
->p_hdr
.span_ix
,
660 u32_t remaining_objix_pages_to_visit
;
661 spiffs_span_ix map_objix_start_spix
;
662 spiffs_span_ix map_objix_end_spix
;
663 } spiffs_ix_map_populate_state
;
665 static s32_t
spiffs_populate_ix_map_v(
667 spiffs_obj_id obj_id
,
670 const void *user_const_p
,
674 spiffs_ix_map_populate_state
*state
= (spiffs_ix_map_populate_state
*)user_var_p
;
675 spiffs_page_ix pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, ix_entry
);
677 // load header to check it
678 spiffs_page_object_ix
*objix
= (spiffs_page_object_ix
*)fs
->work
;
679 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
680 0, SPIFFS_PAGE_TO_PADDR(fs
, pix
), sizeof(spiffs_page_object_ix
), (u8_t
*)objix
);
681 SPIFFS_CHECK_RES(res
);
682 SPIFFS_VALIDATE_OBJIX(objix
->p_hdr
, obj_id
, objix
->p_hdr
.span_ix
);
684 // check if hdr is ok, and if objix range overlap with ix map range
685 if ((objix
->p_hdr
.flags
& (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_IXDELE
)) ==
686 (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
) &&
687 objix
->p_hdr
.span_ix
>= state
->map_objix_start_spix
&&
688 objix
->p_hdr
.span_ix
<= state
->map_objix_end_spix
) {
689 // ok, load rest of object index
690 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
691 0, SPIFFS_PAGE_TO_PADDR(fs
, pix
) + sizeof(spiffs_page_object_ix
),
692 SPIFFS_CFG_LOG_PAGE_SZ(fs
) - sizeof(spiffs_page_object_ix
),
693 (u8_t
*)objix
+ sizeof(spiffs_page_object_ix
));
694 SPIFFS_CHECK_RES(res
);
696 spiffs_update_ix_map(fs
, state
->fd
, objix
->p_hdr
.span_ix
, objix
);
698 state
->remaining_objix_pages_to_visit
--;
699 SPIFFS_DBG("map "_SPIPRIid
" ("_SPIPRIsp
"--"_SPIPRIsp
") remaining objix pages "_SPIPRIi
"\n",
701 state
->fd
->ix_map
->start_spix
, state
->fd
->ix_map
->end_spix
,
702 state
->remaining_objix_pages_to_visit
);
705 if (res
== SPIFFS_OK
) {
706 res
= state
->remaining_objix_pages_to_visit
? SPIFFS_VIS_COUNTINUE
: SPIFFS_VIS_END
;
711 // populates index map, from vector entry start to vector entry end, inclusive
712 s32_t
spiffs_populate_ix_map(spiffs
*fs
, spiffs_fd
*fd
, u32_t vec_entry_start
, u32_t vec_entry_end
) {
714 spiffs_ix_map
*map
= fd
->ix_map
;
715 spiffs_ix_map_populate_state state
;
716 vec_entry_start
= MIN((u32_t
)(map
->end_spix
- map
->start_spix
), vec_entry_start
);
717 vec_entry_end
= MAX((u32_t
)(map
->end_spix
- map
->start_spix
), vec_entry_end
);
718 if (vec_entry_start
> vec_entry_end
) {
719 return SPIFFS_ERR_IX_MAP_BAD_RANGE
;
721 state
.map_objix_start_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, map
->start_spix
+ vec_entry_start
);
722 state
.map_objix_end_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, map
->start_spix
+ vec_entry_end
);
723 state
.remaining_objix_pages_to_visit
=
724 state
.map_objix_end_spix
- state
.map_objix_start_spix
+ 1;
727 res
= spiffs_obj_lu_find_entry_visitor(
729 SPIFFS_BLOCK_FOR_PAGE(fs
, fd
->objix_hdr_pix
),
730 SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs
, fd
->objix_hdr_pix
),
732 fd
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
,
733 spiffs_populate_ix_map_v
,
739 if (res
== SPIFFS_VIS_END
) {
749 #if !SPIFFS_READ_ONLY
750 // Allocates a free defined page with given obj_id
751 // Occupies object lookup entry and page
752 // data may be NULL; where only page header is stored, len and page_offs is ignored
753 s32_t
spiffs_page_allocate_data(
755 spiffs_obj_id obj_id
,
756 spiffs_page_header
*ph
,
761 spiffs_page_ix
*pix
) {
762 s32_t res
= SPIFFS_OK
;
767 res
= spiffs_obj_lu_find_free(fs
, fs
->free_cursor_block_ix
, fs
->free_cursor_obj_lu_entry
, &bix
, &entry
);
768 SPIFFS_CHECK_RES(res
);
770 // occupy page in object lookup
771 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_UPDT
,
772 0, SPIFFS_BLOCK_TO_PADDR(fs
, bix
) + entry
* sizeof(spiffs_obj_id
), sizeof(spiffs_obj_id
), (u8_t
*)&obj_id
);
773 SPIFFS_CHECK_RES(res
);
775 fs
->stats_p_allocated
++;
778 ph
->flags
&= ~SPIFFS_PH_FLAG_USED
;
779 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
780 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs
, bix
, entry
), sizeof(spiffs_page_header
), (u8_t
*)ph
);
781 SPIFFS_CHECK_RES(res
);
785 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
786 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs
, bix
, entry
) + sizeof(spiffs_page_header
) + page_offs
, len
, data
);
787 SPIFFS_CHECK_RES(res
);
790 // finalize header if necessary
791 if (finalize
&& (ph
->flags
& SPIFFS_PH_FLAG_FINAL
)) {
792 ph
->flags
&= ~SPIFFS_PH_FLAG_FINAL
;
793 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
794 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs
, bix
, entry
) + offsetof(spiffs_page_header
, flags
),
797 SPIFFS_CHECK_RES(res
);
800 // return written page
802 *pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
807 #endif // !SPIFFS_READ_ONLY
809 #if !SPIFFS_READ_ONLY
810 // Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page.
811 // If page data is null, provided header is used for metainfo and page data is physically copied.
812 s32_t
spiffs_page_move(
816 spiffs_obj_id obj_id
,
817 spiffs_page_header
*page_hdr
,
818 spiffs_page_ix src_pix
,
819 spiffs_page_ix
*dst_pix
) {
822 spiffs_page_header
*p_hdr
;
825 spiffs_page_ix free_pix
;
828 res
= spiffs_obj_lu_find_free(fs
, fs
->free_cursor_block_ix
, fs
->free_cursor_obj_lu_entry
, &bix
, &entry
);
829 SPIFFS_CHECK_RES(res
);
830 free_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
832 if (dst_pix
) *dst_pix
= free_pix
;
834 p_hdr
= page_data
? (spiffs_page_header
*)page_data
: page_hdr
;
837 was_final
= (p_hdr
->flags
& SPIFFS_PH_FLAG_FINAL
) == 0;
838 // write unfinalized page
839 p_hdr
->flags
|= SPIFFS_PH_FLAG_FINAL
;
840 p_hdr
->flags
&= ~SPIFFS_PH_FLAG_USED
;
841 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
842 0, SPIFFS_PAGE_TO_PADDR(fs
, free_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), page_data
);
845 res
= spiffs_phys_cpy(fs
, fh
, SPIFFS_PAGE_TO_PADDR(fs
, free_pix
), SPIFFS_PAGE_TO_PADDR(fs
, src_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
));
847 SPIFFS_CHECK_RES(res
);
849 // mark entry in destination object lookup
850 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_UPDT
,
851 0, SPIFFS_BLOCK_TO_PADDR(fs
, SPIFFS_BLOCK_FOR_PAGE(fs
, free_pix
)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs
, free_pix
) * sizeof(spiffs_page_ix
),
852 sizeof(spiffs_obj_id
),
854 SPIFFS_CHECK_RES(res
);
856 fs
->stats_p_allocated
++;
859 // mark finalized in destination page
860 p_hdr
->flags
&= ~(SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_USED
);
861 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
863 SPIFFS_PAGE_TO_PADDR(fs
, free_pix
) + offsetof(spiffs_page_header
, flags
),
865 (u8_t
*)&p_hdr
->flags
);
866 SPIFFS_CHECK_RES(res
);
868 // mark source deleted
869 res
= spiffs_page_delete(fs
, src_pix
);
872 #endif // !SPIFFS_READ_ONLY
874 #if !SPIFFS_READ_ONLY
875 // Deletes a page and removes it from object lookup.
876 s32_t
spiffs_page_delete(
878 spiffs_page_ix pix
) {
880 // mark deleted entry in source object lookup
881 spiffs_obj_id d_obj_id
= SPIFFS_OBJ_ID_DELETED
;
882 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_DELE
,
884 SPIFFS_BLOCK_TO_PADDR(fs
, SPIFFS_BLOCK_FOR_PAGE(fs
, pix
)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs
, pix
) * sizeof(spiffs_page_ix
),
885 sizeof(spiffs_obj_id
),
887 SPIFFS_CHECK_RES(res
);
889 fs
->stats_p_deleted
++;
890 fs
->stats_p_allocated
--;
892 // mark deleted in source page
894 #if SPIFFS_NO_BLIND_WRITES
895 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_READ
,
896 0, SPIFFS_PAGE_TO_PADDR(fs
, pix
) + offsetof(spiffs_page_header
, flags
),
897 sizeof(flags
), &flags
);
898 SPIFFS_CHECK_RES(res
);
900 flags
&= ~(SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_USED
);
901 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_DELE
,
903 SPIFFS_PAGE_TO_PADDR(fs
, pix
) + offsetof(spiffs_page_header
, flags
),
904 sizeof(flags
), &flags
);
908 #endif // !SPIFFS_READ_ONLY
910 #if !SPIFFS_READ_ONLY
911 // Create an object index header page with empty index and undefined length
912 s32_t
spiffs_object_create(
914 spiffs_obj_id obj_id
,
917 spiffs_obj_type type
,
918 spiffs_page_ix
*objix_hdr_pix
) {
919 s32_t res
= SPIFFS_OK
;
921 spiffs_page_object_ix_header oix_hdr
;
924 res
= spiffs_gc_check(fs
, SPIFFS_DATA_PAGE_SIZE(fs
));
925 SPIFFS_CHECK_RES(res
);
927 obj_id
|= SPIFFS_OBJ_ID_IX_FLAG
;
930 res
= spiffs_obj_lu_find_free(fs
, fs
->free_cursor_block_ix
, fs
->free_cursor_obj_lu_entry
, &bix
, &entry
);
931 SPIFFS_CHECK_RES(res
);
932 SPIFFS_DBG("create: found free page @ "_SPIPRIpg
" bix:"_SPIPRIbl
" entry:"_SPIPRIsp
"\n", (spiffs_page_ix
)SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
), bix
, entry
);
934 // occupy page in object lookup
935 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_UPDT
,
936 0, SPIFFS_BLOCK_TO_PADDR(fs
, bix
) + entry
* sizeof(spiffs_obj_id
), sizeof(spiffs_obj_id
), (u8_t
*)&obj_id
);
937 SPIFFS_CHECK_RES(res
);
939 fs
->stats_p_allocated
++;
941 // write empty object index page
942 oix_hdr
.p_hdr
.obj_id
= obj_id
;
943 oix_hdr
.p_hdr
.span_ix
= 0;
944 oix_hdr
.p_hdr
.flags
= 0xff & ~(SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_USED
);
946 oix_hdr
.size
= SPIFFS_UNDEFINED_LEN
; // keep ones so we can update later without wasting this page
947 strncpy((char *)oix_hdr
.name
, (const char *)name
, SPIFFS_OBJ_NAME_LEN
- 1);
948 #if SPIFFS_OBJ_META_LEN
950 _SPIFFS_MEMCPY(oix_hdr
.meta
, meta
, SPIFFS_OBJ_META_LEN
);
952 memset(oix_hdr
.meta
, 0xff, SPIFFS_OBJ_META_LEN
);
959 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
960 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs
, bix
, entry
), sizeof(spiffs_page_object_ix_header
), (u8_t
*)&oix_hdr
);
962 SPIFFS_CHECK_RES(res
);
963 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)&oix_hdr
,
964 SPIFFS_EV_IX_NEW
, obj_id
, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
), SPIFFS_UNDEFINED_LEN
);
967 *objix_hdr_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
972 #endif // !SPIFFS_READ_ONLY
974 #if !SPIFFS_READ_ONLY
975 // update object index header with any combination of name/size/index
976 // new_objix_hdr_data may be null, if so the object index header page is loaded
977 // name may be null, if so name is not changed
978 // size may be null, if so size is not changed
979 s32_t
spiffs_object_update_index_hdr(
982 spiffs_obj_id obj_id
,
983 spiffs_page_ix objix_hdr_pix
,
984 u8_t
*new_objix_hdr_data
,
988 spiffs_page_ix
*new_pix
) {
989 s32_t res
= SPIFFS_OK
;
990 spiffs_page_object_ix_header
*objix_hdr
;
991 spiffs_page_ix new_objix_hdr_pix
;
993 obj_id
|= SPIFFS_OBJ_ID_IX_FLAG
;
995 if (new_objix_hdr_data
) {
996 // object index header page already given to us, no need to load it
997 objix_hdr
= (spiffs_page_object_ix_header
*)new_objix_hdr_data
;
999 // read object index header page
1000 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
1001 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, objix_hdr_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1002 SPIFFS_CHECK_RES(res
);
1003 objix_hdr
= (spiffs_page_object_ix_header
*)fs
->work
;
1006 SPIFFS_VALIDATE_OBJIX(objix_hdr
->p_hdr
, obj_id
, 0);
1010 strncpy((char *)objix_hdr
->name
, (const char *)name
, SPIFFS_OBJ_NAME_LEN
- 1);
1012 #if SPIFFS_OBJ_META_LEN
1014 _SPIFFS_MEMCPY(objix_hdr
->meta
, meta
, SPIFFS_OBJ_META_LEN
);
1020 objix_hdr
->size
= size
;
1023 // move and update page
1024 res
= spiffs_page_move(fs
, fd
== 0 ? 0 : fd
->file_nbr
, (u8_t
*)objix_hdr
, obj_id
, 0, objix_hdr_pix
, &new_objix_hdr_pix
);
1026 if (res
== SPIFFS_OK
) {
1028 *new_pix
= new_objix_hdr_pix
;
1030 // callback on object index update
1031 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)objix_hdr
,
1032 new_objix_hdr_data
? SPIFFS_EV_IX_UPD
: SPIFFS_EV_IX_UPD_HDR
,
1033 obj_id
, objix_hdr
->p_hdr
.span_ix
, new_objix_hdr_pix
, objix_hdr
->size
);
1034 if (fd
) fd
->objix_hdr_pix
= new_objix_hdr_pix
; // if this is not in the registered cluster
1039 #endif // !SPIFFS_READ_ONLY
1041 void spiffs_cb_object_event(
1043 spiffs_page_object_ix
*objix
,
1045 spiffs_obj_id obj_id_raw
,
1046 spiffs_span_ix spix
,
1047 spiffs_page_ix new_pix
,
1049 #if SPIFFS_IX_MAP == 0
1052 // update index caches in all file descriptors
1053 spiffs_obj_id obj_id
= obj_id_raw
& ~SPIFFS_OBJ_ID_IX_FLAG
;
1055 spiffs_fd
*fds
= (spiffs_fd
*)fs
->fd_space
;
1056 SPIFFS_DBG(" CALLBACK %s obj_id:"_SPIPRIid
" spix:"_SPIPRIsp
" npix:"_SPIPRIpg
" nsz:"_SPIPRIi
"\n", (const char *[]) {"UPD", "NEW", "DEL", "MOV", "HUP", "???"}[MIN(ev
, 5)],
1057 obj_id_raw
, spix
, new_pix
, new_size
);
1058 for (i
= 0; i
< fs
->fd_count
; i
++) {
1059 spiffs_fd
*cur_fd
= &fds
[i
];
1060 if ((cur_fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
) != obj_id
) continue; // fd not related to updated file
1061 #if !SPIFFS_TEMPORAL_FD_CACHE
1062 if (cur_fd
->file_nbr
== 0) continue; // fd closed
1064 if (spix
== 0) { // object index header update
1065 if (ev
!= SPIFFS_EV_IX_DEL
) {
1066 #if SPIFFS_TEMPORAL_FD_CACHE
1067 if (cur_fd
->score
== 0) continue; // never used fd
1069 SPIFFS_DBG(" callback: setting fd "_SPIPRIfd
":"_SPIPRIid
"(fdoffs:"_SPIPRIi
" offs:"_SPIPRIi
") objix_hdr_pix to "_SPIPRIpg
", size:"_SPIPRIi
"\n",
1070 SPIFFS_FH_OFFS(fs
, cur_fd
->file_nbr
), cur_fd
->obj_id
, cur_fd
->fdoffset
, cur_fd
->offset
, new_pix
, new_size
);
1071 cur_fd
->objix_hdr_pix
= new_pix
;
1072 if (new_size
!= 0) {
1073 // update size and offsets for fds to this file
1074 cur_fd
->size
= new_size
;
1075 u32_t act_new_size
= new_size
== SPIFFS_UNDEFINED_LEN
? 0 : new_size
;
1077 if (act_new_size
> 0 && cur_fd
->cache_page
) {
1078 act_new_size
= MAX(act_new_size
, cur_fd
->cache_page
->ucache
.swrc
.offset
+ cur_fd
->cache_page
->ucache
.swrc
.size
);
1081 if (cur_fd
->offset
> act_new_size
) {
1082 cur_fd
->offset
= act_new_size
;
1084 if (cur_fd
->fdoffset
> act_new_size
) {
1085 cur_fd
->fdoffset
= act_new_size
;
1088 if (cur_fd
->cache_page
&& cur_fd
->cache_page
->ucache
.swrc
.offset
> act_new_size
+ 1) {
1089 SPIFFS_CACHE_DBG("CACHE_DROP: file trunced, dropping cache page "_SPIPRIi
", no writeback\n", cur_fd
->cache_page
->ix
);
1090 spiffs_cache_fd_release(fs
, cur_fd
->cache_page
);
1097 if (cur_fd
->file_nbr
&& cur_fd
->cache_page
) {
1098 SPIFFS_CACHE_DBG("CACHE_DROP: file deleted, dropping cache page "_SPIPRIi
", no writeback\n", cur_fd
->cache_page
->ix
);
1099 spiffs_cache_fd_release(fs
, cur_fd
->cache_page
);
1102 SPIFFS_DBG(" callback: release fd "_SPIPRIfd
":"_SPIPRIid
" span:"_SPIPRIsp
" objix_pix to "_SPIPRIpg
"\n", SPIFFS_FH_OFFS(fs
, cur_fd
->file_nbr
), cur_fd
->obj_id
, spix
, new_pix
);
1103 cur_fd
->file_nbr
= 0;
1104 cur_fd
->obj_id
= SPIFFS_OBJ_ID_DELETED
;
1106 } // object index header update
1107 if (cur_fd
->cursor_objix_spix
== spix
) {
1108 if (ev
!= SPIFFS_EV_IX_DEL
) {
1109 SPIFFS_DBG(" callback: setting fd "_SPIPRIfd
":"_SPIPRIid
" span:"_SPIPRIsp
" objix_pix to "_SPIPRIpg
"\n", SPIFFS_FH_OFFS(fs
, cur_fd
->file_nbr
), cur_fd
->obj_id
, spix
, new_pix
);
1110 cur_fd
->cursor_objix_pix
= new_pix
;
1112 cur_fd
->cursor_objix_pix
= 0;
1119 // update index maps
1120 if (ev
== SPIFFS_EV_IX_UPD
|| ev
== SPIFFS_EV_IX_NEW
) {
1121 for (i
= 0; i
< fs
->fd_count
; i
++) {
1122 spiffs_fd
*cur_fd
= &fds
[i
];
1123 // check fd opened, having ix map, match obj id
1124 if (cur_fd
->file_nbr
== 0 ||
1125 cur_fd
->ix_map
== 0 ||
1126 (cur_fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
) != obj_id
) continue;
1127 SPIFFS_DBG(" callback: map ix update fd "_SPIPRIfd
":"_SPIPRIid
" span:"_SPIPRIsp
"\n", SPIFFS_FH_OFFS(fs
, cur_fd
->file_nbr
), cur_fd
->obj_id
, spix
);
1128 spiffs_update_ix_map(fs
, cur_fd
, spix
, objix
);
1134 // callback to user if object index header
1135 if (fs
->file_cb_f
&& spix
== 0 && (obj_id_raw
& SPIFFS_OBJ_ID_IX_FLAG
)) {
1136 spiffs_fileop_type op
;
1137 if (ev
== SPIFFS_EV_IX_NEW
) {
1138 op
= SPIFFS_CB_CREATED
;
1139 } else if (ev
== SPIFFS_EV_IX_UPD
||
1140 ev
== SPIFFS_EV_IX_MOV
||
1141 ev
== SPIFFS_EV_IX_UPD_HDR
) {
1142 op
= SPIFFS_CB_UPDATED
;
1143 } else if (ev
== SPIFFS_EV_IX_DEL
) {
1144 op
= SPIFFS_CB_DELETED
;
1146 SPIFFS_DBG(" callback: WARNING unknown callback event "_SPIPRIi
"\n", ev
);
1149 fs
->file_cb_f(fs
, op
, obj_id
, new_pix
);
1153 // Open object by id
1154 s32_t
spiffs_object_open_by_id(
1156 spiffs_obj_id obj_id
,
1160 s32_t res
= SPIFFS_OK
;
1163 res
= spiffs_obj_lu_find_id_and_span(fs
, obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, &pix
);
1164 SPIFFS_CHECK_RES(res
);
1166 res
= spiffs_object_open_by_page(fs
, pix
, fd
, flags
, mode
);
1171 // Open object by page index
1172 s32_t
spiffs_object_open_by_page(
1179 s32_t res
= SPIFFS_OK
;
1180 spiffs_page_object_ix_header oix_hdr
;
1181 spiffs_obj_id obj_id
;
1183 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
1184 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, pix
), sizeof(spiffs_page_object_ix_header
), (u8_t
*)&oix_hdr
);
1185 SPIFFS_CHECK_RES(res
);
1187 spiffs_block_ix bix
= SPIFFS_BLOCK_FOR_PAGE(fs
, pix
);
1188 int entry
= SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs
, pix
);
1190 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_READ
,
1191 0, SPIFFS_BLOCK_TO_PADDR(fs
, bix
) + entry
* sizeof(spiffs_obj_id
), sizeof(spiffs_obj_id
), (u8_t
*)&obj_id
);
1194 fd
->objix_hdr_pix
= pix
;
1195 fd
->size
= oix_hdr
.size
;
1197 fd
->cursor_objix_pix
= pix
;
1198 fd
->cursor_objix_spix
= 0;
1199 fd
->obj_id
= obj_id
;
1202 SPIFFS_VALIDATE_OBJIX(oix_hdr
.p_hdr
, fd
->obj_id
, 0);
1204 SPIFFS_DBG("open: fd "_SPIPRIfd
" is obj id "_SPIPRIid
"\n", SPIFFS_FH_OFFS(fs
, fd
->file_nbr
), fd
->obj_id
);
1209 #if !SPIFFS_READ_ONLY
1211 // keep current object index (header) page in fs->work buffer
1212 s32_t
spiffs_object_append(spiffs_fd
*fd
, u32_t offset
, u8_t
*data
, u32_t len
) {
1213 spiffs
*fs
= fd
->fs
;
1214 s32_t res
= SPIFFS_OK
;
1217 SPIFFS_DBG("append: "_SPIPRIi
" bytes @ offs "_SPIPRIi
" of size "_SPIPRIi
"\n", len
, offset
, fd
->size
);
1219 if (offset
> fd
->size
) {
1220 SPIFFS_DBGF("append: offset reversed to size\n");
1224 res
= spiffs_gc_check(fs
, len
+ SPIFFS_DATA_PAGE_SIZE(fs
)); // add an extra page of data worth for meta
1225 if (res
!= SPIFFS_OK
) {
1226 SPIFFS_DBG("append: gc check fail "_SPIPRIi
"\n", res
);
1228 SPIFFS_CHECK_RES(res
);
1230 spiffs_page_object_ix_header
*objix_hdr
= (spiffs_page_object_ix_header
*)fs
->work
;
1231 spiffs_page_object_ix
*objix
= (spiffs_page_object_ix
*)fs
->work
;
1232 spiffs_page_header p_hdr
;
1234 spiffs_span_ix cur_objix_spix
= 0;
1235 spiffs_span_ix prev_objix_spix
= (spiffs_span_ix
) - 1;
1236 spiffs_page_ix cur_objix_pix
= fd
->objix_hdr_pix
;
1237 spiffs_page_ix new_objix_hdr_page
;
1239 spiffs_span_ix data_spix
= offset
/ SPIFFS_DATA_PAGE_SIZE(fs
);
1240 spiffs_page_ix data_page
;
1241 u32_t page_offs
= offset
% SPIFFS_DATA_PAGE_SIZE(fs
);
1244 while (res
== SPIFFS_OK
&& written
< len
) {
1245 // calculate object index page span index
1246 cur_objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
1248 // handle storing and loading of object indices
1249 if (cur_objix_spix
!= prev_objix_spix
) {
1250 // new object index page
1251 // within this clause we return directly if something fails, object index mess-up
1253 // store previous object index page, unless first pass
1254 SPIFFS_DBG("append: "_SPIPRIid
" store objix "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", fd
->obj_id
,
1255 cur_objix_pix
, prev_objix_spix
, written
);
1256 if (prev_objix_spix
== 0) {
1257 // this is an update to object index header page
1258 objix_hdr
->size
= offset
+ written
;
1260 // was an empty object, update same page (size was 0xffffffff)
1261 res
= spiffs_page_index_check(fs
, fd
, cur_objix_pix
, 0);
1262 SPIFFS_CHECK_RES(res
);
1263 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_UPDT
,
1264 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, cur_objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1265 SPIFFS_CHECK_RES(res
);
1267 // was a nonempty object, update to new page
1268 res
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1269 fd
->objix_hdr_pix
, fs
->work
, 0, 0, offset
+ written
, &new_objix_hdr_page
);
1270 SPIFFS_CHECK_RES(res
);
1271 SPIFFS_DBG("append: "_SPIPRIid
" store new objix_hdr, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", fd
->obj_id
,
1272 new_objix_hdr_page
, 0, written
);
1275 // this is an update to an object index page
1276 res
= spiffs_page_index_check(fs
, fd
, cur_objix_pix
, prev_objix_spix
);
1277 SPIFFS_CHECK_RES(res
);
1279 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_UPDT
,
1280 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, cur_objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1281 SPIFFS_CHECK_RES(res
);
1282 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)fs
->work
,
1283 SPIFFS_EV_IX_UPD
, fd
->obj_id
, objix
->p_hdr
.span_ix
, cur_objix_pix
, 0);
1284 // update length in object index header page
1285 res
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1286 fd
->objix_hdr_pix
, 0, 0, 0, offset
+ written
, &new_objix_hdr_page
);
1287 SPIFFS_CHECK_RES(res
);
1288 SPIFFS_DBG("append: "_SPIPRIid
" store new size I "_SPIPRIi
" in objix_hdr, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", fd
->obj_id
,
1289 offset
+ written
, new_objix_hdr_page
, 0, written
);
1291 fd
->size
= offset
+ written
;
1292 fd
->offset
= offset
+ written
;
1295 // create or load new object index page
1296 if (cur_objix_spix
== 0) {
1297 // load object index header page, must always exist
1298 SPIFFS_DBG("append: "_SPIPRIid
" load objixhdr page "_SPIPRIpg
":"_SPIPRIsp
"\n", fd
->obj_id
, cur_objix_pix
, cur_objix_spix
);
1299 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
1300 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, cur_objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1301 SPIFFS_CHECK_RES(res
);
1302 SPIFFS_VALIDATE_OBJIX(objix_hdr
->p_hdr
, fd
->obj_id
, cur_objix_spix
);
1304 spiffs_span_ix len_objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, (fd
->size
- 1) / SPIFFS_DATA_PAGE_SIZE(fs
));
1305 // on subsequent passes, create a new object index page
1306 if (written
> 0 || cur_objix_spix
> len_objix_spix
) {
1307 p_hdr
.obj_id
= fd
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
1308 p_hdr
.span_ix
= cur_objix_spix
;
1309 p_hdr
.flags
= 0xff & ~(SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_INDEX
);
1310 res
= spiffs_page_allocate_data(fs
, fd
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
,
1311 &p_hdr
, 0, 0, 0, 1, &cur_objix_pix
);
1312 SPIFFS_CHECK_RES(res
);
1313 // quick "load" of new object index page
1314 memset(fs
->work
, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs
));
1315 _SPIFFS_MEMCPY(fs
->work
, &p_hdr
, sizeof(spiffs_page_header
));
1316 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)fs
->work
,
1317 SPIFFS_EV_IX_NEW
, fd
->obj_id
, cur_objix_spix
, cur_objix_pix
, 0);
1318 SPIFFS_DBG("append: "_SPIPRIid
" create objix page, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", fd
->obj_id
1319 , cur_objix_pix
, cur_objix_spix
, written
);
1321 // on first pass, we load existing object index page
1323 SPIFFS_DBG("append: "_SPIPRIid
" find objix span_ix:"_SPIPRIsp
"\n", fd
->obj_id
, cur_objix_spix
);
1324 if (fd
->cursor_objix_spix
== cur_objix_spix
) {
1325 pix
= fd
->cursor_objix_pix
;
1327 res
= spiffs_obj_lu_find_id_and_span(fs
, fd
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, cur_objix_spix
, 0, &pix
);
1328 SPIFFS_CHECK_RES(res
);
1330 SPIFFS_DBG("append: "_SPIPRIid
" found object index at page "_SPIPRIpg
" [fd size "_SPIPRIi
"]\n", fd
->obj_id
, pix
, fd
->size
);
1331 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
1332 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1333 SPIFFS_CHECK_RES(res
);
1334 SPIFFS_VALIDATE_OBJIX(objix_hdr
->p_hdr
, fd
->obj_id
, cur_objix_spix
);
1335 cur_objix_pix
= pix
;
1337 fd
->cursor_objix_pix
= cur_objix_pix
;
1338 fd
->cursor_objix_spix
= cur_objix_spix
;
1339 fd
->offset
= offset
+ written
;
1340 fd
->size
= offset
+ written
;
1342 prev_objix_spix
= cur_objix_spix
;
1346 u32_t to_write
= MIN(len
- written
, SPIFFS_DATA_PAGE_SIZE(fs
) - page_offs
);
1347 if (page_offs
== 0) {
1348 // at beginning of a page, allocate and write a new page of data
1349 p_hdr
.obj_id
= fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
1350 p_hdr
.span_ix
= data_spix
;
1351 p_hdr
.flags
= 0xff & ~(SPIFFS_PH_FLAG_FINAL
); // finalize immediately
1352 res
= spiffs_page_allocate_data(fs
, fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
1353 &p_hdr
, &data
[written
], to_write
, page_offs
, 1, &data_page
);
1354 SPIFFS_DBG("append: "_SPIPRIid
" store new data page, "_SPIPRIpg
":"_SPIPRIsp
" offset:"_SPIPRIi
", len "_SPIPRIi
", written "_SPIPRIi
"\n", fd
->obj_id
,
1355 data_page
, data_spix
, page_offs
, to_write
, written
);
1357 // append to existing page, fill out free data in existing page
1358 if (cur_objix_spix
== 0) {
1359 // get data page from object index header page
1360 data_page
= ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
];
1362 // get data page from object index page
1363 data_page
= ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)];
1366 res
= spiffs_page_data_check(fs
, fd
, data_page
, data_spix
);
1367 SPIFFS_CHECK_RES(res
);
1369 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
1370 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, data_page
) + sizeof(spiffs_page_header
) + page_offs
, to_write
, &data
[written
]);
1371 SPIFFS_DBG("append: "_SPIPRIid
" store to existing data page, "_SPIPRIpg
":"_SPIPRIsp
" offset:"_SPIPRIi
", len "_SPIPRIi
", written "_SPIPRIi
"\n", fd
->obj_id
1372 , data_page
, data_spix
, page_offs
, to_write
, written
);
1375 if (res
!= SPIFFS_OK
) break;
1377 // update memory representation of object index page with new data page
1378 if (cur_objix_spix
== 0) {
1379 // update object index header page
1380 ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
] = data_page
;
1381 SPIFFS_DBG("append: "_SPIPRIid
" wrote page "_SPIPRIpg
" to objix_hdr entry "_SPIPRIsp
" in mem\n", fd
->obj_id
1382 , data_page
, data_spix
);
1383 objix_hdr
->size
= offset
+ written
;
1385 // update object index page
1386 ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)] = data_page
;
1387 SPIFFS_DBG("append: "_SPIPRIid
" wrote page "_SPIPRIpg
" to objix entry "_SPIPRIsp
" in mem\n", fd
->obj_id
1388 , data_page
, (spiffs_span_ix
)SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
));
1394 written
+= to_write
;
1397 fd
->size
= offset
+ written
;
1398 fd
->offset
= offset
+ written
;
1399 fd
->cursor_objix_pix
= cur_objix_pix
;
1400 fd
->cursor_objix_spix
= cur_objix_spix
;
1402 // finalize updated object indices
1403 s32_t res2
= SPIFFS_OK
;
1404 if (cur_objix_spix
!= 0) {
1405 // wrote beyond object index header page
1406 // write last modified object index page, unless object header index page
1407 SPIFFS_DBG("append: "_SPIPRIid
" store objix page, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", fd
->obj_id
,
1408 cur_objix_pix
, cur_objix_spix
, written
);
1410 res2
= spiffs_page_index_check(fs
, fd
, cur_objix_pix
, cur_objix_spix
);
1411 SPIFFS_CHECK_RES(res2
);
1413 res2
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_UPDT
,
1414 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, cur_objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1415 SPIFFS_CHECK_RES(res2
);
1416 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)fs
->work
,
1417 SPIFFS_EV_IX_UPD
, fd
->obj_id
, objix
->p_hdr
.span_ix
, cur_objix_pix
, 0);
1419 // update size in object header index page
1420 res2
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1421 fd
->objix_hdr_pix
, 0, 0, 0, offset
+ written
, &new_objix_hdr_page
);
1422 SPIFFS_DBG("append: "_SPIPRIid
" store new size II "_SPIPRIi
" in objix_hdr, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
", res "_SPIPRIi
"\n", fd
->obj_id
1423 , offset
+ written
, new_objix_hdr_page
, 0, written
, res2
);
1424 SPIFFS_CHECK_RES(res2
);
1426 // wrote within object index header page
1428 // wrote to empty object - simply update size and write whole page
1429 objix_hdr
->size
= offset
+ written
;
1430 SPIFFS_DBG("append: "_SPIPRIid
" store fresh objix_hdr page, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", fd
->obj_id
1431 , cur_objix_pix
, cur_objix_spix
, written
);
1433 res2
= spiffs_page_index_check(fs
, fd
, cur_objix_pix
, cur_objix_spix
);
1434 SPIFFS_CHECK_RES(res2
);
1436 res2
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_UPDT
,
1437 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, cur_objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1438 SPIFFS_CHECK_RES(res2
);
1439 // callback on object index update
1440 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)fs
->work
,
1441 SPIFFS_EV_IX_UPD_HDR
, fd
->obj_id
, objix_hdr
->p_hdr
.span_ix
, cur_objix_pix
, objix_hdr
->size
);
1443 // modifying object index header page, update size and make new copy
1444 res2
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1445 fd
->objix_hdr_pix
, fs
->work
, 0, 0, offset
+ written
, &new_objix_hdr_page
);
1446 SPIFFS_DBG("append: "_SPIPRIid
" store modified objix_hdr page, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", fd
->obj_id
1447 , new_objix_hdr_page
, 0, written
);
1448 SPIFFS_CHECK_RES(res2
);
1453 } // spiffs_object_append
1454 #endif // !SPIFFS_READ_ONLY
1456 #if !SPIFFS_READ_ONLY
1458 // keep current object index (header) page in fs->work buffer
1459 s32_t
spiffs_object_modify(spiffs_fd
*fd
, u32_t offset
, u8_t
*data
, u32_t len
) {
1460 spiffs
*fs
= fd
->fs
;
1461 s32_t res
= SPIFFS_OK
;
1464 res
= spiffs_gc_check(fs
, len
+ SPIFFS_DATA_PAGE_SIZE(fs
));
1465 SPIFFS_CHECK_RES(res
);
1467 spiffs_page_object_ix_header
*objix_hdr
= (spiffs_page_object_ix_header
*)fs
->work
;
1468 spiffs_page_object_ix
*objix
= (spiffs_page_object_ix
*)fs
->work
;
1469 spiffs_page_header p_hdr
;
1471 spiffs_span_ix cur_objix_spix
= 0;
1472 spiffs_span_ix prev_objix_spix
= (spiffs_span_ix
) - 1;
1473 spiffs_page_ix cur_objix_pix
= fd
->objix_hdr_pix
;
1474 spiffs_page_ix new_objix_hdr_pix
;
1476 spiffs_span_ix data_spix
= offset
/ SPIFFS_DATA_PAGE_SIZE(fs
);
1477 spiffs_page_ix data_pix
;
1478 u32_t page_offs
= offset
% SPIFFS_DATA_PAGE_SIZE(fs
);
1482 while (res
== SPIFFS_OK
&& written
< len
) {
1483 // calculate object index page span index
1484 cur_objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
1486 // handle storing and loading of object indices
1487 if (cur_objix_spix
!= prev_objix_spix
) {
1488 // new object index page
1489 // within this clause we return directly if something fails, object index mess-up
1491 // store previous object index (header) page, unless first pass
1492 if (prev_objix_spix
== 0) {
1493 // store previous object index header page
1494 res
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1495 fd
->objix_hdr_pix
, fs
->work
, 0, 0, 0, &new_objix_hdr_pix
);
1496 SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", new_objix_hdr_pix
, 0, written
);
1497 SPIFFS_CHECK_RES(res
);
1499 // store new version of previous object index page
1500 spiffs_page_ix new_objix_pix
;
1502 res
= spiffs_page_index_check(fs
, fd
, cur_objix_pix
, prev_objix_spix
);
1503 SPIFFS_CHECK_RES(res
);
1505 res
= spiffs_page_move(fs
, fd
->file_nbr
, (u8_t
*)objix
, fd
->obj_id
, 0, cur_objix_pix
, &new_objix_pix
);
1506 SPIFFS_DBG("modify: store previous modified objix page, "_SPIPRIid
":"_SPIPRIsp
", written "_SPIPRIi
"\n", new_objix_pix
, objix
->p_hdr
.span_ix
, written
);
1507 SPIFFS_CHECK_RES(res
);
1508 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)objix
,
1509 SPIFFS_EV_IX_UPD
, fd
->obj_id
, objix
->p_hdr
.span_ix
, new_objix_pix
, 0);
1513 // load next object index page
1514 if (cur_objix_spix
== 0) {
1515 // load object index header page, must exist
1516 SPIFFS_DBG("modify: load objixhdr page "_SPIPRIpg
":"_SPIPRIsp
"\n", cur_objix_pix
, cur_objix_spix
);
1517 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
1518 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, cur_objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1519 SPIFFS_CHECK_RES(res
);
1520 SPIFFS_VALIDATE_OBJIX(objix_hdr
->p_hdr
, fd
->obj_id
, cur_objix_spix
);
1522 // load existing object index page on first pass
1524 SPIFFS_DBG("modify: find objix span_ix:"_SPIPRIsp
"\n", cur_objix_spix
);
1525 if (fd
->cursor_objix_spix
== cur_objix_spix
) {
1526 pix
= fd
->cursor_objix_pix
;
1528 res
= spiffs_obj_lu_find_id_and_span(fs
, fd
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, cur_objix_spix
, 0, &pix
);
1529 SPIFFS_CHECK_RES(res
);
1531 SPIFFS_DBG("modify: found object index at page "_SPIPRIpg
"\n", pix
);
1532 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
1533 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1534 SPIFFS_CHECK_RES(res
);
1535 SPIFFS_VALIDATE_OBJIX(objix_hdr
->p_hdr
, fd
->obj_id
, cur_objix_spix
);
1536 cur_objix_pix
= pix
;
1538 fd
->cursor_objix_pix
= cur_objix_pix
;
1539 fd
->cursor_objix_spix
= cur_objix_spix
;
1540 fd
->offset
= offset
+ written
;
1541 prev_objix_spix
= cur_objix_spix
;
1544 // write partial data
1545 u32_t to_write
= MIN(len
- written
, SPIFFS_DATA_PAGE_SIZE(fs
) - page_offs
);
1546 spiffs_page_ix orig_data_pix
;
1547 if (cur_objix_spix
== 0) {
1548 // get data page from object index header page
1549 orig_data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
];
1551 // get data page from object index page
1552 orig_data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)];
1555 p_hdr
.obj_id
= fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
1556 p_hdr
.span_ix
= data_spix
;
1558 if (page_offs
== 0 && to_write
== SPIFFS_DATA_PAGE_SIZE(fs
)) {
1559 // a full page, allocate and write a new page of data
1560 res
= spiffs_page_allocate_data(fs
, fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
1561 &p_hdr
, &data
[written
], to_write
, page_offs
, 1, &data_pix
);
1562 SPIFFS_DBG("modify: store new data page, "_SPIPRIpg
":"_SPIPRIsp
" offset:"_SPIPRIi
", len "_SPIPRIi
", written "_SPIPRIi
"\n", data_pix
, data_spix
, page_offs
, to_write
, written
);
1563 if (res
!= SPIFFS_OK
) break;
1565 // write to existing page, allocate new and copy unmodified data
1567 res
= spiffs_page_data_check(fs
, fd
, orig_data_pix
, data_spix
);
1568 SPIFFS_CHECK_RES(res
);
1570 res
= spiffs_page_allocate_data(fs
, fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
1571 &p_hdr
, 0, 0, 0, 0, &data_pix
);
1572 if (res
!= SPIFFS_OK
) break;
1574 // copy unmodified data
1575 if (page_offs
> 0) {
1576 // before modification
1577 res
= spiffs_phys_cpy(fs
, fd
->file_nbr
,
1578 SPIFFS_PAGE_TO_PADDR(fs
, data_pix
) + sizeof(spiffs_page_header
),
1579 SPIFFS_PAGE_TO_PADDR(fs
, orig_data_pix
) + sizeof(spiffs_page_header
),
1581 if (res
!= SPIFFS_OK
) break;
1583 if (page_offs
+ to_write
< SPIFFS_DATA_PAGE_SIZE(fs
)) {
1584 // after modification
1585 res
= spiffs_phys_cpy(fs
, fd
->file_nbr
,
1586 SPIFFS_PAGE_TO_PADDR(fs
, data_pix
) + sizeof(spiffs_page_header
) + page_offs
+ to_write
,
1587 SPIFFS_PAGE_TO_PADDR(fs
, orig_data_pix
) + sizeof(spiffs_page_header
) + page_offs
+ to_write
,
1588 SPIFFS_DATA_PAGE_SIZE(fs
) - (page_offs
+ to_write
));
1589 if (res
!= SPIFFS_OK
) break;
1592 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
1594 SPIFFS_PAGE_TO_PADDR(fs
, data_pix
) + sizeof(spiffs_page_header
) + page_offs
, to_write
, &data
[written
]);
1595 if (res
!= SPIFFS_OK
) break;
1596 p_hdr
.flags
&= ~SPIFFS_PH_FLAG_FINAL
;
1597 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
1599 SPIFFS_PAGE_TO_PADDR(fs
, data_pix
) + offsetof(spiffs_page_header
, flags
),
1601 (u8_t
*)&p_hdr
.flags
);
1602 if (res
!= SPIFFS_OK
) break;
1604 SPIFFS_DBG("modify: store to existing data page, src:"_SPIPRIpg
", dst:"_SPIPRIpg
":"_SPIPRIsp
" offset:"_SPIPRIi
", len "_SPIPRIi
", written "_SPIPRIi
"\n", orig_data_pix
, data_pix
, data_spix
, page_offs
, to_write
, written
);
1607 // delete original data page
1608 res
= spiffs_page_delete(fs
, orig_data_pix
);
1609 if (res
!= SPIFFS_OK
) break;
1610 // update memory representation of object index page with new data page
1611 if (cur_objix_spix
== 0) {
1612 // update object index header page
1613 ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
] = data_pix
;
1614 SPIFFS_DBG("modify: wrote page "_SPIPRIpg
" to objix_hdr entry "_SPIPRIsp
" in mem\n", data_pix
, data_spix
);
1616 // update object index page
1617 ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)] = data_pix
;
1618 SPIFFS_DBG("modify: wrote page "_SPIPRIpg
" to objix entry "_SPIPRIsp
" in mem\n", data_pix
, (spiffs_span_ix
)SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
));
1624 written
+= to_write
;
1627 fd
->offset
= offset
+ written
;
1628 fd
->cursor_objix_pix
= cur_objix_pix
;
1629 fd
->cursor_objix_spix
= cur_objix_spix
;
1631 // finalize updated object indices
1632 s32_t res2
= SPIFFS_OK
;
1633 if (cur_objix_spix
!= 0) {
1634 // wrote beyond object index header page
1635 // write last modified object index page
1636 // move and update page
1637 spiffs_page_ix new_objix_pix
;
1639 res2
= spiffs_page_index_check(fs
, fd
, cur_objix_pix
, cur_objix_spix
);
1640 SPIFFS_CHECK_RES(res2
);
1642 res2
= spiffs_page_move(fs
, fd
->file_nbr
, (u8_t
*)objix
, fd
->obj_id
, 0, cur_objix_pix
, &new_objix_pix
);
1643 SPIFFS_DBG("modify: store modified objix page, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", new_objix_pix
, cur_objix_spix
, written
);
1644 fd
->cursor_objix_pix
= new_objix_pix
;
1645 fd
->cursor_objix_spix
= cur_objix_spix
;
1646 SPIFFS_CHECK_RES(res2
);
1647 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)objix
,
1648 SPIFFS_EV_IX_UPD
, fd
->obj_id
, objix
->p_hdr
.span_ix
, new_objix_pix
, 0);
1651 // wrote within object index header page
1652 res2
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1653 fd
->objix_hdr_pix
, fs
->work
, 0, 0, 0, &new_objix_hdr_pix
);
1654 SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg
":"_SPIPRIsp
", written "_SPIPRIi
"\n", new_objix_hdr_pix
, 0, written
);
1655 SPIFFS_CHECK_RES(res2
);
1659 } // spiffs_object_modify
1660 #endif // !SPIFFS_READ_ONLY
1662 static s32_t
spiffs_object_find_object_index_header_by_name_v(
1664 spiffs_obj_id obj_id
,
1665 spiffs_block_ix bix
,
1667 const void *user_const_p
,
1671 spiffs_page_object_ix_header objix_hdr
;
1672 spiffs_page_ix pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, ix_entry
);
1673 if (obj_id
== SPIFFS_OBJ_ID_FREE
|| obj_id
== SPIFFS_OBJ_ID_DELETED
||
1674 (obj_id
& SPIFFS_OBJ_ID_IX_FLAG
) == 0) {
1675 return SPIFFS_VIS_COUNTINUE
;
1677 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
1678 0, SPIFFS_PAGE_TO_PADDR(fs
, pix
), sizeof(spiffs_page_object_ix_header
), (u8_t
*)&objix_hdr
);
1679 SPIFFS_CHECK_RES(res
);
1680 if (objix_hdr
.p_hdr
.span_ix
== 0 &&
1681 (objix_hdr
.p_hdr
.flags
& (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_IXDELE
)) ==
1682 (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) {
1683 if (strcmp((const char *)user_const_p
, (char *)objix_hdr
.name
) == 0) {
1688 return SPIFFS_VIS_COUNTINUE
;
1691 // Finds object index header page by name
1692 s32_t
spiffs_object_find_object_index_header_by_name(
1694 const u8_t name
[SPIFFS_OBJ_NAME_LEN
],
1695 spiffs_page_ix
*pix
) {
1697 spiffs_block_ix bix
;
1700 res
= spiffs_obj_lu_find_entry_visitor(fs
,
1701 fs
->cursor_block_ix
,
1702 fs
->cursor_obj_lu_entry
,
1705 spiffs_object_find_object_index_header_by_name_v
,
1711 if (res
== SPIFFS_VIS_END
) {
1712 res
= SPIFFS_ERR_NOT_FOUND
;
1714 SPIFFS_CHECK_RES(res
);
1717 *pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
1720 fs
->cursor_block_ix
= bix
;
1721 fs
->cursor_obj_lu_entry
= entry
;
1726 #if !SPIFFS_READ_ONLY
1727 // Truncates object to new size. If new size is null, object may be removed totally
1728 s32_t
spiffs_object_truncate(
1732 s32_t res
= SPIFFS_OK
;
1733 spiffs
*fs
= fd
->fs
;
1735 if ((fd
->size
== SPIFFS_UNDEFINED_LEN
|| fd
->size
== 0) && !remove_full
) {
1740 // need 2 pages if not removing: object index page + possibly chopped data page
1741 if (remove_full
== 0) {
1742 res
= spiffs_gc_check(fs
, SPIFFS_DATA_PAGE_SIZE(fs
) * 2);
1743 SPIFFS_CHECK_RES(res
);
1746 spiffs_page_ix objix_pix
= fd
->objix_hdr_pix
;
1747 spiffs_span_ix data_spix
= (fd
->size
> 0 ? fd
->size
- 1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs
);
1748 u32_t cur_size
= fd
->size
== (u32_t
)SPIFFS_UNDEFINED_LEN
? 0 : fd
->size
;
1749 spiffs_span_ix cur_objix_spix
= 0;
1750 spiffs_span_ix prev_objix_spix
= (spiffs_span_ix
) - 1;
1751 spiffs_page_object_ix_header
*objix_hdr
= (spiffs_page_object_ix_header
*)fs
->work
;
1752 spiffs_page_object_ix
*objix
= (spiffs_page_object_ix
*)fs
->work
;
1753 spiffs_page_ix data_pix
;
1754 spiffs_page_ix new_objix_hdr_pix
;
1756 // before truncating, check if object is to be fully removed and mark this
1757 if (remove_full
&& new_size
== 0) {
1758 u8_t flags
= ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_IXDELE
);
1759 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_UPDT
,
1760 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, fd
->objix_hdr_pix
) + offsetof(spiffs_page_header
, flags
),
1763 SPIFFS_CHECK_RES(res
);
1766 // delete from end of object until desired len is reached
1767 while (cur_size
> new_size
) {
1768 cur_objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
1770 // put object index for current data span index in work buffer
1771 if (prev_objix_spix
!= cur_objix_spix
) {
1772 if (prev_objix_spix
!= (spiffs_span_ix
) - 1) {
1773 // remove previous object index page
1774 SPIFFS_DBG("truncate: delete objix page "_SPIPRIpg
":"_SPIPRIsp
"\n", objix_pix
, prev_objix_spix
);
1776 res
= spiffs_page_index_check(fs
, fd
, objix_pix
, prev_objix_spix
);
1777 SPIFFS_CHECK_RES(res
);
1779 res
= spiffs_page_delete(fs
, objix_pix
);
1780 SPIFFS_CHECK_RES(res
);
1781 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)0,
1782 SPIFFS_EV_IX_DEL
, fd
->obj_id
, objix
->p_hdr
.span_ix
, objix_pix
, 0);
1783 if (prev_objix_spix
> 0) {
1784 // Update object index header page, unless we totally want to remove the file.
1785 // If fully removing, we're not keeping consistency as good as when storing the header between chunks,
1786 // would we be aborted. But when removing full files, a crammed system may otherwise
1787 // report ERR_FULL a la windows. We cannot have that.
1788 // Hence, take the risk - if aborted, a file check would free the lost pages and mend things
1789 // as the file is marked as fully deleted in the beginning.
1790 if (remove_full
== 0) {
1791 SPIFFS_DBG("truncate: update objix hdr page "_SPIPRIpg
":"_SPIPRIsp
" to size "_SPIPRIi
"\n", fd
->objix_hdr_pix
, prev_objix_spix
, cur_size
);
1792 res
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1793 fd
->objix_hdr_pix
, 0, 0, 0, cur_size
, &new_objix_hdr_pix
);
1794 SPIFFS_CHECK_RES(res
);
1796 fd
->size
= cur_size
;
1799 // load current object index (header) page
1800 if (cur_objix_spix
== 0) {
1801 objix_pix
= fd
->objix_hdr_pix
;
1803 res
= spiffs_obj_lu_find_id_and_span(fs
, fd
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, cur_objix_spix
, 0, &objix_pix
);
1804 SPIFFS_CHECK_RES(res
);
1807 SPIFFS_DBG("truncate: load objix page "_SPIPRIpg
":"_SPIPRIsp
" for data spix:"_SPIPRIsp
"\n", objix_pix
, cur_objix_spix
, data_spix
);
1808 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
1809 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
1810 SPIFFS_CHECK_RES(res
);
1811 SPIFFS_VALIDATE_OBJIX(objix_hdr
->p_hdr
, fd
->obj_id
, cur_objix_spix
);
1812 fd
->cursor_objix_pix
= objix_pix
;
1813 fd
->cursor_objix_spix
= cur_objix_spix
;
1814 fd
->offset
= cur_size
;
1816 prev_objix_spix
= cur_objix_spix
;
1819 if (cur_objix_spix
== 0) {
1820 // get data page from object index header page
1821 data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
];
1822 ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
] = SPIFFS_OBJ_ID_FREE
;
1824 // get data page from object index page
1825 data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)];
1826 ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)] = SPIFFS_OBJ_ID_FREE
;
1829 SPIFFS_DBG("truncate: got data pix "_SPIPRIpg
"\n", data_pix
);
1831 if (new_size
== 0 || remove_full
|| cur_size
- new_size
>= SPIFFS_DATA_PAGE_SIZE(fs
)) {
1832 // delete full data page
1833 res
= spiffs_page_data_check(fs
, fd
, data_pix
, data_spix
);
1834 if (res
!= SPIFFS_ERR_DELETED
&& res
!= SPIFFS_OK
&& res
!= SPIFFS_ERR_INDEX_REF_FREE
) {
1835 SPIFFS_DBG("truncate: err validating data pix "_SPIPRIi
"\n", res
);
1839 if (res
== SPIFFS_OK
) {
1840 res
= spiffs_page_delete(fs
, data_pix
);
1841 if (res
!= SPIFFS_OK
) {
1842 SPIFFS_DBG("truncate: err deleting data pix "_SPIPRIi
"\n", res
);
1845 } else if (res
== SPIFFS_ERR_DELETED
|| res
== SPIFFS_ERR_INDEX_REF_FREE
) {
1849 // update current size
1850 if (cur_size
% SPIFFS_DATA_PAGE_SIZE(fs
) == 0) {
1851 cur_size
-= SPIFFS_DATA_PAGE_SIZE(fs
);
1853 cur_size
-= cur_size
% SPIFFS_DATA_PAGE_SIZE(fs
);
1855 fd
->size
= cur_size
;
1856 fd
->offset
= cur_size
;
1857 SPIFFS_DBG("truncate: delete data page "_SPIPRIpg
" for data spix:"_SPIPRIsp
", cur_size:"_SPIPRIi
"\n", data_pix
, data_spix
, cur_size
);
1859 // delete last page, partially
1860 spiffs_page_header p_hdr
;
1861 spiffs_page_ix new_data_pix
;
1862 u32_t bytes_to_remove
= SPIFFS_DATA_PAGE_SIZE(fs
) - (new_size
% SPIFFS_DATA_PAGE_SIZE(fs
));
1863 SPIFFS_DBG("truncate: delete "_SPIPRIi
" bytes from data page "_SPIPRIpg
" for data spix:"_SPIPRIsp
", cur_size:"_SPIPRIi
"\n", bytes_to_remove
, data_pix
, data_spix
, cur_size
);
1865 res
= spiffs_page_data_check(fs
, fd
, data_pix
, data_spix
);
1866 if (res
!= SPIFFS_OK
) break;
1868 p_hdr
.obj_id
= fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
1869 p_hdr
.span_ix
= data_spix
;
1871 // allocate new page and copy unmodified data
1872 res
= spiffs_page_allocate_data(fs
, fd
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
1873 &p_hdr
, 0, 0, 0, 0, &new_data_pix
);
1874 if (res
!= SPIFFS_OK
) break;
1875 res
= spiffs_phys_cpy(fs
, 0,
1876 SPIFFS_PAGE_TO_PADDR(fs
, new_data_pix
) + sizeof(spiffs_page_header
),
1877 SPIFFS_PAGE_TO_PADDR(fs
, data_pix
) + sizeof(spiffs_page_header
),
1878 SPIFFS_DATA_PAGE_SIZE(fs
) - bytes_to_remove
);
1879 if (res
!= SPIFFS_OK
) break;
1880 // delete original data page
1881 res
= spiffs_page_delete(fs
, data_pix
);
1882 if (res
!= SPIFFS_OK
) break;
1883 p_hdr
.flags
&= ~SPIFFS_PH_FLAG_FINAL
;
1884 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
1886 SPIFFS_PAGE_TO_PADDR(fs
, new_data_pix
) + offsetof(spiffs_page_header
, flags
),
1888 (u8_t
*)&p_hdr
.flags
);
1889 if (res
!= SPIFFS_OK
) break;
1891 // update memory representation of object index page with new data page
1892 if (cur_objix_spix
== 0) {
1893 // update object index header page
1894 ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
] = new_data_pix
;
1895 SPIFFS_DBG("truncate: wrote page "_SPIPRIpg
" to objix_hdr entry "_SPIPRIsp
" in mem\n", new_data_pix
, (spiffs_span_ix
)SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
));
1897 // update object index page
1898 ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)] = new_data_pix
;
1899 SPIFFS_DBG("truncate: wrote page "_SPIPRIpg
" to objix entry "_SPIPRIsp
" in mem\n", new_data_pix
, (spiffs_span_ix
)SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
));
1901 cur_size
= new_size
;
1902 fd
->size
= new_size
;
1903 fd
->offset
= cur_size
;
1909 // update object indices
1910 if (cur_objix_spix
== 0) {
1911 // update object index header page
1912 if (cur_size
== 0) {
1914 // remove object altogether
1915 SPIFFS_DBG("truncate: remove object index header page "_SPIPRIpg
"\n", objix_pix
);
1917 res
= spiffs_page_index_check(fs
, fd
, objix_pix
, 0);
1918 SPIFFS_CHECK_RES(res
);
1920 res
= spiffs_page_delete(fs
, objix_pix
);
1921 SPIFFS_CHECK_RES(res
);
1922 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)0,
1923 SPIFFS_EV_IX_DEL
, fd
->obj_id
, 0, objix_pix
, 0);
1925 // make uninitialized object
1926 SPIFFS_DBG("truncate: reset objix_hdr page "_SPIPRIpg
"\n", objix_pix
);
1927 memset(fs
->work
+ sizeof(spiffs_page_object_ix_header
), 0xff,
1928 SPIFFS_CFG_LOG_PAGE_SZ(fs
) - sizeof(spiffs_page_object_ix_header
));
1929 res
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1930 objix_pix
, fs
->work
, 0, 0, SPIFFS_UNDEFINED_LEN
, &new_objix_hdr_pix
);
1931 SPIFFS_CHECK_RES(res
);
1934 // update object index header page
1935 SPIFFS_DBGF("truncate: update object index header page with indices and size\n");
1936 res
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1937 objix_pix
, fs
->work
, 0, 0, cur_size
, &new_objix_hdr_pix
);
1938 SPIFFS_CHECK_RES(res
);
1941 // update both current object index page and object index header page
1942 spiffs_page_ix new_objix_pix
;
1944 res
= spiffs_page_index_check(fs
, fd
, objix_pix
, cur_objix_spix
);
1945 SPIFFS_CHECK_RES(res
);
1947 // move and update object index page
1948 res
= spiffs_page_move(fs
, fd
->file_nbr
, (u8_t
*)objix_hdr
, fd
->obj_id
, 0, objix_pix
, &new_objix_pix
);
1949 SPIFFS_CHECK_RES(res
);
1950 spiffs_cb_object_event(fs
, (spiffs_page_object_ix
*)objix_hdr
,
1951 SPIFFS_EV_IX_UPD
, fd
->obj_id
, objix
->p_hdr
.span_ix
, new_objix_pix
, 0);
1952 SPIFFS_DBG("truncate: store modified objix page, "_SPIPRIpg
":"_SPIPRIsp
"\n", new_objix_pix
, cur_objix_spix
);
1953 fd
->cursor_objix_pix
= new_objix_pix
;
1954 fd
->cursor_objix_spix
= cur_objix_spix
;
1955 fd
->offset
= cur_size
;
1956 // update object index header page with new size
1957 res
= spiffs_object_update_index_hdr(fs
, fd
, fd
->obj_id
,
1958 fd
->objix_hdr_pix
, 0, 0, 0, cur_size
, &new_objix_hdr_pix
);
1959 SPIFFS_CHECK_RES(res
);
1961 fd
->size
= cur_size
;
1964 } // spiffs_object_truncate
1965 #endif // !SPIFFS_READ_ONLY
1967 s32_t
spiffs_object_read(
1972 s32_t res
= SPIFFS_OK
;
1973 spiffs
*fs
= fd
->fs
;
1974 spiffs_page_ix objix_pix
;
1975 spiffs_page_ix data_pix
;
1976 spiffs_span_ix data_spix
= offset
/ SPIFFS_DATA_PAGE_SIZE(fs
);
1977 u32_t cur_offset
= offset
;
1978 spiffs_span_ix cur_objix_spix
;
1979 spiffs_span_ix prev_objix_spix
= (spiffs_span_ix
) - 1;
1980 spiffs_page_object_ix_header
*objix_hdr
= (spiffs_page_object_ix_header
*)fs
->work
;
1981 spiffs_page_object_ix
*objix
= (spiffs_page_object_ix
*)fs
->work
;
1983 while (cur_offset
< offset
+ len
) {
1985 // check if we have a memory, index map and if so, if we're within index map's range
1986 // and if so, if the entry is populated
1987 if (fd
->ix_map
&& data_spix
>= fd
->ix_map
->start_spix
&& data_spix
<= fd
->ix_map
->end_spix
1988 && fd
->ix_map
->map_buf
[data_spix
- fd
->ix_map
->start_spix
]) {
1989 data_pix
= fd
->ix_map
->map_buf
[data_spix
- fd
->ix_map
->start_spix
];
1992 cur_objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
1993 if (prev_objix_spix
!= cur_objix_spix
) {
1994 // load current object index (header) page
1995 if (cur_objix_spix
== 0) {
1996 objix_pix
= fd
->objix_hdr_pix
;
1998 SPIFFS_DBG("read: find objix "_SPIPRIid
":"_SPIPRIsp
"\n", fd
->obj_id
, cur_objix_spix
);
1999 if (fd
->cursor_objix_spix
== cur_objix_spix
) {
2000 objix_pix
= fd
->cursor_objix_pix
;
2002 res
= spiffs_obj_lu_find_id_and_span(fs
, fd
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, cur_objix_spix
, 0, &objix_pix
);
2003 SPIFFS_CHECK_RES(res
);
2006 SPIFFS_DBG("read: load objix page "_SPIPRIpg
":"_SPIPRIsp
" for data spix:"_SPIPRIsp
"\n", objix_pix
, cur_objix_spix
, data_spix
);
2007 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_IX
| SPIFFS_OP_C_READ
,
2008 fd
->file_nbr
, SPIFFS_PAGE_TO_PADDR(fs
, objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->work
);
2009 SPIFFS_CHECK_RES(res
);
2010 SPIFFS_VALIDATE_OBJIX(objix
->p_hdr
, fd
->obj_id
, cur_objix_spix
);
2012 fd
->offset
= cur_offset
;
2013 fd
->cursor_objix_pix
= objix_pix
;
2014 fd
->cursor_objix_spix
= cur_objix_spix
;
2016 prev_objix_spix
= cur_objix_spix
;
2019 if (cur_objix_spix
== 0) {
2020 // get data page from object index header page
2021 data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix_hdr
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
];
2023 // get data page from object index page
2024 data_pix
= ((spiffs_page_ix
*)((u8_t
*)objix
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)];
2029 // all remaining data
2030 u32_t len_to_read
= offset
+ len
- cur_offset
;
2031 // remaining data in page
2032 len_to_read
= MIN(len_to_read
, SPIFFS_DATA_PAGE_SIZE(fs
) - (cur_offset
% SPIFFS_DATA_PAGE_SIZE(fs
)));
2033 // remaining data in file
2034 len_to_read
= MIN(len_to_read
, fd
->size
- cur_offset
);
2035 SPIFFS_DBG("read: offset:"_SPIPRIi
" rd:"_SPIPRIi
" data spix:"_SPIPRIsp
" is data_pix:"_SPIPRIpg
" addr:"_SPIPRIad
"\n", cur_offset
, len_to_read
, data_spix
, data_pix
,
2036 (u32_t
)(SPIFFS_PAGE_TO_PADDR(fs
, data_pix
) + sizeof(spiffs_page_header
) + (cur_offset
% SPIFFS_DATA_PAGE_SIZE(fs
))));
2037 if (len_to_read
== 0) {
2038 res
= SPIFFS_ERR_END_OF_OBJECT
;
2041 res
= spiffs_page_data_check(fs
, fd
, data_pix
, data_spix
);
2042 SPIFFS_CHECK_RES(res
);
2044 fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_READ
,
2046 SPIFFS_PAGE_TO_PADDR(fs
, data_pix
) + sizeof(spiffs_page_header
) + (cur_offset
% SPIFFS_DATA_PAGE_SIZE(fs
)),
2049 SPIFFS_CHECK_RES(res
);
2051 cur_offset
+= len_to_read
;
2052 fd
->offset
= cur_offset
;
2059 #if !SPIFFS_READ_ONLY
2061 spiffs_obj_id min_obj_id
;
2062 spiffs_obj_id max_obj_id
;
2064 const u8_t
*conflicting_name
;
2065 } spiffs_free_obj_id_state
;
2067 static s32_t
spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs
*fs
, spiffs_obj_id id
, spiffs_block_ix bix
, int ix_entry
,
2068 const void *user_const_p
, void *user_var_p
) {
2069 if (id
!= SPIFFS_OBJ_ID_FREE
&& id
!= SPIFFS_OBJ_ID_DELETED
) {
2070 spiffs_obj_id min_obj_id
= *((spiffs_obj_id
*)user_var_p
);
2071 const u8_t
*conflicting_name
= (const u8_t
*)user_const_p
;
2073 // if conflicting name parameter is given, also check if this name is found in object index hdrs
2074 if (conflicting_name
&& (id
& SPIFFS_OBJ_ID_IX_FLAG
)) {
2075 spiffs_page_ix pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, ix_entry
);
2077 spiffs_page_object_ix_header objix_hdr
;
2078 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
2079 0, SPIFFS_PAGE_TO_PADDR(fs
, pix
), sizeof(spiffs_page_object_ix_header
), (u8_t
*)&objix_hdr
);
2080 SPIFFS_CHECK_RES(res
);
2081 if (objix_hdr
.p_hdr
.span_ix
== 0 &&
2082 (objix_hdr
.p_hdr
.flags
& (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_IXDELE
)) ==
2083 (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) {
2084 if (strcmp((const char *)user_const_p
, (char *)objix_hdr
.name
) == 0) {
2085 return SPIFFS_ERR_CONFLICTING_NAME
;
2090 id
&= ~SPIFFS_OBJ_ID_IX_FLAG
;
2091 u32_t bit_ix
= (id
- min_obj_id
) & 7;
2092 int byte_ix
= (id
- min_obj_id
) >> 3;
2093 if (byte_ix
>= 0 && (u32_t
)byte_ix
< SPIFFS_CFG_LOG_PAGE_SZ(fs
)) {
2094 fs
->work
[byte_ix
] |= (1 << bit_ix
);
2097 return SPIFFS_VIS_COUNTINUE
;
2100 static s32_t
spiffs_obj_lu_find_free_obj_id_compact_v(spiffs
*fs
, spiffs_obj_id id
, spiffs_block_ix bix
, int ix_entry
,
2101 const void *user_const_p
, void *user_var_p
) {
2103 if (id
!= SPIFFS_OBJ_ID_FREE
&& id
!= SPIFFS_OBJ_ID_DELETED
&& (id
& SPIFFS_OBJ_ID_IX_FLAG
)) {
2105 const spiffs_free_obj_id_state
*state
= (const spiffs_free_obj_id_state
*)user_const_p
;
2106 spiffs_page_object_ix_header objix_hdr
;
2108 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
2109 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs
, bix
, ix_entry
), sizeof(spiffs_page_object_ix_header
), (u8_t
*)&objix_hdr
);
2110 if (res
== SPIFFS_OK
&& objix_hdr
.p_hdr
.span_ix
== 0 &&
2111 ((objix_hdr
.p_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
)) ==
2112 (SPIFFS_PH_FLAG_DELET
))) {
2113 // ok object look up entry
2114 if (state
->conflicting_name
&& strcmp((const char *)state
->conflicting_name
, (char *)objix_hdr
.name
) == 0) {
2115 return SPIFFS_ERR_CONFLICTING_NAME
;
2118 id
&= ~SPIFFS_OBJ_ID_IX_FLAG
;
2119 if (id
>= state
->min_obj_id
&& id
<= state
->max_obj_id
) {
2120 u8_t
*map
= (u8_t
*)fs
->work
;
2121 int ix
= (id
- state
->min_obj_id
) / state
->compaction
;
2122 //SPIFFS_DBG("free_obj_id: add ix "_SPIPRIi" for id "_SPIPRIid" min"_SPIPRIid" max"_SPIPRIid" comp:"_SPIPRIi"\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
2127 return SPIFFS_VIS_COUNTINUE
;
2130 // Scans thru all object lookup for object index header pages. If total possible number of
2131 // object ids cannot fit into a work buffer, these are grouped. When a group containing free
2132 // object ids is found, the object lu is again scanned for object ids within group and bitmasked.
2133 // Finally, the bitmask is searched for a free id
2134 s32_t
spiffs_obj_lu_find_free_obj_id(spiffs
*fs
, spiffs_obj_id
*obj_id
, const u8_t
*conflicting_name
) {
2135 s32_t res
= SPIFFS_OK
;
2136 u32_t max_objects
= (fs
->block_count
* SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs
)) / 2;
2137 spiffs_free_obj_id_state state
;
2138 spiffs_obj_id free_obj_id
= SPIFFS_OBJ_ID_FREE
;
2139 state
.min_obj_id
= 1;
2140 state
.max_obj_id
= max_objects
+ 1;
2141 if (state
.max_obj_id
& SPIFFS_OBJ_ID_IX_FLAG
) {
2142 state
.max_obj_id
= ((spiffs_obj_id
) - 1) & ~SPIFFS_OBJ_ID_IX_FLAG
;
2144 state
.compaction
= 0;
2145 state
.conflicting_name
= conflicting_name
;
2146 while (res
== SPIFFS_OK
&& free_obj_id
== SPIFFS_OBJ_ID_FREE
) {
2147 if (state
.max_obj_id
- state
.min_obj_id
<= (spiffs_obj_id
)SPIFFS_CFG_LOG_PAGE_SZ(fs
) * 8) {
2148 // possible to represent in bitmap
2150 SPIFFS_DBG("free_obj_id: BITM min:"_SPIPRIid
" max:"_SPIPRIid
"\n", state
.min_obj_id
, state
.max_obj_id
);
2152 memset(fs
->work
, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs
));
2153 res
= spiffs_obj_lu_find_entry_visitor(fs
, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v
,
2154 conflicting_name
, &state
.min_obj_id
, 0, 0);
2155 if (res
== SPIFFS_VIS_END
) res
= SPIFFS_OK
;
2156 SPIFFS_CHECK_RES(res
);
2157 // traverse bitmask until found free obj_id
2158 for (i
= 0; i
< SPIFFS_CFG_LOG_PAGE_SZ(fs
); i
++) {
2159 u8_t mask
= fs
->work
[i
];
2163 for (j
= 0; j
< 8; j
++) {
2164 if ((mask
& (1 << j
)) == 0) {
2165 *obj_id
= (i
<< 3) + j
+ state
.min_obj_id
;
2170 return SPIFFS_ERR_FULL
;
2172 // not possible to represent all ids in range in a bitmap, compact and count
2173 if (state
.compaction
!= 0) {
2174 // select element in compacted table, decrease range and recompact
2176 u8_t
*map
= (u8_t
*)fs
->work
;
2177 u8_t min_count
= 0xff;
2179 for (i
= 0; i
< SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(u8_t
); i
++) {
2180 if (map
[i
] < min_count
) {
2183 if (min_count
== 0) {
2189 if (min_count
== state
.compaction
) {
2190 // there are no free objids!
2191 SPIFFS_DBGF("free_obj_id: compacted table is full\n");
2192 return SPIFFS_ERR_FULL
;
2195 SPIFFS_DBG("free_obj_id: COMP select index:"_SPIPRIi
" min_count:"_SPIPRIi
" min:"_SPIPRIid
" max:"_SPIPRIid
" compact:"_SPIPRIi
"\n", min_i
, min_count
, state
.min_obj_id
, state
.max_obj_id
, state
.compaction
);
2197 if (min_count
== 0) {
2198 // no id in this range, skip compacting and use directly
2199 *obj_id
= min_i
* state
.compaction
+ state
.min_obj_id
;
2202 SPIFFS_DBG("free_obj_id: COMP SEL chunk:"_SPIPRIi
" min:"_SPIPRIid
" -> "_SPIPRIid
"\n", state
.compaction
, state
.min_obj_id
, state
.min_obj_id
+ min_i
* state
.compaction
);
2203 state
.min_obj_id
+= min_i
* state
.compaction
;
2204 state
.max_obj_id
= state
.min_obj_id
+ state
.compaction
;
2205 // decrease compaction
2207 if ((state
.max_obj_id
- state
.min_obj_id
<= (spiffs_obj_id
)SPIFFS_CFG_LOG_PAGE_SZ(fs
) * 8)) {
2208 // no need for compacting, use bitmap
2212 // in a work memory of log_page_size bytes, we may fit in log_page_size ids
2213 // todo what if compaction is > 255 - then we cannot fit it in a byte
2214 state
.compaction
= (state
.max_obj_id
- state
.min_obj_id
) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(u8_t
)));
2215 SPIFFS_DBG("free_obj_id: COMP min:"_SPIPRIid
" max:"_SPIPRIid
" compact:"_SPIPRIi
"\n", state
.min_obj_id
, state
.max_obj_id
, state
.compaction
);
2217 memset(fs
->work
, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs
));
2218 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);
2219 if (res
== SPIFFS_VIS_END
) res
= SPIFFS_OK
;
2220 SPIFFS_CHECK_RES(res
);
2221 state
.conflicting_name
= 0; // searched for conflicting name once, no need to do it again
2227 #endif // !SPIFFS_READ_ONLY
2229 #if SPIFFS_TEMPORAL_FD_CACHE
2231 static u32_t
spiffs_hash(spiffs
*fs
, const u8_t
*name
) {
2236 while ((c
= name
[i
++]) && i
< SPIFFS_OBJ_NAME_LEN
) {
2237 hash
= (hash
* 33) ^ c
;
2243 s32_t
spiffs_fd_find_new(spiffs
*fs
, spiffs_fd
**fd
, const char *name
) {
2244 #if SPIFFS_TEMPORAL_FD_CACHE
2246 u16_t min_score
= 0xffff;
2247 u32_t cand_ix
= (u32_t
) - 1;
2248 u32_t name_hash
= name
? spiffs_hash(fs
, (const u8_t
*)name
) : 0;
2249 spiffs_fd
*fds
= (spiffs_fd
*)fs
->fd_space
;
2252 // first, decrease score of all closed descriptors
2253 for (i
= 0; i
< fs
->fd_count
; i
++) {
2254 spiffs_fd
*cur_fd
= &fds
[i
];
2255 if (cur_fd
->file_nbr
== 0) {
2256 if (cur_fd
->score
> 1) { // score == 0 indicates never used fd
2263 // find the free fd with least score or name match
2264 for (i
= 0; i
< fs
->fd_count
; i
++) {
2265 spiffs_fd
*cur_fd
= &fds
[i
];
2266 if (cur_fd
->file_nbr
== 0) {
2267 if (name
&& cur_fd
->name_hash
== name_hash
) {
2271 if (cur_fd
->score
< min_score
) {
2272 min_score
= cur_fd
->score
;
2278 if (cand_ix
!= (u32_t
) - 1) {
2279 spiffs_fd
*cur_fd
= &fds
[cand_ix
];
2281 if (cur_fd
->name_hash
== name_hash
&& cur_fd
->score
> 0) {
2282 // opened an fd with same name hash, assume same file
2283 // set search point to saved obj index page and hope we have a correct match directly
2284 // when start searching - if not, we will just keep searching until it is found
2285 fs
->cursor_block_ix
= SPIFFS_BLOCK_FOR_PAGE(fs
, cur_fd
->objix_hdr_pix
);
2286 fs
->cursor_obj_lu_entry
= SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs
, cur_fd
->objix_hdr_pix
);
2288 if (cur_fd
->score
< 0xffff - SPIFFS_TEMPORAL_CACHE_HIT_SCORE
) {
2289 cur_fd
->score
+= SPIFFS_TEMPORAL_CACHE_HIT_SCORE
;
2291 cur_fd
->score
= 0xffff;
2294 // no hash hit, restore this fd to initial state
2295 cur_fd
->score
= SPIFFS_TEMPORAL_CACHE_HIT_SCORE
;
2296 cur_fd
->name_hash
= name_hash
;
2299 cur_fd
->file_nbr
= cand_ix
+ 1;
2303 return SPIFFS_ERR_OUT_OF_FILE_DESCS
;
2308 spiffs_fd
*fds
= (spiffs_fd
*)fs
->fd_space
;
2309 for (i
= 0; i
< fs
->fd_count
; i
++) {
2310 spiffs_fd
*cur_fd
= &fds
[i
];
2311 if (cur_fd
->file_nbr
== 0) {
2312 cur_fd
->file_nbr
= i
+ 1;
2317 return SPIFFS_ERR_OUT_OF_FILE_DESCS
;
2321 s32_t
spiffs_fd_return(spiffs
*fs
, spiffs_file f
) {
2322 if (f
<= 0 || f
> (s16_t
)fs
->fd_count
) {
2323 return SPIFFS_ERR_BAD_DESCRIPTOR
;
2325 spiffs_fd
*fds
= (spiffs_fd
*)fs
->fd_space
;
2326 spiffs_fd
*fd
= &fds
[f
- 1];
2327 if (fd
->file_nbr
== 0) {
2328 return SPIFFS_ERR_FILE_CLOSED
;
2337 s32_t
spiffs_fd_get(spiffs
*fs
, spiffs_file f
, spiffs_fd
**fd
) {
2338 if (f
<= 0 || f
> (s16_t
)fs
->fd_count
) {
2339 return SPIFFS_ERR_BAD_DESCRIPTOR
;
2341 spiffs_fd
*fds
= (spiffs_fd
*)fs
->fd_space
;
2343 if ((*fd
)->file_nbr
== 0) {
2344 return SPIFFS_ERR_FILE_CLOSED
;
2349 #if SPIFFS_TEMPORAL_FD_CACHE
2350 void spiffs_fd_temporal_cache_rehash(
2352 const char *old_path
,
2353 const char *new_path
) {
2355 u32_t old_hash
= spiffs_hash(fs
, (const u8_t
*)old_path
);
2356 u32_t new_hash
= spiffs_hash(fs
, (const u8_t
*)new_path
);
2357 spiffs_fd
*fds
= (spiffs_fd
*)fs
->fd_space
;
2358 for (i
= 0; i
< fs
->fd_count
; i
++) {
2359 spiffs_fd
*cur_fd
= &fds
[i
];
2360 if (cur_fd
->score
> 0 && cur_fd
->name_hash
== old_hash
) {
2361 cur_fd
->name_hash
= new_hash
;