Filesystem library designed for flash devices

Dependents:   flash-fs-example Dragonfly_Filesystem_Example STM32F407VET6_SPIFlash Dragonfly_Filesystem_Example_mbed_5

Committer:
Leon Lindenfelser
Date:
Fri Jun 26 14:21:17 2020 -0500
Revision:
4:7a3c79b0d570
Parent:
2:de478b250060
Update to latest from Multitech git repo

1. Change "errno" to "err_code" to address ARM compiler errors
2. Feature: add move file support

Who changed what in which revision?

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