Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / examples / common / m5stack-tft / repo / components / spiffs / spiffs_check.c
1 /*
2  * spiffs_check.c
3  *
4  * Contains functionality for checking file system consistency
5  * and mending problems.
6  * Three levels of consistency checks are implemented:
7  *
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
16  *
17  *
18  *  Created on: Jul 7, 2013
19  *      Author: petera
20  */
21
22
23 #include "spiffs.h"
24 #include "spiffs_nucleus.h"
25
26 #if !SPIFFS_READ_ONLY
27
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
39
40 //---------------------------------------
41 // Look up consistency
42
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;
53
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);
56
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);
60
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);
69   }
70
71   res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);
72
73   return res;
74 }
75
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;
87 }
88
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;
97
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);
102
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);
111
112   }
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;
118
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;
123   }
124   if (objix_p_hdr->span_ix != objix_spix) {
125     spiffs_page_delete(fs, free_pix);
126     return SPIFFS_ERR_CHECK_SPIX_MISM;
127   }
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;
133   }
134
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;
140   }
141
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);
151
152   return res;
153 }
154
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;
162   }
163   SPIFFS_CHECK_RES(res);
164   u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;
165   res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
166       0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
167       sizeof(u8_t),
168       (u8_t *)&flags);
169   return res;
170 }
171
172 // validates the given look up entry
173 static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
174     spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
175   (void)cur_block;
176   (void)cur_entry;
177   u8_t delete_page = 0;
178   s32_t res = SPIFFS_OK;
179   spiffs_page_ix objix_pix;
180   spiffs_page_ix ref_pix;
181   // check validity, take actions
182   if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||
183       ((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {
184     // look up entry deleted / free but used in page header
185     SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" deleted/free in lu but not on page\n", cur_pix);
186     *reload_lu = 1;
187     delete_page = 1;
188     if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
189       // header says data page
190       // data page can be removed if not referenced by some object index
191       res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
192       if (res == SPIFFS_ERR_NOT_FOUND) {
193         // no object with this id, so remove page safely
194         res = SPIFFS_OK;
195       } else {
196         SPIFFS_CHECK_RES(res);
197         if (ref_pix == cur_pix) {
198           // data page referenced by object index but deleted in lu
199           // copy page to new place and re-write the object index to new place
200           spiffs_page_ix new_pix;
201           res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
202           SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
203           SPIFFS_CHECK_RES(res);
204           *reload_lu = 1;
205           SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg" rewritten to "_SPIPRIpg", affected objix_pix "_SPIPRIpg"\n", cur_pix, new_pix, objix_pix);
206           res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
207           if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
208             // index bad also, cannot mend this file
209             SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
210             res = spiffs_page_delete(fs, new_pix);
211             SPIFFS_CHECK_RES(res);
212             res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
213             CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
214           } else {
215             CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
216           }
217           SPIFFS_CHECK_RES(res);
218         }
219       }
220     } else {
221       // header says index page
222       // index page can be removed if other index with same obj_id and spanix is found
223       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);
224       if (res == SPIFFS_ERR_NOT_FOUND) {
225         // no such index page found, check for a data page amongst page headers
226         // lu cannot be trusted
227         res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);
228         if (res == SPIFFS_OK) { // ignore other errors
229           // got a data page also, assume lu corruption only, rewrite to new page
230           spiffs_page_ix new_pix;
231           res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
232           SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
233           SPIFFS_CHECK_RES(res);
234           *reload_lu = 1;
235           CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
236         }
237       } else {
238         SPIFFS_CHECK_RES(res);
239       }
240     }
241   }
242   if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {
243     // look up entry used
244     if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {
245       SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" differ in obj_id lu:"_SPIPRIid" ph:"_SPIPRIid"\n", cur_pix, lu_obj_id, p_hdr->obj_id);
246       delete_page = 1;
247       if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||
248           (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||
249           (p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {
250         // page deleted or not finalized, just remove it
251       } else {
252         if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
253           // if data page, check for reference to this page
254           res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
255           if (res == SPIFFS_ERR_NOT_FOUND) {
256             // no object with this id, so remove page safely
257             res = SPIFFS_OK;
258           } else {
259             SPIFFS_CHECK_RES(res);
260             //   if found, rewrite page with object id, update index, and delete current
261             if (ref_pix == cur_pix) {
262               spiffs_page_ix new_pix;
263               res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
264               SPIFFS_CHECK_RES(res);
265               res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
266               if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
267                 // index bad also, cannot mend this file
268                 SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
269                 res = spiffs_page_delete(fs, new_pix);
270                 SPIFFS_CHECK_RES(res);
271                 res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
272                 *reload_lu = 1;
273                 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
274               }
275               SPIFFS_CHECK_RES(res);
276             }
277           }
278         } else {
279           // else if index, check for other pages with both obj_id's and spanix
280           spiffs_page_ix objix_pix_lu, objix_pix_ph;
281           // see if other object index page exists for lookup obj id and span index
282           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);
283           if (res == SPIFFS_ERR_NOT_FOUND) {
284             res = SPIFFS_OK;
285             objix_pix_lu = 0;
286           }
287           SPIFFS_CHECK_RES(res);
288           // see if other object index exists for page header obj id and span index
289           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);
290           if (res == SPIFFS_ERR_NOT_FOUND) {
291             res = SPIFFS_OK;
292             objix_pix_ph = 0;
293           }
294           SPIFFS_CHECK_RES(res);
295           //   if both obj_id's found, just delete current
296           if (objix_pix_ph == 0 || objix_pix_lu == 0) {
297             // otherwise try finding first corresponding data pages
298             spiffs_page_ix data_pix_lu, data_pix_ph;
299             // see if other data page exists for look up obj id and span index
300             res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);
301             if (res == SPIFFS_ERR_NOT_FOUND) {
302               res = SPIFFS_OK;
303               objix_pix_lu = 0;
304             }
305             SPIFFS_CHECK_RES(res);
306             // see if other data page exists for page header obj id and span index
307             res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);
308             if (res == SPIFFS_ERR_NOT_FOUND) {
309               res = SPIFFS_OK;
310               objix_pix_ph = 0;
311             }
312             SPIFFS_CHECK_RES(res);
313
314             spiffs_page_header new_ph;
315             new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);
316             new_ph.span_ix = p_hdr->span_ix;
317             spiffs_page_ix new_pix;
318             if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||
319                 (objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {
320               //   got a data page for page header obj id
321               //   rewrite as obj_id_ph
322               new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
323               res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
324               SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid" to pix "_SPIPRIpg"\n", cur_pix, new_ph.obj_id, new_pix);
325               CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
326               SPIFFS_CHECK_RES(res);
327               *reload_lu = 1;
328             } else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
329                 (objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {
330               //   got a data page for look up obj id
331               //   rewrite as obj_id_lu
332               new_ph.obj_id =  lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
333               SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid"\n", cur_pix, new_ph.obj_id);
334               CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
335               res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
336               SPIFFS_CHECK_RES(res);
337               *reload_lu = 1;
338             } else {
339               // cannot safely do anything
340               SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n");
341             }
342           }
343         }
344       }
345     } else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||
346         ((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {
347       SPIFFS_CHECK_DBG("LU: "_SPIPRIpg" lu/page index marking differ\n", cur_pix);
348       spiffs_page_ix data_pix, objix_pix_d;
349       // see if other data page exists for given obj id and span index
350       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);
351       if (res == SPIFFS_ERR_NOT_FOUND) {
352         res = SPIFFS_OK;
353         data_pix = 0;
354       }
355       SPIFFS_CHECK_RES(res);
356       // see if other object index exists for given obj id and span index
357       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);
358       if (res == SPIFFS_ERR_NOT_FOUND) {
359         res = SPIFFS_OK;
360         objix_pix_d = 0;
361       }
362       SPIFFS_CHECK_RES(res);
363
364       delete_page = 1;
365       // if other data page exists and object index exists, just delete page
366       if (data_pix && objix_pix_d) {
367         SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n");
368       } else
369       // if only data page exists, make this page index
370       if (data_pix && objix_pix_d == 0) {
371         SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
372         CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
373         spiffs_page_header new_ph;
374         spiffs_page_ix new_pix;
375         new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
376         new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
377         new_ph.span_ix = p_hdr->span_ix;
378         res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
379         SPIFFS_CHECK_RES(res);
380         res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
381             SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
382             SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
383         SPIFFS_CHECK_RES(res);
384       } else
385       // if only index exists, make data page
386       if (data_pix == 0 && objix_pix_d) {
387         SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
388         CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
389         spiffs_page_header new_ph;
390         spiffs_page_ix new_pix;
391         new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
392         new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
393         new_ph.span_ix = p_hdr->span_ix;
394         res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
395         SPIFFS_CHECK_RES(res);
396         res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
397             SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
398             SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
399         SPIFFS_CHECK_RES(res);
400       } else {
401         // if nothing exists, we cannot safely make a decision - delete
402       }
403     }
404     else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
405       SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy in lu but deleted on page\n", cur_pix);
406       delete_page = 1;
407     } else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
408       SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy but not final\n", cur_pix);
409       // page can be removed if not referenced by object index
410       *reload_lu = 1;
411       res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
412       if (res == SPIFFS_ERR_NOT_FOUND) {
413         // no object with this id, so remove page safely
414         res = SPIFFS_OK;
415         delete_page = 1;
416       } else {
417         SPIFFS_CHECK_RES(res);
418         if (ref_pix != cur_pix) {
419           SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n");
420           delete_page = 1;
421         } else {
422           // page referenced by object index but not final
423           // just finalize
424           SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
425           CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
426           u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
427           res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
428               0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
429               sizeof(u8_t), (u8_t*)&flags);
430         }
431       }
432     }
433   }
434
435   if (delete_page) {
436     SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
437     CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
438     res = spiffs_page_delete(fs, cur_pix);
439     SPIFFS_CHECK_RES(res);
440   }
441
442   return res;
443 }
444
445 static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
446     const void *user_const_p, void *user_var_p) {
447   (void)user_const_p;
448   (void)user_var_p;
449   s32_t res = SPIFFS_OK;
450   spiffs_page_header p_hdr;
451   spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
452
453   CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
454       (cur_block * 256)/fs->block_count, 0);
455
456   // load header
457   res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
458       0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
459   SPIFFS_CHECK_RES(res);
460
461   int reload_lu = 0;
462
463   res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
464   SPIFFS_CHECK_RES(res);
465
466   if (res == SPIFFS_OK) {
467     return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;
468   }
469   return res;
470 }
471
472
473 // Scans all object look up. For each entry, corresponding page header is checked for validity.
474 // If an object index header page is found, this is also checked
475 s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
476   (void)check_all_objects;
477   s32_t res = SPIFFS_OK;
478
479   CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
480
481   res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
482
483   if (res == SPIFFS_VIS_END) {
484     res = SPIFFS_OK;
485   }
486
487   if (res != SPIFFS_OK) {
488     CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
489   }
490
491   CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
492
493   return res;
494 }
495
496 //---------------------------------------
497 // Page consistency
498
499 // Scans all pages (except lu pages), reserves 4 bits in working memory for each page
500 // bit 0: 0 == FREE|DELETED, 1 == USED
501 // bit 1: 0 == UNREFERENCED, 1 == REFERENCED
502 // bit 2: 0 == NOT_INDEX,    1 == INDEX
503 // bit 3: unused
504 // A consistent file system will have only pages being
505 //  * x000 free, unreferenced, not index
506 //  * x011 used, referenced only once, not index
507 //  * x101 used, unreferenced, index
508 // The working memory might not fit all pages so several scans might be needed
509 static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
510   const u32_t bits = 4;
511   const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;
512
513   s32_t res = SPIFFS_OK;
514   spiffs_page_ix pix_offset = 0;
515
516   // for each range of pages fitting into work memory
517   while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
518     // set this flag to abort all checks and rescan the page range
519     u8_t restart = 0;
520     memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
521
522     spiffs_block_ix cur_block = 0;
523     // build consistency bitmap for id range traversing all blocks
524     while (!restart && cur_block < fs->block_count) {
525       CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
526           (pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
527           ((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
528           0);
529       // traverse each page except for lookup pages
530       spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
531       while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
532         //if ((cur_pix & 0xff) == 0)
533         //  SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
534         //      cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
535
536         // read header
537         spiffs_page_header p_hdr;
538         res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
539             0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
540         SPIFFS_CHECK_RES(res);
541
542         u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);
543         const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);
544         const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;
545
546         if (within_range &&
547             (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
548           // used
549           fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));
550         }
551         if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&
552             (p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&
553             (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {
554           // found non-deleted index
555           if (within_range) {
556             fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));
557           }
558
559           // load non-deleted index
560           res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
561               0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
562           SPIFFS_CHECK_RES(res);
563
564           // traverse index for referenced pages
565           spiffs_page_ix *object_page_index;
566           spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
567
568           int entries;
569           int i;
570           spiffs_span_ix data_spix_offset;
571           if (p_hdr.span_ix == 0) {
572             // object header page index
573             entries = SPIFFS_OBJ_HDR_IX_LEN(fs);
574             data_spix_offset = 0;
575             object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));
576           } else {
577             // object page index
578             entries = SPIFFS_OBJ_IX_LEN(fs);
579             data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);
580             object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));
581           }
582
583           // for all entries in index
584           for (i = 0; !restart && i < entries; i++) {
585             spiffs_page_ix rpix = object_page_index[i];
586             u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;
587
588             if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))
589                 || (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {
590
591               // bad reference
592               SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n",
593                   rpix, cur_pix);
594               // check for data page elsewhere
595               spiffs_page_ix data_pix;
596               res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
597                   data_spix_offset + i, 0, &data_pix);
598               if (res == SPIFFS_ERR_NOT_FOUND) {
599                 res = SPIFFS_OK;
600                 data_pix = 0;
601               }
602               SPIFFS_CHECK_RES(res);
603               if (data_pix == 0) {
604                 // if not, allocate free page
605                 spiffs_page_header new_ph;
606                 new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
607                 new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
608                 new_ph.span_ix = data_spix_offset + i;
609                 res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);
610                 SPIFFS_CHECK_RES(res);
611                 SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg"\n", data_pix);
612               }
613               // remap index
614               SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg"\n", cur_pix);
615               res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
616                   data_spix_offset + i, data_pix, cur_pix);
617               if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
618                 // index bad also, cannot mend this file
619                 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend - delete object\n", res);
620                 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
621                 // delete file
622                 res = spiffs_page_delete(fs, cur_pix);
623               } else {
624                 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
625               }
626               SPIFFS_CHECK_RES(res);
627               restart = 1;
628
629             } else if (rpix_within_range) {
630
631               // valid reference
632               // read referenced page header
633               spiffs_page_header rp_hdr;
634               res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
635                   0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
636               SPIFFS_CHECK_RES(res);
637
638               // cross reference page header check
639               if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||
640                   rp_hdr.span_ix != data_spix_offset + i ||
641                   (rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=
642                       (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {
643                SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" has inconsistent page header ix id/span:"_SPIPRIid"/"_SPIPRIsp", ref id/span:"_SPIPRIid"/"_SPIPRIsp" flags:"_SPIPRIfl"\n",
644                     rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,
645                     rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);
646                // try finding correct page
647                spiffs_page_ix data_pix;
648                res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
649                    data_spix_offset + i, rpix, &data_pix);
650                if (res == SPIFFS_ERR_NOT_FOUND) {
651                  res = SPIFFS_OK;
652                  data_pix = 0;
653                }
654                SPIFFS_CHECK_RES(res);
655                if (data_pix == 0) {
656                  // not found, this index is badly borked
657                  SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid"\n", p_hdr.obj_id);
658                  CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
659                  res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
660                  SPIFFS_CHECK_RES(res);
661                  break;
662                } else {
663                  // found it, so rewrite index
664                  SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg", rewrite ix pix "_SPIPRIpg" id "_SPIPRIid"\n",
665                      data_pix, cur_pix, p_hdr.obj_id);
666                  res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
667                  if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
668                    // index bad also, cannot mend this file
669                    SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
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                  } else {
673                    CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
674                  }
675                  SPIFFS_CHECK_RES(res);
676                  restart = 1;
677                }
678               }
679               else {
680                 // mark rpix as referenced
681                 const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);
682                 const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;
683                 if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {
684                   SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" multiple referenced from page "_SPIPRIpg"\n",
685                       rpix, cur_pix);
686                   // Here, we should have fixed all broken references - getting this means there
687                   // must be multiple files with same object id. Only solution is to delete
688                   // the object which is referring to this page
689                   SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid" and page "_SPIPRIpg"\n",
690                       p_hdr.obj_id, cur_pix);
691                   CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
692                   res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
693                   SPIFFS_CHECK_RES(res);
694                   // extra precaution, delete this page also
695                   res = spiffs_page_delete(fs, cur_pix);
696                   SPIFFS_CHECK_RES(res);
697                   restart = 1;
698                 }
699                 fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));
700               }
701             }
702           } // for all index entries
703         } // found index
704
705         // next page
706         cur_pix++;
707       }
708       // next block
709       cur_block++;
710     }
711     // check consistency bitmap
712     if (!restart) {
713       spiffs_page_ix objix_pix;
714       spiffs_page_ix rpix;
715
716       u32_t byte_ix;
717       u8_t bit_ix;
718       for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {
719         for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {
720           u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;
721           spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;
722
723           // 000 ok - free, unreferenced, not index
724
725           if (bitmask == 0x1) {
726
727             // 001
728             SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, UNREFERENCED, not index\n", cur_pix);
729
730             u8_t rewrite_ix_to_this = 0;
731             u8_t delete_page = 0;
732             // check corresponding object index entry
733             spiffs_page_header p_hdr;
734             res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
735                 0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
736             SPIFFS_CHECK_RES(res);
737
738             res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,
739                 &rpix, &objix_pix);
740             if (res == SPIFFS_OK) {
741               if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {
742                 // pointing to a bad page altogether, rewrite index to this
743                 rewrite_ix_to_this = 1;
744                 SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg", rewrite to this "_SPIPRIpg"\n", rpix, cur_pix);
745               } else {
746                 // pointing to something else, check what
747                 spiffs_page_header rp_hdr;
748                 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
749                     0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
750                 SPIFFS_CHECK_RES(res);
751                 if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&
752                     ((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==
753                         (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {
754                   // pointing to something else valid, just delete this page then
755                   SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg", delete this "_SPIPRIpg"\n", rpix, cur_pix);
756                   delete_page = 1;
757                 } else {
758                   // pointing to something weird, update index to point to this page instead
759                   if (rpix != cur_pix) {
760                     SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg" %s%s%s%s, rewrite this "_SPIPRIpg"\n", rpix,
761                         (rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ",
762                             (rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ",
763                                 (rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "",
764                                     (rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "",
765                         cur_pix);
766                     rewrite_ix_to_this = 1;
767                   } else {
768                     // should not happen, destined for fubar
769                   }
770                 }
771               }
772             } else if (res == SPIFFS_ERR_NOT_FOUND) {
773               SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg"\n", cur_pix);
774               delete_page = 1;
775               res = SPIFFS_OK;
776             }
777
778             if (rewrite_ix_to_this) {
779               // if pointing to invalid page, redirect index to this page
780               SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid" data spix "_SPIPRIsp" to point to this pix: "_SPIPRIpg"\n",
781                   p_hdr.obj_id, p_hdr.span_ix, cur_pix);
782               res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
783               if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
784                 // index bad also, cannot mend this file
785                 SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
786                 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
787                 res = spiffs_page_delete(fs, cur_pix);
788                 SPIFFS_CHECK_RES(res);
789                 res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
790               } else {
791                 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
792               }
793               SPIFFS_CHECK_RES(res);
794               restart = 1;
795               continue;
796             } else if (delete_page) {
797               SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
798               CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
799               res = spiffs_page_delete(fs, cur_pix);
800             }
801             SPIFFS_CHECK_RES(res);
802           }
803           if (bitmask == 0x2) {
804
805             // 010
806             SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, not index\n", cur_pix);
807
808             // no op, this should be taken care of when checking valid references
809           }
810
811           // 011 ok - busy, referenced, not index
812
813           if (bitmask == 0x4) {
814
815             // 100
816             SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, unreferenced, INDEX\n", cur_pix);
817
818             // this should never happen, major fubar
819           }
820
821           // 101 ok - busy, unreferenced, index
822
823           if (bitmask == 0x6) {
824
825             // 110
826             SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, INDEX\n", cur_pix);
827
828             // no op, this should be taken care of when checking valid references
829           }
830           if (bitmask == 0x7) {
831
832             // 111
833             SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, REFERENCED, INDEX\n", cur_pix);
834
835             // no op, this should be taken care of when checking valid references
836           }
837         }
838       }
839     }
840
841     SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg", restart "_SPIPRIi"\n", pix_offset, restart);
842     // next page range
843     if (!restart) {
844       pix_offset += pages_per_scan;
845     }
846   } // while page range not reached end
847   return res;
848 }
849
850 // Checks consistency amongst all pages and fixes irregularities
851 s32_t spiffs_page_consistency_check(spiffs *fs) {
852   CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
853   s32_t res = spiffs_page_consistency_check_i(fs);
854   if (res != SPIFFS_OK) {
855     CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
856   }
857   CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
858   return res;
859 }
860
861 //---------------------------------------
862 // Object index consistency
863
864 // searches for given object id in temporary object id index,
865 // returns the index or -1
866 static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
867   u32_t i;
868   spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
869   obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
870   for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {
871     if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {
872       return i;
873     }
874   }
875   return -1;
876 }
877
878 static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
879     int cur_entry, const void *user_const_p, void *user_var_p) {
880   (void)user_const_p;
881   s32_t res_c = SPIFFS_VIS_COUNTINUE;
882   s32_t res = SPIFFS_OK;
883   u32_t *log_ix = (u32_t*)user_var_p;
884   spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
885
886   CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
887       (cur_block * 256)/fs->block_count, 0);
888
889   if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
890     spiffs_page_header p_hdr;
891     spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
892
893     // load header
894     res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
895         0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
896     SPIFFS_CHECK_RES(res);
897
898     if (p_hdr.span_ix == 0 &&
899         (p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
900         (SPIFFS_PH_FLAG_DELET)) {
901       SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" header not fully deleted - deleting\n",
902           cur_pix, obj_id, p_hdr.span_ix);
903       CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
904       res = spiffs_page_delete(fs, cur_pix);
905       SPIFFS_CHECK_RES(res);
906       return res_c;
907     }
908
909     if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
910         (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
911       return res_c;
912     }
913
914     if (p_hdr.span_ix == 0) {
915       // objix header page, register objid as reachable
916       int r = spiffs_object_index_search(fs, obj_id);
917       if (r == -1) {
918         // not registered, do it
919         obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
920         (*log_ix)++;
921         if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
922           *log_ix = 0;
923         }
924       }
925     } else { // span index
926       // objix page, see if header can be found
927       int r = spiffs_object_index_search(fs, obj_id);
928       u8_t delete = 0;
929       if (r == -1) {
930         // not in temporary index, try finding it
931         spiffs_page_ix objix_hdr_pix;
932         res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);
933         res_c = SPIFFS_VIS_COUNTINUE_RELOAD;
934         if (res == SPIFFS_OK) {
935           // found, register as reachable
936           obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
937         } else if (res == SPIFFS_ERR_NOT_FOUND) {
938           // not found, register as unreachable
939           delete = 1;
940           obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
941         } else {
942           SPIFFS_CHECK_RES(res);
943         }
944         (*log_ix)++;
945         if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
946           *log_ix = 0;
947         }
948       } else {
949         // in temporary index, check reachable flag
950         if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
951           // registered as unreachable
952           delete = 1;
953         }
954       }
955
956       if (delete) {
957         SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" is orphan index - deleting\n",
958             cur_pix, obj_id, p_hdr.span_ix);
959         CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
960         res = spiffs_page_delete(fs, cur_pix);
961         SPIFFS_CHECK_RES(res);
962       }
963     } // span index
964   } // valid object index id
965
966   return res_c;
967 }
968
969 // Removes orphaned and partially deleted index pages.
970 // Scans for index pages. When an index page is found, corresponding index header is searched for.
971 // If no such page exists, the index page cannot be reached as no index header exists and must be
972 // deleted.
973 s32_t spiffs_object_index_consistency_check(spiffs *fs) {
974   s32_t res = SPIFFS_OK;
975   // impl note:
976   // fs->work is used for a temporary object index memory, listing found object ids and
977   // indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
978   // In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
979   // a reachable/unreachable object id.
980   memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
981   u32_t obj_id_log_ix = 0;
982   CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
983   res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
984         0, 0);
985   if (res == SPIFFS_VIS_END) {
986     res = SPIFFS_OK;
987   }
988   if (res != SPIFFS_OK) {
989     CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
990   }
991   CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
992   return res;
993 }
994
995 #endif // !SPIFFS_READ_ONLY