-

Committer:
aguscahya
Date:
Thu Apr 22 03:49:45 2021 +0000
Revision:
0:1f44439df816
-

Who changed what in which revision?

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