spiffs_check.c 43 KB

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