spiffs_nucleus.c 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899
  1. #include "spiffs.h"
  2. #include "spiffs_nucleus.h"
  3. static s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {
  4. s32_t res = SPIFFS_OK;
  5. if (pix == (spiffs_page_ix)-1) {
  6. // referring to page 0xffff...., bad object index
  7. return SPIFFS_ERR_INDEX_REF_FREE;
  8. }
  9. if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
  10. // referring to an object lookup page, bad object index
  11. return SPIFFS_ERR_INDEX_REF_LU;
  12. }
  13. if (pix > SPIFFS_MAX_PAGES(fs)) {
  14. // referring to a bad page
  15. return SPIFFS_ERR_INDEX_REF_INVALID;
  16. }
  17. #if SPIFFS_PAGE_CHECK
  18. spiffs_page_header ph;
  19. res = _spiffs_rd(
  20. fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
  21. fd->file_nbr,
  22. SPIFFS_PAGE_TO_PADDR(fs, pix),
  23. sizeof(spiffs_page_header),
  24. (u8_t *)&ph);
  25. SPIFFS_CHECK_RES(res);
  26. SPIFFS_VALIDATE_DATA(ph, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, spix);
  27. #endif
  28. return res;
  29. }
  30. static s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {
  31. s32_t res = SPIFFS_OK;
  32. if (pix == (spiffs_page_ix)-1) {
  33. // referring to page 0xffff...., bad object index
  34. return SPIFFS_ERR_INDEX_FREE;
  35. }
  36. if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
  37. // referring to an object lookup page, bad object index
  38. return SPIFFS_ERR_INDEX_LU;
  39. }
  40. if (pix > SPIFFS_MAX_PAGES(fs)) {
  41. // referring to a bad page
  42. return SPIFFS_ERR_INDEX_INVALID;
  43. }
  44. #if SPIFFS_PAGE_CHECK
  45. spiffs_page_header ph;
  46. res = _spiffs_rd(
  47. fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  48. fd->file_nbr,
  49. SPIFFS_PAGE_TO_PADDR(fs, pix),
  50. sizeof(spiffs_page_header),
  51. (u8_t *)&ph);
  52. SPIFFS_CHECK_RES(res);
  53. SPIFFS_VALIDATE_OBJIX(ph, fd->obj_id, spix);
  54. #endif
  55. return res;
  56. }
  57. #if !SPIFFS_CACHE
  58. s32_t spiffs_phys_rd(
  59. spiffs *fs,
  60. u32_t addr,
  61. u32_t len,
  62. u8_t *dst) {
  63. return fs->cfg.hal_read_f(addr, len, dst);
  64. }
  65. s32_t spiffs_phys_wr(
  66. spiffs *fs,
  67. u32_t addr,
  68. u32_t len,
  69. u8_t *src) {
  70. return fs->cfg.hal_write_f(addr, len, src);
  71. }
  72. #endif
  73. s32_t spiffs_phys_cpy(
  74. spiffs *fs,
  75. spiffs_file fh,
  76. u32_t dst,
  77. u32_t src,
  78. u32_t len) {
  79. s32_t res;
  80. u8_t b[SPIFFS_COPY_BUFFER_STACK];
  81. while (len > 0) {
  82. u32_t chunk_size = MIN(SPIFFS_COPY_BUFFER_STACK, len);
  83. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVS, fh, src, chunk_size, b);
  84. SPIFFS_CHECK_RES(res);
  85. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVD, fh, dst, chunk_size, b);
  86. SPIFFS_CHECK_RES(res);
  87. len -= chunk_size;
  88. src += chunk_size;
  89. dst += chunk_size;
  90. }
  91. return SPIFFS_OK;
  92. }
  93. // Find object lookup entry containing given id with visitor.
  94. // Iterate over object lookup pages in each block until a given object id entry is found.
  95. // When found, the visitor function is called with block index, entry index and user_data.
  96. // If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be
  97. // ended and visitor's return code is returned to caller.
  98. // If no visitor is given (0) the search returns on first entry with matching object id.
  99. // If no match is found in all look up, SPIFFS_VIS_END is returned.
  100. // @param fs the file system
  101. // @param starting_block the starting block to start search in
  102. // @param starting_lu_entry the look up index entry to start search in
  103. // @param flags ored combination of SPIFFS_VIS_CHECK_ID, SPIFFS_VIS_CHECK_PH,
  104. // SPIFFS_VIS_NO_WRAP
  105. // @param obj_id argument object id
  106. // @param v visitor callback function
  107. // @param user_data any data, passed to the callback visitor function
  108. // @param user_p any pointer, passed to the callback visitor function
  109. // @param block_ix reported block index where match was found
  110. // @param lu_entry reported look up index where match was found
  111. s32_t spiffs_obj_lu_find_entry_visitor(
  112. spiffs *fs,
  113. spiffs_block_ix starting_block,
  114. int starting_lu_entry,
  115. u8_t flags,
  116. spiffs_obj_id obj_id,
  117. spiffs_visitor_f v,
  118. u32_t user_data,
  119. void *user_p,
  120. spiffs_block_ix *block_ix,
  121. int *lu_entry) {
  122. s32_t res = SPIFFS_OK;
  123. s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs);
  124. spiffs_block_ix cur_block = starting_block;
  125. u32_t cur_block_addr = starting_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);
  126. spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
  127. int cur_entry = starting_lu_entry;
  128. int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
  129. // wrap initial
  130. if (cur_entry >= (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) - 1) {
  131. cur_entry = 0;
  132. cur_block++;
  133. cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);
  134. if (cur_block >= fs->block_count) {
  135. if (flags & SPIFFS_VIS_NO_WRAP) {
  136. return SPIFFS_VIS_END;
  137. } else {
  138. // block wrap
  139. cur_block = 0;
  140. cur_block_addr = 0;
  141. }
  142. }
  143. }
  144. // check each block
  145. while (res == SPIFFS_OK && entry_count > 0) {
  146. int obj_lookup_page = cur_entry / entries_per_page;
  147. // check each object lookup page
  148. while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
  149. int entry_offset = obj_lookup_page * entries_per_page;
  150. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
  151. 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
  152. // check each entry
  153. while (res == SPIFFS_OK &&
  154. cur_entry - entry_offset < entries_per_page && // for non-last obj lookup pages
  155. cur_entry < (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) // for last obj lookup page
  156. {
  157. if ((flags & SPIFFS_VIS_CHECK_ID) == 0 || obj_lu_buf[cur_entry-entry_offset] == obj_id) {
  158. if (block_ix) *block_ix = cur_block;
  159. if (lu_entry) *lu_entry = cur_entry;
  160. if (v) {
  161. res = v(
  162. fs,
  163. (flags & SPIFFS_VIS_CHECK_PH) ? obj_id : obj_lu_buf[cur_entry-entry_offset],
  164. cur_block,
  165. cur_entry,
  166. user_data,
  167. user_p);
  168. if (res == SPIFFS_VIS_COUNTINUE || res == SPIFFS_VIS_COUNTINUE_RELOAD) {
  169. if (res == SPIFFS_VIS_COUNTINUE_RELOAD) {
  170. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
  171. 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
  172. SPIFFS_CHECK_RES(res);
  173. }
  174. res = SPIFFS_OK;
  175. cur_entry++;
  176. entry_count--;
  177. continue;
  178. } else {
  179. return res;
  180. }
  181. } else {
  182. return SPIFFS_OK;
  183. }
  184. }
  185. entry_count--;
  186. cur_entry++;
  187. } // per entry
  188. obj_lookup_page++;
  189. } // per object lookup page
  190. cur_entry = 0;
  191. cur_block++;
  192. cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
  193. if (cur_block >= fs->block_count) {
  194. if (flags & SPIFFS_VIS_NO_WRAP) {
  195. return SPIFFS_VIS_END;
  196. } else {
  197. // block wrap
  198. cur_block = 0;
  199. cur_block_addr = 0;
  200. }
  201. }
  202. } // per block
  203. SPIFFS_CHECK_RES(res);
  204. return SPIFFS_VIS_END;
  205. }
  206. s32_t spiffs_erase_block(
  207. spiffs *fs,
  208. spiffs_block_ix bix) {
  209. s32_t res;
  210. u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix);
  211. s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);
  212. // here we ignore res, just try erasing the block
  213. while (size > 0) {
  214. SPIFFS_DBG("erase %08x:%08x\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
  215. (void)fs->cfg.hal_erase_f(addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
  216. addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
  217. size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
  218. }
  219. fs->free_blocks++;
  220. // register erase count for this block
  221. res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,
  222. SPIFFS_ERASE_COUNT_PADDR(fs, bix),
  223. sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count);
  224. SPIFFS_CHECK_RES(res);
  225. #if SPIFFS_USE_MAGIC
  226. // finally, write magic
  227. spiffs_obj_id magic = SPIFFS_MAGIC(fs);
  228. res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,
  229. SPIFFS_MAGIC_PADDR(fs, bix),
  230. sizeof(spiffs_obj_id), (u8_t *)&magic);
  231. SPIFFS_CHECK_RES(res);
  232. #endif
  233. fs->max_erase_count++;
  234. if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) {
  235. fs->max_erase_count = 0;
  236. }
  237. return res;
  238. }
  239. static s32_t spiffs_obj_lu_scan_v(
  240. spiffs *fs,
  241. spiffs_obj_id obj_id,
  242. spiffs_block_ix bix,
  243. int ix_entry,
  244. u32_t user_data,
  245. void *user_p) {
  246. (void)bix;
  247. (void)user_data;
  248. (void)user_p;
  249. if (obj_id == SPIFFS_OBJ_ID_FREE) {
  250. if (ix_entry == 0) {
  251. fs->free_blocks++;
  252. // todo optimize further, return SPIFFS_NEXT_BLOCK
  253. }
  254. } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
  255. fs->stats_p_deleted++;
  256. } else {
  257. fs->stats_p_allocated++;
  258. }
  259. return SPIFFS_VIS_COUNTINUE;
  260. }
  261. // Scans thru all obj lu and counts free, deleted and used pages
  262. // Find the maximum block erase count
  263. // Checks magic if enabled
  264. s32_t spiffs_obj_lu_scan(
  265. spiffs *fs) {
  266. s32_t res;
  267. spiffs_block_ix bix;
  268. int entry;
  269. #if SPIFFS_USE_MAGIC
  270. spiffs_block_ix unerased_bix = (spiffs_block_ix)-1;
  271. #endif
  272. // find out erase count
  273. // if enabled, check magic
  274. bix = 0;
  275. spiffs_obj_id erase_count_final;
  276. spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE;
  277. spiffs_obj_id erase_count_max = 0;
  278. while (bix < fs->block_count) {
  279. #if SPIFFS_USE_MAGIC
  280. spiffs_obj_id magic;
  281. res = _spiffs_rd(fs,
  282. SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  283. 0, SPIFFS_MAGIC_PADDR(fs, bix) ,
  284. sizeof(spiffs_obj_id), (u8_t *)&magic);
  285. SPIFFS_CHECK_RES(res);
  286. if (magic != SPIFFS_MAGIC(fs)) {
  287. if (unerased_bix == (spiffs_block_ix)-1) {
  288. // allow one unerased block as it might be powered down during an erase
  289. unerased_bix = bix;
  290. } else {
  291. // more than one unerased block, bail out
  292. SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS);
  293. }
  294. }
  295. #endif
  296. spiffs_obj_id erase_count;
  297. res = _spiffs_rd(fs,
  298. SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  299. 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix) ,
  300. sizeof(spiffs_obj_id), (u8_t *)&erase_count);
  301. SPIFFS_CHECK_RES(res);
  302. if (erase_count != SPIFFS_OBJ_ID_FREE) {
  303. erase_count_min = MIN(erase_count_min, erase_count);
  304. erase_count_max = MAX(erase_count_max, erase_count);
  305. }
  306. bix++;
  307. }
  308. if (erase_count_min == 0 && erase_count_max == SPIFFS_OBJ_ID_FREE) {
  309. // clean system, set counter to zero
  310. erase_count_final = 0;
  311. } else if (erase_count_max - erase_count_min > (SPIFFS_OBJ_ID_FREE)/2) {
  312. // wrap, take min
  313. erase_count_final = erase_count_min+1;
  314. } else {
  315. erase_count_final = erase_count_max+1;
  316. }
  317. fs->max_erase_count = erase_count_final;
  318. #if SPIFFS_USE_MAGIC
  319. if (unerased_bix != (spiffs_block_ix)-1) {
  320. // found one unerased block, remedy
  321. SPIFFS_DBG("mount: erase block %i\n", bix);
  322. res = spiffs_erase_block(fs, unerased_bix);
  323. SPIFFS_CHECK_RES(res);
  324. }
  325. #endif
  326. // count blocks
  327. fs->free_blocks = 0;
  328. fs->stats_p_allocated = 0;
  329. fs->stats_p_deleted = 0;
  330. res = spiffs_obj_lu_find_entry_visitor(fs,
  331. 0,
  332. 0,
  333. 0,
  334. 0,
  335. spiffs_obj_lu_scan_v,
  336. 0,
  337. 0,
  338. &bix,
  339. &entry);
  340. if (res == SPIFFS_VIS_END) {
  341. res = SPIFFS_OK;
  342. }
  343. SPIFFS_CHECK_RES(res);
  344. return res;
  345. }
  346. // Find free object lookup entry
  347. // Iterate over object lookup pages in each block until a free object id entry is found
  348. s32_t spiffs_obj_lu_find_free(
  349. spiffs *fs,
  350. spiffs_block_ix starting_block,
  351. int starting_lu_entry,
  352. spiffs_block_ix *block_ix,
  353. int *lu_entry) {
  354. s32_t res;
  355. if (!fs->cleaning && fs->free_blocks < 2) {
  356. res = spiffs_gc_quick(fs, 0);
  357. if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) {
  358. res = SPIFFS_OK;
  359. }
  360. SPIFFS_CHECK_RES(res);
  361. if (fs->free_blocks < 2) {
  362. return SPIFFS_ERR_FULL;
  363. }
  364. }
  365. res = spiffs_obj_lu_find_id(fs, starting_block, starting_lu_entry,
  366. SPIFFS_OBJ_ID_FREE, block_ix, lu_entry);
  367. if (res == SPIFFS_OK) {
  368. fs->free_cursor_block_ix = *block_ix;
  369. fs->free_cursor_obj_lu_entry = *lu_entry;
  370. if (*lu_entry == 0) {
  371. fs->free_blocks--;
  372. }
  373. }
  374. if (res == SPIFFS_VIS_END) {
  375. SPIFFS_DBG("fs full\n");
  376. }
  377. return res == SPIFFS_VIS_END ? SPIFFS_ERR_FULL : res;
  378. }
  379. // Find object lookup entry containing given id
  380. // Iterate over object lookup pages in each block until a given object id entry is found
  381. s32_t spiffs_obj_lu_find_id(
  382. spiffs *fs,
  383. spiffs_block_ix starting_block,
  384. int starting_lu_entry,
  385. spiffs_obj_id obj_id,
  386. spiffs_block_ix *block_ix,
  387. int *lu_entry) {
  388. s32_t res = spiffs_obj_lu_find_entry_visitor(
  389. fs, starting_block, starting_lu_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, lu_entry);
  390. if (res == SPIFFS_VIS_END) {
  391. res = SPIFFS_ERR_NOT_FOUND;
  392. }
  393. return res;
  394. }
  395. static s32_t spiffs_obj_lu_find_id_and_span_v(
  396. spiffs *fs,
  397. spiffs_obj_id obj_id,
  398. spiffs_block_ix bix,
  399. int ix_entry,
  400. u32_t user_data,
  401. void *user_p) {
  402. s32_t res;
  403. spiffs_page_header ph;
  404. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  405. res = _spiffs_rd(fs, 0, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  406. SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph);
  407. SPIFFS_CHECK_RES(res);
  408. if (ph.obj_id == obj_id &&
  409. ph.span_ix == (spiffs_span_ix)user_data &&
  410. (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET &&
  411. !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) &&
  412. (user_p == 0 || *((spiffs_page_ix *)user_p) != pix)) {
  413. return SPIFFS_OK;
  414. } else {
  415. return SPIFFS_VIS_COUNTINUE;
  416. }
  417. }
  418. // Find object lookup entry containing given id and span index
  419. // Iterate over object lookup pages in each block until a given object id entry is found
  420. s32_t spiffs_obj_lu_find_id_and_span(
  421. spiffs *fs,
  422. spiffs_obj_id obj_id,
  423. spiffs_span_ix spix,
  424. spiffs_page_ix exclusion_pix,
  425. spiffs_page_ix *pix) {
  426. s32_t res;
  427. spiffs_block_ix bix;
  428. int entry;
  429. res = spiffs_obj_lu_find_entry_visitor(fs,
  430. fs->cursor_block_ix,
  431. fs->cursor_obj_lu_entry,
  432. SPIFFS_VIS_CHECK_ID,
  433. obj_id,
  434. spiffs_obj_lu_find_id_and_span_v,
  435. (u32_t)spix,
  436. exclusion_pix ? &exclusion_pix : 0,
  437. &bix,
  438. &entry);
  439. if (res == SPIFFS_VIS_END) {
  440. res = SPIFFS_ERR_NOT_FOUND;
  441. }
  442. SPIFFS_CHECK_RES(res);
  443. if (pix) {
  444. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  445. }
  446. fs->cursor_block_ix = bix;
  447. fs->cursor_obj_lu_entry = entry;
  448. return res;
  449. }
  450. // Find object lookup entry containing given id and span index in page headers only
  451. // Iterate over object lookup pages in each block until a given object id entry is found
  452. s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
  453. spiffs *fs,
  454. spiffs_obj_id obj_id,
  455. spiffs_span_ix spix,
  456. spiffs_page_ix exclusion_pix,
  457. spiffs_page_ix *pix) {
  458. s32_t res;
  459. spiffs_block_ix bix;
  460. int entry;
  461. res = spiffs_obj_lu_find_entry_visitor(fs,
  462. fs->cursor_block_ix,
  463. fs->cursor_obj_lu_entry,
  464. SPIFFS_VIS_CHECK_PH,
  465. obj_id,
  466. spiffs_obj_lu_find_id_and_span_v,
  467. (u32_t)spix,
  468. exclusion_pix ? &exclusion_pix : 0,
  469. &bix,
  470. &entry);
  471. if (res == SPIFFS_VIS_END) {
  472. res = SPIFFS_ERR_NOT_FOUND;
  473. }
  474. SPIFFS_CHECK_RES(res);
  475. if (pix) {
  476. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  477. }
  478. fs->cursor_block_ix = bix;
  479. fs->cursor_obj_lu_entry = entry;
  480. return res;
  481. }
  482. // Allocates a free defined page with given obj_id
  483. // Occupies object lookup entry and page
  484. // data may be NULL; where only page header is stored, len and page_offs is ignored
  485. s32_t spiffs_page_allocate_data(
  486. spiffs *fs,
  487. spiffs_obj_id obj_id,
  488. spiffs_page_header *ph,
  489. u8_t *data,
  490. u32_t len,
  491. u32_t page_offs,
  492. u8_t finalize,
  493. spiffs_page_ix *pix) {
  494. s32_t res = SPIFFS_OK;
  495. spiffs_block_ix bix;
  496. int entry;
  497. // find free entry
  498. res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
  499. SPIFFS_CHECK_RES(res);
  500. // occupy page in object lookup
  501. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  502. 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);
  503. SPIFFS_CHECK_RES(res);
  504. fs->stats_p_allocated++;
  505. // write page header
  506. ph->flags &= ~SPIFFS_PH_FLAG_USED;
  507. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  508. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_header), (u8_t*)ph);
  509. SPIFFS_CHECK_RES(res);
  510. // write page data
  511. if (data) {
  512. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  513. 0,SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + sizeof(spiffs_page_header) + page_offs, len, data);
  514. SPIFFS_CHECK_RES(res);
  515. }
  516. // finalize header if necessary
  517. if (finalize && (ph->flags & SPIFFS_PH_FLAG_FINAL)) {
  518. ph->flags &= ~SPIFFS_PH_FLAG_FINAL;
  519. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  520. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + offsetof(spiffs_page_header, flags),
  521. sizeof(u8_t),
  522. (u8_t *)&ph->flags);
  523. SPIFFS_CHECK_RES(res);
  524. }
  525. // return written page
  526. if (pix) {
  527. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  528. }
  529. return res;
  530. }
  531. // Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page.
  532. // If page data is null, provided header is used for metainfo and page data is physically copied.
  533. s32_t spiffs_page_move(
  534. spiffs *fs,
  535. spiffs_file fh,
  536. u8_t *page_data,
  537. spiffs_obj_id obj_id,
  538. spiffs_page_header *page_hdr,
  539. spiffs_page_ix src_pix,
  540. spiffs_page_ix *dst_pix) {
  541. s32_t res;
  542. u8_t was_final = 0;
  543. spiffs_page_header *p_hdr;
  544. spiffs_block_ix bix;
  545. int entry;
  546. spiffs_page_ix free_pix;
  547. // find free entry
  548. res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
  549. SPIFFS_CHECK_RES(res);
  550. free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  551. if (dst_pix) *dst_pix = free_pix;
  552. p_hdr = page_data ? (spiffs_page_header *)page_data : page_hdr;
  553. if (page_data) {
  554. // got page data
  555. was_final = (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) == 0;
  556. // write unfinalized page
  557. p_hdr->flags |= SPIFFS_PH_FLAG_FINAL;
  558. p_hdr->flags &= ~SPIFFS_PH_FLAG_USED;
  559. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  560. 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), page_data);
  561. } else {
  562. // copy page data
  563. res = spiffs_phys_cpy(fs, fh, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_PAGE_TO_PADDR(fs, src_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs));
  564. }
  565. SPIFFS_CHECK_RES(res);
  566. // mark entry in destination object lookup
  567. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  568. 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),
  569. sizeof(spiffs_obj_id),
  570. (u8_t *)&obj_id);
  571. SPIFFS_CHECK_RES(res);
  572. fs->stats_p_allocated++;
  573. if (was_final) {
  574. // mark finalized in destination page
  575. p_hdr->flags &= ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED);
  576. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  577. fh,
  578. SPIFFS_PAGE_TO_PADDR(fs, free_pix) + offsetof(spiffs_page_header, flags),
  579. sizeof(u8_t),
  580. (u8_t *)&p_hdr->flags);
  581. SPIFFS_CHECK_RES(res);
  582. }
  583. // mark source deleted
  584. res = spiffs_page_delete(fs, src_pix);
  585. return res;
  586. }
  587. // Deletes a page and removes it from object lookup.
  588. s32_t spiffs_page_delete(
  589. spiffs *fs,
  590. spiffs_page_ix pix) {
  591. s32_t res;
  592. spiffs_page_header hdr;
  593. hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED);
  594. // mark deleted entry in source object lookup
  595. spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED;
  596. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE,
  597. 0,
  598. SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_page_ix),
  599. sizeof(spiffs_obj_id),
  600. (u8_t *)&d_obj_id);
  601. SPIFFS_CHECK_RES(res);
  602. fs->stats_p_deleted++;
  603. fs->stats_p_allocated--;
  604. // mark deleted in source page
  605. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE,
  606. 0,
  607. SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),
  608. sizeof(u8_t),
  609. (u8_t *)&hdr.flags);
  610. return res;
  611. }
  612. // Create an object index header page with empty index and undefined length
  613. s32_t spiffs_object_create(
  614. spiffs *fs,
  615. spiffs_obj_id obj_id,
  616. u8_t name[SPIFFS_OBJ_NAME_LEN],
  617. spiffs_obj_type type,
  618. spiffs_page_ix *objix_hdr_pix) {
  619. s32_t res = SPIFFS_OK;
  620. spiffs_block_ix bix;
  621. spiffs_page_object_ix_header oix_hdr;
  622. int entry;
  623. res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs));
  624. SPIFFS_CHECK_RES(res);
  625. obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
  626. // find free entry
  627. res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
  628. SPIFFS_CHECK_RES(res);
  629. SPIFFS_DBG("create: found free page @ %04x bix:%i entry:%i\n", SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
  630. // occupy page in object lookup
  631. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  632. 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);
  633. SPIFFS_CHECK_RES(res);
  634. fs->stats_p_allocated++;
  635. // write empty object index page
  636. oix_hdr.p_hdr.obj_id = obj_id;
  637. oix_hdr.p_hdr.span_ix = 0;
  638. oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED);
  639. oix_hdr.type = type;
  640. oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page
  641. strncpy((char *)&oix_hdr.name, (char *)name, SPIFFS_OBJ_NAME_LEN);
  642. // update page
  643. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  644. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&oix_hdr);
  645. SPIFFS_CHECK_RES(res);
  646. spiffs_cb_object_event(fs, 0, SPIFFS_EV_IX_NEW, obj_id, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), SPIFFS_UNDEFINED_LEN);
  647. if (objix_hdr_pix) {
  648. *objix_hdr_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  649. }
  650. return res;
  651. }
  652. // update object index header with any combination of name/size/index
  653. // new_objix_hdr_data may be null, if so the object index header page is loaded
  654. // name may be null, if so name is not changed
  655. // size may be null, if so size is not changed
  656. s32_t spiffs_object_update_index_hdr(
  657. spiffs *fs,
  658. spiffs_fd *fd,
  659. spiffs_obj_id obj_id,
  660. spiffs_page_ix objix_hdr_pix,
  661. u8_t *new_objix_hdr_data,
  662. u8_t name[SPIFFS_OBJ_NAME_LEN],
  663. u32_t size,
  664. spiffs_page_ix *new_pix) {
  665. s32_t res = SPIFFS_OK;
  666. spiffs_page_object_ix_header *objix_hdr;
  667. spiffs_page_ix new_objix_hdr_pix;
  668. obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
  669. if (new_objix_hdr_data) {
  670. // object index header page already given to us, no need to load it
  671. objix_hdr = (spiffs_page_object_ix_header *)new_objix_hdr_data;
  672. } else {
  673. // read object index header page
  674. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  675. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  676. SPIFFS_CHECK_RES(res);
  677. objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  678. }
  679. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, obj_id, 0);
  680. // change name
  681. if (name) {
  682. strncpy((char *)objix_hdr->name, (char *)name, SPIFFS_OBJ_NAME_LEN);
  683. }
  684. if (size) {
  685. objix_hdr->size = size;
  686. }
  687. // move and update page
  688. res = spiffs_page_move(fs, fd == 0 ? 0 : fd->file_nbr, (u8_t*)objix_hdr, obj_id, 0, objix_hdr_pix, &new_objix_hdr_pix);
  689. if (res == SPIFFS_OK) {
  690. if (new_pix) {
  691. *new_pix = new_objix_hdr_pix;
  692. }
  693. // callback on object index update
  694. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, obj_id, objix_hdr->p_hdr.span_ix, new_objix_hdr_pix, objix_hdr->size);
  695. if (fd) fd->objix_hdr_pix = new_objix_hdr_pix; // if this is not in the registered cluster
  696. }
  697. return res;
  698. }
  699. void spiffs_cb_object_event(
  700. spiffs *fs,
  701. spiffs_fd *fd,
  702. int ev,
  703. spiffs_obj_id obj_id,
  704. spiffs_span_ix spix,
  705. spiffs_page_ix new_pix,
  706. u32_t new_size) {
  707. (void)fd;
  708. // update index caches in all file descriptors
  709. obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
  710. u32_t i;
  711. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  712. for (i = 0; i < fs->fd_count; i++) {
  713. spiffs_fd *cur_fd = &fds[i];
  714. if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
  715. if (spix == 0) {
  716. if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
  717. SPIFFS_DBG(" callback: setting fd %i:%04x objix_hdr_pix to %04x, size:%i\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
  718. cur_fd->objix_hdr_pix = new_pix;
  719. if (new_size != 0) {
  720. cur_fd->size = new_size;
  721. }
  722. } else if (ev == SPIFFS_EV_IX_DEL) {
  723. cur_fd->file_nbr = 0;
  724. cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED;
  725. }
  726. }
  727. if (cur_fd->cursor_objix_spix == spix) {
  728. if (ev == SPIFFS_EV_IX_NEW || ev == SPIFFS_EV_IX_UPD) {
  729. SPIFFS_DBG(" callback: setting fd %i:%04x span:%04x objix_pix to %04x\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
  730. cur_fd->cursor_objix_pix = new_pix;
  731. } else {
  732. cur_fd->cursor_objix_pix = 0;
  733. }
  734. }
  735. }
  736. }
  737. // Open object by id
  738. s32_t spiffs_object_open_by_id(
  739. spiffs *fs,
  740. spiffs_obj_id obj_id,
  741. spiffs_fd *fd,
  742. spiffs_flags flags,
  743. spiffs_mode mode) {
  744. s32_t res = SPIFFS_OK;
  745. spiffs_page_ix pix;
  746. res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
  747. SPIFFS_CHECK_RES(res);
  748. res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);
  749. return res;
  750. }
  751. // Open object by page index
  752. s32_t spiffs_object_open_by_page(
  753. spiffs *fs,
  754. spiffs_page_ix pix,
  755. spiffs_fd *fd,
  756. spiffs_flags flags,
  757. spiffs_mode mode) {
  758. (void)mode;
  759. s32_t res = SPIFFS_OK;
  760. spiffs_page_object_ix_header oix_hdr;
  761. spiffs_obj_id obj_id;
  762. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  763. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr);
  764. SPIFFS_CHECK_RES(res);
  765. spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(fs, pix);
  766. int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix);
  767. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
  768. 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id);
  769. fd->fs = fs;
  770. fd->objix_hdr_pix = pix;
  771. fd->size = oix_hdr.size;
  772. fd->offset = 0;
  773. fd->cursor_objix_pix = pix;
  774. fd->cursor_objix_spix = 0;
  775. fd->obj_id = obj_id;
  776. fd->flags = flags;
  777. SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
  778. SPIFFS_DBG("open: fd %i is obj id %04x\n", fd->file_nbr, fd->obj_id);
  779. return res;
  780. }
  781. // Append to object
  782. // keep current object index (header) page in fs->work buffer
  783. s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
  784. spiffs *fs = fd->fs;
  785. s32_t res = SPIFFS_OK;
  786. u32_t written = 0;
  787. SPIFFS_DBG("append: %i bytes @ offs %i of size %i\n", len, offset, fd->size);
  788. if (offset > fd->size) {
  789. SPIFFS_DBG("append: offset reversed to size\n");
  790. offset = fd->size;
  791. }
  792. res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
  793. if (res != SPIFFS_OK) {
  794. SPIFFS_DBG("append: gc check fail %i\n", res);
  795. }
  796. SPIFFS_CHECK_RES(res);
  797. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  798. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  799. spiffs_page_header p_hdr;
  800. spiffs_span_ix cur_objix_spix = 0;
  801. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  802. spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;
  803. spiffs_page_ix new_objix_hdr_page;
  804. spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
  805. spiffs_page_ix data_page;
  806. u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);
  807. // write all data
  808. while (res == SPIFFS_OK && written < len) {
  809. // calculate object index page span index
  810. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  811. // handle storing and loading of object indices
  812. if (cur_objix_spix != prev_objix_spix) {
  813. // new object index page
  814. // within this clause we return directly if something fails, object index mess-up
  815. if (written > 0) {
  816. // store previous object index page, unless first pass
  817. SPIFFS_DBG("append: %04x store objix %04x:%04x, written %i\n", fd->obj_id,
  818. cur_objix_pix, prev_objix_spix, written);
  819. if (prev_objix_spix == 0) {
  820. // this is an update to object index header page
  821. objix_hdr->size = offset+written;
  822. if (offset == 0) {
  823. // was an empty object, update same page (size was 0xffffffff)
  824. res = spiffs_page_index_check(fs, fd, cur_objix_pix, 0);
  825. SPIFFS_CHECK_RES(res);
  826. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  827. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  828. SPIFFS_CHECK_RES(res);
  829. } else {
  830. // was a nonempty object, update to new page
  831. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  832. fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
  833. SPIFFS_CHECK_RES(res);
  834. SPIFFS_DBG("append: %04x store new objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
  835. new_objix_hdr_page, 0, written);
  836. }
  837. } else {
  838. // this is an update to an object index page
  839. res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);
  840. SPIFFS_CHECK_RES(res);
  841. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  842. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  843. SPIFFS_CHECK_RES(res);
  844. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD,fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);
  845. // update length in object index header page
  846. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  847. fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
  848. SPIFFS_CHECK_RES(res);
  849. SPIFFS_DBG("append: %04x store new size I %i in objix_hdr, %04x:%04x, written %i\n", fd->obj_id,
  850. offset+written, new_objix_hdr_page, 0, written);
  851. }
  852. fd->size = offset+written;
  853. fd->offset = offset+written;
  854. }
  855. // create or load new object index page
  856. if (cur_objix_spix == 0) {
  857. // load object index header page, must always exist
  858. SPIFFS_DBG("append: %04x load objixhdr page %04x:%04x\n", fd->obj_id, cur_objix_pix, cur_objix_spix);
  859. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  860. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  861. SPIFFS_CHECK_RES(res);
  862. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  863. } else {
  864. spiffs_span_ix len_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, (fd->size-1)/SPIFFS_DATA_PAGE_SIZE(fs));
  865. // on subsequent passes, create a new object index page
  866. if (written > 0 || cur_objix_spix > len_objix_spix) {
  867. p_hdr.obj_id = fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
  868. p_hdr.span_ix = cur_objix_spix;
  869. p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
  870. res = spiffs_page_allocate_data(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
  871. &p_hdr, 0, 0, 0, 1, &cur_objix_pix);
  872. SPIFFS_CHECK_RES(res);
  873. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);
  874. // quick "load" of new object index page
  875. c_memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  876. c_memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
  877. SPIFFS_DBG("append: %04x create objix page, %04x:%04x, written %i\n", fd->obj_id
  878. , cur_objix_pix, cur_objix_spix, written);
  879. } else {
  880. // on first pass, we load existing object index page
  881. spiffs_page_ix pix;
  882. SPIFFS_DBG("append: %04x find objix span_ix:%04x\n", fd->obj_id, cur_objix_spix);
  883. if (fd->cursor_objix_spix == cur_objix_spix) {
  884. pix = fd->cursor_objix_pix;
  885. } else {
  886. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
  887. SPIFFS_CHECK_RES(res);
  888. }
  889. SPIFFS_DBG("append: %04x found object index at page %04x [fd size %i]\n", fd->obj_id, pix, fd->size);
  890. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  891. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  892. SPIFFS_CHECK_RES(res);
  893. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  894. cur_objix_pix = pix;
  895. }
  896. fd->cursor_objix_pix = cur_objix_pix;
  897. fd->cursor_objix_spix = cur_objix_spix;
  898. fd->offset = offset+written;
  899. fd->size = offset+written;
  900. }
  901. prev_objix_spix = cur_objix_spix;
  902. }
  903. // write data
  904. u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);
  905. if (page_offs == 0) {
  906. // at beginning of a page, allocate and write a new page of data
  907. p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  908. p_hdr.span_ix = data_spix;
  909. p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately
  910. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  911. &p_hdr, &data[written], to_write, page_offs, 1, &data_page);
  912. SPIFFS_DBG("append: %04x store new data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id,
  913. data_page, data_spix, page_offs, to_write, written);
  914. } else {
  915. // append to existing page, fill out free data in existing page
  916. if (cur_objix_spix == 0) {
  917. // get data page from object index header page
  918. data_page = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  919. } else {
  920. // get data page from object index page
  921. data_page = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  922. }
  923. res = spiffs_page_data_check(fs, fd, data_page, data_spix);
  924. SPIFFS_CHECK_RES(res);
  925. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  926. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
  927. SPIFFS_DBG("append: %04x store to existing data page, %04x:%04x offset:%i, len %i, written %i\n", fd->obj_id
  928. , data_page, data_spix, page_offs, to_write, written);
  929. }
  930. if (res != SPIFFS_OK) break;
  931. // update memory representation of object index page with new data page
  932. if (cur_objix_spix == 0) {
  933. // update object index header page
  934. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page;
  935. SPIFFS_DBG("append: %04x wrote page %04x to objix_hdr entry %02x in mem\n", fd->obj_id
  936. , data_page, data_spix);
  937. objix_hdr->size = offset+written;
  938. } else {
  939. // update object index page
  940. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page;
  941. SPIFFS_DBG("append: %04x wrote page %04x to objix entry %02x in mem\n", fd->obj_id
  942. , data_page, SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  943. }
  944. // update internals
  945. page_offs = 0;
  946. data_spix++;
  947. written += to_write;
  948. } // while all data
  949. fd->size = offset+written;
  950. fd->offset = offset+written;
  951. fd->cursor_objix_pix = cur_objix_pix;
  952. fd->cursor_objix_spix = cur_objix_spix;
  953. // finalize updated object indices
  954. s32_t res2 = SPIFFS_OK;
  955. if (cur_objix_spix != 0) {
  956. // wrote beyond object index header page
  957. // write last modified object index page, unless object header index page
  958. SPIFFS_DBG("append: %04x store objix page, %04x:%04x, written %i\n", fd->obj_id,
  959. cur_objix_pix, cur_objix_spix, written);
  960. res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
  961. SPIFFS_CHECK_RES(res2);
  962. res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  963. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  964. SPIFFS_CHECK_RES(res2);
  965. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);
  966. // update size in object header index page
  967. res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  968. fd->objix_hdr_pix, 0, 0, offset+written, &new_objix_hdr_page);
  969. SPIFFS_DBG("append: %04x store new size II %i in objix_hdr, %04x:%04x, written %i, res %i\n", fd->obj_id
  970. , offset+written, new_objix_hdr_page, 0, written, res2);
  971. SPIFFS_CHECK_RES(res2);
  972. } else {
  973. // wrote within object index header page
  974. if (offset == 0) {
  975. // wrote to empty object - simply update size and write whole page
  976. objix_hdr->size = offset+written;
  977. SPIFFS_DBG("append: %04x store fresh objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
  978. , cur_objix_pix, cur_objix_spix, written);
  979. res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
  980. SPIFFS_CHECK_RES(res2);
  981. res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  982. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  983. SPIFFS_CHECK_RES(res2);
  984. // callback on object index update
  985. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix_hdr->p_hdr.span_ix, cur_objix_pix, objix_hdr->size);
  986. } else {
  987. // modifying object index header page, update size and make new copy
  988. res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  989. fd->objix_hdr_pix, fs->work, 0, offset+written, &new_objix_hdr_page);
  990. SPIFFS_DBG("append: %04x store modified objix_hdr page, %04x:%04x, written %i\n", fd->obj_id
  991. , new_objix_hdr_page, 0, written);
  992. SPIFFS_CHECK_RES(res2);
  993. }
  994. }
  995. return res;
  996. }
  997. // Modify object
  998. // keep current object index (header) page in fs->work buffer
  999. s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
  1000. spiffs *fs = fd->fs;
  1001. s32_t res = SPIFFS_OK;
  1002. u32_t written = 0;
  1003. res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs));
  1004. SPIFFS_CHECK_RES(res);
  1005. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  1006. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  1007. spiffs_page_header p_hdr;
  1008. spiffs_span_ix cur_objix_spix = 0;
  1009. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  1010. spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;
  1011. spiffs_page_ix new_objix_hdr_pix;
  1012. spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
  1013. spiffs_page_ix data_pix;
  1014. u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);
  1015. // write all data
  1016. while (res == SPIFFS_OK && written < len) {
  1017. // calculate object index page span index
  1018. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  1019. // handle storing and loading of object indices
  1020. if (cur_objix_spix != prev_objix_spix) {
  1021. // new object index page
  1022. // within this clause we return directly if something fails, object index mess-up
  1023. if (written > 0) {
  1024. // store previous object index (header) page, unless first pass
  1025. if (prev_objix_spix == 0) {
  1026. // store previous object index header page
  1027. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1028. fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
  1029. SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
  1030. SPIFFS_CHECK_RES(res);
  1031. } else {
  1032. // store new version of previous object index page
  1033. spiffs_page_ix new_objix_pix;
  1034. res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);
  1035. SPIFFS_CHECK_RES(res);
  1036. res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
  1037. SPIFFS_DBG("modify: store previous modified objix page, %04x:%04x, written %i\n", new_objix_pix, objix->p_hdr.span_ix, written);
  1038. SPIFFS_CHECK_RES(res);
  1039. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
  1040. }
  1041. }
  1042. // load next object index page
  1043. if (cur_objix_spix == 0) {
  1044. // load object index header page, must exist
  1045. SPIFFS_DBG("modify: load objixhdr page %04x:%04x\n", cur_objix_pix, cur_objix_spix);
  1046. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1047. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1048. SPIFFS_CHECK_RES(res);
  1049. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1050. } else {
  1051. // load existing object index page on first pass
  1052. spiffs_page_ix pix;
  1053. SPIFFS_DBG("modify: find objix span_ix:%04x\n", cur_objix_spix);
  1054. if (fd->cursor_objix_spix == cur_objix_spix) {
  1055. pix = fd->cursor_objix_pix;
  1056. } else {
  1057. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
  1058. SPIFFS_CHECK_RES(res);
  1059. }
  1060. SPIFFS_DBG("modify: found object index at page %04x\n", pix);
  1061. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1062. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1063. SPIFFS_CHECK_RES(res);
  1064. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1065. cur_objix_pix = pix;
  1066. }
  1067. fd->cursor_objix_pix = cur_objix_pix;
  1068. fd->cursor_objix_spix = cur_objix_spix;
  1069. fd->offset = offset+written;
  1070. prev_objix_spix = cur_objix_spix;
  1071. }
  1072. // write partial data
  1073. u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);
  1074. spiffs_page_ix orig_data_pix;
  1075. if (cur_objix_spix == 0) {
  1076. // get data page from object index header page
  1077. orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  1078. } else {
  1079. // get data page from object index page
  1080. orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  1081. }
  1082. p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  1083. p_hdr.span_ix = data_spix;
  1084. p_hdr.flags = 0xff;
  1085. if (page_offs == 0 && to_write == SPIFFS_DATA_PAGE_SIZE(fs)) {
  1086. // a full page, allocate and write a new page of data
  1087. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  1088. &p_hdr, &data[written], to_write, page_offs, 1, &data_pix);
  1089. SPIFFS_DBG("modify: store new data page, %04x:%04x offset:%i, len %i, written %i\n", data_pix, data_spix, page_offs, to_write, written);
  1090. } else {
  1091. // write to existing page, allocate new and copy unmodified data
  1092. res = spiffs_page_data_check(fs, fd, orig_data_pix, data_spix);
  1093. SPIFFS_CHECK_RES(res);
  1094. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  1095. &p_hdr, 0, 0, 0, 0, &data_pix);
  1096. if (res != SPIFFS_OK) break;
  1097. // copy unmodified data
  1098. if (page_offs > 0) {
  1099. // before modification
  1100. res = spiffs_phys_cpy(fs, fd->file_nbr,
  1101. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),
  1102. SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header),
  1103. page_offs);
  1104. if (res != SPIFFS_OK) break;
  1105. }
  1106. if (page_offs + to_write < SPIFFS_DATA_PAGE_SIZE(fs)) {
  1107. // after modification
  1108. res = spiffs_phys_cpy(fs, fd->file_nbr,
  1109. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,
  1110. SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,
  1111. SPIFFS_DATA_PAGE_SIZE(fs) - (page_offs + to_write));
  1112. if (res != SPIFFS_OK) break;
  1113. }
  1114. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  1115. fd->file_nbr,
  1116. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
  1117. if (res != SPIFFS_OK) break;
  1118. p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;
  1119. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  1120. fd->file_nbr,
  1121. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + offsetof(spiffs_page_header, flags),
  1122. sizeof(u8_t),
  1123. (u8_t *)&p_hdr.flags);
  1124. if (res != SPIFFS_OK) break;
  1125. SPIFFS_DBG("modify: store to existing data page, src:%04x, dst:%04x:%04x offset:%i, len %i, written %i\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
  1126. }
  1127. // delete original data page
  1128. res = spiffs_page_delete(fs, orig_data_pix);
  1129. if (res != SPIFFS_OK) break;
  1130. // update memory representation of object index page with new data page
  1131. if (cur_objix_spix == 0) {
  1132. // update object index header page
  1133. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix;
  1134. SPIFFS_DBG("modify: wrote page %04x to objix_hdr entry %02x in mem\n", data_pix, data_spix);
  1135. } else {
  1136. // update object index page
  1137. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix;
  1138. SPIFFS_DBG("modify: wrote page %04x to objix entry %02x in mem\n", data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  1139. }
  1140. // update internals
  1141. page_offs = 0;
  1142. data_spix++;
  1143. written += to_write;
  1144. } // while all data
  1145. fd->offset = offset+written;
  1146. fd->cursor_objix_pix = cur_objix_pix;
  1147. fd->cursor_objix_spix = cur_objix_spix;
  1148. // finalize updated object indices
  1149. s32_t res2 = SPIFFS_OK;
  1150. if (cur_objix_spix != 0) {
  1151. // wrote beyond object index header page
  1152. // write last modified object index page
  1153. // move and update page
  1154. spiffs_page_ix new_objix_pix;
  1155. res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
  1156. SPIFFS_CHECK_RES(res2);
  1157. res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
  1158. SPIFFS_DBG("modify: store modified objix page, %04x:%04x, written %i\n", new_objix_pix, cur_objix_spix, written);
  1159. fd->cursor_objix_pix = new_objix_pix;
  1160. fd->cursor_objix_spix = cur_objix_spix;
  1161. SPIFFS_CHECK_RES(res2);
  1162. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
  1163. } else {
  1164. // wrote within object index header page
  1165. res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1166. fd->objix_hdr_pix, fs->work, 0, 0, &new_objix_hdr_pix);
  1167. SPIFFS_DBG("modify: store modified objix_hdr page, %04x:%04x, written %i\n", new_objix_hdr_pix, 0, written);
  1168. SPIFFS_CHECK_RES(res2);
  1169. }
  1170. return res;
  1171. }
  1172. static s32_t spiffs_object_find_object_index_header_by_name_v(
  1173. spiffs *fs,
  1174. spiffs_obj_id obj_id,
  1175. spiffs_block_ix bix,
  1176. int ix_entry,
  1177. u32_t user_data,
  1178. void *user_p) {
  1179. (void)user_data;
  1180. s32_t res;
  1181. spiffs_page_object_ix_header objix_hdr;
  1182. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  1183. if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||
  1184. (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
  1185. return SPIFFS_VIS_COUNTINUE;
  1186. }
  1187. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  1188. 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
  1189. SPIFFS_CHECK_RES(res);
  1190. if (objix_hdr.p_hdr.span_ix == 0 &&
  1191. (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
  1192. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
  1193. if (strncmp((char *)user_p, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN) == 0) {
  1194. return SPIFFS_OK;
  1195. }
  1196. }
  1197. return SPIFFS_VIS_COUNTINUE;
  1198. }
  1199. // Finds object index header page by name
  1200. s32_t spiffs_object_find_object_index_header_by_name(
  1201. spiffs *fs,
  1202. u8_t name[SPIFFS_OBJ_NAME_LEN],
  1203. spiffs_page_ix *pix) {
  1204. s32_t res;
  1205. spiffs_block_ix bix;
  1206. int entry;
  1207. res = spiffs_obj_lu_find_entry_visitor(fs,
  1208. fs->cursor_block_ix,
  1209. fs->cursor_obj_lu_entry,
  1210. 0,
  1211. 0,
  1212. spiffs_object_find_object_index_header_by_name_v,
  1213. 0,
  1214. name,
  1215. &bix,
  1216. &entry);
  1217. if (res == SPIFFS_VIS_END) {
  1218. res = SPIFFS_ERR_NOT_FOUND;
  1219. }
  1220. SPIFFS_CHECK_RES(res);
  1221. if (pix) {
  1222. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  1223. }
  1224. fs->cursor_block_ix = bix;
  1225. fs->cursor_obj_lu_entry = entry;
  1226. return res;
  1227. }
  1228. // Truncates object to new size. If new size is null, object may be removed totally
  1229. s32_t spiffs_object_truncate(
  1230. spiffs_fd *fd,
  1231. u32_t new_size,
  1232. u8_t remove) {
  1233. s32_t res = SPIFFS_OK;
  1234. spiffs *fs = fd->fs;
  1235. res = spiffs_gc_check(fs, remove ? 0 : SPIFFS_DATA_PAGE_SIZE(fs));
  1236. SPIFFS_CHECK_RES(res);
  1237. spiffs_page_ix objix_pix = fd->objix_hdr_pix;
  1238. spiffs_span_ix data_spix = (fd->size > 0 ? fd->size-1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs);
  1239. u32_t cur_size = fd->size == (u32_t)SPIFFS_UNDEFINED_LEN ? 0 : fd->size ;
  1240. spiffs_span_ix cur_objix_spix = 0;
  1241. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  1242. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  1243. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  1244. spiffs_page_ix data_pix;
  1245. spiffs_page_ix new_objix_hdr_pix;
  1246. // before truncating, check if object is to be fully removed and mark this
  1247. if (remove && new_size == 0) {
  1248. u8_t flags = ~( SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE);
  1249. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  1250. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix) + offsetof(spiffs_page_header, flags),
  1251. sizeof(u8_t),
  1252. (u8_t *)&flags);
  1253. SPIFFS_CHECK_RES(res);
  1254. }
  1255. // delete from end of object until desired len is reached
  1256. while (cur_size > new_size) {
  1257. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  1258. // put object index for current data span index in work buffer
  1259. if (prev_objix_spix != cur_objix_spix) {
  1260. if (prev_objix_spix != (spiffs_span_ix)-1) {
  1261. // remove previous object index page
  1262. SPIFFS_DBG("truncate: delete objix page %04x:%04x\n", objix_pix, prev_objix_spix);
  1263. res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix);
  1264. SPIFFS_CHECK_RES(res);
  1265. res = spiffs_page_delete(fs, objix_pix);
  1266. SPIFFS_CHECK_RES(res);
  1267. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);
  1268. if (prev_objix_spix > 0) {
  1269. // update object index header page
  1270. SPIFFS_DBG("truncate: update objix hdr page %04x:%04x to size %i\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
  1271. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1272. fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix);
  1273. SPIFFS_CHECK_RES(res);
  1274. fd->size = cur_size;
  1275. }
  1276. }
  1277. // load current object index (header) page
  1278. if (cur_objix_spix == 0) {
  1279. objix_pix = fd->objix_hdr_pix;
  1280. } else {
  1281. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);
  1282. SPIFFS_CHECK_RES(res);
  1283. }
  1284. SPIFFS_DBG("truncate: load objix page %04x:%04x for data spix:%04x\n", objix_pix, cur_objix_spix, data_spix);
  1285. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1286. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1287. SPIFFS_CHECK_RES(res);
  1288. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1289. fd->cursor_objix_pix = objix_pix;
  1290. fd->cursor_objix_spix = cur_objix_spix;
  1291. fd->offset = cur_size;
  1292. prev_objix_spix = cur_objix_spix;
  1293. }
  1294. if (cur_objix_spix == 0) {
  1295. // get data page from object index header page
  1296. data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  1297. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = SPIFFS_OBJ_ID_FREE;
  1298. } else {
  1299. // get data page from object index page
  1300. data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  1301. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;
  1302. }
  1303. SPIFFS_DBG("truncate: got data pix %04x\n", data_pix);
  1304. if (cur_size - SPIFFS_DATA_PAGE_SIZE(fs) >= new_size) {
  1305. // delete full data page
  1306. res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
  1307. if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
  1308. SPIFFS_DBG("truncate: err validating data pix %i\n", res);
  1309. break;
  1310. }
  1311. if (res == SPIFFS_OK) {
  1312. res = spiffs_page_delete(fs, data_pix);
  1313. if (res != SPIFFS_OK) {
  1314. SPIFFS_DBG("truncate: err deleting data pix %i\n", res);
  1315. break;
  1316. }
  1317. } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
  1318. res = SPIFFS_OK;
  1319. }
  1320. // update current size
  1321. if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {
  1322. cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);
  1323. } else {
  1324. cur_size -= cur_size % SPIFFS_DATA_PAGE_SIZE(fs);
  1325. }
  1326. fd->size = cur_size;
  1327. fd->offset = cur_size;
  1328. SPIFFS_DBG("truncate: delete data page %04x for data spix:%04x, cur_size:%i\n", data_pix, data_spix, cur_size);
  1329. } else {
  1330. // delete last page, partially
  1331. spiffs_page_header p_hdr;
  1332. spiffs_page_ix new_data_pix;
  1333. u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));
  1334. SPIFFS_DBG("truncate: delete %i bytes from data page %04x for data spix:%04x, cur_size:%i\n", bytes_to_remove, data_pix, data_spix, cur_size);
  1335. res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
  1336. if (res != SPIFFS_OK) break;
  1337. p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  1338. p_hdr.span_ix = data_spix;
  1339. p_hdr.flags = 0xff;
  1340. // allocate new page and copy unmodified data
  1341. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  1342. &p_hdr, 0, 0, 0, 0, &new_data_pix);
  1343. if (res != SPIFFS_OK) break;
  1344. res = spiffs_phys_cpy(fs, 0,
  1345. SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + sizeof(spiffs_page_header),
  1346. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),
  1347. SPIFFS_DATA_PAGE_SIZE(fs) - bytes_to_remove);
  1348. if (res != SPIFFS_OK) break;
  1349. // delete original data page
  1350. res = spiffs_page_delete(fs, data_pix);
  1351. if (res != SPIFFS_OK) break;
  1352. p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;
  1353. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  1354. fd->file_nbr,
  1355. SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + offsetof(spiffs_page_header, flags),
  1356. sizeof(u8_t),
  1357. (u8_t *)&p_hdr.flags);
  1358. if (res != SPIFFS_OK) break;
  1359. // update memory representation of object index page with new data page
  1360. if (cur_objix_spix == 0) {
  1361. // update object index header page
  1362. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
  1363. SPIFFS_DBG("truncate: wrote page %04x to objix_hdr entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  1364. } else {
  1365. // update object index page
  1366. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
  1367. SPIFFS_DBG("truncate: wrote page %04x to objix entry %02x in mem\n", new_data_pix, SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  1368. }
  1369. cur_size = new_size;
  1370. fd->size = new_size;
  1371. fd->offset = cur_size;
  1372. break;
  1373. }
  1374. data_spix--;
  1375. } // while all data
  1376. // update object indices
  1377. if (cur_objix_spix == 0) {
  1378. // update object index header page
  1379. if (cur_size == 0) {
  1380. if (remove) {
  1381. // remove object altogether
  1382. SPIFFS_DBG("truncate: remove object index header page %04x\n", objix_pix);
  1383. res = spiffs_page_index_check(fs, fd, objix_pix, 0);
  1384. SPIFFS_CHECK_RES(res);
  1385. res = spiffs_page_delete(fs, objix_pix);
  1386. SPIFFS_CHECK_RES(res);
  1387. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0);
  1388. } else {
  1389. // make uninitialized object
  1390. SPIFFS_DBG("truncate: reset objix_hdr page %04x\n", objix_pix);
  1391. c_memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,
  1392. SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));
  1393. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1394. objix_pix, fs->work, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);
  1395. SPIFFS_CHECK_RES(res);
  1396. }
  1397. } else {
  1398. // update object index header page
  1399. SPIFFS_DBG("truncate: update object index header page with indices and size\n");
  1400. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1401. objix_pix, fs->work, 0, cur_size, &new_objix_hdr_pix);
  1402. SPIFFS_CHECK_RES(res);
  1403. }
  1404. } else {
  1405. // update both current object index page and object index header page
  1406. spiffs_page_ix new_objix_pix;
  1407. res = spiffs_page_index_check(fs, fd, objix_pix, cur_objix_spix);
  1408. SPIFFS_CHECK_RES(res);
  1409. // move and update object index page
  1410. res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix_hdr, fd->obj_id, 0, objix_pix, &new_objix_pix);
  1411. SPIFFS_CHECK_RES(res);
  1412. spiffs_cb_object_event(fs, fd, SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
  1413. SPIFFS_DBG("truncate: store modified objix page, %04x:%04x\n", new_objix_pix, cur_objix_spix);
  1414. fd->cursor_objix_pix = new_objix_pix;
  1415. fd->cursor_objix_spix = cur_objix_spix;
  1416. fd->offset = cur_size;
  1417. // update object index header page with new size
  1418. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1419. fd->objix_hdr_pix, 0, 0, cur_size, &new_objix_hdr_pix);
  1420. SPIFFS_CHECK_RES(res);
  1421. }
  1422. fd->size = cur_size;
  1423. return res;
  1424. }
  1425. s32_t spiffs_object_read(
  1426. spiffs_fd *fd,
  1427. u32_t offset,
  1428. u32_t len,
  1429. u8_t *dst) {
  1430. s32_t res = SPIFFS_OK;
  1431. spiffs *fs = fd->fs;
  1432. spiffs_page_ix objix_pix;
  1433. spiffs_page_ix data_pix;
  1434. spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
  1435. u32_t cur_offset = offset;
  1436. spiffs_span_ix cur_objix_spix;
  1437. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  1438. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  1439. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  1440. while (cur_offset < offset + len) {
  1441. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  1442. if (prev_objix_spix != cur_objix_spix) {
  1443. // load current object index (header) page
  1444. if (cur_objix_spix == 0) {
  1445. objix_pix = fd->objix_hdr_pix;
  1446. } else {
  1447. SPIFFS_DBG("read: find objix %04x:%04x\n", fd->obj_id, cur_objix_spix);
  1448. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);
  1449. SPIFFS_CHECK_RES(res);
  1450. }
  1451. SPIFFS_DBG("read: load objix page %04x:%04x for data spix:%04x\n", objix_pix, cur_objix_spix, data_spix);
  1452. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1453. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1454. SPIFFS_CHECK_RES(res);
  1455. SPIFFS_VALIDATE_OBJIX(objix->p_hdr, fd->obj_id, cur_objix_spix);
  1456. fd->offset = cur_offset;
  1457. fd->cursor_objix_pix = objix_pix;
  1458. fd->cursor_objix_spix = cur_objix_spix;
  1459. prev_objix_spix = cur_objix_spix;
  1460. }
  1461. if (cur_objix_spix == 0) {
  1462. // get data page from object index header page
  1463. data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  1464. } else {
  1465. // get data page from object index page
  1466. data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  1467. }
  1468. // all remaining data
  1469. u32_t len_to_read = offset + len - cur_offset;
  1470. // remaining data in page
  1471. len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
  1472. // remaining data in file
  1473. len_to_read = MIN(len_to_read, fd->size);
  1474. SPIFFS_DBG("read: offset:%i rd:%i data spix:%04x is data_pix:%04x addr:%08x\n", cur_offset, len_to_read, data_spix, data_pix,
  1475. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
  1476. if (len_to_read <= 0) {
  1477. res = SPIFFS_ERR_END_OF_OBJECT;
  1478. break;
  1479. }
  1480. res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
  1481. SPIFFS_CHECK_RES(res);
  1482. res = _spiffs_rd(
  1483. fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
  1484. fd->file_nbr,
  1485. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)),
  1486. len_to_read,
  1487. dst);
  1488. SPIFFS_CHECK_RES(res);
  1489. dst += len_to_read;
  1490. cur_offset += len_to_read;
  1491. fd->offset = cur_offset;
  1492. data_spix++;
  1493. }
  1494. return res;
  1495. }
  1496. typedef struct {
  1497. spiffs_obj_id min_obj_id;
  1498. spiffs_obj_id max_obj_id;
  1499. u32_t compaction;
  1500. const u8_t *conflicting_name;
  1501. } spiffs_free_obj_id_state;
  1502. static s32_t spiffs_obj_lu_find_free_obj_id_bitmap_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
  1503. u32_t user_data, void *user_p) {
  1504. if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) {
  1505. spiffs_obj_id min_obj_id = user_data;
  1506. u8_t *conflicting_name = (u8_t *)user_p;
  1507. // if conflicting name parameter is given, also check if this name is found in object index hdrs
  1508. if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) {
  1509. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  1510. int res;
  1511. spiffs_page_object_ix_header objix_hdr;
  1512. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  1513. 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
  1514. SPIFFS_CHECK_RES(res);
  1515. if (objix_hdr.p_hdr.span_ix == 0 &&
  1516. (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
  1517. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
  1518. if (strncmp((char *)user_p, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN) == 0) {
  1519. return SPIFFS_ERR_CONFLICTING_NAME;
  1520. }
  1521. }
  1522. }
  1523. id &= ~SPIFFS_OBJ_ID_IX_FLAG;
  1524. u32_t bit_ix = (id-min_obj_id) & 7;
  1525. int byte_ix = (id-min_obj_id) >> 3;
  1526. if (byte_ix >= 0 && (u32_t)byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
  1527. fs->work[byte_ix] |= (1<<bit_ix);
  1528. }
  1529. }
  1530. return SPIFFS_VIS_COUNTINUE;
  1531. }
  1532. static s32_t spiffs_obj_lu_find_free_obj_id_compact_v(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
  1533. u32_t user_data, void *user_p) {
  1534. (void)user_data;
  1535. if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED && (id & SPIFFS_OBJ_ID_IX_FLAG)) {
  1536. s32_t res;
  1537. spiffs_free_obj_id_state *state = (spiffs_free_obj_id_state *)user_p;
  1538. spiffs_page_object_ix_header objix_hdr;
  1539. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  1540. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, ix_entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&objix_hdr);
  1541. if (res == SPIFFS_OK && objix_hdr.p_hdr.span_ix == 0 &&
  1542. ((objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) ==
  1543. (SPIFFS_PH_FLAG_DELET))) {
  1544. // ok object look up entry
  1545. if (state->conflicting_name && strncmp((const char *)state->conflicting_name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN) == 0) {
  1546. return SPIFFS_ERR_CONFLICTING_NAME;
  1547. }
  1548. id &= ~SPIFFS_OBJ_ID_IX_FLAG;
  1549. if (id >= state->min_obj_id && id <= state->max_obj_id) {
  1550. u8_t *map = (u8_t *)fs->work;
  1551. int ix = (id - state->min_obj_id) / state->compaction;
  1552. //SPIFFS_DBG("free_obj_id: add ix %i for id %04x min:%04x max%04x comp:%i\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
  1553. map[ix]++;
  1554. }
  1555. }
  1556. }
  1557. return SPIFFS_VIS_COUNTINUE;
  1558. }
  1559. // Scans thru all object lookup for object index header pages. If total possible number of
  1560. // object ids cannot fit into a work buffer, these are grouped. When a group containing free
  1561. // object ids is found, the object lu is again scanned for object ids within group and bitmasked.
  1562. // Finally, the bitmasked is searched for a free id
  1563. s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, u8_t *conflicting_name) {
  1564. s32_t res = SPIFFS_OK;
  1565. u32_t max_objects = (SPIFFS_CFG_PHYS_SZ(fs) / (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) / 2;
  1566. spiffs_free_obj_id_state state;
  1567. spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE;
  1568. state.min_obj_id = 1;
  1569. state.max_obj_id = max_objects + 1;
  1570. if (state.max_obj_id & SPIFFS_OBJ_ID_IX_FLAG) {
  1571. state.max_obj_id = ((spiffs_obj_id)-1) & ~SPIFFS_OBJ_ID_IX_FLAG;
  1572. }
  1573. state.compaction = 0;
  1574. state.conflicting_name = conflicting_name;
  1575. while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) {
  1576. if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) {
  1577. // possible to represent in bitmap
  1578. u32_t i, j;
  1579. SPIFFS_DBG("free_obj_id: BITM min:%04x max:%04x\n", state.min_obj_id, state.max_obj_id);
  1580. c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  1581. res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v, state.min_obj_id,
  1582. conflicting_name, 0, 0);
  1583. if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
  1584. SPIFFS_CHECK_RES(res);
  1585. // traverse bitmask until found free obj_id
  1586. for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) {
  1587. u8_t mask = fs->work[i];
  1588. if (mask == 0xff) {
  1589. continue;
  1590. }
  1591. for (j = 0; j < 8; j++) {
  1592. if ((mask & (1<<j)) == 0) {
  1593. *obj_id = (i<<3)+j+state.min_obj_id;
  1594. return SPIFFS_OK;
  1595. }
  1596. }
  1597. }
  1598. return SPIFFS_ERR_FULL;
  1599. } else {
  1600. // not possible to represent all ids in range in a bitmap, compact and count
  1601. if (state.compaction != 0) {
  1602. // select element in compacted table, decrease range and recompact
  1603. u32_t i, min_i = 0;
  1604. u8_t *map = (u8_t *)fs->work;
  1605. u8_t min_count = 0xff;
  1606. for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(u8_t); i++) {
  1607. if (map[i] < min_count) {
  1608. min_count = map[i];
  1609. min_i = i;
  1610. if (min_count == 0) {
  1611. break;
  1612. }
  1613. }
  1614. }
  1615. if (min_count == state.compaction) {
  1616. // there are no free objids!
  1617. SPIFFS_DBG("free_obj_id: compacted table is full\n");
  1618. return SPIFFS_ERR_FULL;
  1619. }
  1620. SPIFFS_DBG("free_obj_id: COMP select index:%i min_count:%i min:%04x max:%04x compact:%i\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
  1621. if (min_count == 0) {
  1622. // no id in this range, skip compacting and use directly
  1623. *obj_id = min_i * state.compaction + state.min_obj_id;
  1624. return SPIFFS_OK;
  1625. } else {
  1626. SPIFFS_DBG("free_obj_id: COMP SEL chunk:%04x min:%04x -> %04x\n", state.compaction, state.min_obj_id, state.min_obj_id + min_i * state.compaction);
  1627. state.min_obj_id += min_i * state.compaction;
  1628. state.max_obj_id = state.min_obj_id + state.compaction;
  1629. // decrease compaction
  1630. }
  1631. if ((state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8)) {
  1632. // no need for compacting, use bitmap
  1633. continue;
  1634. }
  1635. }
  1636. // in a work memory of log_page_size bytes, we may fit in log_page_size ids
  1637. // todo what if compaction is > 255 - then we cannot fit it in a byte
  1638. state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));
  1639. SPIFFS_DBG("free_obj_id: COMP min:%04x max:%04x compact:%i\n", state.min_obj_id, state.max_obj_id, state.compaction);
  1640. c_memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  1641. res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_compact_v, 0, &state, 0, 0);
  1642. if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
  1643. SPIFFS_CHECK_RES(res);
  1644. state.conflicting_name = 0; // searched for conflicting name once, no need to do it again
  1645. }
  1646. }
  1647. return res;
  1648. }
  1649. s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd) {
  1650. u32_t i;
  1651. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  1652. for (i = 0; i < fs->fd_count; i++) {
  1653. spiffs_fd *cur_fd = &fds[i];
  1654. if (cur_fd->file_nbr == 0) {
  1655. cur_fd->file_nbr = i+1;
  1656. *fd = cur_fd;
  1657. return SPIFFS_OK;
  1658. }
  1659. }
  1660. return SPIFFS_ERR_OUT_OF_FILE_DESCS;
  1661. }
  1662. s32_t spiffs_fd_return(spiffs *fs, spiffs_file f) {
  1663. if (f <= 0 || f > (s16_t)fs->fd_count) {
  1664. return SPIFFS_ERR_BAD_DESCRIPTOR;
  1665. }
  1666. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  1667. spiffs_fd *fd = &fds[f-1];
  1668. if (fd->file_nbr == 0) {
  1669. return SPIFFS_ERR_FILE_CLOSED;
  1670. }
  1671. fd->file_nbr = 0;
  1672. return SPIFFS_OK;
  1673. }
  1674. s32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) {
  1675. if (f <= 0 || f > (s16_t)fs->fd_count) {
  1676. return SPIFFS_ERR_BAD_DESCRIPTOR;
  1677. }
  1678. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  1679. *fd = &fds[f-1];
  1680. if ((*fd)->file_nbr == 0) {
  1681. return SPIFFS_ERR_FILE_CLOSED;
  1682. }
  1683. return SPIFFS_OK;
  1684. }