spiffs_check.c 43 KB

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