fix coverity CID 349303
[RRG-proxmark3.git] / armsrc / spiffs_check.c
blob90fba8a4110ab7c4979111498c13af7c22587982
1 /*
2 * spiffs_check.c
4 * Contains functionality for checking file system consistency
5 * and mending problems.
6 * Three levels of consistency checks are implemented:
8 * Look up consistency
9 * Checks if indices in lookup pages are coherent with page headers
10 * Object index consistency
11 * Checks if there are any orphaned object indices (missing object index headers).
12 * If an object index is found but not its header, the object index is deleted.
13 * This is critical for the following page consistency check.
14 * Page consistency
15 * Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
18 * Created on: Jul 7, 2013
19 * Author: petera
23 #include "spiffs.h"
24 #include "spiffs_nucleus.h"
26 #if !SPIFFS_READ_ONLY
28 #if SPIFFS_HAL_CALLBACK_EXTRA
29 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
30 do { \
31 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
32 } while (0)
33 #else
34 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
35 do { \
36 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
37 } while (0)
38 #endif
40 //---------------------------------------
41 // Look up consistency
43 // searches in the object indices and returns the referenced page index given
44 // the object id and the data span index
45 // destroys fs->lu_work
46 static s32_t spiffs_object_get_data_page_index_reference(
47 spiffs *fs,
48 spiffs_obj_id obj_id,
49 spiffs_span_ix data_spix,
50 spiffs_page_ix *pix,
51 spiffs_page_ix *objix_pix) {
52 s32_t res;
54 // calculate object index span index for given data page span index
55 spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
57 // find obj index for obj id and span index
58 res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);
59 SPIFFS_CHECK_RES(res);
61 // load obj index entry
62 u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);
63 if (objix_spix == 0) {
64 // get referenced page from object index header
65 addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);
66 } else {
67 // get referenced page from object index
68 addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);
71 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);
73 return res;
76 // copies page contents to a new page
77 static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {
78 s32_t res;
79 res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0, 0, 0, 0, new_pix);
80 SPIFFS_CHECK_RES(res);
81 res = spiffs_phys_cpy(fs, 0,
82 SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),
83 SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
84 SPIFFS_DATA_PAGE_SIZE(fs));
85 SPIFFS_CHECK_RES(res);
86 return res;
89 // rewrites the object index for given object id and replaces the
90 // data page index to a new page index
91 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) {
92 s32_t res;
93 spiffs_block_ix bix;
94 int entry;
95 spiffs_page_ix free_pix;
96 obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
98 // find free entry
99 res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
100 SPIFFS_CHECK_RES(res);
101 free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
103 // calculate object index span index for given data page span index
104 spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
105 if (objix_spix == 0) {
106 // calc index in index header
107 entry = data_spix;
108 } else {
109 // calc entry in index
110 entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
113 // load index
114 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
115 0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
116 SPIFFS_CHECK_RES(res);
117 spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
119 // be ultra safe, double check header against provided data
120 if (objix_p_hdr->obj_id != obj_id) {
121 spiffs_page_delete(fs, free_pix);
122 return SPIFFS_ERR_CHECK_OBJ_ID_MISM;
124 if (objix_p_hdr->span_ix != objix_spix) {
125 spiffs_page_delete(fs, free_pix);
126 return SPIFFS_ERR_CHECK_SPIX_MISM;
128 if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |
129 SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=
130 (SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {
131 spiffs_page_delete(fs, free_pix);
132 return SPIFFS_ERR_CHECK_FLAGS_BAD;
135 // rewrite in mem
136 if (objix_spix == 0) {
137 ((spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
138 } else {
139 ((spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
142 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
143 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
144 SPIFFS_CHECK_RES(res);
145 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
146 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),
147 sizeof(spiffs_obj_id),
148 (u8_t *)&obj_id);
149 SPIFFS_CHECK_RES(res);
150 res = spiffs_page_delete(fs, objix_pix);
152 return res;
155 // deletes an object just by marking object index header as deleted
156 static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {
157 spiffs_page_ix objix_hdr_pix;
158 s32_t res;
159 res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);
160 if (res == SPIFFS_ERR_NOT_FOUND) {
161 return SPIFFS_OK;
163 SPIFFS_CHECK_RES(res);
164 u8_t flags = 0xff;
165 #if SPIFFS_NO_BLIND_WRITES
166 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
167 0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
168 sizeof(flags), &flags);
169 SPIFFS_CHECK_RES(res);
170 #endif
171 flags &= ~SPIFFS_PH_FLAG_IXDELE;
172 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
173 0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
174 sizeof(flags), &flags);
175 return res;
178 // validates the given look up entry
179 static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
180 spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
181 (void)cur_block;
182 (void)cur_entry;
183 u8_t delete_page = 0;
184 s32_t res = SPIFFS_OK;
185 spiffs_page_ix objix_pix;
186 spiffs_page_ix ref_pix;
187 // check validity, take actions
188 if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||
189 ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {
190 // look up entry deleted / free but used in page header
191 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" deleted/free in lu but not on page\n", cur_pix);
192 *reload_lu = 1;
193 delete_page = 1;
194 if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
195 // header says data page
196 // data page can be removed if not referenced by some object index
197 res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
198 if (res == SPIFFS_ERR_NOT_FOUND) {
199 // no object with this id, so remove page safely
200 res = SPIFFS_OK;
201 } else {
202 SPIFFS_CHECK_RES(res);
203 if (ref_pix == cur_pix) {
204 // data page referenced by object index but deleted in lu
205 // copy page to new place and re-write the object index to new place
206 spiffs_page_ix new_pix;
207 res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
208 SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
209 SPIFFS_CHECK_RES(res);
210 *reload_lu = 1;
211 SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg" rewritten to "_SPIPRIpg", affected objix_pix "_SPIPRIpg"\n", cur_pix, new_pix, objix_pix);
212 res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
213 if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
214 // index bad also, cannot mend this file
215 SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
216 res = spiffs_page_delete(fs, new_pix);
217 SPIFFS_CHECK_RES(res);
218 res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
219 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
220 } else {
221 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
223 SPIFFS_CHECK_RES(res);
226 } else {
227 // header says index page
228 // index page can be removed if other index with same obj_id and spanix is found
229 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);
230 if (res == SPIFFS_ERR_NOT_FOUND) {
231 // no such index page found, check for a data page amongst page headers
232 // lu cannot be trusted
233 res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);
234 if (res == SPIFFS_OK) { // ignore other errors
235 // got a data page also, assume lu corruption only, rewrite to new page
236 spiffs_page_ix new_pix;
237 res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
238 SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
239 SPIFFS_CHECK_RES(res);
240 *reload_lu = 1;
241 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
243 } else {
244 SPIFFS_CHECK_RES(res);
248 if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {
249 // look up entry used
250 if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {
251 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" differ in obj_id lu:"_SPIPRIid" ph:"_SPIPRIid"\n", cur_pix, lu_obj_id, p_hdr->obj_id);
252 delete_page = 1;
253 if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||
254 (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||
255 (p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {
256 // page deleted or not finalized, just remove it
257 } else {
258 if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
259 // if data page, check for reference to this page
260 res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
261 if (res == SPIFFS_ERR_NOT_FOUND) {
262 // no object with this id, so remove page safely
263 res = SPIFFS_OK;
264 } else {
265 SPIFFS_CHECK_RES(res);
266 // if found, rewrite page with object id, update index, and delete current
267 if (ref_pix == cur_pix) {
268 spiffs_page_ix new_pix;
269 res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
270 SPIFFS_CHECK_RES(res);
271 res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
272 if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
273 // index bad also, cannot mend this file
274 SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
275 res = spiffs_page_delete(fs, new_pix);
276 SPIFFS_CHECK_RES(res);
277 res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
278 *reload_lu = 1;
279 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
281 SPIFFS_CHECK_RES(res);
284 } else {
285 // else if index, check for other pages with both obj_id's and spanix
286 spiffs_page_ix objix_pix_lu, objix_pix_ph;
287 // see if other object index page exists for lookup obj id and span index
288 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);
289 if (res == SPIFFS_ERR_NOT_FOUND) {
290 res = SPIFFS_OK;
291 objix_pix_lu = 0;
293 SPIFFS_CHECK_RES(res);
294 // see if other object index exists for page header obj id and span index
295 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);
296 if (res == SPIFFS_ERR_NOT_FOUND) {
297 res = SPIFFS_OK;
298 objix_pix_ph = 0;
300 SPIFFS_CHECK_RES(res);
301 // if both obj_id's found, just delete current
302 if (objix_pix_ph == 0 || objix_pix_lu == 0) {
303 // otherwise try finding first corresponding data pages
304 spiffs_page_ix data_pix_lu, data_pix_ph;
305 // see if other data page exists for look up obj id and span index
306 res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);
307 if (res == SPIFFS_ERR_NOT_FOUND) {
308 res = SPIFFS_OK;
309 objix_pix_lu = 0;
311 SPIFFS_CHECK_RES(res);
312 // see if other data page exists for page header obj id and span index
313 res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);
314 if (res == SPIFFS_ERR_NOT_FOUND) {
315 res = SPIFFS_OK;
316 objix_pix_ph = 0;
318 SPIFFS_CHECK_RES(res);
320 spiffs_page_header new_ph;
321 new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);
322 new_ph.span_ix = p_hdr->span_ix;
323 spiffs_page_ix new_pix;
324 if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||
325 (objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {
326 // got a data page for page header obj id
327 // rewrite as obj_id_ph
328 new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
329 res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
330 SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid" to pix "_SPIPRIpg"\n", cur_pix, new_ph.obj_id, new_pix);
331 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
332 SPIFFS_CHECK_RES(res);
333 *reload_lu = 1;
334 } else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
335 (objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {
336 // got a data page for look up obj id
337 // rewrite as obj_id_lu
338 new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
339 SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid"\n", cur_pix, new_ph.obj_id);
340 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
341 res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
342 SPIFFS_CHECK_RES(res);
343 *reload_lu = 1;
344 } else {
345 // cannot safely do anything
346 SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n", NULL);
351 } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||
352 ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {
353 SPIFFS_CHECK_DBG("LU: "_SPIPRIpg" lu/page index marking differ\n", cur_pix);
354 spiffs_page_ix data_pix, objix_pix_d;
355 // see if other data page exists for given obj id and span index
356 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);
357 if (res == SPIFFS_ERR_NOT_FOUND) {
358 res = SPIFFS_OK;
359 data_pix = 0;
361 SPIFFS_CHECK_RES(res);
362 // see if other object index exists for given obj id and span index
363 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);
364 if (res == SPIFFS_ERR_NOT_FOUND) {
365 res = SPIFFS_OK;
366 objix_pix_d = 0;
368 SPIFFS_CHECK_RES(res);
370 delete_page = 1;
371 // if other data page exists and object index exists, just delete page
372 if (data_pix && objix_pix_d) {
373 SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n", NULL);
374 } else
375 // if only data page exists, make this page index
376 if (data_pix && objix_pix_d == 0) {
377 SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n", NULL);
378 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
379 spiffs_page_header new_ph;
380 spiffs_page_ix new_pix;
381 new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
382 new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
383 new_ph.span_ix = p_hdr->span_ix;
384 res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
385 SPIFFS_CHECK_RES(res);
386 res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
387 SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
388 SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
389 SPIFFS_CHECK_RES(res);
390 } else
391 // if only index exists, make data page
392 if (data_pix == 0 && objix_pix_d) {
393 SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n", NULL);
394 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
395 spiffs_page_header new_ph;
396 spiffs_page_ix new_pix;
397 new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
398 new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
399 new_ph.span_ix = p_hdr->span_ix;
400 res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
401 SPIFFS_CHECK_RES(res);
402 res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
403 SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
404 SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
405 SPIFFS_CHECK_RES(res);
406 } else {
407 // if nothing exists, we cannot safely make a decision - delete
409 } else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
410 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy in lu but deleted on page\n", cur_pix);
411 delete_page = 1;
412 } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
413 SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy but not final\n", cur_pix);
414 // page can be removed if not referenced by object index
415 *reload_lu = 1;
416 res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
417 if (res == SPIFFS_ERR_NOT_FOUND) {
418 // no object with this id, so remove page safely
419 res = SPIFFS_OK;
420 delete_page = 1;
421 } else {
422 SPIFFS_CHECK_RES(res);
423 if (ref_pix != cur_pix) {
424 SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n", NULL);
425 delete_page = 1;
426 } else {
427 // page referenced by object index but not final
428 // just finalize
429 SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n", NULL);
430 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
431 u8_t flags = 0xff;
432 #if SPIFFS_NO_BLIND_WRITES
433 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
434 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
435 sizeof(flags), &flags);
436 SPIFFS_CHECK_RES(res);
437 #endif
438 flags &= ~SPIFFS_PH_FLAG_FINAL;
439 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
440 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
441 sizeof(flags), &flags);
447 if (delete_page) {
448 SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
449 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
450 res = spiffs_page_delete(fs, cur_pix);
451 SPIFFS_CHECK_RES(res);
454 return res;
457 static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
458 const void *user_const_p, void *user_var_p) {
459 (void)user_const_p;
460 (void)user_var_p;
461 s32_t res = SPIFFS_OK;
462 spiffs_page_header p_hdr;
463 spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
465 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
466 (cur_block * 256) / fs->block_count, 0);
468 // load header
469 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
470 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t *)&p_hdr);
471 SPIFFS_CHECK_RES(res);
473 int reload_lu = 0;
475 res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
476 SPIFFS_CHECK_RES(res);
478 if (res == SPIFFS_OK) {
479 return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;
481 return res;
485 // Scans all object look up. For each entry, corresponding page header is checked for validity.
486 // If an object index header page is found, this is also checked
487 s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
488 (void)check_all_objects;
489 s32_t res = SPIFFS_OK;
491 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
493 res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
495 if (res == SPIFFS_VIS_END) {
496 res = SPIFFS_OK;
499 if (res != SPIFFS_OK) {
500 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
503 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
505 return res;
508 //---------------------------------------
509 // Page consistency
511 // Scans all pages (except lu pages), reserves 4 bits in working memory for each page
512 // bit 0: 0 == FREE|DELETED, 1 == USED
513 // bit 1: 0 == UNREFERENCED, 1 == REFERENCED
514 // bit 2: 0 == NOT_INDEX, 1 == INDEX
515 // bit 3: unused
516 // A consistent file system will have only pages being
517 // * x000 free, unreferenced, not index
518 // * x011 used, referenced only once, not index
519 // * x101 used, unreferenced, index
520 // The working memory might not fit all pages so several scans might be needed
521 static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
522 const u32_t bits = 4;
523 const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;
525 s32_t res = SPIFFS_OK;
526 spiffs_page_ix pix_offset = 0;
528 // for each range of pages fitting into work memory
529 while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
530 // set this flag to abort all checks and rescan the page range
531 u8_t restart = 0;
532 memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
534 spiffs_block_ix cur_block = 0;
535 // build consistency bitmap for id range traversing all blocks
536 while (!restart && cur_block < fs->block_count) {
537 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
538 (pix_offset * 256) / (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
539 ((((cur_block * pages_per_scan * 256) / (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
541 // traverse each page except for lookup pages
542 spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
543 while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block + 1)) {
544 //if ((cur_pix & 0xff) == 0)
545 // SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
546 // cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
548 // read header
549 spiffs_page_header p_hdr;
550 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
551 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t *)&p_hdr);
552 SPIFFS_CHECK_RES(res);
554 u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);
555 const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8 / bits);
556 const u8_t pix_bit_ix = (cur_pix & ((8 / bits) - 1)) * bits;
558 if (within_range &&
559 (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
560 // used
561 fs->work[pix_byte_ix] |= (1 << (pix_bit_ix + 0));
563 if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&
564 (p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&
565 (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {
566 // found non-deleted index
567 if (within_range) {
568 fs->work[pix_byte_ix] |= (1 << (pix_bit_ix + 2));
571 // load non-deleted index
572 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
573 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
574 SPIFFS_CHECK_RES(res);
576 // traverse index for referenced pages
577 spiffs_page_ix *object_page_index;
578 spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
580 int entries;
581 int i;
582 spiffs_span_ix data_spix_offset;
583 if (p_hdr.span_ix == 0) {
584 // object header page index
585 entries = SPIFFS_OBJ_HDR_IX_LEN(fs);
586 data_spix_offset = 0;
587 object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));
588 } else {
589 // object page index
590 entries = SPIFFS_OBJ_IX_LEN(fs);
591 data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);
592 object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));
595 // for all entries in index
596 for (i = 0; !restart && i < entries; i++) {
597 spiffs_page_ix rpix = object_page_index[i];
598 u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;
600 if ((rpix != (spiffs_page_ix) - 1 && rpix > SPIFFS_MAX_PAGES(fs))
601 || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {
603 // bad reference
604 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n",
605 rpix, cur_pix);
606 // check for data page elsewhere
607 spiffs_page_ix data_pix;
608 res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
609 data_spix_offset + i, 0, &data_pix);
610 if (res == SPIFFS_ERR_NOT_FOUND) {
611 res = SPIFFS_OK;
612 data_pix = 0;
614 SPIFFS_CHECK_RES(res);
615 if (data_pix == 0) {
616 // if not, allocate free page
617 spiffs_page_header new_ph;
618 new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
619 new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
620 new_ph.span_ix = data_spix_offset + i;
621 res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);
622 SPIFFS_CHECK_RES(res);
623 SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg"\n", data_pix);
625 // remap index
626 SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg"\n", cur_pix);
627 res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
628 data_spix_offset + i, data_pix, cur_pix);
629 if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
630 // index bad also, cannot mend this file
631 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend - delete object\n", res);
632 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
633 // delete file
634 res = spiffs_page_delete(fs, cur_pix);
635 } else {
636 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
638 SPIFFS_CHECK_RES(res);
639 restart = 1;
641 } else if (rpix_within_range) {
643 // valid reference
644 // read referenced page header
645 spiffs_page_header rp_hdr;
646 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
647 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t *)&rp_hdr);
648 SPIFFS_CHECK_RES(res);
650 // cross reference page header check
651 if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||
652 rp_hdr.span_ix != data_spix_offset + i ||
653 (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=
654 (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {
655 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" has inconsistent page header ix id/span:"_SPIPRIid"/"_SPIPRIsp", ref id/span:"_SPIPRIid"/"_SPIPRIsp" flags:"_SPIPRIfl"\n",
656 rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,
657 rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);
658 // try finding correct page
659 spiffs_page_ix data_pix;
660 res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
661 data_spix_offset + i, rpix, &data_pix);
662 if (res == SPIFFS_ERR_NOT_FOUND) {
663 res = SPIFFS_OK;
664 data_pix = 0;
666 SPIFFS_CHECK_RES(res);
667 if (data_pix == 0) {
668 // not found, this index is badly borked
669 SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid"\n", p_hdr.obj_id);
670 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
671 res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
672 SPIFFS_CHECK_RES(res);
673 break;
674 } else {
675 // found it, so rewrite index
676 SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg", rewrite ix pix "_SPIPRIpg" id "_SPIPRIid"\n",
677 data_pix, cur_pix, p_hdr.obj_id);
678 res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
679 if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
680 // index bad also, cannot mend this file
681 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
682 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
683 res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
684 } else {
685 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
687 SPIFFS_CHECK_RES(res);
688 restart = 1;
690 } else {
691 // mark rpix as referenced
692 const u32_t rpix_byte_ix = (rpix - pix_offset) / (8 / bits);
693 const u8_t rpix_bit_ix = (rpix & ((8 / bits) - 1)) * bits;
694 if (fs->work[rpix_byte_ix] & (1 << (rpix_bit_ix + 1))) {
695 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" multiple referenced from page "_SPIPRIpg"\n",
696 rpix, cur_pix);
697 // Here, we should have fixed all broken references - getting this means there
698 // must be multiple files with same object id. Only solution is to delete
699 // the object which is referring to this page
700 SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid" and page "_SPIPRIpg"\n",
701 p_hdr.obj_id, cur_pix);
702 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
703 res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
704 SPIFFS_CHECK_RES(res);
705 // extra precaution, delete this page also
706 res = spiffs_page_delete(fs, cur_pix);
707 SPIFFS_CHECK_RES(res);
708 restart = 1;
710 fs->work[rpix_byte_ix] |= (1 << (rpix_bit_ix + 1));
713 } // for all index entries
714 } // found index
716 // next page
717 cur_pix++;
719 // next block
720 cur_block++;
722 // check consistency bitmap
723 if (!restart) {
724 spiffs_page_ix objix_pix;
725 spiffs_page_ix rpix;
727 u32_t byte_ix;
728 u8_t bit_ix;
729 for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {
730 for (bit_ix = 0; !restart && bit_ix < 8 / bits; bit_ix ++) {
731 u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;
732 spiffs_page_ix cur_pix = pix_offset + byte_ix * (8 / bits) + bit_ix;
734 // 000 ok - free, unreferenced, not index
736 if (bitmask == 0x1) {
738 // 001
739 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, UNREFERENCED, not index\n", cur_pix);
741 u8_t rewrite_ix_to_this = 0;
742 u8_t delete_page = 0;
743 // check corresponding object index entry
744 spiffs_page_header p_hdr;
745 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
746 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t *)&p_hdr);
747 SPIFFS_CHECK_RES(res);
749 res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,
750 &rpix, &objix_pix);
751 if (res == SPIFFS_OK) {
752 if (((rpix == (spiffs_page_ix) - 1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {
753 // pointing to a bad page altogether, rewrite index to this
754 rewrite_ix_to_this = 1;
755 SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg", rewrite to this "_SPIPRIpg"\n", rpix, cur_pix);
756 } else {
757 // pointing to something else, check what
758 spiffs_page_header rp_hdr;
759 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
760 0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t *)&rp_hdr);
761 SPIFFS_CHECK_RES(res);
762 if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&
763 ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==
764 (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {
765 // pointing to something else valid, just delete this page then
766 SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg", delete this "_SPIPRIpg"\n", rpix, cur_pix);
767 delete_page = 1;
768 } else {
769 // pointing to something weird, update index to point to this page instead
770 if (rpix != cur_pix) {
771 SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg" %s%s%s%s, rewrite this "_SPIPRIpg"\n", rpix,
772 (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ",
773 (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ",
774 (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "",
775 (rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "",
776 cur_pix);
777 rewrite_ix_to_this = 1;
778 } else {
779 // should not happen, destined for fubar
783 } else if (res == SPIFFS_ERR_NOT_FOUND) {
784 SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg"\n", cur_pix);
785 delete_page = 1;
786 res = SPIFFS_OK;
789 if (rewrite_ix_to_this) {
790 // if pointing to invalid page, redirect index to this page
791 SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid" data spix "_SPIPRIsp" to point to this pix: "_SPIPRIpg"\n",
792 p_hdr.obj_id, p_hdr.span_ix, cur_pix);
793 res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
794 if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
795 // index bad also, cannot mend this file
796 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
797 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
798 res = spiffs_page_delete(fs, cur_pix);
799 SPIFFS_CHECK_RES(res);
800 res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
801 } else {
802 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
804 SPIFFS_CHECK_RES(res);
805 restart = 1;
806 continue;
807 } else if (delete_page) {
808 SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
809 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
810 res = spiffs_page_delete(fs, cur_pix);
812 SPIFFS_CHECK_RES(res);
814 if (bitmask == 0x2) {
816 // 010
817 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, not index\n", cur_pix);
819 // no op, this should be taken care of when checking valid references
822 // 011 ok - busy, referenced, not index
824 if (bitmask == 0x4) {
826 // 100
827 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, unreferenced, INDEX\n", cur_pix);
829 // this should never happen, major fubar
832 // 101 ok - busy, unreferenced, index
834 if (bitmask == 0x6) {
836 // 110
837 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, INDEX\n", cur_pix);
839 // no op, this should be taken care of when checking valid references
841 if (bitmask == 0x7) {
843 // 111
844 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, REFERENCED, INDEX\n", cur_pix);
846 // no op, this should be taken care of when checking valid references
852 SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg", restart "_SPIPRIi"\n", pix_offset, restart);
853 // next page range
854 if (!restart) {
855 pix_offset += pages_per_scan;
857 } // while page range not reached end
858 return res;
861 // Checks consistency amongst all pages and fixes irregularities
862 s32_t spiffs_page_consistency_check(spiffs *fs) {
863 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
864 s32_t res = spiffs_page_consistency_check_i(fs);
865 if (res != SPIFFS_OK) {
866 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
868 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
869 return res;
872 //---------------------------------------
873 // Object index consistency
875 // searches for given object id in temporary object id index,
876 // returns the index or -1
877 static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
878 u32_t i;
879 spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
880 obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
881 for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {
882 if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {
883 return i;
886 return -1;
889 static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
890 int cur_entry, const void *user_const_p, void *user_var_p) {
891 (void)user_const_p;
892 s32_t res_c = SPIFFS_VIS_COUNTINUE;
893 s32_t res = SPIFFS_OK;
894 u32_t *log_ix = (u32_t *)user_var_p;
895 spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
897 CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
898 (cur_block * 256) / fs->block_count, 0);
900 if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
901 spiffs_page_header p_hdr;
902 spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
904 // load header
905 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
906 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t *)&p_hdr);
907 SPIFFS_CHECK_RES(res);
909 if (p_hdr.span_ix == 0 &&
910 (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
911 (SPIFFS_PH_FLAG_DELET)) {
912 SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" header not fully deleted - deleting\n",
913 cur_pix, obj_id, p_hdr.span_ix);
914 CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
915 res = spiffs_page_delete(fs, cur_pix);
916 SPIFFS_CHECK_RES(res);
917 return res_c;
920 if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
921 (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
922 return res_c;
925 if (p_hdr.span_ix == 0) {
926 // objix header page, register objid as reachable
927 int r = spiffs_object_index_search(fs, obj_id);
928 if (r == -1) {
929 // not registered, do it
930 obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
931 (*log_ix)++;
932 if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
933 *log_ix = 0;
936 } else { // span index
937 // objix page, see if header can be found
938 int r = spiffs_object_index_search(fs, obj_id);
939 u8_t delete = 0;
940 if (r == -1) {
941 // not in temporary index, try finding it
942 spiffs_page_ix objix_hdr_pix;
943 res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);
944 res_c = SPIFFS_VIS_COUNTINUE_RELOAD;
945 if (res == SPIFFS_OK) {
946 // found, register as reachable
947 obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
948 } else if (res == SPIFFS_ERR_NOT_FOUND) {
949 // not found, register as unreachable
950 delete = 1;
951 obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
952 } else {
953 SPIFFS_CHECK_RES(res);
955 (*log_ix)++;
956 if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
957 *log_ix = 0;
959 } else {
960 // in temporary index, check reachable flag
961 if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
962 // registered as unreachable
963 delete = 1;
967 if (delete) {
968 SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" is orphan index - deleting\n",
969 cur_pix, obj_id, p_hdr.span_ix);
970 CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
971 res = spiffs_page_delete(fs, cur_pix);
972 SPIFFS_CHECK_RES(res);
974 } // span index
975 } // valid object index id
977 return res_c;
980 // Removes orphaned and partially deleted index pages.
981 // Scans for index pages. When an index page is found, corresponding index header is searched for.
982 // If no such page exists, the index page cannot be reached as no index header exists and must be
983 // deleted.
984 s32_t spiffs_object_index_consistency_check(spiffs *fs) {
985 s32_t res = SPIFFS_OK;
986 // impl note:
987 // fs->work is used for a temporary object index memory, listing found object ids and
988 // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
989 // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
990 // a reachable/unreachable object id.
991 memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
992 u32_t obj_id_log_ix = 0;
993 CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
994 res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
995 0, 0);
996 if (res == SPIFFS_VIS_END) {
997 res = SPIFFS_OK;
999 if (res != SPIFFS_OK) {
1000 CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
1002 CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
1003 return res;
1006 #endif // !SPIFFS_READ_ONLY