spiffs_nucleus.c 67 KB

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