Merge pull request #2616 from jmichelp/fix14b
[RRG-proxmark3.git] / armsrc / spiffs_check.c
blobc59fcabef4c447c9246ac392182d649e0f148dbd
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.
5 //
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:
23 * Look up consistency
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.
29 * Page consistency
30 * Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
34 #include "spiffs.h"
35 #include "spiffs_nucleus.h"
37 #if !SPIFFS_READ_ONLY
39 #if SPIFFS_HAL_CALLBACK_EXTRA
40 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
41 do { \
42 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
43 } while (0)
44 #else
45 #define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
46 do { \
47 if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
48 } while (0)
49 #endif
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(
58 spiffs *fs,
59 spiffs_obj_id obj_id,
60 spiffs_span_ix data_spix,
61 spiffs_page_ix *pix,
62 spiffs_page_ix *objix_pix) {
63 s32_t res;
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);
77 } else {
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);
84 return res;
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) {
89 s32_t res;
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);
97 return 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) {
103 s32_t res;
104 spiffs_block_ix bix;
105 int entry;
106 spiffs_page_ix free_pix;
107 obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
109 // find free entry
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
118 entry = data_spix;
119 } else {
120 // calc entry in index
121 entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
124 // load index
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;
146 // rewrite in mem
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;
149 } else {
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),
159 (u8_t *)&obj_id);
160 SPIFFS_CHECK_RES(res);
161 res = spiffs_page_delete(fs, objix_pix);
163 return res;
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;
169 s32_t res;
170 res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);
171 if (res == SPIFFS_ERR_NOT_FOUND) {
172 return SPIFFS_OK;
174 SPIFFS_CHECK_RES(res);
175 u8_t flags = 0xff;
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);
181 #endif
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);
186 return res;
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) {
192 (void)cur_block;
193 (void)cur_entry;
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);
203 *reload_lu = 1;
204 delete_page = 1;
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
211 res = SPIFFS_OK;
212 } else {
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);
221 *reload_lu = 1;
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);
231 } else {
232 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
234 SPIFFS_CHECK_RES(res);
237 } else {
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);
251 *reload_lu = 1;
252 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
254 } else {
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);
263 delete_page = 1;
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
268 } else {
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
274 res = SPIFFS_OK;
275 } else {
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);
289 *reload_lu = 1;
290 CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
292 SPIFFS_CHECK_RES(res);
295 } else {
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) {
301 res = SPIFFS_OK;
302 objix_pix_lu = 0;
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) {
308 res = SPIFFS_OK;
309 objix_pix_ph = 0;
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) {
319 res = SPIFFS_OK;
320 objix_pix_lu = 0;
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) {
326 res = SPIFFS_OK;
327 objix_pix_ph = 0;
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);
344 *reload_lu = 1;
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);
354 *reload_lu = 1;
355 } else {
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) {
369 res = SPIFFS_OK;
370 data_pix = 0;
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) {
376 res = SPIFFS_OK;
377 objix_pix_d = 0;
379 SPIFFS_CHECK_RES(res);
381 delete_page = 1;
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);
385 } else
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);
401 } else
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);
417 } else {
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);
422 delete_page = 1;
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
426 *reload_lu = 1;
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
430 res = SPIFFS_OK;
431 delete_page = 1;
432 } else {
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);
436 delete_page = 1;
437 } else {
438 // page referenced by object index but not final
439 // just finalize
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);
442 u8_t flags = 0xff;
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);
448 #endif
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);
458 if (delete_page) {
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);
465 return 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) {
470 (void)user_const_p;
471 (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);
479 // load header
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);
484 int reload_lu = 0;
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;
492 return res;
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) {
507 res = SPIFFS_OK;
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);
516 return res;
519 //---------------------------------------
520 // Page consistency
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
526 // bit 3: unused
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
542 u8_t restart = 0;
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);
559 // read header
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;
569 if (within_range &&
570 (p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
571 // used
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
578 if (within_range) {
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;
591 int entries;
592 int i;
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));
599 } else {
600 // object page index
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))) {
614 // bad reference
615 SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n",
616 rpix, cur_pix);
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) {
622 res = SPIFFS_OK;
623 data_pix = 0;
625 SPIFFS_CHECK_RES(res);
626 if (data_pix == 0) {
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);
636 // remap index
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);
644 // delete file
645 res = spiffs_page_delete(fs, cur_pix);
646 } else {
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);
650 restart = 1;
652 } else if (rpix_within_range) {
654 // valid reference
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) {
674 res = SPIFFS_OK;
675 data_pix = 0;
677 SPIFFS_CHECK_RES(res);
678 if (data_pix == 0) {
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);
684 break;
685 } else {
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);
695 } else {
696 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
698 SPIFFS_CHECK_RES(res);
699 restart = 1;
701 } else {
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",
707 rpix, cur_pix);
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);
719 restart = 1;
721 fs->work[rpix_byte_ix] |= (1 << (rpix_bit_ix + 1));
724 } // for all index entries
725 } // found index
727 // next page
728 cur_pix++;
730 // next block
731 cur_block++;
733 // check consistency bitmap
734 if (!restart) {
735 spiffs_page_ix objix_pix;
736 spiffs_page_ix rpix;
738 u32_t byte_ix;
739 u8_t bit_ix;
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) {
749 // 001
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,
761 &rpix, &objix_pix);
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);
767 } else {
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);
778 delete_page = 1;
779 } else {
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 " : "",
787 cur_pix);
788 rewrite_ix_to_this = 1;
789 } else {
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);
796 delete_page = 1;
797 res = SPIFFS_OK;
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);
812 } else {
813 CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
815 SPIFFS_CHECK_RES(res);
816 restart = 1;
817 continue;
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) {
827 // 010
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) {
837 // 100
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) {
847 // 110
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) {
854 // 111
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);
864 // next page range
865 if (!restart) {
866 pix_offset += pages_per_scan;
868 } // while page range not reached end
869 return res;
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);
880 return res;
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) {
889 u32_t i;
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) {
894 return i;
897 return -1;
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) {
902 (void)user_const_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);
915 // load header
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);
928 return res_c;
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)) {
933 return res_c;
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);
939 if (r == -1) {
940 // not registered, do it
941 obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
942 (*log_ix)++;
943 if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
944 *log_ix = 0;
947 } else { // span index
948 // objix page, see if header can be found
949 int r = spiffs_object_index_search(fs, obj_id);
950 u8_t delete = 0;
951 if (r == -1) {
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
961 delete = 1;
962 obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
963 } else {
964 SPIFFS_CHECK_RES(res);
966 (*log_ix)++;
967 if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
968 *log_ix = 0;
970 } else {
971 // in temporary index, check reachable flag
972 if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
973 // registered as unreachable
974 delete = 1;
978 if (delete) {
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);
985 } // span index
986 } // valid object index id
988 return res_c;
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
994 // deleted.
995 s32_t spiffs_object_index_consistency_check(spiffs *fs) {
996 s32_t res = SPIFFS_OK;
997 // impl note:
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,
1006 0, 0);
1007 if (res == SPIFFS_VIS_END) {
1008 res = SPIFFS_OK;
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);
1014 return res;
1017 #endif // !SPIFFS_READ_ONLY