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 //-----------------------------------------------------------------------------
19 * Contains functionality for checking file system consistency
20 * and mending problems.
21 * Three levels of consistency checks are implemented:
24 * Checks if indices in lookup pages are coherent with page headers
25 * Object index consistency
26 * Checks if there are any orphaned object indices (missing object index headers).
27 * If an object index is found but not its header, the object index is deleted.
28 * This is critical for the following page consistency check.
30 * Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
35 #include "spiffs_nucleus.h"
39 #if SPIFFS_HAL_CALLBACK_EXTRA
40 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
42 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
45 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
47 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
51 //---------------------------------------
52 // Look up consistency
54 // searches in the object indices and returns the referenced page index given
55 // the object id and the data span index
56 // destroys fs->lu_work
57 static s32_t
spiffs_object_get_data_page_index_reference(
60 spiffs_span_ix data_spix
,
62 spiffs_page_ix
*objix_pix
) {
65 // calculate object index span index for given data page span index
66 spiffs_span_ix objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
68 // find obj index for obj id and span index
69 res
= spiffs_obj_lu_find_id_and_span(fs
, obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, objix_spix
, 0, objix_pix
);
70 SPIFFS_CHECK_RES(res
);
72 // load obj index entry
73 u32_t addr
= SPIFFS_PAGE_TO_PADDR(fs
, *objix_pix
);
74 if (objix_spix
== 0) {
75 // get referenced page from object index header
76 addr
+= sizeof(spiffs_page_object_ix_header
) + data_spix
* sizeof(spiffs_page_ix
);
78 // get referenced page from object index
79 addr
+= sizeof(spiffs_page_object_ix
) + SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
) * sizeof(spiffs_page_ix
);
82 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
, 0, addr
, sizeof(spiffs_page_ix
), (u8_t
*)pix
);
87 // copies page contents to a new page
88 static s32_t
spiffs_rewrite_page(spiffs
*fs
, spiffs_page_ix cur_pix
, spiffs_page_header
*p_hdr
, spiffs_page_ix
*new_pix
) {
90 res
= spiffs_page_allocate_data(fs
, p_hdr
->obj_id
, p_hdr
, 0, 0, 0, 0, new_pix
);
91 SPIFFS_CHECK_RES(res
);
92 res
= spiffs_phys_cpy(fs
, 0,
93 SPIFFS_PAGE_TO_PADDR(fs
, *new_pix
) + sizeof(spiffs_page_header
),
94 SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + sizeof(spiffs_page_header
),
95 SPIFFS_DATA_PAGE_SIZE(fs
));
96 SPIFFS_CHECK_RES(res
);
100 // rewrites the object index for given object id and replaces the
101 // data page index to a new page index
102 static s32_t
spiffs_rewrite_index(spiffs
*fs
, spiffs_obj_id obj_id
, spiffs_span_ix data_spix
, spiffs_page_ix new_data_pix
, spiffs_page_ix objix_pix
) {
106 spiffs_page_ix free_pix
;
107 obj_id
|= SPIFFS_OBJ_ID_IX_FLAG
;
110 res
= spiffs_obj_lu_find_free(fs
, fs
->free_cursor_block_ix
, fs
->free_cursor_obj_lu_entry
, &bix
, &entry
);
111 SPIFFS_CHECK_RES(res
);
112 free_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, bix
, entry
);
114 // calculate object index span index for given data page span index
115 spiffs_span_ix objix_spix
= SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs
, data_spix
);
116 if (objix_spix
== 0) {
117 // calc index in index header
120 // calc entry in index
121 entry
= SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
);
125 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
126 0, SPIFFS_PAGE_TO_PADDR(fs
, objix_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
127 SPIFFS_CHECK_RES(res
);
128 spiffs_page_header
*objix_p_hdr
= (spiffs_page_header
*)fs
->lu_work
;
130 // be ultra safe, double check header against provided data
131 if (objix_p_hdr
->obj_id
!= obj_id
) {
132 spiffs_page_delete(fs
, free_pix
);
133 return SPIFFS_ERR_CHECK_OBJ_ID_MISM
;
135 if (objix_p_hdr
->span_ix
!= objix_spix
) {
136 spiffs_page_delete(fs
, free_pix
);
137 return SPIFFS_ERR_CHECK_SPIX_MISM
;
139 if ((objix_p_hdr
->flags
& (SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_IXDELE
| SPIFFS_PH_FLAG_INDEX
|
140 SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
)) !=
141 (SPIFFS_PH_FLAG_IXDELE
| SPIFFS_PH_FLAG_DELET
)) {
142 spiffs_page_delete(fs
, free_pix
);
143 return SPIFFS_ERR_CHECK_FLAGS_BAD
;
147 if (objix_spix
== 0) {
148 ((spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix_header
)))[data_spix
] = new_data_pix
;
150 ((spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix
)))[SPIFFS_OBJ_IX_ENTRY(fs
, data_spix
)] = new_data_pix
;
153 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
154 0, SPIFFS_PAGE_TO_PADDR(fs
, free_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
155 SPIFFS_CHECK_RES(res
);
156 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_UPDT
,
157 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
),
158 sizeof(spiffs_obj_id
),
160 SPIFFS_CHECK_RES(res
);
161 res
= spiffs_page_delete(fs
, objix_pix
);
166 // deletes an object just by marking object index header as deleted
167 static s32_t
spiffs_delete_obj_lazy(spiffs
*fs
, spiffs_obj_id obj_id
) {
168 spiffs_page_ix objix_hdr_pix
;
170 res
= spiffs_obj_lu_find_id_and_span(fs
, obj_id
, 0, 0, &objix_hdr_pix
);
171 if (res
== SPIFFS_ERR_NOT_FOUND
) {
174 SPIFFS_CHECK_RES(res
);
176 #if SPIFFS_NO_BLIND_WRITES
177 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_READ
,
178 0, SPIFFS_PAGE_TO_PADDR(fs
, objix_hdr_pix
) + offsetof(spiffs_page_header
, flags
),
179 sizeof(flags
), &flags
);
180 SPIFFS_CHECK_RES(res
);
182 flags
&= ~SPIFFS_PH_FLAG_IXDELE
;
183 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_LU
| SPIFFS_OP_C_UPDT
,
184 0, SPIFFS_PAGE_TO_PADDR(fs
, objix_hdr_pix
) + offsetof(spiffs_page_header
, flags
),
185 sizeof(flags
), &flags
);
189 // validates the given look up entry
190 static s32_t
spiffs_lookup_check_validate(spiffs
*fs
, spiffs_obj_id lu_obj_id
, spiffs_page_header
*p_hdr
,
191 spiffs_page_ix cur_pix
, spiffs_block_ix cur_block
, int cur_entry
, int *reload_lu
) {
194 u8_t delete_page
= 0;
195 s32_t res
= SPIFFS_OK
;
196 spiffs_page_ix objix_pix
;
197 spiffs_page_ix ref_pix
;
198 // check validity, take actions
199 if (((lu_obj_id
== SPIFFS_OBJ_ID_DELETED
) && (p_hdr
->flags
& SPIFFS_PH_FLAG_DELET
)) ||
200 ((lu_obj_id
== SPIFFS_OBJ_ID_FREE
) && (p_hdr
->flags
& SPIFFS_PH_FLAG_USED
) == 0)) {
201 // look up entry deleted / free but used in page header
202 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" deleted/free in lu but not on page\n", cur_pix
);
205 if (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
) {
206 // header says data page
207 // data page can be removed if not referenced by some object index
208 res
= spiffs_object_get_data_page_index_reference(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, &ref_pix
, &objix_pix
);
209 if (res
== SPIFFS_ERR_NOT_FOUND
) {
210 // no object with this id, so remove page safely
213 SPIFFS_CHECK_RES(res
);
214 if (ref_pix
== cur_pix
) {
215 // data page referenced by object index but deleted in lu
216 // copy page to new place and re-write the object index to new place
217 spiffs_page_ix new_pix
;
218 res
= spiffs_rewrite_page(fs
, cur_pix
, p_hdr
, &new_pix
);
219 SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg
" to new page "_SPIPRIpg
"\n", cur_pix
, new_pix
);
220 SPIFFS_CHECK_RES(res
);
222 SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg
" rewritten to "_SPIPRIpg
", affected objix_pix "_SPIPRIpg
"\n", cur_pix
, new_pix
, objix_pix
);
223 res
= spiffs_rewrite_index(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, new_pix
, objix_pix
);
224 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
225 // index bad also, cannot mend this file
226 SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
227 res
= spiffs_page_delete(fs
, new_pix
);
228 SPIFFS_CHECK_RES(res
);
229 res
= spiffs_delete_obj_lazy(fs
, p_hdr
->obj_id
);
230 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
->obj_id
, 0);
232 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_INDEX
, p_hdr
->obj_id
, p_hdr
->span_ix
);
234 SPIFFS_CHECK_RES(res
);
238 // header says index page
239 // index page can be removed if other index with same obj_id and spanix is found
240 res
= spiffs_obj_lu_find_id_and_span(fs
, p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, p_hdr
->span_ix
, cur_pix
, 0);
241 if (res
== SPIFFS_ERR_NOT_FOUND
) {
242 // no such index page found, check for a data page amongst page headers
243 // lu cannot be trusted
244 res
= spiffs_obj_lu_find_id_and_span_by_phdr(fs
, p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, 0);
245 if (res
== SPIFFS_OK
) { // ignore other errors
246 // got a data page also, assume lu corruption only, rewrite to new page
247 spiffs_page_ix new_pix
;
248 res
= spiffs_rewrite_page(fs
, cur_pix
, p_hdr
, &new_pix
);
249 SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg
" to new page "_SPIPRIpg
"\n", cur_pix
, new_pix
);
250 SPIFFS_CHECK_RES(res
);
252 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
255 SPIFFS_CHECK_RES(res
);
259 if (lu_obj_id
!= SPIFFS_OBJ_ID_FREE
&& lu_obj_id
!= SPIFFS_OBJ_ID_DELETED
) {
260 // look up entry used
261 if ((p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
) != (lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
)) {
262 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" differ in obj_id lu:"_SPIPRIid
" ph:"_SPIPRIid
"\n", cur_pix
, lu_obj_id
, p_hdr
->obj_id
);
264 if ((p_hdr
->flags
& SPIFFS_PH_FLAG_DELET
) == 0 ||
265 (p_hdr
->flags
& SPIFFS_PH_FLAG_FINAL
) ||
266 (p_hdr
->flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_IXDELE
)) == 0) {
267 // page deleted or not finalized, just remove it
269 if (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
) {
270 // if data page, check for reference to this page
271 res
= spiffs_object_get_data_page_index_reference(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, &ref_pix
, &objix_pix
);
272 if (res
== SPIFFS_ERR_NOT_FOUND
) {
273 // no object with this id, so remove page safely
276 SPIFFS_CHECK_RES(res
);
277 // if found, rewrite page with object id, update index, and delete current
278 if (ref_pix
== cur_pix
) {
279 spiffs_page_ix new_pix
;
280 res
= spiffs_rewrite_page(fs
, cur_pix
, p_hdr
, &new_pix
);
281 SPIFFS_CHECK_RES(res
);
282 res
= spiffs_rewrite_index(fs
, p_hdr
->obj_id
, p_hdr
->span_ix
, new_pix
, objix_pix
);
283 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
284 // index bad also, cannot mend this file
285 SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
286 res
= spiffs_page_delete(fs
, new_pix
);
287 SPIFFS_CHECK_RES(res
);
288 res
= spiffs_delete_obj_lazy(fs
, p_hdr
->obj_id
);
290 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
->obj_id
, 0);
292 SPIFFS_CHECK_RES(res
);
296 // else if index, check for other pages with both obj_id's and spanix
297 spiffs_page_ix objix_pix_lu
, objix_pix_ph
;
298 // see if other object index page exists for lookup obj id and span index
299 res
= spiffs_obj_lu_find_id_and_span(fs
, lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, p_hdr
->span_ix
, 0, &objix_pix_lu
);
300 if (res
== SPIFFS_ERR_NOT_FOUND
) {
304 SPIFFS_CHECK_RES(res
);
305 // see if other object index exists for page header obj id and span index
306 res
= spiffs_obj_lu_find_id_and_span(fs
, p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, p_hdr
->span_ix
, 0, &objix_pix_ph
);
307 if (res
== SPIFFS_ERR_NOT_FOUND
) {
311 SPIFFS_CHECK_RES(res
);
312 // if both obj_id's found, just delete current
313 if (objix_pix_ph
== 0 || objix_pix_lu
== 0) {
314 // otherwise try finding first corresponding data pages
315 spiffs_page_ix data_pix_lu
, data_pix_ph
;
316 // see if other data page exists for look up obj id and span index
317 res
= spiffs_obj_lu_find_id_and_span(fs
, lu_obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, &data_pix_lu
);
318 if (res
== SPIFFS_ERR_NOT_FOUND
) {
322 SPIFFS_CHECK_RES(res
);
323 // see if other data page exists for page header obj id and span index
324 res
= spiffs_obj_lu_find_id_and_span(fs
, p_hdr
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, &data_pix_ph
);
325 if (res
== SPIFFS_ERR_NOT_FOUND
) {
329 SPIFFS_CHECK_RES(res
);
331 spiffs_page_header new_ph
;
332 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
);
333 new_ph
.span_ix
= p_hdr
->span_ix
;
334 spiffs_page_ix new_pix
;
335 if ((objix_pix_lu
&& data_pix_lu
&& data_pix_ph
&& objix_pix_ph
== 0) ||
336 (objix_pix_lu
== 0 && data_pix_ph
&& objix_pix_ph
== 0)) {
337 // got a data page for page header obj id
338 // rewrite as obj_id_ph
339 new_ph
.obj_id
= p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
340 res
= spiffs_rewrite_page(fs
, cur_pix
, &new_ph
, &new_pix
);
341 SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg
" as "_SPIPRIid
" to pix "_SPIPRIpg
"\n", cur_pix
, new_ph
.obj_id
, new_pix
);
342 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
343 SPIFFS_CHECK_RES(res
);
345 } else if ((objix_pix_ph
&& data_pix_ph
&& data_pix_lu
&& objix_pix_lu
== 0) ||
346 (objix_pix_ph
== 0 && data_pix_lu
&& objix_pix_lu
== 0)) {
347 // got a data page for look up obj id
348 // rewrite as obj_id_lu
349 new_ph
.obj_id
= lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
350 SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg
" as "_SPIPRIid
"\n", cur_pix
, new_ph
.obj_id
);
351 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
352 res
= spiffs_rewrite_page(fs
, cur_pix
, &new_ph
, &new_pix
);
353 SPIFFS_CHECK_RES(res
);
356 // cannot safely do anything
357 SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n", NULL
);
362 } else if (((lu_obj_id
& SPIFFS_OBJ_ID_IX_FLAG
) && (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
)) ||
363 ((lu_obj_id
& SPIFFS_OBJ_ID_IX_FLAG
) == 0 && (p_hdr
->flags
& SPIFFS_PH_FLAG_INDEX
) == 0)) {
364 SPIFFS_CHECK_DBG("LU: "_SPIPRIpg
" lu/page index marking differ\n", cur_pix
);
365 spiffs_page_ix data_pix
, objix_pix_d
;
366 // see if other data page exists for given obj id and span index
367 res
= spiffs_obj_lu_find_id_and_span(fs
, lu_obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, p_hdr
->span_ix
, cur_pix
, &data_pix
);
368 if (res
== SPIFFS_ERR_NOT_FOUND
) {
372 SPIFFS_CHECK_RES(res
);
373 // see if other object index exists for given obj id and span index
374 res
= spiffs_obj_lu_find_id_and_span(fs
, lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, p_hdr
->span_ix
, cur_pix
, &objix_pix_d
);
375 if (res
== SPIFFS_ERR_NOT_FOUND
) {
379 SPIFFS_CHECK_RES(res
);
382 // if other data page exists and object index exists, just delete page
383 if (data_pix
&& objix_pix_d
) {
384 SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n", NULL
);
386 // if only data page exists, make this page index
387 if (data_pix
&& objix_pix_d
== 0) {
388 SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n", NULL
);
389 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_INDEX
, lu_obj_id
, p_hdr
->span_ix
);
390 spiffs_page_header new_ph
;
391 spiffs_page_ix new_pix
;
392 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_INDEX
);
393 new_ph
.obj_id
= lu_obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
394 new_ph
.span_ix
= p_hdr
->span_ix
;
395 res
= spiffs_page_allocate_data(fs
, new_ph
.obj_id
, &new_ph
, 0, 0, 0, 1, &new_pix
);
396 SPIFFS_CHECK_RES(res
);
397 res
= spiffs_phys_cpy(fs
, 0, SPIFFS_PAGE_TO_PADDR(fs
, new_pix
) + sizeof(spiffs_page_header
),
398 SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + sizeof(spiffs_page_header
),
399 SPIFFS_CFG_LOG_PAGE_SZ(fs
) - sizeof(spiffs_page_header
));
400 SPIFFS_CHECK_RES(res
);
402 // if only index exists, make data page
403 if (data_pix
== 0 && objix_pix_d
) {
404 SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n", NULL
);
405 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, lu_obj_id
, p_hdr
->span_ix
);
406 spiffs_page_header new_ph
;
407 spiffs_page_ix new_pix
;
408 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
);
409 new_ph
.obj_id
= lu_obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
410 new_ph
.span_ix
= p_hdr
->span_ix
;
411 res
= spiffs_page_allocate_data(fs
, new_ph
.obj_id
, &new_ph
, 0, 0, 0, 1, &new_pix
);
412 SPIFFS_CHECK_RES(res
);
413 res
= spiffs_phys_cpy(fs
, 0, SPIFFS_PAGE_TO_PADDR(fs
, new_pix
) + sizeof(spiffs_page_header
),
414 SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + sizeof(spiffs_page_header
),
415 SPIFFS_CFG_LOG_PAGE_SZ(fs
) - sizeof(spiffs_page_header
));
416 SPIFFS_CHECK_RES(res
);
418 // if nothing exists, we cannot safely make a decision - delete
420 } else if ((p_hdr
->flags
& SPIFFS_PH_FLAG_DELET
) == 0) {
421 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" busy in lu but deleted on page\n", cur_pix
);
423 } else if ((p_hdr
->flags
& SPIFFS_PH_FLAG_FINAL
)) {
424 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg
" busy but not final\n", cur_pix
);
425 // page can be removed if not referenced by object index
427 res
= spiffs_object_get_data_page_index_reference(fs
, lu_obj_id
, p_hdr
->span_ix
, &ref_pix
, &objix_pix
);
428 if (res
== SPIFFS_ERR_NOT_FOUND
) {
429 // no object with this id, so remove page safely
433 SPIFFS_CHECK_RES(res
);
434 if (ref_pix
!= cur_pix
) {
435 SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n", NULL
);
438 // page referenced by object index but not final
440 SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n", NULL
);
441 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_FIX_LOOKUP
, p_hdr
->obj_id
, p_hdr
->span_ix
);
443 #if SPIFFS_NO_BLIND_WRITES
444 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_READ
,
445 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + offsetof(spiffs_page_header
, flags
),
446 sizeof(flags
), &flags
);
447 SPIFFS_CHECK_RES(res
);
449 flags
&= ~SPIFFS_PH_FLAG_FINAL
;
450 res
= _spiffs_wr(fs
, SPIFFS_OP_T_OBJ_DA
| SPIFFS_OP_C_UPDT
,
451 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
) + offsetof(spiffs_page_header
, flags
),
452 sizeof(flags
), &flags
);
459 SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg
"\n", cur_pix
);
460 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_DELETE_PAGE
, cur_pix
, 0);
461 res
= spiffs_page_delete(fs
, cur_pix
);
462 SPIFFS_CHECK_RES(res
);
468 static s32_t
spiffs_lookup_check_v(spiffs
*fs
, spiffs_obj_id obj_id
, spiffs_block_ix cur_block
, int cur_entry
,
469 const void *user_const_p
, void *user_var_p
) {
472 s32_t res
= SPIFFS_OK
;
473 spiffs_page_header p_hdr
;
474 spiffs_page_ix cur_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, cur_block
, cur_entry
);
476 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_PROGRESS
,
477 (cur_block
* 256) / fs
->block_count
, 0);
480 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
481 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
482 SPIFFS_CHECK_RES(res
);
486 res
= spiffs_lookup_check_validate(fs
, obj_id
, &p_hdr
, cur_pix
, cur_block
, cur_entry
, &reload_lu
);
487 SPIFFS_CHECK_RES(res
);
489 if (res
== SPIFFS_OK
) {
490 return reload_lu
? SPIFFS_VIS_COUNTINUE_RELOAD
: SPIFFS_VIS_COUNTINUE
;
496 // Scans all object look up. For each entry, corresponding page header is checked for validity.
497 // If an object index header page is found, this is also checked
498 s32_t
spiffs_lookup_consistency_check(spiffs
*fs
, u8_t check_all_objects
) {
499 (void)check_all_objects
;
500 s32_t res
= SPIFFS_OK
;
502 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_PROGRESS
, 0, 0);
504 res
= spiffs_obj_lu_find_entry_visitor(fs
, 0, 0, 0, 0, spiffs_lookup_check_v
, 0, 0, 0, 0);
506 if (res
== SPIFFS_VIS_END
) {
510 if (res
!= SPIFFS_OK
) {
511 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_ERROR
, res
, 0);
514 CHECK_CB(fs
, SPIFFS_CHECK_LOOKUP
, SPIFFS_CHECK_PROGRESS
, 256, 0);
519 //---------------------------------------
522 // Scans all pages (except lu pages), reserves 4 bits in working memory for each page
523 // bit 0: 0 == FREE|DELETED, 1 == USED
524 // bit 1: 0 == UNREFERENCED, 1 == REFERENCED
525 // bit 2: 0 == NOT_INDEX, 1 == INDEX
527 // A consistent file system will have only pages being
528 // * x000 free, unreferenced, not index
529 // * x011 used, referenced only once, not index
530 // * x101 used, unreferenced, index
531 // The working memory might not fit all pages so several scans might be needed
532 static s32_t
spiffs_page_consistency_check_i(spiffs
*fs
) {
533 const u32_t bits
= 4;
534 const spiffs_page_ix pages_per_scan
= SPIFFS_CFG_LOG_PAGE_SZ(fs
) * 8 / bits
;
536 s32_t res
= SPIFFS_OK
;
537 spiffs_page_ix pix_offset
= 0;
539 // for each range of pages fitting into work memory
540 while (pix_offset
< SPIFFS_PAGES_PER_BLOCK(fs
) * fs
->block_count
) {
541 // set this flag to abort all checks and rescan the page range
543 memset(fs
->work
, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs
));
545 spiffs_block_ix cur_block
= 0;
546 // build consistency bitmap for id range traversing all blocks
547 while (!restart
&& cur_block
< fs
->block_count
) {
548 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_PROGRESS
,
549 (pix_offset
* 256) / (SPIFFS_PAGES_PER_BLOCK(fs
) * fs
->block_count
) +
550 ((((cur_block
* pages_per_scan
* 256) / (SPIFFS_PAGES_PER_BLOCK(fs
) * fs
->block_count
))) / fs
->block_count
),
552 // traverse each page except for lookup pages
553 spiffs_page_ix cur_pix
= SPIFFS_OBJ_LOOKUP_PAGES(fs
) + SPIFFS_PAGES_PER_BLOCK(fs
) * cur_block
;
554 while (!restart
&& cur_pix
< SPIFFS_PAGES_PER_BLOCK(fs
) * (cur_block
+ 1)) {
555 //if ((cur_pix & 0xff) == 0)
556 // SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
557 // cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
560 spiffs_page_header p_hdr
;
561 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
562 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
563 SPIFFS_CHECK_RES(res
);
565 u8_t within_range
= (cur_pix
>= pix_offset
&& cur_pix
< pix_offset
+ pages_per_scan
);
566 const u32_t pix_byte_ix
= (cur_pix
- pix_offset
) / (8 / bits
);
567 const u8_t pix_bit_ix
= (cur_pix
& ((8 / bits
) - 1)) * bits
;
570 (p_hdr
.flags
& SPIFFS_PH_FLAG_DELET
) && (p_hdr
.flags
& SPIFFS_PH_FLAG_USED
) == 0) {
572 fs
->work
[pix_byte_ix
] |= (1 << (pix_bit_ix
+ 0));
574 if ((p_hdr
.flags
& SPIFFS_PH_FLAG_DELET
) &&
575 (p_hdr
.flags
& SPIFFS_PH_FLAG_IXDELE
) &&
576 (p_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_USED
)) == 0) {
577 // found non-deleted index
579 fs
->work
[pix_byte_ix
] |= (1 << (pix_bit_ix
+ 2));
582 // load non-deleted index
583 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
584 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), SPIFFS_CFG_LOG_PAGE_SZ(fs
), fs
->lu_work
);
585 SPIFFS_CHECK_RES(res
);
587 // traverse index for referenced pages
588 spiffs_page_ix
*object_page_index
;
589 spiffs_page_header
*objix_p_hdr
= (spiffs_page_header
*)fs
->lu_work
;
593 spiffs_span_ix data_spix_offset
;
594 if (p_hdr
.span_ix
== 0) {
595 // object header page index
596 entries
= SPIFFS_OBJ_HDR_IX_LEN(fs
);
597 data_spix_offset
= 0;
598 object_page_index
= (spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix_header
));
601 entries
= SPIFFS_OBJ_IX_LEN(fs
);
602 data_spix_offset
= SPIFFS_OBJ_HDR_IX_LEN(fs
) + SPIFFS_OBJ_IX_LEN(fs
) * (p_hdr
.span_ix
- 1);
603 object_page_index
= (spiffs_page_ix
*)((u8_t
*)fs
->lu_work
+ sizeof(spiffs_page_object_ix
));
606 // for all entries in index
607 for (i
= 0; !restart
&& i
< entries
; i
++) {
608 spiffs_page_ix rpix
= object_page_index
[i
];
609 u8_t rpix_within_range
= rpix
>= pix_offset
&& rpix
< pix_offset
+ pages_per_scan
;
611 if ((rpix
!= (spiffs_page_ix
) - 1 && rpix
> SPIFFS_MAX_PAGES(fs
))
612 || (rpix_within_range
&& SPIFFS_IS_LOOKUP_PAGE(fs
, rpix
))) {
615 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
"x bad pix / LU referenced from page "_SPIPRIpg
"\n",
617 // check for data page elsewhere
618 spiffs_page_ix data_pix
;
619 res
= spiffs_obj_lu_find_id_and_span(fs
, objix_p_hdr
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
620 data_spix_offset
+ i
, 0, &data_pix
);
621 if (res
== SPIFFS_ERR_NOT_FOUND
) {
625 SPIFFS_CHECK_RES(res
);
627 // if not, allocate free page
628 spiffs_page_header new_ph
;
629 new_ph
.flags
= 0xff & ~(SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
);
630 new_ph
.obj_id
= objix_p_hdr
->obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
631 new_ph
.span_ix
= data_spix_offset
+ i
;
632 res
= spiffs_page_allocate_data(fs
, new_ph
.obj_id
, &new_ph
, 0, 0, 0, 1, &data_pix
);
633 SPIFFS_CHECK_RES(res
);
634 SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg
"\n", data_pix
);
637 SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg
"\n", cur_pix
);
638 res
= spiffs_rewrite_index(fs
, objix_p_hdr
->obj_id
| SPIFFS_OBJ_ID_IX_FLAG
,
639 data_spix_offset
+ i
, data_pix
, cur_pix
);
640 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
641 // index bad also, cannot mend this file
642 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi
", cannot mend - delete object\n", res
);
643 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, objix_p_hdr
->obj_id
, 0);
645 res
= spiffs_page_delete(fs
, cur_pix
);
647 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_FIX_INDEX
, objix_p_hdr
->obj_id
, objix_p_hdr
->span_ix
);
649 SPIFFS_CHECK_RES(res
);
652 } else if (rpix_within_range
) {
655 // read referenced page header
656 spiffs_page_header rp_hdr
;
657 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
658 0, SPIFFS_PAGE_TO_PADDR(fs
, rpix
), sizeof(spiffs_page_header
), (u8_t
*)&rp_hdr
);
659 SPIFFS_CHECK_RES(res
);
661 // cross reference page header check
662 if (rp_hdr
.obj_id
!= (p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
) ||
663 rp_hdr
.span_ix
!= data_spix_offset
+ i
||
664 (rp_hdr
.flags
& (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_USED
)) !=
665 (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_INDEX
)) {
666 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" has inconsistent page header ix id/span:"_SPIPRIid
"/"_SPIPRIsp
", ref id/span:"_SPIPRIid
"/"_SPIPRIsp
" flags:"_SPIPRIfl
"\n",
667 rpix
, p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
, data_spix_offset
+ i
,
668 rp_hdr
.obj_id
, rp_hdr
.span_ix
, rp_hdr
.flags
);
669 // try finding correct page
670 spiffs_page_ix data_pix
;
671 res
= spiffs_obj_lu_find_id_and_span(fs
, p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
,
672 data_spix_offset
+ i
, rpix
, &data_pix
);
673 if (res
== SPIFFS_ERR_NOT_FOUND
) {
677 SPIFFS_CHECK_RES(res
);
679 // not found, this index is badly borked
680 SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid
"\n", p_hdr
.obj_id
);
681 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
682 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
683 SPIFFS_CHECK_RES(res
);
686 // found it, so rewrite index
687 SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg
", rewrite ix pix "_SPIPRIpg
" id "_SPIPRIid
"\n",
688 data_pix
, cur_pix
, p_hdr
.obj_id
);
689 res
= spiffs_rewrite_index(fs
, p_hdr
.obj_id
, data_spix_offset
+ i
, data_pix
, cur_pix
);
690 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
691 // index bad also, cannot mend this file
692 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
693 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
694 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
696 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_FIX_INDEX
, p_hdr
.obj_id
, p_hdr
.span_ix
);
698 SPIFFS_CHECK_RES(res
);
702 // mark rpix as referenced
703 const u32_t rpix_byte_ix
= (rpix
- pix_offset
) / (8 / bits
);
704 const u8_t rpix_bit_ix
= (rpix
& ((8 / bits
) - 1)) * bits
;
705 if (fs
->work
[rpix_byte_ix
] & (1 << (rpix_bit_ix
+ 1))) {
706 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" multiple referenced from page "_SPIPRIpg
"\n",
708 // Here, we should have fixed all broken references - getting this means there
709 // must be multiple files with same object id. Only solution is to delete
710 // the object which is referring to this page
711 SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid
" and page "_SPIPRIpg
"\n",
712 p_hdr
.obj_id
, cur_pix
);
713 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
714 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
715 SPIFFS_CHECK_RES(res
);
716 // extra precaution, delete this page also
717 res
= spiffs_page_delete(fs
, cur_pix
);
718 SPIFFS_CHECK_RES(res
);
721 fs
->work
[rpix_byte_ix
] |= (1 << (rpix_bit_ix
+ 1));
724 } // for all index entries
733 // check consistency bitmap
735 spiffs_page_ix objix_pix
;
740 for (byte_ix
= 0; !restart
&& byte_ix
< SPIFFS_CFG_LOG_PAGE_SZ(fs
); byte_ix
++) {
741 for (bit_ix
= 0; !restart
&& bit_ix
< 8 / bits
; bit_ix
++) {
742 u8_t bitmask
= (fs
->work
[byte_ix
] >> (bit_ix
* bits
)) & 0x7;
743 spiffs_page_ix cur_pix
= pix_offset
+ byte_ix
* (8 / bits
) + bit_ix
;
745 // 000 ok - free, unreferenced, not index
747 if (bitmask
== 0x1) {
750 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" USED, UNREFERENCED, not index\n", cur_pix
);
752 u8_t rewrite_ix_to_this
= 0;
753 u8_t delete_page
= 0;
754 // check corresponding object index entry
755 spiffs_page_header p_hdr
;
756 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
757 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
758 SPIFFS_CHECK_RES(res
);
760 res
= spiffs_object_get_data_page_index_reference(fs
, p_hdr
.obj_id
, p_hdr
.span_ix
,
762 if (res
== SPIFFS_OK
) {
763 if (((rpix
== (spiffs_page_ix
) - 1 || rpix
> SPIFFS_MAX_PAGES(fs
)) || (SPIFFS_IS_LOOKUP_PAGE(fs
, rpix
)))) {
764 // pointing to a bad page altogether, rewrite index to this
765 rewrite_ix_to_this
= 1;
766 SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg
", rewrite to this "_SPIPRIpg
"\n", rpix
, cur_pix
);
768 // pointing to something else, check what
769 spiffs_page_header rp_hdr
;
770 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
771 0, SPIFFS_PAGE_TO_PADDR(fs
, rpix
), sizeof(spiffs_page_header
), (u8_t
*)&rp_hdr
);
772 SPIFFS_CHECK_RES(res
);
773 if (((p_hdr
.obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
) == rp_hdr
.obj_id
) &&
774 ((rp_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_USED
| SPIFFS_PH_FLAG_FINAL
)) ==
775 (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_DELET
))) {
776 // pointing to something else valid, just delete this page then
777 SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg
", delete this "_SPIPRIpg
"\n", rpix
, cur_pix
);
780 // pointing to something weird, update index to point to this page instead
781 if (rpix
!= cur_pix
) {
782 SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg
" %s%s%s%s, rewrite this "_SPIPRIpg
"\n", rpix
,
783 (rp_hdr
.flags
& SPIFFS_PH_FLAG_INDEX
) ? "" : "INDEX ",
784 (rp_hdr
.flags
& SPIFFS_PH_FLAG_DELET
) ? "" : "DELETED ",
785 (rp_hdr
.flags
& SPIFFS_PH_FLAG_USED
) ? "NOTUSED " : "",
786 (rp_hdr
.flags
& SPIFFS_PH_FLAG_FINAL
) ? "NOTFINAL " : "",
788 rewrite_ix_to_this
= 1;
790 // should not happen, destined for fubar
794 } else if (res
== SPIFFS_ERR_NOT_FOUND
) {
795 SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg
"\n", cur_pix
);
800 if (rewrite_ix_to_this
) {
801 // if pointing to invalid page, redirect index to this page
802 SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid
" data spix "_SPIPRIsp
" to point to this pix: "_SPIPRIpg
"\n",
803 p_hdr
.obj_id
, p_hdr
.span_ix
, cur_pix
);
804 res
= spiffs_rewrite_index(fs
, p_hdr
.obj_id
, p_hdr
.span_ix
, cur_pix
, objix_pix
);
805 if (res
<= _SPIFFS_ERR_CHECK_FIRST
&& res
> _SPIFFS_ERR_CHECK_LAST
) {
806 // index bad also, cannot mend this file
807 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi
", cannot mend!\n", res
);
808 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_BAD_FILE
, p_hdr
.obj_id
, 0);
809 res
= spiffs_page_delete(fs
, cur_pix
);
810 SPIFFS_CHECK_RES(res
);
811 res
= spiffs_delete_obj_lazy(fs
, p_hdr
.obj_id
);
813 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_FIX_INDEX
, p_hdr
.obj_id
, p_hdr
.span_ix
);
815 SPIFFS_CHECK_RES(res
);
818 } else if (delete_page
) {
819 SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg
"\n", cur_pix
);
820 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_DELETE_PAGE
, cur_pix
, 0);
821 res
= spiffs_page_delete(fs
, cur_pix
);
823 SPIFFS_CHECK_RES(res
);
825 if (bitmask
== 0x2) {
828 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" FREE, REFERENCED, not index\n", cur_pix
);
830 // no op, this should be taken care of when checking valid references
833 // 011 ok - busy, referenced, not index
835 if (bitmask
== 0x4) {
838 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" FREE, unreferenced, INDEX\n", cur_pix
);
840 // this should never happen, major fubar
843 // 101 ok - busy, unreferenced, index
845 if (bitmask
== 0x6) {
848 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" FREE, REFERENCED, INDEX\n", cur_pix
);
850 // no op, this should be taken care of when checking valid references
852 if (bitmask
== 0x7) {
855 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg
" USED, REFERENCED, INDEX\n", cur_pix
);
857 // no op, this should be taken care of when checking valid references
863 SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg
", restart "_SPIPRIi
"\n", pix_offset
, restart
);
866 pix_offset
+= pages_per_scan
;
868 } // while page range not reached end
872 // Checks consistency amongst all pages and fixes irregularities
873 s32_t
spiffs_page_consistency_check(spiffs
*fs
) {
874 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_PROGRESS
, 0, 0);
875 s32_t res
= spiffs_page_consistency_check_i(fs
);
876 if (res
!= SPIFFS_OK
) {
877 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_ERROR
, res
, 0);
879 CHECK_CB(fs
, SPIFFS_CHECK_PAGE
, SPIFFS_CHECK_PROGRESS
, 256, 0);
883 //---------------------------------------
884 // Object index consistency
886 // searches for given object id in temporary object id index,
887 // returns the index or -1
888 static int spiffs_object_index_search(spiffs
*fs
, spiffs_obj_id obj_id
) {
890 spiffs_obj_id
*obj_table
= (spiffs_obj_id
*)fs
->work
;
891 obj_id
&= ~SPIFFS_OBJ_ID_IX_FLAG
;
892 for (i
= 0; i
< SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(spiffs_obj_id
); i
++) {
893 if ((obj_table
[i
] & ~SPIFFS_OBJ_ID_IX_FLAG
) == obj_id
) {
900 static s32_t
spiffs_object_index_consistency_check_v(spiffs
*fs
, spiffs_obj_id obj_id
, spiffs_block_ix cur_block
,
901 int cur_entry
, const void *user_const_p
, void *user_var_p
) {
903 s32_t res_c
= SPIFFS_VIS_COUNTINUE
;
904 s32_t res
= SPIFFS_OK
;
905 u32_t
*log_ix
= (u32_t
*)user_var_p
;
906 spiffs_obj_id
*obj_table
= (spiffs_obj_id
*)fs
->work
;
908 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_PROGRESS
,
909 (cur_block
* 256) / fs
->block_count
, 0);
911 if (obj_id
!= SPIFFS_OBJ_ID_FREE
&& obj_id
!= SPIFFS_OBJ_ID_DELETED
&& (obj_id
& SPIFFS_OBJ_ID_IX_FLAG
)) {
912 spiffs_page_header p_hdr
;
913 spiffs_page_ix cur_pix
= SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs
, cur_block
, cur_entry
);
916 res
= _spiffs_rd(fs
, SPIFFS_OP_T_OBJ_LU2
| SPIFFS_OP_C_READ
,
917 0, SPIFFS_PAGE_TO_PADDR(fs
, cur_pix
), sizeof(spiffs_page_header
), (u8_t
*)&p_hdr
);
918 SPIFFS_CHECK_RES(res
);
920 if (p_hdr
.span_ix
== 0 &&
921 (p_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) ==
922 (SPIFFS_PH_FLAG_DELET
)) {
923 SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg
", obj id:"_SPIPRIid
" spix:"_SPIPRIsp
" header not fully deleted - deleting\n",
924 cur_pix
, obj_id
, p_hdr
.span_ix
);
925 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_DELETE_PAGE
, cur_pix
, obj_id
);
926 res
= spiffs_page_delete(fs
, cur_pix
);
927 SPIFFS_CHECK_RES(res
);
931 if ((p_hdr
.flags
& (SPIFFS_PH_FLAG_INDEX
| SPIFFS_PH_FLAG_FINAL
| SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) ==
932 (SPIFFS_PH_FLAG_DELET
| SPIFFS_PH_FLAG_IXDELE
)) {
936 if (p_hdr
.span_ix
== 0) {
937 // objix header page, register objid as reachable
938 int r
= spiffs_object_index_search(fs
, obj_id
);
940 // not registered, do it
941 obj_table
[*log_ix
] = obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
943 if (*log_ix
>= SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(spiffs_obj_id
)) {
947 } else { // span index
948 // objix page, see if header can be found
949 int r
= spiffs_object_index_search(fs
, obj_id
);
952 // not in temporary index, try finding it
953 spiffs_page_ix objix_hdr_pix
;
954 res
= spiffs_obj_lu_find_id_and_span(fs
, obj_id
| SPIFFS_OBJ_ID_IX_FLAG
, 0, 0, &objix_hdr_pix
);
955 res_c
= SPIFFS_VIS_COUNTINUE_RELOAD
;
956 if (res
== SPIFFS_OK
) {
957 // found, register as reachable
958 obj_table
[*log_ix
] = obj_id
& ~SPIFFS_OBJ_ID_IX_FLAG
;
959 } else if (res
== SPIFFS_ERR_NOT_FOUND
) {
960 // not found, register as unreachable
962 obj_table
[*log_ix
] = obj_id
| SPIFFS_OBJ_ID_IX_FLAG
;
964 SPIFFS_CHECK_RES(res
);
967 if (*log_ix
>= SPIFFS_CFG_LOG_PAGE_SZ(fs
) / sizeof(spiffs_obj_id
)) {
971 // in temporary index, check reachable flag
972 if ((obj_table
[r
] & SPIFFS_OBJ_ID_IX_FLAG
)) {
973 // registered as unreachable
979 SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg
", obj id:"_SPIPRIid
" spix:"_SPIPRIsp
" is orphan index - deleting\n",
980 cur_pix
, obj_id
, p_hdr
.span_ix
);
981 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_DELETE_ORPHANED_INDEX
, cur_pix
, obj_id
);
982 res
= spiffs_page_delete(fs
, cur_pix
);
983 SPIFFS_CHECK_RES(res
);
986 } // valid object index id
991 // Removes orphaned and partially deleted index pages.
992 // Scans for index pages. When an index page is found, corresponding index header is searched for.
993 // If no such page exists, the index page cannot be reached as no index header exists and must be
995 s32_t
spiffs_object_index_consistency_check(spiffs
*fs
) {
996 s32_t res
= SPIFFS_OK
;
998 // fs->work is used for a temporary object index memory, listing found object ids and
999 // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
1000 // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
1001 // a reachable/unreachable object id.
1002 memset(fs
->work
, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs
));
1003 u32_t obj_id_log_ix
= 0;
1004 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_PROGRESS
, 0, 0);
1005 res
= spiffs_obj_lu_find_entry_visitor(fs
, 0, 0, 0, 0, spiffs_object_index_consistency_check_v
, 0, &obj_id_log_ix
,
1007 if (res
== SPIFFS_VIS_END
) {
1010 if (res
!= SPIFFS_OK
) {
1011 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_ERROR
, res
, 0);
1013 CHECK_CB(fs
, SPIFFS_CHECK_INDEX
, SPIFFS_CHECK_PROGRESS
, 256, 0);
1017 #endif // !SPIFFS_READ_ONLY