spiffs_nucleus.c 74 KB

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