Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 

2328 Zeilen
84 KiB

  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 "_SPIPRIad":"_SPIPRIi"\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 we have sane number of blocks
  272. if (bix_count[0] < 3) return SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS;
  273. // check that the order is correct, take aborted erases in calculation
  274. // first block aborted erase
  275. if (magic[0] == (spiffs_obj_id)(-1) && bix_count[1] - bix_count[2] == 1) {
  276. return (bix_count[1]+1) * cfg->log_block_size;
  277. }
  278. // second block aborted erase
  279. if (magic[1] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[2] == 2) {
  280. return bix_count[0] * cfg->log_block_size;
  281. }
  282. // third block aborted erase
  283. if (magic[2] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[1] == 1) {
  284. return bix_count[0] * cfg->log_block_size;
  285. }
  286. // no block has aborted erase
  287. if (bix_count[0] - bix_count[1] == 1 && bix_count[1] - bix_count[2] == 1) {
  288. return bix_count[0] * cfg->log_block_size;
  289. }
  290. return SPIFFS_ERR_PROBE_NOT_A_FS;
  291. }
  292. #endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
  293. static s32_t spiffs_obj_lu_scan_v(
  294. spiffs *fs,
  295. spiffs_obj_id obj_id,
  296. spiffs_block_ix bix,
  297. int ix_entry,
  298. const void *user_const_p,
  299. void *user_var_p) {
  300. (void)bix;
  301. (void)user_const_p;
  302. (void)user_var_p;
  303. if (obj_id == SPIFFS_OBJ_ID_FREE) {
  304. if (ix_entry == 0) {
  305. fs->free_blocks++;
  306. // todo optimize further, return SPIFFS_NEXT_BLOCK
  307. }
  308. } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
  309. fs->stats_p_deleted++;
  310. } else {
  311. fs->stats_p_allocated++;
  312. }
  313. return SPIFFS_VIS_COUNTINUE;
  314. }
  315. // Scans thru all obj lu and counts free, deleted and used pages
  316. // Find the maximum block erase count
  317. // Checks magic if enabled
  318. s32_t spiffs_obj_lu_scan(
  319. spiffs *fs) {
  320. s32_t res;
  321. spiffs_block_ix bix;
  322. int entry;
  323. #if SPIFFS_USE_MAGIC
  324. spiffs_block_ix unerased_bix = (spiffs_block_ix)-1;
  325. #endif
  326. // find out erase count
  327. // if enabled, check magic
  328. bix = 0;
  329. spiffs_obj_id erase_count_final;
  330. spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE;
  331. spiffs_obj_id erase_count_max = 0;
  332. while (bix < fs->block_count) {
  333. #if SPIFFS_USE_MAGIC
  334. spiffs_obj_id magic;
  335. res = _spiffs_rd(fs,
  336. SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  337. 0, SPIFFS_MAGIC_PADDR(fs, bix) ,
  338. sizeof(spiffs_obj_id), (u8_t *)&magic);
  339. SPIFFS_CHECK_RES(res);
  340. if (magic != SPIFFS_MAGIC(fs, bix)) {
  341. if (unerased_bix == (spiffs_block_ix)-1) {
  342. // allow one unerased block as it might be powered down during an erase
  343. unerased_bix = bix;
  344. } else {
  345. // more than one unerased block, bail out
  346. SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS);
  347. }
  348. }
  349. #endif
  350. spiffs_obj_id erase_count;
  351. res = _spiffs_rd(fs,
  352. SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  353. 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix) ,
  354. sizeof(spiffs_obj_id), (u8_t *)&erase_count);
  355. SPIFFS_CHECK_RES(res);
  356. if (erase_count != SPIFFS_OBJ_ID_FREE) {
  357. erase_count_min = MIN(erase_count_min, erase_count);
  358. erase_count_max = MAX(erase_count_max, erase_count);
  359. }
  360. bix++;
  361. }
  362. if (erase_count_min == 0 && erase_count_max == SPIFFS_OBJ_ID_FREE) {
  363. // clean system, set counter to zero
  364. erase_count_final = 0;
  365. } else if (erase_count_max - erase_count_min > (SPIFFS_OBJ_ID_FREE)/2) {
  366. // wrap, take min
  367. erase_count_final = erase_count_min+1;
  368. } else {
  369. erase_count_final = erase_count_max+1;
  370. }
  371. fs->max_erase_count = erase_count_final;
  372. #if SPIFFS_USE_MAGIC
  373. if (unerased_bix != (spiffs_block_ix)-1) {
  374. // found one unerased block, remedy
  375. SPIFFS_DBG("mount: erase block "_SPIPRIbl"\n", bix);
  376. #if SPIFFS_READ_ONLY
  377. res = SPIFFS_ERR_RO_ABORTED_OPERATION;
  378. #else
  379. res = spiffs_erase_block(fs, unerased_bix);
  380. #endif // SPIFFS_READ_ONLY
  381. SPIFFS_CHECK_RES(res);
  382. }
  383. #endif
  384. // count blocks
  385. fs->free_blocks = 0;
  386. fs->stats_p_allocated = 0;
  387. fs->stats_p_deleted = 0;
  388. res = spiffs_obj_lu_find_entry_visitor(fs,
  389. 0,
  390. 0,
  391. 0,
  392. 0,
  393. spiffs_obj_lu_scan_v,
  394. 0,
  395. 0,
  396. &bix,
  397. &entry);
  398. if (res == SPIFFS_VIS_END) {
  399. res = SPIFFS_OK;
  400. }
  401. SPIFFS_CHECK_RES(res);
  402. return res;
  403. }
  404. #if !SPIFFS_READ_ONLY
  405. // Find free object lookup entry
  406. // Iterate over object lookup pages in each block until a free object id entry is found
  407. s32_t spiffs_obj_lu_find_free(
  408. spiffs *fs,
  409. spiffs_block_ix starting_block,
  410. int starting_lu_entry,
  411. spiffs_block_ix *block_ix,
  412. int *lu_entry) {
  413. s32_t res;
  414. if (!fs->cleaning && fs->free_blocks < 2) {
  415. res = spiffs_gc_quick(fs, 0);
  416. if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) {
  417. res = SPIFFS_OK;
  418. }
  419. SPIFFS_CHECK_RES(res);
  420. if (fs->free_blocks < 2) {
  421. return SPIFFS_ERR_FULL;
  422. }
  423. }
  424. res = spiffs_obj_lu_find_id(fs, starting_block, starting_lu_entry,
  425. SPIFFS_OBJ_ID_FREE, block_ix, lu_entry);
  426. if (res == SPIFFS_OK) {
  427. fs->free_cursor_block_ix = *block_ix;
  428. fs->free_cursor_obj_lu_entry = (*lu_entry) + 1;
  429. if (*lu_entry == 0) {
  430. fs->free_blocks--;
  431. }
  432. }
  433. if (res == SPIFFS_ERR_FULL) {
  434. SPIFFS_DBG("fs full\n");
  435. }
  436. return res;
  437. }
  438. #endif // !SPIFFS_READ_ONLY
  439. // Find object lookup entry containing given id
  440. // Iterate over object lookup pages in each block until a given object id entry is found
  441. s32_t spiffs_obj_lu_find_id(
  442. spiffs *fs,
  443. spiffs_block_ix starting_block,
  444. int starting_lu_entry,
  445. spiffs_obj_id obj_id,
  446. spiffs_block_ix *block_ix,
  447. int *lu_entry) {
  448. s32_t res = spiffs_obj_lu_find_entry_visitor(
  449. fs, starting_block, starting_lu_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, lu_entry);
  450. if (res == SPIFFS_VIS_END) {
  451. res = SPIFFS_ERR_NOT_FOUND;
  452. }
  453. return res;
  454. }
  455. static s32_t spiffs_obj_lu_find_id_and_span_v(
  456. spiffs *fs,
  457. spiffs_obj_id obj_id,
  458. spiffs_block_ix bix,
  459. int ix_entry,
  460. const void *user_const_p,
  461. void *user_var_p) {
  462. s32_t res;
  463. spiffs_page_header ph;
  464. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  465. res = _spiffs_rd(fs, 0, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  466. SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph);
  467. SPIFFS_CHECK_RES(res);
  468. if (ph.obj_id == obj_id &&
  469. ph.span_ix == *((spiffs_span_ix*)user_var_p) &&
  470. (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET &&
  471. !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) &&
  472. (user_const_p == 0 || *((const spiffs_page_ix*)user_const_p) != pix)) {
  473. return SPIFFS_OK;
  474. } else {
  475. return SPIFFS_VIS_COUNTINUE;
  476. }
  477. }
  478. // Find object lookup entry containing given id and span index
  479. // Iterate over object lookup pages in each block until a given object id entry is found
  480. s32_t spiffs_obj_lu_find_id_and_span(
  481. spiffs *fs,
  482. spiffs_obj_id obj_id,
  483. spiffs_span_ix spix,
  484. spiffs_page_ix exclusion_pix,
  485. spiffs_page_ix *pix) {
  486. s32_t res;
  487. spiffs_block_ix bix;
  488. int entry;
  489. res = spiffs_obj_lu_find_entry_visitor(fs,
  490. fs->cursor_block_ix,
  491. fs->cursor_obj_lu_entry,
  492. SPIFFS_VIS_CHECK_ID,
  493. obj_id,
  494. spiffs_obj_lu_find_id_and_span_v,
  495. exclusion_pix ? &exclusion_pix : 0,
  496. &spix,
  497. &bix,
  498. &entry);
  499. if (res == SPIFFS_VIS_END) {
  500. res = SPIFFS_ERR_NOT_FOUND;
  501. }
  502. SPIFFS_CHECK_RES(res);
  503. if (pix) {
  504. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  505. }
  506. fs->cursor_block_ix = bix;
  507. fs->cursor_obj_lu_entry = entry;
  508. return res;
  509. }
  510. // Find object lookup entry containing given id and span index in page headers only
  511. // Iterate over object lookup pages in each block until a given object id entry is found
  512. s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
  513. spiffs *fs,
  514. spiffs_obj_id obj_id,
  515. spiffs_span_ix spix,
  516. spiffs_page_ix exclusion_pix,
  517. spiffs_page_ix *pix) {
  518. s32_t res;
  519. spiffs_block_ix bix;
  520. int entry;
  521. res = spiffs_obj_lu_find_entry_visitor(fs,
  522. fs->cursor_block_ix,
  523. fs->cursor_obj_lu_entry,
  524. SPIFFS_VIS_CHECK_PH,
  525. obj_id,
  526. spiffs_obj_lu_find_id_and_span_v,
  527. exclusion_pix ? &exclusion_pix : 0,
  528. &spix,
  529. &bix,
  530. &entry);
  531. if (res == SPIFFS_VIS_END) {
  532. res = SPIFFS_ERR_NOT_FOUND;
  533. }
  534. SPIFFS_CHECK_RES(res);
  535. if (pix) {
  536. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  537. }
  538. fs->cursor_block_ix = bix;
  539. fs->cursor_obj_lu_entry = entry;
  540. return res;
  541. }
  542. #if SPIFFS_IX_MAP
  543. // update index map of given fd with given object index data
  544. static void spiffs_update_ix_map(spiffs *fs,
  545. spiffs_fd *fd, spiffs_span_ix objix_spix, spiffs_page_object_ix *objix) {
  546. #if SPIFFS_SINGLETON
  547. (void)fs;
  548. #endif
  549. spiffs_ix_map *map = fd->ix_map;
  550. spiffs_span_ix map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix);
  551. spiffs_span_ix map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->end_spix);
  552. // check if updated ix is within map range
  553. if (objix_spix < map_objix_start_spix || objix_spix > map_objix_end_spix) {
  554. return;
  555. }
  556. // update memory mapped page index buffer to new pages
  557. // get range of updated object index map data span indices
  558. spiffs_span_ix objix_data_spix_start =
  559. SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, objix_spix);
  560. spiffs_span_ix objix_data_spix_end = objix_data_spix_start +
  561. (objix_spix == 0 ? SPIFFS_OBJ_HDR_IX_LEN(fs) : SPIFFS_OBJ_IX_LEN(fs));
  562. // calc union of object index range and index map range array
  563. spiffs_span_ix map_spix = MAX(map->start_spix, objix_data_spix_start);
  564. spiffs_span_ix map_spix_end = MIN(map->end_spix + 1, objix_data_spix_end);
  565. while (map_spix < map_spix_end) {
  566. spiffs_page_ix objix_data_pix;
  567. if (objix_spix == 0) {
  568. // get data page from object index header page
  569. objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix_header)))[map_spix];
  570. } else {
  571. // get data page from object index page
  572. objix_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, map_spix)];
  573. }
  574. if (objix_data_pix == (spiffs_page_ix)-1) {
  575. // reached end of object, abort
  576. break;
  577. }
  578. map->map_buf[map_spix - map->start_spix] = objix_data_pix;
  579. SPIFFS_DBG("map "_SPIPRIid":"_SPIPRIsp" ("_SPIPRIsp"--"_SPIPRIsp") objix.spix:"_SPIPRIsp" to pix "_SPIPRIpg"\n",
  580. fd->obj_id, map_spix - map->start_spix,
  581. map->start_spix, map->end_spix,
  582. objix->p_hdr.span_ix,
  583. objix_data_pix);
  584. map_spix++;
  585. }
  586. }
  587. typedef struct {
  588. spiffs_fd *fd;
  589. u32_t remaining_objix_pages_to_visit;
  590. spiffs_span_ix map_objix_start_spix;
  591. spiffs_span_ix map_objix_end_spix;
  592. } spiffs_ix_map_populate_state;
  593. static s32_t spiffs_populate_ix_map_v(
  594. spiffs *fs,
  595. spiffs_obj_id obj_id,
  596. spiffs_block_ix bix,
  597. int ix_entry,
  598. const void *user_const_p,
  599. void *user_var_p) {
  600. (void)user_const_p;
  601. s32_t res;
  602. spiffs_ix_map_populate_state *state = (spiffs_ix_map_populate_state *)user_var_p;
  603. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  604. // load header to check it
  605. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  606. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  607. 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix), (u8_t *)objix);
  608. SPIFFS_CHECK_RES(res);
  609. SPIFFS_VALIDATE_OBJIX(objix->p_hdr, obj_id, objix->p_hdr.span_ix);
  610. // check if hdr is ok, and if objix range overlap with ix map range
  611. if ((objix->p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
  612. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE) &&
  613. objix->p_hdr.span_ix >= state->map_objix_start_spix &&
  614. objix->p_hdr.span_ix <= state->map_objix_end_spix) {
  615. // ok, load rest of object index
  616. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  617. 0, SPIFFS_PAGE_TO_PADDR(fs, pix) + sizeof(spiffs_page_object_ix),
  618. SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix),
  619. (u8_t *)objix + sizeof(spiffs_page_object_ix));
  620. SPIFFS_CHECK_RES(res);
  621. spiffs_update_ix_map(fs, state->fd, objix->p_hdr.span_ix, objix);
  622. state->remaining_objix_pages_to_visit--;
  623. SPIFFS_DBG("map "_SPIPRIid" ("_SPIPRIsp"--"_SPIPRIsp") remaining objix pages "_SPIPRIi"\n",
  624. state->fd->obj_id,
  625. state->fd->ix_map->start_spix, state->fd->ix_map->end_spix,
  626. state->remaining_objix_pages_to_visit);
  627. }
  628. if (res == SPIFFS_OK) {
  629. res = state->remaining_objix_pages_to_visit ? SPIFFS_VIS_COUNTINUE : SPIFFS_VIS_END;
  630. }
  631. return res;
  632. }
  633. // populates index map, from vector entry start to vector entry end, inclusive
  634. s32_t spiffs_populate_ix_map(spiffs *fs, spiffs_fd *fd, u32_t vec_entry_start, u32_t vec_entry_end) {
  635. s32_t res;
  636. spiffs_ix_map *map = fd->ix_map;
  637. spiffs_ix_map_populate_state state;
  638. vec_entry_start = MIN((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_start);
  639. vec_entry_end = MAX((map->end_spix - map->start_spix + 1) - 1, (s32_t)vec_entry_end);
  640. if (vec_entry_start > vec_entry_end) {
  641. return SPIFFS_ERR_IX_MAP_BAD_RANGE;
  642. }
  643. state.map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_start);
  644. state.map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_end);
  645. state.remaining_objix_pages_to_visit =
  646. state.map_objix_end_spix - state.map_objix_start_spix + 1;
  647. state.fd = fd;
  648. res = spiffs_obj_lu_find_entry_visitor(
  649. fs,
  650. SPIFFS_BLOCK_FOR_PAGE(fs, fd->objix_hdr_pix),
  651. SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, fd->objix_hdr_pix),
  652. SPIFFS_VIS_CHECK_ID,
  653. fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
  654. spiffs_populate_ix_map_v,
  655. 0,
  656. &state,
  657. 0,
  658. 0);
  659. if (res == SPIFFS_VIS_END) {
  660. res = SPIFFS_OK;
  661. }
  662. return res;
  663. }
  664. #endif
  665. #if !SPIFFS_READ_ONLY
  666. // Allocates a free defined page with given obj_id
  667. // Occupies object lookup entry and page
  668. // data may be NULL; where only page header is stored, len and page_offs is ignored
  669. s32_t spiffs_page_allocate_data(
  670. spiffs *fs,
  671. spiffs_obj_id obj_id,
  672. spiffs_page_header *ph,
  673. u8_t *data,
  674. u32_t len,
  675. u32_t page_offs,
  676. u8_t finalize,
  677. spiffs_page_ix *pix) {
  678. s32_t res = SPIFFS_OK;
  679. spiffs_block_ix bix;
  680. int entry;
  681. // find free entry
  682. res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
  683. SPIFFS_CHECK_RES(res);
  684. // occupy page in object lookup
  685. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  686. 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);
  687. SPIFFS_CHECK_RES(res);
  688. fs->stats_p_allocated++;
  689. // write page header
  690. ph->flags &= ~SPIFFS_PH_FLAG_USED;
  691. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  692. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_header), (u8_t*)ph);
  693. SPIFFS_CHECK_RES(res);
  694. // write page data
  695. if (data) {
  696. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  697. 0,SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + sizeof(spiffs_page_header) + page_offs, len, data);
  698. SPIFFS_CHECK_RES(res);
  699. }
  700. // finalize header if necessary
  701. if (finalize && (ph->flags & SPIFFS_PH_FLAG_FINAL)) {
  702. ph->flags &= ~SPIFFS_PH_FLAG_FINAL;
  703. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  704. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + offsetof(spiffs_page_header, flags),
  705. sizeof(u8_t),
  706. (u8_t *)&ph->flags);
  707. SPIFFS_CHECK_RES(res);
  708. }
  709. // return written page
  710. if (pix) {
  711. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  712. }
  713. return res;
  714. }
  715. #endif // !SPIFFS_READ_ONLY
  716. #if !SPIFFS_READ_ONLY
  717. // Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page.
  718. // If page data is null, provided header is used for metainfo and page data is physically copied.
  719. s32_t spiffs_page_move(
  720. spiffs *fs,
  721. spiffs_file fh,
  722. u8_t *page_data,
  723. spiffs_obj_id obj_id,
  724. spiffs_page_header *page_hdr,
  725. spiffs_page_ix src_pix,
  726. spiffs_page_ix *dst_pix) {
  727. s32_t res;
  728. u8_t was_final = 0;
  729. spiffs_page_header *p_hdr;
  730. spiffs_block_ix bix;
  731. int entry;
  732. spiffs_page_ix free_pix;
  733. // find free entry
  734. res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
  735. SPIFFS_CHECK_RES(res);
  736. free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  737. if (dst_pix) *dst_pix = free_pix;
  738. p_hdr = page_data ? (spiffs_page_header *)page_data : page_hdr;
  739. if (page_data) {
  740. // got page data
  741. was_final = (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) == 0;
  742. // write unfinalized page
  743. p_hdr->flags |= SPIFFS_PH_FLAG_FINAL;
  744. p_hdr->flags &= ~SPIFFS_PH_FLAG_USED;
  745. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  746. 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), page_data);
  747. } else {
  748. // copy page data
  749. 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));
  750. }
  751. SPIFFS_CHECK_RES(res);
  752. // mark entry in destination object lookup
  753. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  754. 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),
  755. sizeof(spiffs_obj_id),
  756. (u8_t *)&obj_id);
  757. SPIFFS_CHECK_RES(res);
  758. fs->stats_p_allocated++;
  759. if (was_final) {
  760. // mark finalized in destination page
  761. p_hdr->flags &= ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED);
  762. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  763. fh,
  764. SPIFFS_PAGE_TO_PADDR(fs, free_pix) + offsetof(spiffs_page_header, flags),
  765. sizeof(u8_t),
  766. (u8_t *)&p_hdr->flags);
  767. SPIFFS_CHECK_RES(res);
  768. }
  769. // mark source deleted
  770. res = spiffs_page_delete(fs, src_pix);
  771. return res;
  772. }
  773. #endif // !SPIFFS_READ_ONLY
  774. #if !SPIFFS_READ_ONLY
  775. // Deletes a page and removes it from object lookup.
  776. s32_t spiffs_page_delete(
  777. spiffs *fs,
  778. spiffs_page_ix pix) {
  779. s32_t res;
  780. spiffs_page_header hdr;
  781. hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED);
  782. // mark deleted entry in source object lookup
  783. spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED;
  784. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE,
  785. 0,
  786. SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_page_ix),
  787. sizeof(spiffs_obj_id),
  788. (u8_t *)&d_obj_id);
  789. SPIFFS_CHECK_RES(res);
  790. fs->stats_p_deleted++;
  791. fs->stats_p_allocated--;
  792. // mark deleted in source page
  793. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE,
  794. 0,
  795. SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),
  796. sizeof(u8_t),
  797. (u8_t *)&hdr.flags);
  798. return res;
  799. }
  800. #endif // !SPIFFS_READ_ONLY
  801. #if !SPIFFS_READ_ONLY
  802. // Create an object index header page with empty index and undefined length
  803. s32_t spiffs_object_create(
  804. spiffs *fs,
  805. spiffs_obj_id obj_id,
  806. const u8_t name[],
  807. const u8_t meta[],
  808. spiffs_obj_type type,
  809. spiffs_page_ix *objix_hdr_pix) {
  810. s32_t res = SPIFFS_OK;
  811. spiffs_block_ix bix;
  812. spiffs_page_object_ix_header oix_hdr;
  813. int entry;
  814. res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs));
  815. SPIFFS_CHECK_RES(res);
  816. obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
  817. // find free entry
  818. res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
  819. SPIFFS_CHECK_RES(res);
  820. SPIFFS_DBG("create: found free page @ "_SPIPRIpg" bix:"_SPIPRIbl" entry:"_SPIPRIsp"\n", (spiffs_page_ix)SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), bix, entry);
  821. // occupy page in object lookup
  822. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
  823. 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t*)&obj_id);
  824. SPIFFS_CHECK_RES(res);
  825. fs->stats_p_allocated++;
  826. // write empty object index page
  827. oix_hdr.p_hdr.obj_id = obj_id;
  828. oix_hdr.p_hdr.span_ix = 0;
  829. oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED);
  830. oix_hdr.type = type;
  831. oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page
  832. strncpy((char*)oix_hdr.name, (const char*)name, SPIFFS_OBJ_NAME_LEN);
  833. #if SPIFFS_OBJ_META_LEN
  834. if (meta) {
  835. memcpy(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN);
  836. } else {
  837. memset(oix_hdr.meta, 0xff, SPIFFS_OBJ_META_LEN);
  838. }
  839. #else
  840. (void) meta;
  841. #endif
  842. // update page
  843. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  844. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&oix_hdr);
  845. SPIFFS_CHECK_RES(res);
  846. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&oix_hdr,
  847. SPIFFS_EV_IX_NEW, obj_id, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), SPIFFS_UNDEFINED_LEN);
  848. if (objix_hdr_pix) {
  849. *objix_hdr_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  850. }
  851. return res;
  852. }
  853. #endif // !SPIFFS_READ_ONLY
  854. #if !SPIFFS_READ_ONLY
  855. // update object index header with any combination of name/size/index
  856. // new_objix_hdr_data may be null, if so the object index header page is loaded
  857. // name may be null, if so name is not changed
  858. // size may be null, if so size is not changed
  859. s32_t spiffs_object_update_index_hdr(
  860. spiffs *fs,
  861. spiffs_fd *fd,
  862. spiffs_obj_id obj_id,
  863. spiffs_page_ix objix_hdr_pix,
  864. u8_t *new_objix_hdr_data,
  865. const u8_t name[],
  866. const u8_t meta[],
  867. u32_t size,
  868. spiffs_page_ix *new_pix) {
  869. s32_t res = SPIFFS_OK;
  870. spiffs_page_object_ix_header *objix_hdr;
  871. spiffs_page_ix new_objix_hdr_pix;
  872. obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
  873. if (new_objix_hdr_data) {
  874. // object index header page already given to us, no need to load it
  875. objix_hdr = (spiffs_page_object_ix_header *)new_objix_hdr_data;
  876. } else {
  877. // read object index header page
  878. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  879. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  880. SPIFFS_CHECK_RES(res);
  881. objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  882. }
  883. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, obj_id, 0);
  884. // change name
  885. if (name) {
  886. strncpy((char*)objix_hdr->name, (const char*)name, SPIFFS_OBJ_NAME_LEN);
  887. }
  888. #if SPIFFS_OBJ_META_LEN
  889. if (meta) {
  890. memcpy(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN);
  891. }
  892. #else
  893. (void) meta;
  894. #endif
  895. if (size) {
  896. objix_hdr->size = size;
  897. }
  898. // move and update page
  899. 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);
  900. if (res == SPIFFS_OK) {
  901. if (new_pix) {
  902. *new_pix = new_objix_hdr_pix;
  903. }
  904. // callback on object index update
  905. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,
  906. new_objix_hdr_data ? SPIFFS_EV_IX_UPD : SPIFFS_EV_IX_UPD_HDR,
  907. obj_id, objix_hdr->p_hdr.span_ix, new_objix_hdr_pix, objix_hdr->size);
  908. if (fd) fd->objix_hdr_pix = new_objix_hdr_pix; // if this is not in the registered cluster
  909. }
  910. return res;
  911. }
  912. #endif // !SPIFFS_READ_ONLY
  913. void spiffs_cb_object_event(
  914. spiffs *fs,
  915. spiffs_page_object_ix *objix,
  916. int ev,
  917. spiffs_obj_id obj_id_raw,
  918. spiffs_span_ix spix,
  919. spiffs_page_ix new_pix,
  920. u32_t new_size) {
  921. #if SPIFFS_IX_MAP == 0
  922. (void)objix;
  923. #endif
  924. // update index caches in all file descriptors
  925. spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG;
  926. u32_t i;
  927. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  928. for (i = 0; i < fs->fd_count; i++) {
  929. spiffs_fd *cur_fd = &fds[i];
  930. #if SPIFFS_TEMPORAL_FD_CACHE
  931. if (cur_fd->score == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
  932. #else
  933. if (cur_fd->file_nbr == 0 || (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
  934. #endif
  935. if (spix == 0) {
  936. if (ev != SPIFFS_EV_IX_DEL) {
  937. SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid" objix_hdr_pix to "_SPIPRIpg", size:"_SPIPRIi"\n", cur_fd->file_nbr, cur_fd->obj_id, new_pix, new_size);
  938. cur_fd->objix_hdr_pix = new_pix;
  939. if (new_size != 0) {
  940. cur_fd->size = new_size;
  941. }
  942. } else {
  943. cur_fd->file_nbr = 0;
  944. cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED;
  945. }
  946. }
  947. if (cur_fd->cursor_objix_spix == spix) {
  948. if (ev != SPIFFS_EV_IX_DEL) {
  949. SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", cur_fd->file_nbr, cur_fd->obj_id, spix, new_pix);
  950. cur_fd->cursor_objix_pix = new_pix;
  951. } else {
  952. cur_fd->cursor_objix_pix = 0;
  953. }
  954. }
  955. }
  956. #if SPIFFS_IX_MAP
  957. // update index maps
  958. if (ev == SPIFFS_EV_IX_UPD || ev == SPIFFS_EV_IX_NEW) {
  959. for (i = 0; i < fs->fd_count; i++) {
  960. spiffs_fd *cur_fd = &fds[i];
  961. // check fd opened, having ix map, match obj id
  962. if (cur_fd->file_nbr == 0 ||
  963. cur_fd->ix_map == 0 ||
  964. (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
  965. SPIFFS_DBG(" callback: map ix update fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp"\n", cur_fd->file_nbr, cur_fd->obj_id, spix);
  966. spiffs_update_ix_map(fs, cur_fd, spix, objix);
  967. }
  968. }
  969. #endif
  970. // callback to user if object index header
  971. if (fs->file_cb_f && spix == 0 && (obj_id_raw & SPIFFS_OBJ_ID_IX_FLAG)) {
  972. spiffs_fileop_type op;
  973. if (ev == SPIFFS_EV_IX_NEW) {
  974. op = SPIFFS_CB_CREATED;
  975. } else if (ev == SPIFFS_EV_IX_UPD ||
  976. ev == SPIFFS_EV_IX_MOV ||
  977. ev == SPIFFS_EV_IX_UPD_HDR) {
  978. op = SPIFFS_CB_UPDATED;
  979. } else if (ev == SPIFFS_EV_IX_DEL) {
  980. op = SPIFFS_CB_DELETED;
  981. } else {
  982. SPIFFS_DBG(" callback: WARNING unknown callback event "_SPIPRIi"\n", ev);
  983. return; // bail out
  984. }
  985. fs->file_cb_f(fs, op, obj_id, new_pix);
  986. }
  987. }
  988. // Open object by id
  989. s32_t spiffs_object_open_by_id(
  990. spiffs *fs,
  991. spiffs_obj_id obj_id,
  992. spiffs_fd *fd,
  993. spiffs_flags flags,
  994. spiffs_mode mode) {
  995. s32_t res = SPIFFS_OK;
  996. spiffs_page_ix pix;
  997. res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
  998. SPIFFS_CHECK_RES(res);
  999. res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);
  1000. return res;
  1001. }
  1002. // Open object by page index
  1003. s32_t spiffs_object_open_by_page(
  1004. spiffs *fs,
  1005. spiffs_page_ix pix,
  1006. spiffs_fd *fd,
  1007. spiffs_flags flags,
  1008. spiffs_mode mode) {
  1009. (void)mode;
  1010. s32_t res = SPIFFS_OK;
  1011. spiffs_page_object_ix_header oix_hdr;
  1012. spiffs_obj_id obj_id;
  1013. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1014. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr);
  1015. SPIFFS_CHECK_RES(res);
  1016. spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(fs, pix);
  1017. int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix);
  1018. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
  1019. 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id);
  1020. fd->fs = fs;
  1021. fd->objix_hdr_pix = pix;
  1022. fd->size = oix_hdr.size;
  1023. fd->offset = 0;
  1024. fd->cursor_objix_pix = pix;
  1025. fd->cursor_objix_spix = 0;
  1026. fd->obj_id = obj_id;
  1027. fd->flags = flags;
  1028. SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
  1029. SPIFFS_DBG("open: fd "_SPIPRIfd" is obj id "_SPIPRIid"\n", fd->file_nbr, fd->obj_id);
  1030. return res;
  1031. }
  1032. #if !SPIFFS_READ_ONLY
  1033. // Append to object
  1034. // keep current object index (header) page in fs->work buffer
  1035. s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
  1036. spiffs *fs = fd->fs;
  1037. s32_t res = SPIFFS_OK;
  1038. u32_t written = 0;
  1039. SPIFFS_DBG("append: "_SPIPRIi" bytes @ offs "_SPIPRIi" of size "_SPIPRIi"\n", len, offset, fd->size);
  1040. if (offset > fd->size) {
  1041. SPIFFS_DBG("append: offset reversed to size\n");
  1042. offset = fd->size;
  1043. }
  1044. res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
  1045. if (res != SPIFFS_OK) {
  1046. SPIFFS_DBG("append: gc check fail "_SPIPRIi"\n", res);
  1047. }
  1048. SPIFFS_CHECK_RES(res);
  1049. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  1050. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  1051. spiffs_page_header p_hdr;
  1052. spiffs_span_ix cur_objix_spix = 0;
  1053. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  1054. spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;
  1055. spiffs_page_ix new_objix_hdr_page;
  1056. spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
  1057. spiffs_page_ix data_page;
  1058. u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);
  1059. // write all data
  1060. while (res == SPIFFS_OK && written < len) {
  1061. // calculate object index page span index
  1062. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  1063. // handle storing and loading of object indices
  1064. if (cur_objix_spix != prev_objix_spix) {
  1065. // new object index page
  1066. // within this clause we return directly if something fails, object index mess-up
  1067. if (written > 0) {
  1068. // store previous object index page, unless first pass
  1069. SPIFFS_DBG("append: "_SPIPRIid" store objix "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
  1070. cur_objix_pix, prev_objix_spix, written);
  1071. if (prev_objix_spix == 0) {
  1072. // this is an update to object index header page
  1073. objix_hdr->size = offset+written;
  1074. if (offset == 0) {
  1075. // was an empty object, update same page (size was 0xffffffff)
  1076. res = spiffs_page_index_check(fs, fd, cur_objix_pix, 0);
  1077. SPIFFS_CHECK_RES(res);
  1078. res = _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(res);
  1081. } else {
  1082. // was a nonempty object, update to new page
  1083. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1084. fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page);
  1085. SPIFFS_CHECK_RES(res);
  1086. SPIFFS_DBG("append: "_SPIPRIid" store new objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
  1087. new_objix_hdr_page, 0, written);
  1088. }
  1089. } else {
  1090. // this is an update to an object index page
  1091. res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);
  1092. SPIFFS_CHECK_RES(res);
  1093. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  1094. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1095. SPIFFS_CHECK_RES(res);
  1096. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
  1097. SPIFFS_EV_IX_UPD,fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);
  1098. // update length in object index header page
  1099. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1100. fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page);
  1101. SPIFFS_CHECK_RES(res);
  1102. SPIFFS_DBG("append: "_SPIPRIid" store new size I "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
  1103. offset+written, new_objix_hdr_page, 0, written);
  1104. }
  1105. fd->size = offset+written;
  1106. fd->offset = offset+written;
  1107. }
  1108. // create or load new object index page
  1109. if (cur_objix_spix == 0) {
  1110. // load object index header page, must always exist
  1111. SPIFFS_DBG("append: "_SPIPRIid" load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", fd->obj_id, cur_objix_pix, cur_objix_spix);
  1112. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1113. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1114. SPIFFS_CHECK_RES(res);
  1115. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1116. } else {
  1117. spiffs_span_ix len_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, (fd->size-1)/SPIFFS_DATA_PAGE_SIZE(fs));
  1118. // on subsequent passes, create a new object index page
  1119. if (written > 0 || cur_objix_spix > len_objix_spix) {
  1120. p_hdr.obj_id = fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
  1121. p_hdr.span_ix = cur_objix_spix;
  1122. p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
  1123. res = spiffs_page_allocate_data(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
  1124. &p_hdr, 0, 0, 0, 1, &cur_objix_pix);
  1125. SPIFFS_CHECK_RES(res);
  1126. // quick "load" of new object index page
  1127. memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  1128. memcpy(fs->work, &p_hdr, sizeof(spiffs_page_header));
  1129. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
  1130. SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);
  1131. SPIFFS_DBG("append: "_SPIPRIid" create objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id
  1132. , cur_objix_pix, cur_objix_spix, written);
  1133. } else {
  1134. // on first pass, we load existing object index page
  1135. spiffs_page_ix pix;
  1136. SPIFFS_DBG("append: "_SPIPRIid" find objix span_ix:"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix);
  1137. if (fd->cursor_objix_spix == cur_objix_spix) {
  1138. pix = fd->cursor_objix_pix;
  1139. } else {
  1140. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
  1141. SPIFFS_CHECK_RES(res);
  1142. }
  1143. SPIFFS_DBG("append: "_SPIPRIid" found object index at page "_SPIPRIpg" [fd size "_SPIPRIi"]\n", fd->obj_id, pix, fd->size);
  1144. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1145. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1146. SPIFFS_CHECK_RES(res);
  1147. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1148. cur_objix_pix = pix;
  1149. }
  1150. fd->cursor_objix_pix = cur_objix_pix;
  1151. fd->cursor_objix_spix = cur_objix_spix;
  1152. fd->offset = offset+written;
  1153. fd->size = offset+written;
  1154. }
  1155. prev_objix_spix = cur_objix_spix;
  1156. }
  1157. // write data
  1158. u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);
  1159. if (page_offs == 0) {
  1160. // at beginning of a page, allocate and write a new page of data
  1161. p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  1162. p_hdr.span_ix = data_spix;
  1163. p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately
  1164. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  1165. &p_hdr, &data[written], to_write, page_offs, 1, &data_page);
  1166. SPIFFS_DBG("append: "_SPIPRIid" store new data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id,
  1167. data_page, data_spix, page_offs, to_write, written);
  1168. } else {
  1169. // append to existing page, fill out free data in existing page
  1170. if (cur_objix_spix == 0) {
  1171. // get data page from object index header page
  1172. data_page = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  1173. } else {
  1174. // get data page from object index page
  1175. data_page = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  1176. }
  1177. res = spiffs_page_data_check(fs, fd, data_page, data_spix);
  1178. SPIFFS_CHECK_RES(res);
  1179. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  1180. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
  1181. SPIFFS_DBG("append: "_SPIPRIid" store to existing data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id
  1182. , data_page, data_spix, page_offs, to_write, written);
  1183. }
  1184. if (res != SPIFFS_OK) break;
  1185. // update memory representation of object index page with new data page
  1186. if (cur_objix_spix == 0) {
  1187. // update object index header page
  1188. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page;
  1189. SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", fd->obj_id
  1190. , data_page, data_spix);
  1191. objix_hdr->size = offset+written;
  1192. } else {
  1193. // update object index page
  1194. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page;
  1195. SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", fd->obj_id
  1196. , data_page, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  1197. }
  1198. // update internals
  1199. page_offs = 0;
  1200. data_spix++;
  1201. written += to_write;
  1202. } // while all data
  1203. fd->size = offset+written;
  1204. fd->offset = offset+written;
  1205. fd->cursor_objix_pix = cur_objix_pix;
  1206. fd->cursor_objix_spix = cur_objix_spix;
  1207. // finalize updated object indices
  1208. s32_t res2 = SPIFFS_OK;
  1209. if (cur_objix_spix != 0) {
  1210. // wrote beyond object index header page
  1211. // write last modified object index page, unless object header index page
  1212. SPIFFS_DBG("append: "_SPIPRIid" store objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
  1213. cur_objix_pix, cur_objix_spix, written);
  1214. res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
  1215. SPIFFS_CHECK_RES(res2);
  1216. res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  1217. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1218. SPIFFS_CHECK_RES(res2);
  1219. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
  1220. SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);
  1221. // update size in object header index page
  1222. res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1223. fd->objix_hdr_pix, 0, 0, 0, offset+written, &new_objix_hdr_page);
  1224. SPIFFS_DBG("append: "_SPIPRIid" store new size II "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi", res "_SPIPRIi"\n", fd->obj_id
  1225. , offset+written, new_objix_hdr_page, 0, written, res2);
  1226. SPIFFS_CHECK_RES(res2);
  1227. } else {
  1228. // wrote within object index header page
  1229. if (offset == 0) {
  1230. // wrote to empty object - simply update size and write whole page
  1231. objix_hdr->size = offset+written;
  1232. SPIFFS_DBG("append: "_SPIPRIid" store fresh objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id
  1233. , cur_objix_pix, cur_objix_spix, written);
  1234. res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
  1235. SPIFFS_CHECK_RES(res2);
  1236. res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  1237. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1238. SPIFFS_CHECK_RES(res2);
  1239. // callback on object index update
  1240. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
  1241. SPIFFS_EV_IX_UPD_HDR, fd->obj_id, objix_hdr->p_hdr.span_ix, cur_objix_pix, objix_hdr->size);
  1242. } else {
  1243. // modifying object index header page, update size and make new copy
  1244. res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1245. fd->objix_hdr_pix, fs->work, 0, 0, offset+written, &new_objix_hdr_page);
  1246. SPIFFS_DBG("append: "_SPIPRIid" store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id
  1247. , new_objix_hdr_page, 0, written);
  1248. SPIFFS_CHECK_RES(res2);
  1249. }
  1250. }
  1251. return res;
  1252. } // spiffs_object_append
  1253. #endif // !SPIFFS_READ_ONLY
  1254. #if !SPIFFS_READ_ONLY
  1255. // Modify object
  1256. // keep current object index (header) page in fs->work buffer
  1257. s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
  1258. spiffs *fs = fd->fs;
  1259. s32_t res = SPIFFS_OK;
  1260. u32_t written = 0;
  1261. res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs));
  1262. SPIFFS_CHECK_RES(res);
  1263. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  1264. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  1265. spiffs_page_header p_hdr;
  1266. spiffs_span_ix cur_objix_spix = 0;
  1267. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  1268. spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;
  1269. spiffs_page_ix new_objix_hdr_pix;
  1270. spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
  1271. spiffs_page_ix data_pix;
  1272. u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);
  1273. // write all data
  1274. while (res == SPIFFS_OK && written < len) {
  1275. // calculate object index page span index
  1276. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  1277. // handle storing and loading of object indices
  1278. if (cur_objix_spix != prev_objix_spix) {
  1279. // new object index page
  1280. // within this clause we return directly if something fails, object index mess-up
  1281. if (written > 0) {
  1282. // store previous object index (header) page, unless first pass
  1283. if (prev_objix_spix == 0) {
  1284. // store previous object index header page
  1285. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1286. fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);
  1287. SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written);
  1288. SPIFFS_CHECK_RES(res);
  1289. } else {
  1290. // store new version of previous object index page
  1291. spiffs_page_ix new_objix_pix;
  1292. res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);
  1293. SPIFFS_CHECK_RES(res);
  1294. res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
  1295. SPIFFS_DBG("modify: store previous modified objix page, "_SPIPRIid":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, objix->p_hdr.span_ix, written);
  1296. SPIFFS_CHECK_RES(res);
  1297. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,
  1298. SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
  1299. }
  1300. }
  1301. // load next object index page
  1302. if (cur_objix_spix == 0) {
  1303. // load object index header page, must exist
  1304. SPIFFS_DBG("modify: load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", cur_objix_pix, cur_objix_spix);
  1305. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1306. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1307. SPIFFS_CHECK_RES(res);
  1308. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1309. } else {
  1310. // load existing object index page on first pass
  1311. spiffs_page_ix pix;
  1312. SPIFFS_DBG("modify: find objix span_ix:"_SPIPRIsp"\n", cur_objix_spix);
  1313. if (fd->cursor_objix_spix == cur_objix_spix) {
  1314. pix = fd->cursor_objix_pix;
  1315. } else {
  1316. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
  1317. SPIFFS_CHECK_RES(res);
  1318. }
  1319. SPIFFS_DBG("modify: found object index at page "_SPIPRIpg"\n", pix);
  1320. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1321. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1322. SPIFFS_CHECK_RES(res);
  1323. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1324. cur_objix_pix = pix;
  1325. }
  1326. fd->cursor_objix_pix = cur_objix_pix;
  1327. fd->cursor_objix_spix = cur_objix_spix;
  1328. fd->offset = offset+written;
  1329. prev_objix_spix = cur_objix_spix;
  1330. }
  1331. // write partial data
  1332. u32_t to_write = MIN(len-written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);
  1333. spiffs_page_ix orig_data_pix;
  1334. if (cur_objix_spix == 0) {
  1335. // get data page from object index header page
  1336. orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  1337. } else {
  1338. // get data page from object index page
  1339. orig_data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  1340. }
  1341. p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  1342. p_hdr.span_ix = data_spix;
  1343. p_hdr.flags = 0xff;
  1344. if (page_offs == 0 && to_write == SPIFFS_DATA_PAGE_SIZE(fs)) {
  1345. // a full page, allocate and write a new page of data
  1346. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  1347. &p_hdr, &data[written], to_write, page_offs, 1, &data_pix);
  1348. SPIFFS_DBG("modify: store new data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", data_pix, data_spix, page_offs, to_write, written);
  1349. } else {
  1350. // write to existing page, allocate new and copy unmodified data
  1351. res = spiffs_page_data_check(fs, fd, orig_data_pix, data_spix);
  1352. SPIFFS_CHECK_RES(res);
  1353. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  1354. &p_hdr, 0, 0, 0, 0, &data_pix);
  1355. if (res != SPIFFS_OK) break;
  1356. // copy unmodified data
  1357. if (page_offs > 0) {
  1358. // before modification
  1359. res = spiffs_phys_cpy(fs, fd->file_nbr,
  1360. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),
  1361. SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header),
  1362. page_offs);
  1363. if (res != SPIFFS_OK) break;
  1364. }
  1365. if (page_offs + to_write < SPIFFS_DATA_PAGE_SIZE(fs)) {
  1366. // after modification
  1367. res = spiffs_phys_cpy(fs, fd->file_nbr,
  1368. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,
  1369. SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,
  1370. SPIFFS_DATA_PAGE_SIZE(fs) - (page_offs + to_write));
  1371. if (res != SPIFFS_OK) break;
  1372. }
  1373. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  1374. fd->file_nbr,
  1375. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
  1376. if (res != SPIFFS_OK) break;
  1377. p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;
  1378. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  1379. fd->file_nbr,
  1380. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + offsetof(spiffs_page_header, flags),
  1381. sizeof(u8_t),
  1382. (u8_t *)&p_hdr.flags);
  1383. if (res != SPIFFS_OK) break;
  1384. SPIFFS_DBG("modify: store to existing data page, src:"_SPIPRIpg", dst:"_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", orig_data_pix, data_pix, data_spix, page_offs, to_write, written);
  1385. }
  1386. // delete original data page
  1387. res = spiffs_page_delete(fs, orig_data_pix);
  1388. if (res != SPIFFS_OK) break;
  1389. // update memory representation of object index page with new data page
  1390. if (cur_objix_spix == 0) {
  1391. // update object index header page
  1392. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix;
  1393. SPIFFS_DBG("modify: wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", data_pix, data_spix);
  1394. } else {
  1395. // update object index page
  1396. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix;
  1397. SPIFFS_DBG("modify: wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  1398. }
  1399. // update internals
  1400. page_offs = 0;
  1401. data_spix++;
  1402. written += to_write;
  1403. } // while all data
  1404. fd->offset = offset+written;
  1405. fd->cursor_objix_pix = cur_objix_pix;
  1406. fd->cursor_objix_spix = cur_objix_spix;
  1407. // finalize updated object indices
  1408. s32_t res2 = SPIFFS_OK;
  1409. if (cur_objix_spix != 0) {
  1410. // wrote beyond object index header page
  1411. // write last modified object index page
  1412. // move and update page
  1413. spiffs_page_ix new_objix_pix;
  1414. res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
  1415. SPIFFS_CHECK_RES(res2);
  1416. res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
  1417. SPIFFS_DBG("modify: store modified objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, cur_objix_spix, written);
  1418. fd->cursor_objix_pix = new_objix_pix;
  1419. fd->cursor_objix_spix = cur_objix_spix;
  1420. SPIFFS_CHECK_RES(res2);
  1421. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,
  1422. SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
  1423. } else {
  1424. // wrote within object index header page
  1425. res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1426. fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);
  1427. SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written);
  1428. SPIFFS_CHECK_RES(res2);
  1429. }
  1430. return res;
  1431. } // spiffs_object_modify
  1432. #endif // !SPIFFS_READ_ONLY
  1433. static s32_t spiffs_object_find_object_index_header_by_name_v(
  1434. spiffs *fs,
  1435. spiffs_obj_id obj_id,
  1436. spiffs_block_ix bix,
  1437. int ix_entry,
  1438. const void *user_const_p,
  1439. void *user_var_p) {
  1440. (void)user_var_p;
  1441. s32_t res;
  1442. spiffs_page_object_ix_header objix_hdr;
  1443. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  1444. if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||
  1445. (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
  1446. return SPIFFS_VIS_COUNTINUE;
  1447. }
  1448. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  1449. 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
  1450. SPIFFS_CHECK_RES(res);
  1451. if (objix_hdr.p_hdr.span_ix == 0 &&
  1452. (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
  1453. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
  1454. if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) {
  1455. return SPIFFS_OK;
  1456. }
  1457. }
  1458. return SPIFFS_VIS_COUNTINUE;
  1459. }
  1460. // Finds object index header page by name
  1461. s32_t spiffs_object_find_object_index_header_by_name(
  1462. spiffs *fs,
  1463. const u8_t name[SPIFFS_OBJ_NAME_LEN],
  1464. spiffs_page_ix *pix) {
  1465. s32_t res;
  1466. spiffs_block_ix bix;
  1467. int entry;
  1468. res = spiffs_obj_lu_find_entry_visitor(fs,
  1469. fs->cursor_block_ix,
  1470. fs->cursor_obj_lu_entry,
  1471. 0,
  1472. 0,
  1473. spiffs_object_find_object_index_header_by_name_v,
  1474. name,
  1475. 0,
  1476. &bix,
  1477. &entry);
  1478. if (res == SPIFFS_VIS_END) {
  1479. res = SPIFFS_ERR_NOT_FOUND;
  1480. }
  1481. SPIFFS_CHECK_RES(res);
  1482. if (pix) {
  1483. *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
  1484. }
  1485. fs->cursor_block_ix = bix;
  1486. fs->cursor_obj_lu_entry = entry;
  1487. return res;
  1488. }
  1489. #if !SPIFFS_READ_ONLY
  1490. // Truncates object to new size. If new size is null, object may be removed totally
  1491. s32_t spiffs_object_truncate(
  1492. spiffs_fd *fd,
  1493. u32_t new_size,
  1494. u8_t remove_full) {
  1495. s32_t res = SPIFFS_OK;
  1496. spiffs *fs = fd->fs;
  1497. if ((fd->size == SPIFFS_UNDEFINED_LEN || fd->size == 0) && !remove_full) {
  1498. // no op
  1499. return res;
  1500. }
  1501. // need 2 pages if not removing: object index page + possibly chopped data page
  1502. if (remove_full == 0) {
  1503. res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs) * 2);
  1504. SPIFFS_CHECK_RES(res);
  1505. }
  1506. spiffs_page_ix objix_pix = fd->objix_hdr_pix;
  1507. spiffs_span_ix data_spix = (fd->size > 0 ? fd->size-1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs);
  1508. u32_t cur_size = fd->size == (u32_t)SPIFFS_UNDEFINED_LEN ? 0 : fd->size ;
  1509. spiffs_span_ix cur_objix_spix = 0;
  1510. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  1511. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  1512. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  1513. spiffs_page_ix data_pix;
  1514. spiffs_page_ix new_objix_hdr_pix;
  1515. // before truncating, check if object is to be fully removed and mark this
  1516. if (remove_full && new_size == 0) {
  1517. u8_t flags = ~( SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE);
  1518. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
  1519. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix) + offsetof(spiffs_page_header, flags),
  1520. sizeof(u8_t),
  1521. (u8_t *)&flags);
  1522. SPIFFS_CHECK_RES(res);
  1523. }
  1524. // delete from end of object until desired len is reached
  1525. while (cur_size > new_size) {
  1526. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  1527. // put object index for current data span index in work buffer
  1528. if (prev_objix_spix != cur_objix_spix) {
  1529. if (prev_objix_spix != (spiffs_span_ix)-1) {
  1530. // remove previous object index page
  1531. SPIFFS_DBG("truncate: delete objix page "_SPIPRIpg":"_SPIPRIsp"\n", objix_pix, prev_objix_spix);
  1532. res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix);
  1533. SPIFFS_CHECK_RES(res);
  1534. res = spiffs_page_delete(fs, objix_pix);
  1535. SPIFFS_CHECK_RES(res);
  1536. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
  1537. SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);
  1538. if (prev_objix_spix > 0) {
  1539. // Update object index header page, unless we totally want to remove the file.
  1540. // If fully removing, we're not keeping consistency as good as when storing the header between chunks,
  1541. // would we be aborted. But when removing full files, a crammed system may otherwise
  1542. // report ERR_FULL a la windows. We cannot have that.
  1543. // Hence, take the risk - if aborted, a file check would free the lost pages and mend things
  1544. // as the file is marked as fully deleted in the beginning.
  1545. if (remove_full == 0) {
  1546. SPIFFS_DBG("truncate: update objix hdr page "_SPIPRIpg":"_SPIPRIsp" to size "_SPIPRIi"\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
  1547. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1548. fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);
  1549. SPIFFS_CHECK_RES(res);
  1550. }
  1551. fd->size = cur_size;
  1552. }
  1553. }
  1554. // load current object index (header) page
  1555. if (cur_objix_spix == 0) {
  1556. objix_pix = fd->objix_hdr_pix;
  1557. } else {
  1558. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);
  1559. SPIFFS_CHECK_RES(res);
  1560. }
  1561. SPIFFS_DBG("truncate: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix);
  1562. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1563. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1564. SPIFFS_CHECK_RES(res);
  1565. SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
  1566. fd->cursor_objix_pix = objix_pix;
  1567. fd->cursor_objix_spix = cur_objix_spix;
  1568. fd->offset = cur_size;
  1569. prev_objix_spix = cur_objix_spix;
  1570. }
  1571. if (cur_objix_spix == 0) {
  1572. // get data page from object index header page
  1573. data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  1574. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = SPIFFS_OBJ_ID_FREE;
  1575. } else {
  1576. // get data page from object index page
  1577. data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  1578. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;
  1579. }
  1580. SPIFFS_DBG("truncate: got data pix "_SPIPRIpg"\n", data_pix);
  1581. if (new_size == 0 || remove_full || cur_size - new_size >= SPIFFS_DATA_PAGE_SIZE(fs)) {
  1582. // delete full data page
  1583. res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
  1584. if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
  1585. SPIFFS_DBG("truncate: err validating data pix "_SPIPRIi"\n", res);
  1586. break;
  1587. }
  1588. if (res == SPIFFS_OK) {
  1589. res = spiffs_page_delete(fs, data_pix);
  1590. if (res != SPIFFS_OK) {
  1591. SPIFFS_DBG("truncate: err deleting data pix "_SPIPRIi"\n", res);
  1592. break;
  1593. }
  1594. } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
  1595. res = SPIFFS_OK;
  1596. }
  1597. // update current size
  1598. if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {
  1599. cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);
  1600. } else {
  1601. cur_size -= cur_size % SPIFFS_DATA_PAGE_SIZE(fs);
  1602. }
  1603. fd->size = cur_size;
  1604. fd->offset = cur_size;
  1605. SPIFFS_DBG("truncate: delete data page "_SPIPRIpg" for data spix:"_SPIPRIsp", cur_size:"_SPIPRIi"\n", data_pix, data_spix, cur_size);
  1606. } else {
  1607. // delete last page, partially
  1608. spiffs_page_header p_hdr;
  1609. spiffs_page_ix new_data_pix;
  1610. u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));
  1611. SPIFFS_DBG("truncate: delete "_SPIPRIi" bytes from data page "_SPIPRIpg" for data spix:"_SPIPRIsp", cur_size:"_SPIPRIi"\n", bytes_to_remove, data_pix, data_spix, cur_size);
  1612. res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
  1613. if (res != SPIFFS_OK) break;
  1614. p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
  1615. p_hdr.span_ix = data_spix;
  1616. p_hdr.flags = 0xff;
  1617. // allocate new page and copy unmodified data
  1618. res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
  1619. &p_hdr, 0, 0, 0, 0, &new_data_pix);
  1620. if (res != SPIFFS_OK) break;
  1621. res = spiffs_phys_cpy(fs, 0,
  1622. SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + sizeof(spiffs_page_header),
  1623. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),
  1624. SPIFFS_DATA_PAGE_SIZE(fs) - bytes_to_remove);
  1625. if (res != SPIFFS_OK) break;
  1626. // delete original data page
  1627. res = spiffs_page_delete(fs, data_pix);
  1628. if (res != SPIFFS_OK) break;
  1629. p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;
  1630. res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
  1631. fd->file_nbr,
  1632. SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + offsetof(spiffs_page_header, flags),
  1633. sizeof(u8_t),
  1634. (u8_t *)&p_hdr.flags);
  1635. if (res != SPIFFS_OK) break;
  1636. // update memory representation of object index page with new data page
  1637. if (cur_objix_spix == 0) {
  1638. // update object index header page
  1639. ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
  1640. SPIFFS_DBG("truncate: wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  1641. } else {
  1642. // update object index page
  1643. ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
  1644. SPIFFS_DBG("truncate: wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
  1645. }
  1646. cur_size = new_size;
  1647. fd->size = new_size;
  1648. fd->offset = cur_size;
  1649. break;
  1650. }
  1651. data_spix--;
  1652. } // while all data
  1653. // update object indices
  1654. if (cur_objix_spix == 0) {
  1655. // update object index header page
  1656. if (cur_size == 0) {
  1657. if (remove_full) {
  1658. // remove object altogether
  1659. SPIFFS_DBG("truncate: remove object index header page "_SPIPRIpg"\n", objix_pix);
  1660. res = spiffs_page_index_check(fs, fd, objix_pix, 0);
  1661. SPIFFS_CHECK_RES(res);
  1662. res = spiffs_page_delete(fs, objix_pix);
  1663. SPIFFS_CHECK_RES(res);
  1664. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
  1665. SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0);
  1666. } else {
  1667. // make uninitialized object
  1668. SPIFFS_DBG("truncate: reset objix_hdr page "_SPIPRIpg"\n", objix_pix);
  1669. memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,
  1670. SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));
  1671. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1672. objix_pix, fs->work, 0, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);
  1673. SPIFFS_CHECK_RES(res);
  1674. }
  1675. } else {
  1676. // update object index header page
  1677. SPIFFS_DBG("truncate: update object index header page with indices and size\n");
  1678. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1679. objix_pix, fs->work, 0, 0, cur_size, &new_objix_hdr_pix);
  1680. SPIFFS_CHECK_RES(res);
  1681. }
  1682. } else {
  1683. // update both current object index page and object index header page
  1684. spiffs_page_ix new_objix_pix;
  1685. res = spiffs_page_index_check(fs, fd, objix_pix, cur_objix_spix);
  1686. SPIFFS_CHECK_RES(res);
  1687. // move and update object index page
  1688. res = spiffs_page_move(fs, fd->file_nbr, (u8_t*)objix_hdr, fd->obj_id, 0, objix_pix, &new_objix_pix);
  1689. SPIFFS_CHECK_RES(res);
  1690. spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,
  1691. SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
  1692. SPIFFS_DBG("truncate: store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, cur_objix_spix);
  1693. fd->cursor_objix_pix = new_objix_pix;
  1694. fd->cursor_objix_spix = cur_objix_spix;
  1695. fd->offset = cur_size;
  1696. // update object index header page with new size
  1697. res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
  1698. fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);
  1699. SPIFFS_CHECK_RES(res);
  1700. }
  1701. fd->size = cur_size;
  1702. return res;
  1703. } // spiffs_object_truncate
  1704. #endif // !SPIFFS_READ_ONLY
  1705. s32_t spiffs_object_read(
  1706. spiffs_fd *fd,
  1707. u32_t offset,
  1708. u32_t len,
  1709. u8_t *dst) {
  1710. s32_t res = SPIFFS_OK;
  1711. spiffs *fs = fd->fs;
  1712. spiffs_page_ix objix_pix;
  1713. spiffs_page_ix data_pix;
  1714. spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
  1715. u32_t cur_offset = offset;
  1716. spiffs_span_ix cur_objix_spix;
  1717. spiffs_span_ix prev_objix_spix = (spiffs_span_ix)-1;
  1718. spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
  1719. spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
  1720. while (cur_offset < offset + len) {
  1721. #if SPIFFS_IX_MAP
  1722. // check if we have a memory, index map and if so, if we're within index map's range
  1723. // and if so, if the entry is populated
  1724. if (fd->ix_map && data_spix >= fd->ix_map->start_spix && data_spix <= fd->ix_map->end_spix
  1725. && fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix]) {
  1726. data_pix = fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix];
  1727. } else {
  1728. #endif
  1729. cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
  1730. if (prev_objix_spix != cur_objix_spix) {
  1731. // load current object index (header) page
  1732. if (cur_objix_spix == 0) {
  1733. objix_pix = fd->objix_hdr_pix;
  1734. } else {
  1735. SPIFFS_DBG("read: find objix "_SPIPRIid":"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix);
  1736. if (fd->cursor_objix_spix == cur_objix_spix) {
  1737. objix_pix = fd->cursor_objix_pix;
  1738. } else {
  1739. res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);
  1740. SPIFFS_CHECK_RES(res);
  1741. }
  1742. }
  1743. SPIFFS_DBG("read: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix);
  1744. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
  1745. fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
  1746. SPIFFS_CHECK_RES(res);
  1747. SPIFFS_VALIDATE_OBJIX(objix->p_hdr, fd->obj_id, cur_objix_spix);
  1748. fd->offset = cur_offset;
  1749. fd->cursor_objix_pix = objix_pix;
  1750. fd->cursor_objix_spix = cur_objix_spix;
  1751. prev_objix_spix = cur_objix_spix;
  1752. }
  1753. if (cur_objix_spix == 0) {
  1754. // get data page from object index header page
  1755. data_pix = ((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
  1756. } else {
  1757. // get data page from object index page
  1758. data_pix = ((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
  1759. }
  1760. #if SPIFFS_IX_MAP
  1761. }
  1762. #endif
  1763. // all remaining data
  1764. u32_t len_to_read = offset + len - cur_offset;
  1765. // remaining data in page
  1766. len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
  1767. // remaining data in file
  1768. len_to_read = MIN(len_to_read, fd->size);
  1769. SPIFFS_DBG("read: offset:"_SPIPRIi" rd:"_SPIPRIi" data spix:"_SPIPRIsp" is data_pix:"_SPIPRIpg" addr:"_SPIPRIad"\n", cur_offset, len_to_read, data_spix, data_pix,
  1770. (u32_t)(SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))));
  1771. if (len_to_read <= 0) {
  1772. res = SPIFFS_ERR_END_OF_OBJECT;
  1773. break;
  1774. }
  1775. res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
  1776. SPIFFS_CHECK_RES(res);
  1777. res = _spiffs_rd(
  1778. fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
  1779. fd->file_nbr,
  1780. SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)),
  1781. len_to_read,
  1782. dst);
  1783. SPIFFS_CHECK_RES(res);
  1784. dst += len_to_read;
  1785. cur_offset += len_to_read;
  1786. fd->offset = cur_offset;
  1787. data_spix++;
  1788. }
  1789. return res;
  1790. }
  1791. #if !SPIFFS_READ_ONLY
  1792. typedef struct {
  1793. spiffs_obj_id min_obj_id;
  1794. spiffs_obj_id max_obj_id;
  1795. u32_t compaction;
  1796. const u8_t *conflicting_name;
  1797. } spiffs_free_obj_id_state;
  1798. 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,
  1799. const void *user_const_p, void *user_var_p) {
  1800. if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) {
  1801. spiffs_obj_id min_obj_id = *((spiffs_obj_id*)user_var_p);
  1802. const u8_t *conflicting_name = (const u8_t*)user_const_p;
  1803. // if conflicting name parameter is given, also check if this name is found in object index hdrs
  1804. if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) {
  1805. spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
  1806. int res;
  1807. spiffs_page_object_ix_header objix_hdr;
  1808. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  1809. 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
  1810. SPIFFS_CHECK_RES(res);
  1811. if (objix_hdr.p_hdr.span_ix == 0 &&
  1812. (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
  1813. (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
  1814. if (strcmp((const char*)user_const_p, (char*)objix_hdr.name) == 0) {
  1815. return SPIFFS_ERR_CONFLICTING_NAME;
  1816. }
  1817. }
  1818. }
  1819. id &= ~SPIFFS_OBJ_ID_IX_FLAG;
  1820. u32_t bit_ix = (id-min_obj_id) & 7;
  1821. int byte_ix = (id-min_obj_id) >> 3;
  1822. if (byte_ix >= 0 && (u32_t)byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
  1823. fs->work[byte_ix] |= (1<<bit_ix);
  1824. }
  1825. }
  1826. return SPIFFS_VIS_COUNTINUE;
  1827. }
  1828. 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,
  1829. const void *user_const_p, void *user_var_p) {
  1830. (void)user_var_p;
  1831. if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED && (id & SPIFFS_OBJ_ID_IX_FLAG)) {
  1832. s32_t res;
  1833. const spiffs_free_obj_id_state *state = (const spiffs_free_obj_id_state*)user_const_p;
  1834. spiffs_page_object_ix_header objix_hdr;
  1835. res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
  1836. 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, ix_entry), sizeof(spiffs_page_object_ix_header), (u8_t*)&objix_hdr);
  1837. if (res == SPIFFS_OK && objix_hdr.p_hdr.span_ix == 0 &&
  1838. ((objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) ==
  1839. (SPIFFS_PH_FLAG_DELET))) {
  1840. // ok object look up entry
  1841. if (state->conflicting_name && strcmp((const char *)state->conflicting_name, (char *)objix_hdr.name) == 0) {
  1842. return SPIFFS_ERR_CONFLICTING_NAME;
  1843. }
  1844. id &= ~SPIFFS_OBJ_ID_IX_FLAG;
  1845. if (id >= state->min_obj_id && id <= state->max_obj_id) {
  1846. u8_t *map = (u8_t *)fs->work;
  1847. int ix = (id - state->min_obj_id) / state->compaction;
  1848. //SPIFFS_DBG("free_obj_id: add ix "_SPIPRIi" for id "_SPIPRIid" min"_SPIPRIid" max"_SPIPRIid" comp:"_SPIPRIi"\n", ix, id, state->min_obj_id, state->max_obj_id, state->compaction);
  1849. map[ix]++;
  1850. }
  1851. }
  1852. }
  1853. return SPIFFS_VIS_COUNTINUE;
  1854. }
  1855. // Scans thru all object lookup for object index header pages. If total possible number of
  1856. // object ids cannot fit into a work buffer, these are grouped. When a group containing free
  1857. // object ids is found, the object lu is again scanned for object ids within group and bitmasked.
  1858. // Finally, the bitmask is searched for a free id
  1859. s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8_t *conflicting_name) {
  1860. s32_t res = SPIFFS_OK;
  1861. u32_t max_objects = (fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) / 2;
  1862. spiffs_free_obj_id_state state;
  1863. spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE;
  1864. state.min_obj_id = 1;
  1865. state.max_obj_id = max_objects + 1;
  1866. if (state.max_obj_id & SPIFFS_OBJ_ID_IX_FLAG) {
  1867. state.max_obj_id = ((spiffs_obj_id)-1) & ~SPIFFS_OBJ_ID_IX_FLAG;
  1868. }
  1869. state.compaction = 0;
  1870. state.conflicting_name = conflicting_name;
  1871. while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) {
  1872. if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8) {
  1873. // possible to represent in bitmap
  1874. u32_t i, j;
  1875. SPIFFS_DBG("free_obj_id: BITM min:"_SPIPRIid" max:"_SPIPRIid"\n", state.min_obj_id, state.max_obj_id);
  1876. memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  1877. res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v,
  1878. conflicting_name, &state.min_obj_id, 0, 0);
  1879. if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
  1880. SPIFFS_CHECK_RES(res);
  1881. // traverse bitmask until found free obj_id
  1882. for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) {
  1883. u8_t mask = fs->work[i];
  1884. if (mask == 0xff) {
  1885. continue;
  1886. }
  1887. for (j = 0; j < 8; j++) {
  1888. if ((mask & (1<<j)) == 0) {
  1889. *obj_id = (i<<3)+j+state.min_obj_id;
  1890. return SPIFFS_OK;
  1891. }
  1892. }
  1893. }
  1894. return SPIFFS_ERR_FULL;
  1895. } else {
  1896. // not possible to represent all ids in range in a bitmap, compact and count
  1897. if (state.compaction != 0) {
  1898. // select element in compacted table, decrease range and recompact
  1899. u32_t i, min_i = 0;
  1900. u8_t *map = (u8_t *)fs->work;
  1901. u8_t min_count = 0xff;
  1902. for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(u8_t); i++) {
  1903. if (map[i] < min_count) {
  1904. min_count = map[i];
  1905. min_i = i;
  1906. if (min_count == 0) {
  1907. break;
  1908. }
  1909. }
  1910. }
  1911. if (min_count == state.compaction) {
  1912. // there are no free objids!
  1913. SPIFFS_DBG("free_obj_id: compacted table is full\n");
  1914. return SPIFFS_ERR_FULL;
  1915. }
  1916. SPIFFS_DBG("free_obj_id: COMP select index:"_SPIPRIi" min_count:"_SPIPRIi" min:"_SPIPRIid" max:"_SPIPRIid" compact:"_SPIPRIi"\n", min_i, min_count, state.min_obj_id, state.max_obj_id, state.compaction);
  1917. if (min_count == 0) {
  1918. // no id in this range, skip compacting and use directly
  1919. *obj_id = min_i * state.compaction + state.min_obj_id;
  1920. return SPIFFS_OK;
  1921. } else {
  1922. SPIFFS_DBG("free_obj_id: COMP SEL chunk:"_SPIPRIi" min:"_SPIPRIid" -> "_SPIPRIid"\n", state.compaction, state.min_obj_id, state.min_obj_id + min_i * state.compaction);
  1923. state.min_obj_id += min_i * state.compaction;
  1924. state.max_obj_id = state.min_obj_id + state.compaction;
  1925. // decrease compaction
  1926. }
  1927. if ((state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs)*8)) {
  1928. // no need for compacting, use bitmap
  1929. continue;
  1930. }
  1931. }
  1932. // in a work memory of log_page_size bytes, we may fit in log_page_size ids
  1933. // todo what if compaction is > 255 - then we cannot fit it in a byte
  1934. state.compaction = (state.max_obj_id-state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));
  1935. SPIFFS_DBG("free_obj_id: COMP min:"_SPIPRIid" max:"_SPIPRIid" compact:"_SPIPRIi"\n", state.min_obj_id, state.max_obj_id, state.compaction);
  1936. memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
  1937. 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);
  1938. if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
  1939. SPIFFS_CHECK_RES(res);
  1940. state.conflicting_name = 0; // searched for conflicting name once, no need to do it again
  1941. }
  1942. }
  1943. return res;
  1944. }
  1945. #endif // !SPIFFS_READ_ONLY
  1946. #if SPIFFS_TEMPORAL_FD_CACHE
  1947. // djb2 hash
  1948. static u32_t spiffs_hash(spiffs *fs, const u8_t *name) {
  1949. (void)fs;
  1950. u32_t hash = 5381;
  1951. u8_t c;
  1952. int i = 0;
  1953. while ((c = name[i++]) && i < SPIFFS_OBJ_NAME_LEN) {
  1954. hash = (hash * 33) ^ c;
  1955. }
  1956. return hash;
  1957. }
  1958. #endif
  1959. s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) {
  1960. #if SPIFFS_TEMPORAL_FD_CACHE
  1961. u32_t i;
  1962. u16_t min_score = 0xffff;
  1963. u32_t cand_ix = (u32_t)-1;
  1964. u32_t name_hash = name ? spiffs_hash(fs, (const u8_t *)name) : 0;
  1965. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  1966. if (name) {
  1967. // first, decrease score of all closed descriptors
  1968. for (i = 0; i < fs->fd_count; i++) {
  1969. spiffs_fd *cur_fd = &fds[i];
  1970. if (cur_fd->file_nbr == 0) {
  1971. if (cur_fd->score > 1) { // score == 0 indicates never used fd
  1972. cur_fd->score--;
  1973. }
  1974. }
  1975. }
  1976. }
  1977. // find the free fd with least score
  1978. for (i = 0; i < fs->fd_count; i++) {
  1979. spiffs_fd *cur_fd = &fds[i];
  1980. if (cur_fd->file_nbr == 0) {
  1981. if (name && cur_fd->name_hash == name_hash) {
  1982. cand_ix = i;
  1983. break;
  1984. }
  1985. if (cur_fd->score < min_score) {
  1986. min_score = cur_fd->score;
  1987. cand_ix = i;
  1988. }
  1989. }
  1990. }
  1991. if (cand_ix != (u32_t)-1) {
  1992. spiffs_fd *cur_fd = &fds[cand_ix];
  1993. if (name) {
  1994. if (cur_fd->name_hash == name_hash && cur_fd->score > 0) {
  1995. // opened an fd with same name hash, assume same file
  1996. // set search point to saved obj index page and hope we have a correct match directly
  1997. // when start searching - if not, we will just keep searching until it is found
  1998. fs->cursor_block_ix = SPIFFS_BLOCK_FOR_PAGE(fs, cur_fd->objix_hdr_pix);
  1999. fs->cursor_obj_lu_entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, cur_fd->objix_hdr_pix);
  2000. // update score
  2001. if (cur_fd->score < 0xffff-SPIFFS_TEMPORAL_CACHE_HIT_SCORE) {
  2002. cur_fd->score += SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
  2003. } else {
  2004. cur_fd->score = 0xffff;
  2005. }
  2006. } else {
  2007. // no hash hit, restore this fd to initial state
  2008. cur_fd->score = SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
  2009. cur_fd->name_hash = name_hash;
  2010. }
  2011. }
  2012. cur_fd->file_nbr = cand_ix+1;
  2013. *fd = cur_fd;
  2014. return SPIFFS_OK;
  2015. } else {
  2016. return SPIFFS_ERR_OUT_OF_FILE_DESCS;
  2017. }
  2018. #else
  2019. (void)name;
  2020. u32_t i;
  2021. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  2022. for (i = 0; i < fs->fd_count; i++) {
  2023. spiffs_fd *cur_fd = &fds[i];
  2024. if (cur_fd->file_nbr == 0) {
  2025. cur_fd->file_nbr = i+1;
  2026. *fd = cur_fd;
  2027. return SPIFFS_OK;
  2028. }
  2029. }
  2030. return SPIFFS_ERR_OUT_OF_FILE_DESCS;
  2031. #endif
  2032. }
  2033. s32_t spiffs_fd_return(spiffs *fs, spiffs_file f) {
  2034. if (f <= 0 || f > (s16_t)fs->fd_count) {
  2035. return SPIFFS_ERR_BAD_DESCRIPTOR;
  2036. }
  2037. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  2038. spiffs_fd *fd = &fds[f-1];
  2039. if (fd->file_nbr == 0) {
  2040. return SPIFFS_ERR_FILE_CLOSED;
  2041. }
  2042. fd->file_nbr = 0;
  2043. #if SPIFFS_IX_MAP
  2044. fd->ix_map = 0;
  2045. #endif
  2046. return SPIFFS_OK;
  2047. }
  2048. s32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) {
  2049. if (f <= 0 || f > (s16_t)fs->fd_count) {
  2050. return SPIFFS_ERR_BAD_DESCRIPTOR;
  2051. }
  2052. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  2053. *fd = &fds[f-1];
  2054. if ((*fd)->file_nbr == 0) {
  2055. return SPIFFS_ERR_FILE_CLOSED;
  2056. }
  2057. return SPIFFS_OK;
  2058. }
  2059. #if SPIFFS_TEMPORAL_FD_CACHE
  2060. void spiffs_fd_temporal_cache_rehash(
  2061. spiffs *fs,
  2062. const char *old_path,
  2063. const char *new_path) {
  2064. u32_t i;
  2065. u32_t old_hash = spiffs_hash(fs, (const u8_t *)old_path);
  2066. u32_t new_hash = spiffs_hash(fs, (const u8_t *)new_path);
  2067. spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
  2068. for (i = 0; i < fs->fd_count; i++) {
  2069. spiffs_fd *cur_fd = &fds[i];
  2070. if (cur_fd->score > 0 && cur_fd->name_hash == old_hash) {
  2071. cur_fd->name_hash = new_hash;
  2072. }
  2073. }
  2074. }
  2075. #endif