Merge pull request #1331 from Guilhem7/master
[RRG-proxmark3.git] / armsrc / spiffs_nucleus.c
blob74c5ade091394959be2a20a9abdf020f9608ba0b
1 #include "spiffs.h"
2 #include "spiffs_nucleus.h"
3 #include "printf.h"
5 static s32_t spiffs_page_data_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {
6 s32_t res = SPIFFS_OK;
7 if (pix == (spiffs_page_ix) - 1) {
8 // referring to page 0xffff...., bad object index
9 return SPIFFS_ERR_INDEX_REF_FREE;
11 if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
12 // referring to an object lookup page, bad object index
13 return SPIFFS_ERR_INDEX_REF_LU;
15 if (pix > SPIFFS_MAX_PAGES(fs)) {
16 // referring to a bad page
17 return SPIFFS_ERR_INDEX_REF_INVALID;
19 #if SPIFFS_PAGE_CHECK
20 spiffs_page_header ph;
21 res = _spiffs_rd(
22 fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
23 fd->file_nbr,
24 SPIFFS_PAGE_TO_PADDR(fs, pix),
25 sizeof(spiffs_page_header),
26 (u8_t *)&ph);
27 SPIFFS_CHECK_RES(res);
28 SPIFFS_VALIDATE_DATA(ph, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, spix);
29 #endif
30 return res;
33 #if !SPIFFS_READ_ONLY
34 static s32_t spiffs_page_index_check(spiffs *fs, spiffs_fd *fd, spiffs_page_ix pix, spiffs_span_ix spix) {
35 s32_t res = SPIFFS_OK;
36 if (pix == (spiffs_page_ix) - 1) {
37 // referring to page 0xffff...., bad object index
38 return SPIFFS_ERR_INDEX_FREE;
40 if (pix % SPIFFS_PAGES_PER_BLOCK(fs) < SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
41 // referring to an object lookup page, bad object index
42 return SPIFFS_ERR_INDEX_LU;
44 if (pix > SPIFFS_MAX_PAGES(fs)) {
45 // referring to a bad page
46 return SPIFFS_ERR_INDEX_INVALID;
48 #if SPIFFS_PAGE_CHECK
49 spiffs_page_header ph;
50 res = _spiffs_rd(
51 fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
52 fd->file_nbr,
53 SPIFFS_PAGE_TO_PADDR(fs, pix),
54 sizeof(spiffs_page_header),
55 (u8_t *)&ph);
56 SPIFFS_CHECK_RES(res);
57 SPIFFS_VALIDATE_OBJIX(ph, fd->obj_id, spix);
58 #endif
59 return res;
61 #endif // !SPIFFS_READ_ONLY
63 #if !SPIFFS_CACHE
65 s32_t spiffs_phys_rd(
66 spiffs *fs,
67 u32_t addr,
68 u32_t len,
69 u8_t *dst) {
70 return SPIFFS_HAL_READ(fs, addr, len, dst);
73 s32_t spiffs_phys_wr(
74 spiffs *fs,
75 u32_t addr,
76 u32_t len,
77 u8_t *src) {
78 return SPIFFS_HAL_WRITE(fs, addr, len, src);
81 #endif
83 #if !SPIFFS_READ_ONLY
84 s32_t spiffs_phys_cpy(
85 spiffs *fs,
86 spiffs_file fh,
87 u32_t dst,
88 u32_t src,
89 u32_t len) {
90 (void)fh;
91 s32_t res;
92 u8_t b[SPIFFS_COPY_BUFFER_STACK];
93 while (len > 0) {
94 u32_t chunk_size = MIN(SPIFFS_COPY_BUFFER_STACK, len);
95 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVS, fh, src, chunk_size, b);
96 SPIFFS_CHECK_RES(res);
97 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_MOVD, fh, dst, chunk_size, b);
98 SPIFFS_CHECK_RES(res);
99 len -= chunk_size;
100 src += chunk_size;
101 dst += chunk_size;
103 return SPIFFS_OK;
105 #endif // !SPIFFS_READ_ONLY
107 // Find object lookup entry containing given id with visitor.
108 // Iterate over object lookup pages in each block until a given object id entry is found.
109 // When found, the visitor function is called with block index, entry index and user data.
110 // If visitor returns SPIFFS_VIS_CONTINUE, the search goes on. Otherwise, the search will be
111 // ended and visitor's return code is returned to caller.
112 // If no visitor is given (0) the search returns on first entry with matching object id.
113 // If no match is found in all look up, SPIFFS_VIS_END is returned.
114 // @param fs the file system
115 // @param starting_block the starting block to start search in
116 // @param starting_lu_entry the look up index entry to start search in
117 // @param flags ored combination of SPIFFS_VIS_CHECK_ID, SPIFFS_VIS_CHECK_PH,
118 // SPIFFS_VIS_NO_WRAP
119 // @param obj_id argument object id
120 // @param v visitor callback function
121 // @param user_const_p any const pointer, passed to the callback visitor function
122 // @param user_var_p any pointer, passed to the callback visitor function
123 // @param block_ix reported block index where match was found
124 // @param lu_entry reported look up index where match was found
125 s32_t spiffs_obj_lu_find_entry_visitor(
126 spiffs *fs,
127 spiffs_block_ix starting_block,
128 int starting_lu_entry,
129 u8_t flags,
130 spiffs_obj_id obj_id,
131 spiffs_visitor_f v,
132 const void *user_const_p,
133 void *user_var_p,
134 spiffs_block_ix *block_ix,
135 int *lu_entry) {
136 s32_t res = SPIFFS_OK;
137 s32_t entry_count = fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs);
138 spiffs_block_ix cur_block = starting_block;
139 u32_t cur_block_addr = starting_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);
141 spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
142 int cur_entry = starting_lu_entry;
143 int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
145 // wrap initial
146 if (cur_entry > (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) - 1) {
147 cur_entry = 0;
148 cur_block++;
149 cur_block_addr = cur_block * SPIFFS_CFG_LOG_BLOCK_SZ(fs);
150 if (cur_block >= fs->block_count) {
151 if (flags & SPIFFS_VIS_NO_WRAP) {
152 return SPIFFS_VIS_END;
153 } else {
154 // block wrap
155 cur_block = 0;
156 cur_block_addr = 0;
161 // check each block
162 while (res == SPIFFS_OK && entry_count > 0) {
163 int obj_lookup_page = cur_entry / entries_per_page;
164 // check each object lookup page
165 while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
166 int entry_offset = obj_lookup_page * entries_per_page;
167 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
168 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
169 // check each entry
170 while (res == SPIFFS_OK &&
171 cur_entry - entry_offset < entries_per_page && // for non-last obj lookup pages
172 cur_entry < (int)SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) { // for last obj lookup page
173 if ((flags & SPIFFS_VIS_CHECK_ID) == 0 || obj_lu_buf[cur_entry - entry_offset] == obj_id) {
174 if (block_ix) *block_ix = cur_block;
175 if (lu_entry) *lu_entry = cur_entry;
176 if (v) {
177 res = v(
179 (flags & SPIFFS_VIS_CHECK_PH) ? obj_id : obj_lu_buf[cur_entry - entry_offset],
180 cur_block,
181 cur_entry,
182 user_const_p,
183 user_var_p);
184 if (res == SPIFFS_VIS_COUNTINUE || res == SPIFFS_VIS_COUNTINUE_RELOAD) {
185 if (res == SPIFFS_VIS_COUNTINUE_RELOAD) {
186 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
187 0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
188 SPIFFS_CHECK_RES(res);
190 res = SPIFFS_OK;
191 cur_entry++;
192 entry_count--;
193 continue;
194 } else {
195 return res;
197 } else {
198 return SPIFFS_OK;
201 entry_count--;
202 cur_entry++;
203 } // per entry
204 obj_lookup_page++;
205 } // per object lookup page
206 cur_entry = 0;
207 cur_block++;
208 cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
209 if (cur_block >= fs->block_count) {
210 if (flags & SPIFFS_VIS_NO_WRAP) {
211 return SPIFFS_VIS_END;
212 } else {
213 // block wrap
214 cur_block = 0;
215 cur_block_addr = 0;
218 } // per block
220 SPIFFS_CHECK_RES(res);
222 return SPIFFS_VIS_END;
225 #if !SPIFFS_READ_ONLY
226 s32_t spiffs_erase_block(
227 spiffs *fs,
228 spiffs_block_ix bix) {
229 s32_t res;
230 u32_t addr = SPIFFS_BLOCK_TO_PADDR(fs, bix);
231 s32_t size = SPIFFS_CFG_LOG_BLOCK_SZ(fs);
233 // here we ignore res, just try erasing the block
234 while (size > 0) {
235 SPIFFS_DBG("erase "_SPIPRIad":"_SPIPRIi"\n", addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
236 SPIFFS_HAL_ERASE(fs, addr, SPIFFS_CFG_PHYS_ERASE_SZ(fs));
238 addr += SPIFFS_CFG_PHYS_ERASE_SZ(fs);
239 size -= SPIFFS_CFG_PHYS_ERASE_SZ(fs);
241 fs->free_blocks++;
243 // register erase count for this block
244 res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,
245 SPIFFS_ERASE_COUNT_PADDR(fs, bix),
246 sizeof(spiffs_obj_id), (u8_t *)&fs->max_erase_count);
247 SPIFFS_CHECK_RES(res);
249 #if SPIFFS_USE_MAGIC
250 // finally, write magic
251 spiffs_obj_id magic = SPIFFS_MAGIC(fs, bix);
252 res = _spiffs_wr(fs, SPIFFS_OP_C_WRTHRU | SPIFFS_OP_T_OBJ_LU2, 0,
253 SPIFFS_MAGIC_PADDR(fs, bix),
254 sizeof(spiffs_obj_id), (u8_t *)&magic);
255 SPIFFS_CHECK_RES(res);
256 #endif
258 fs->max_erase_count++;
259 if (fs->max_erase_count == SPIFFS_OBJ_ID_IX_FLAG) {
260 fs->max_erase_count = 0;
263 return res;
265 #endif // !SPIFFS_READ_ONLY
267 #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
268 s32_t spiffs_probe(
269 spiffs_config *cfg) {
270 s32_t res;
271 u32_t paddr;
272 spiffs dummy_fs; // create a dummy fs struct just to be able to use macros
273 _SPIFFS_MEMCPY(&dummy_fs.cfg, cfg, sizeof(spiffs_config));
274 dummy_fs.block_count = 0;
276 // Read three magics, as one block may be in an aborted erase state.
277 // At least two of these must contain magic and be in decreasing order.
278 spiffs_obj_id magic[3];
279 spiffs_obj_id bix_count[3];
281 spiffs_block_ix bix;
282 for (bix = 0; bix < 3; bix++) {
283 paddr = SPIFFS_MAGIC_PADDR(&dummy_fs, bix);
284 #if SPIFFS_HAL_CALLBACK_EXTRA
285 // not any proper fs to report here, so callback with null
286 // (cross fingers that no-one gets angry)
287 res = cfg->hal_read_f((void *)0, paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]);
288 #else
289 res = cfg->hal_read_f(paddr, sizeof(spiffs_obj_id), (u8_t *)&magic[bix]);
290 #endif
291 bix_count[bix] = magic[bix] ^ SPIFFS_MAGIC(&dummy_fs, 0);
292 SPIFFS_CHECK_RES(res);
295 // check that we have sane number of blocks
296 if (bix_count[0] < 3) return SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS;
297 // check that the order is correct, take aborted erases in calculation
298 // first block aborted erase
299 if (magic[0] == (spiffs_obj_id)(-1) && bix_count[1] - bix_count[2] == 1) {
300 return (bix_count[1] + 1) * cfg->log_block_size;
302 // second block aborted erase
303 if (magic[1] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[2] == 2) {
304 return bix_count[0] * cfg->log_block_size;
306 // third block aborted erase
307 if (magic[2] == (spiffs_obj_id)(-1) && bix_count[0] - bix_count[1] == 1) {
308 return bix_count[0] * cfg->log_block_size;
310 // no block has aborted erase
311 if (bix_count[0] - bix_count[1] == 1 && bix_count[1] - bix_count[2] == 1) {
312 return bix_count[0] * cfg->log_block_size;
315 return SPIFFS_ERR_PROBE_NOT_A_FS;
317 #endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
320 static s32_t spiffs_obj_lu_scan_v(
321 spiffs *fs,
322 spiffs_obj_id obj_id,
323 spiffs_block_ix bix,
324 int ix_entry,
325 const void *user_const_p,
326 void *user_var_p) {
327 (void)bix;
328 (void)user_const_p;
329 (void)user_var_p;
330 if (obj_id == SPIFFS_OBJ_ID_FREE) {
331 if (ix_entry == 0) {
332 fs->free_blocks++;
333 // todo optimize further, return SPIFFS_NEXT_BLOCK
335 } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
336 fs->stats_p_deleted++;
337 } else {
338 fs->stats_p_allocated++;
341 return SPIFFS_VIS_COUNTINUE;
345 // Scans thru all obj lu and counts free, deleted and used pages
346 // Find the maximum block erase count
347 // Checks magic if enabled
348 s32_t spiffs_obj_lu_scan(
349 spiffs *fs) {
350 s32_t res;
351 spiffs_block_ix bix;
352 int entry;
353 #if SPIFFS_USE_MAGIC
354 spiffs_block_ix unerased_bix = (spiffs_block_ix) - 1;
355 #endif
357 // find out erase count
358 // if enabled, check magic
359 bix = 0;
360 spiffs_obj_id erase_count_final;
361 spiffs_obj_id erase_count_min = SPIFFS_OBJ_ID_FREE;
362 spiffs_obj_id erase_count_max = 0;
363 while (bix < fs->block_count) {
364 #if SPIFFS_USE_MAGIC
365 spiffs_obj_id magic;
366 res = _spiffs_rd(fs,
367 SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
368 0, SPIFFS_MAGIC_PADDR(fs, bix),
369 sizeof(spiffs_obj_id), (u8_t *)&magic);
371 SPIFFS_CHECK_RES(res);
372 if (magic != SPIFFS_MAGIC(fs, bix)) {
373 if (unerased_bix == (spiffs_block_ix) - 1) {
374 // allow one unerased block as it might be powered down during an erase
375 unerased_bix = bix;
376 } else {
377 // more than one unerased block, bail out
378 SPIFFS_CHECK_RES(SPIFFS_ERR_NOT_A_FS);
381 #endif
382 spiffs_obj_id erase_count;
383 res = _spiffs_rd(fs,
384 SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
385 0, SPIFFS_ERASE_COUNT_PADDR(fs, bix),
386 sizeof(spiffs_obj_id), (u8_t *)&erase_count);
387 SPIFFS_CHECK_RES(res);
388 if (erase_count != SPIFFS_OBJ_ID_FREE) {
389 erase_count_min = MIN(erase_count_min, erase_count);
390 erase_count_max = MAX(erase_count_max, erase_count);
392 bix++;
395 if (erase_count_min == 0 && erase_count_max == SPIFFS_OBJ_ID_FREE) {
396 // clean system, set counter to zero
397 erase_count_final = 0;
398 } else if (erase_count_max - erase_count_min > (SPIFFS_OBJ_ID_FREE) / 2) {
399 // wrap, take min
400 erase_count_final = erase_count_min + 1;
401 } else {
402 erase_count_final = erase_count_max + 1;
405 fs->max_erase_count = erase_count_final;
407 #if SPIFFS_USE_MAGIC
408 if (unerased_bix != (spiffs_block_ix) - 1) {
409 // found one unerased block, remedy
410 SPIFFS_DBG("mount: erase block "_SPIPRIbl"\n", bix);
411 #if SPIFFS_READ_ONLY
412 res = SPIFFS_ERR_RO_ABORTED_OPERATION;
413 #else
414 res = spiffs_erase_block(fs, unerased_bix);
415 #endif // SPIFFS_READ_ONLY
416 SPIFFS_CHECK_RES(res);
418 #endif
420 // count blocks
422 fs->free_blocks = 0;
423 fs->stats_p_allocated = 0;
424 fs->stats_p_deleted = 0;
426 res = spiffs_obj_lu_find_entry_visitor(fs,
431 spiffs_obj_lu_scan_v,
434 &bix,
435 &entry);
437 if (res == SPIFFS_VIS_END) {
438 res = SPIFFS_OK;
441 SPIFFS_CHECK_RES(res);
443 return res;
446 #if !SPIFFS_READ_ONLY
447 // Find free object lookup entry
448 // Iterate over object lookup pages in each block until a free object id entry is found
449 s32_t spiffs_obj_lu_find_free(
450 spiffs *fs,
451 spiffs_block_ix starting_block,
452 int starting_lu_entry,
453 spiffs_block_ix *block_ix,
454 int *lu_entry) {
455 s32_t res;
456 if (!fs->cleaning && fs->free_blocks < 2) {
457 res = spiffs_gc_quick(fs, 0);
458 if (res == SPIFFS_ERR_NO_DELETED_BLOCKS) {
459 res = SPIFFS_OK;
461 SPIFFS_CHECK_RES(res);
462 if (fs->free_blocks < 2) {
463 return SPIFFS_ERR_FULL;
466 res = spiffs_obj_lu_find_id(fs, starting_block, starting_lu_entry,
467 SPIFFS_OBJ_ID_FREE, block_ix, lu_entry);
468 if (res == SPIFFS_OK) {
469 fs->free_cursor_block_ix = *block_ix;
470 fs->free_cursor_obj_lu_entry = (*lu_entry) + 1;
471 if (*lu_entry == 0) {
472 fs->free_blocks--;
475 if (res == SPIFFS_ERR_FULL) {
476 SPIFFS_DBGF("fs full\n");
479 return res;
481 #endif // !SPIFFS_READ_ONLY
483 // Find object lookup entry containing given id
484 // Iterate over object lookup pages in each block until a given object id entry is found
485 s32_t spiffs_obj_lu_find_id(
486 spiffs *fs,
487 spiffs_block_ix starting_block,
488 int starting_lu_entry,
489 spiffs_obj_id obj_id,
490 spiffs_block_ix *block_ix,
491 int *lu_entry) {
492 s32_t res = spiffs_obj_lu_find_entry_visitor(
493 fs, starting_block, starting_lu_entry, SPIFFS_VIS_CHECK_ID, obj_id, 0, 0, 0, block_ix, lu_entry);
494 if (res == SPIFFS_VIS_END) {
495 res = SPIFFS_ERR_NOT_FOUND;
497 return res;
501 static s32_t spiffs_obj_lu_find_id_and_span_v(
502 spiffs *fs,
503 spiffs_obj_id obj_id,
504 spiffs_block_ix bix,
505 int ix_entry,
506 const void *user_const_p,
507 void *user_var_p) {
508 s32_t res;
509 spiffs_page_header ph;
510 spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
511 res = _spiffs_rd(fs, 0, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
512 SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_header), (u8_t *)&ph);
513 SPIFFS_CHECK_RES(res);
514 if (ph.obj_id == obj_id &&
515 ph.span_ix == *((spiffs_span_ix *)user_var_p) &&
516 (ph.flags & (SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED)) == SPIFFS_PH_FLAG_DELET &&
517 !((obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (ph.flags & SPIFFS_PH_FLAG_IXDELE) == 0 && ph.span_ix == 0) &&
518 (user_const_p == 0 || *((const spiffs_page_ix *)user_const_p) != pix)) {
519 return SPIFFS_OK;
520 } else {
521 return SPIFFS_VIS_COUNTINUE;
525 // Find object lookup entry containing given id and span index
526 // Iterate over object lookup pages in each block until a given object id entry is found
527 s32_t spiffs_obj_lu_find_id_and_span(
528 spiffs *fs,
529 spiffs_obj_id obj_id,
530 spiffs_span_ix spix,
531 spiffs_page_ix exclusion_pix,
532 spiffs_page_ix *pix) {
533 s32_t res;
534 spiffs_block_ix bix;
535 int entry;
537 res = spiffs_obj_lu_find_entry_visitor(fs,
538 fs->cursor_block_ix,
539 fs->cursor_obj_lu_entry,
540 SPIFFS_VIS_CHECK_ID,
541 obj_id,
542 spiffs_obj_lu_find_id_and_span_v,
543 exclusion_pix ? &exclusion_pix : 0,
544 &spix,
545 &bix,
546 &entry);
548 if (res == SPIFFS_VIS_END) {
549 res = SPIFFS_ERR_NOT_FOUND;
552 SPIFFS_CHECK_RES(res);
554 if (pix) {
555 *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
558 fs->cursor_block_ix = bix;
559 fs->cursor_obj_lu_entry = entry;
561 return res;
564 // Find object lookup entry containing given id and span index in page headers only
565 // Iterate over object lookup pages in each block until a given object id entry is found
566 s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
567 spiffs *fs,
568 spiffs_obj_id obj_id,
569 spiffs_span_ix spix,
570 spiffs_page_ix exclusion_pix,
571 spiffs_page_ix *pix) {
572 s32_t res;
573 spiffs_block_ix bix;
574 int entry;
576 res = spiffs_obj_lu_find_entry_visitor(fs,
577 fs->cursor_block_ix,
578 fs->cursor_obj_lu_entry,
579 SPIFFS_VIS_CHECK_PH,
580 obj_id,
581 spiffs_obj_lu_find_id_and_span_v,
582 exclusion_pix ? &exclusion_pix : 0,
583 &spix,
584 &bix,
585 &entry);
587 if (res == SPIFFS_VIS_END) {
588 res = SPIFFS_ERR_NOT_FOUND;
591 SPIFFS_CHECK_RES(res);
593 if (pix) {
594 *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
597 fs->cursor_block_ix = bix;
598 fs->cursor_obj_lu_entry = entry;
600 return res;
603 #if SPIFFS_IX_MAP
605 // update index map of given fd with given object index data
606 static void spiffs_update_ix_map(spiffs *fs,
607 spiffs_fd *fd, spiffs_span_ix objix_spix, spiffs_page_object_ix *objix) {
608 #if SPIFFS_SINGLETON
609 (void)fs;
610 #endif
611 spiffs_ix_map *map = fd->ix_map;
612 spiffs_span_ix map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix);
613 spiffs_span_ix map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->end_spix);
615 // check if updated ix is within map range
616 if (objix_spix < map_objix_start_spix || objix_spix > map_objix_end_spix) {
617 return;
620 // update memory mapped page index buffer to new pages
622 // get range of updated object index map data span indices
623 spiffs_span_ix objix_data_spix_start =
624 SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, objix_spix);
625 spiffs_span_ix objix_data_spix_end = objix_data_spix_start +
626 (objix_spix == 0 ? SPIFFS_OBJ_HDR_IX_LEN(fs) : SPIFFS_OBJ_IX_LEN(fs));
628 // calc union of object index range and index map range array
629 spiffs_span_ix map_spix = MAX(map->start_spix, objix_data_spix_start);
630 spiffs_span_ix map_spix_end = MIN(map->end_spix + 1, objix_data_spix_end);
632 while (map_spix < map_spix_end) {
633 spiffs_page_ix objix_data_pix;
634 if (objix_spix == 0) {
635 // get data page from object index header page
636 objix_data_pix = ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix_header)))[map_spix];
637 } else {
638 // get data page from object index page
639 objix_data_pix = ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, map_spix)];
642 if (objix_data_pix == (spiffs_page_ix) - 1) {
643 // reached end of object, abort
644 break;
647 map->map_buf[map_spix - map->start_spix] = objix_data_pix;
648 SPIFFS_DBG("map "_SPIPRIid":"_SPIPRIsp" ("_SPIPRIsp"--"_SPIPRIsp") objix.spix:"_SPIPRIsp" to pix "_SPIPRIpg"\n",
649 fd->obj_id, map_spix - map->start_spix,
650 map->start_spix, map->end_spix,
651 objix->p_hdr.span_ix,
652 objix_data_pix);
654 map_spix++;
658 typedef struct {
659 spiffs_fd *fd;
660 u32_t remaining_objix_pages_to_visit;
661 spiffs_span_ix map_objix_start_spix;
662 spiffs_span_ix map_objix_end_spix;
663 } spiffs_ix_map_populate_state;
665 static s32_t spiffs_populate_ix_map_v(
666 spiffs *fs,
667 spiffs_obj_id obj_id,
668 spiffs_block_ix bix,
669 int ix_entry,
670 const void *user_const_p,
671 void *user_var_p) {
672 (void)user_const_p;
673 s32_t res;
674 spiffs_ix_map_populate_state *state = (spiffs_ix_map_populate_state *)user_var_p;
675 spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
677 // load header to check it
678 spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
679 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
680 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix), (u8_t *)objix);
681 SPIFFS_CHECK_RES(res);
682 SPIFFS_VALIDATE_OBJIX(objix->p_hdr, obj_id, objix->p_hdr.span_ix);
684 // check if hdr is ok, and if objix range overlap with ix map range
685 if ((objix->p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
686 (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE) &&
687 objix->p_hdr.span_ix >= state->map_objix_start_spix &&
688 objix->p_hdr.span_ix <= state->map_objix_end_spix) {
689 // ok, load rest of object index
690 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
691 0, SPIFFS_PAGE_TO_PADDR(fs, pix) + sizeof(spiffs_page_object_ix),
692 SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix),
693 (u8_t *)objix + sizeof(spiffs_page_object_ix));
694 SPIFFS_CHECK_RES(res);
696 spiffs_update_ix_map(fs, state->fd, objix->p_hdr.span_ix, objix);
698 state->remaining_objix_pages_to_visit--;
699 SPIFFS_DBG("map "_SPIPRIid" ("_SPIPRIsp"--"_SPIPRIsp") remaining objix pages "_SPIPRIi"\n",
700 state->fd->obj_id,
701 state->fd->ix_map->start_spix, state->fd->ix_map->end_spix,
702 state->remaining_objix_pages_to_visit);
705 if (res == SPIFFS_OK) {
706 res = state->remaining_objix_pages_to_visit ? SPIFFS_VIS_COUNTINUE : SPIFFS_VIS_END;
708 return res;
711 // populates index map, from vector entry start to vector entry end, inclusive
712 s32_t spiffs_populate_ix_map(spiffs *fs, spiffs_fd *fd, u32_t vec_entry_start, u32_t vec_entry_end) {
713 s32_t res;
714 spiffs_ix_map *map = fd->ix_map;
715 spiffs_ix_map_populate_state state;
716 vec_entry_start = MIN((u32_t)(map->end_spix - map->start_spix), vec_entry_start);
717 vec_entry_end = MAX((u32_t)(map->end_spix - map->start_spix), vec_entry_end);
718 if (vec_entry_start > vec_entry_end) {
719 return SPIFFS_ERR_IX_MAP_BAD_RANGE;
721 state.map_objix_start_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_start);
722 state.map_objix_end_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, map->start_spix + vec_entry_end);
723 state.remaining_objix_pages_to_visit =
724 state.map_objix_end_spix - state.map_objix_start_spix + 1;
725 state.fd = fd;
727 res = spiffs_obj_lu_find_entry_visitor(
729 SPIFFS_BLOCK_FOR_PAGE(fs, fd->objix_hdr_pix),
730 SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, fd->objix_hdr_pix),
731 SPIFFS_VIS_CHECK_ID,
732 fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
733 spiffs_populate_ix_map_v,
735 &state,
739 if (res == SPIFFS_VIS_END) {
740 res = SPIFFS_OK;
743 return res;
746 #endif
749 #if !SPIFFS_READ_ONLY
750 // Allocates a free defined page with given obj_id
751 // Occupies object lookup entry and page
752 // data may be NULL; where only page header is stored, len and page_offs is ignored
753 s32_t spiffs_page_allocate_data(
754 spiffs *fs,
755 spiffs_obj_id obj_id,
756 spiffs_page_header *ph,
757 u8_t *data,
758 u32_t len,
759 u32_t page_offs,
760 u8_t finalize,
761 spiffs_page_ix *pix) {
762 s32_t res = SPIFFS_OK;
763 spiffs_block_ix bix;
764 int entry;
766 // find free entry
767 res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
768 SPIFFS_CHECK_RES(res);
770 // occupy page in object lookup
771 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
772 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id);
773 SPIFFS_CHECK_RES(res);
775 fs->stats_p_allocated++;
777 // write page header
778 ph->flags &= ~SPIFFS_PH_FLAG_USED;
779 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
780 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_header), (u8_t *)ph);
781 SPIFFS_CHECK_RES(res);
783 // write page data
784 if (data) {
785 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
786 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + sizeof(spiffs_page_header) + page_offs, len, data);
787 SPIFFS_CHECK_RES(res);
790 // finalize header if necessary
791 if (finalize && (ph->flags & SPIFFS_PH_FLAG_FINAL)) {
792 ph->flags &= ~SPIFFS_PH_FLAG_FINAL;
793 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
794 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry) + offsetof(spiffs_page_header, flags),
795 sizeof(u8_t),
796 (u8_t *)&ph->flags);
797 SPIFFS_CHECK_RES(res);
800 // return written page
801 if (pix) {
802 *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
805 return res;
807 #endif // !SPIFFS_READ_ONLY
809 #if !SPIFFS_READ_ONLY
810 // Moves a page from src to a free page and finalizes it. Updates page index. Page data is given in param page.
811 // If page data is null, provided header is used for metainfo and page data is physically copied.
812 s32_t spiffs_page_move(
813 spiffs *fs,
814 spiffs_file fh,
815 u8_t *page_data,
816 spiffs_obj_id obj_id,
817 spiffs_page_header *page_hdr,
818 spiffs_page_ix src_pix,
819 spiffs_page_ix *dst_pix) {
820 s32_t res;
821 u8_t was_final = 0;
822 spiffs_page_header *p_hdr;
823 spiffs_block_ix bix;
824 int entry;
825 spiffs_page_ix free_pix;
827 // find free entry
828 res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
829 SPIFFS_CHECK_RES(res);
830 free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
832 if (dst_pix) *dst_pix = free_pix;
834 p_hdr = page_data ? (spiffs_page_header *)page_data : page_hdr;
835 if (page_data) {
836 // got page data
837 was_final = (p_hdr->flags & SPIFFS_PH_FLAG_FINAL) == 0;
838 // write unfinalized page
839 p_hdr->flags |= SPIFFS_PH_FLAG_FINAL;
840 p_hdr->flags &= ~SPIFFS_PH_FLAG_USED;
841 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
842 0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), page_data);
843 } else {
844 // copy page data
845 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));
847 SPIFFS_CHECK_RES(res);
849 // mark entry in destination object lookup
850 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
851 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),
852 sizeof(spiffs_obj_id),
853 (u8_t *)&obj_id);
854 SPIFFS_CHECK_RES(res);
856 fs->stats_p_allocated++;
858 if (was_final) {
859 // mark finalized in destination page
860 p_hdr->flags &= ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_USED);
861 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
863 SPIFFS_PAGE_TO_PADDR(fs, free_pix) + offsetof(spiffs_page_header, flags),
864 sizeof(u8_t),
865 (u8_t *)&p_hdr->flags);
866 SPIFFS_CHECK_RES(res);
868 // mark source deleted
869 res = spiffs_page_delete(fs, src_pix);
870 return res;
872 #endif // !SPIFFS_READ_ONLY
874 #if !SPIFFS_READ_ONLY
875 // Deletes a page and removes it from object lookup.
876 s32_t spiffs_page_delete(
877 spiffs *fs,
878 spiffs_page_ix pix) {
879 s32_t res;
880 // mark deleted entry in source object lookup
881 spiffs_obj_id d_obj_id = SPIFFS_OBJ_ID_DELETED;
882 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_DELE,
884 SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_page_ix),
885 sizeof(spiffs_obj_id),
886 (u8_t *)&d_obj_id);
887 SPIFFS_CHECK_RES(res);
889 fs->stats_p_deleted++;
890 fs->stats_p_allocated--;
892 // mark deleted in source page
893 u8_t flags = 0xff;
894 #if SPIFFS_NO_BLIND_WRITES
895 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
896 0, SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),
897 sizeof(flags), &flags);
898 SPIFFS_CHECK_RES(res);
899 #endif
900 flags &= ~(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED);
901 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_DELE,
903 SPIFFS_PAGE_TO_PADDR(fs, pix) + offsetof(spiffs_page_header, flags),
904 sizeof(flags), &flags);
906 return res;
908 #endif // !SPIFFS_READ_ONLY
910 #if !SPIFFS_READ_ONLY
911 // Create an object index header page with empty index and undefined length
912 s32_t spiffs_object_create(
913 spiffs *fs,
914 spiffs_obj_id obj_id,
915 const u8_t name[],
916 const u8_t meta[],
917 spiffs_obj_type type,
918 spiffs_page_ix *objix_hdr_pix) {
919 s32_t res = SPIFFS_OK;
920 spiffs_block_ix bix;
921 spiffs_page_object_ix_header oix_hdr;
922 int entry;
924 res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs));
925 SPIFFS_CHECK_RES(res);
927 obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
929 // find free entry
930 res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
931 SPIFFS_CHECK_RES(res);
932 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);
934 // occupy page in object lookup
935 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
936 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id);
937 SPIFFS_CHECK_RES(res);
939 fs->stats_p_allocated++;
941 // write empty object index page
942 oix_hdr.p_hdr.obj_id = obj_id;
943 oix_hdr.p_hdr.span_ix = 0;
944 oix_hdr.p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED);
945 oix_hdr.type = type;
946 oix_hdr.size = SPIFFS_UNDEFINED_LEN; // keep ones so we can update later without wasting this page
947 strncpy((char *)oix_hdr.name, (const char *)name, SPIFFS_OBJ_NAME_LEN - 1);
948 #if SPIFFS_OBJ_META_LEN
949 if (meta) {
950 _SPIFFS_MEMCPY(oix_hdr.meta, meta, SPIFFS_OBJ_META_LEN);
951 } else {
952 memset(oix_hdr.meta, 0xff, SPIFFS_OBJ_META_LEN);
954 #else
955 (void) meta;
956 #endif
958 // update page
959 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
960 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, entry), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr);
962 SPIFFS_CHECK_RES(res);
963 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&oix_hdr,
964 SPIFFS_EV_IX_NEW, obj_id, 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry), SPIFFS_UNDEFINED_LEN);
966 if (objix_hdr_pix) {
967 *objix_hdr_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
970 return res;
972 #endif // !SPIFFS_READ_ONLY
974 #if !SPIFFS_READ_ONLY
975 // update object index header with any combination of name/size/index
976 // new_objix_hdr_data may be null, if so the object index header page is loaded
977 // name may be null, if so name is not changed
978 // size may be null, if so size is not changed
979 s32_t spiffs_object_update_index_hdr(
980 spiffs *fs,
981 spiffs_fd *fd,
982 spiffs_obj_id obj_id,
983 spiffs_page_ix objix_hdr_pix,
984 u8_t *new_objix_hdr_data,
985 const u8_t name[],
986 const u8_t meta[],
987 u32_t size,
988 spiffs_page_ix *new_pix) {
989 s32_t res = SPIFFS_OK;
990 spiffs_page_object_ix_header *objix_hdr;
991 spiffs_page_ix new_objix_hdr_pix;
993 obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
995 if (new_objix_hdr_data) {
996 // object index header page already given to us, no need to load it
997 objix_hdr = (spiffs_page_object_ix_header *)new_objix_hdr_data;
998 } else {
999 // read object index header page
1000 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
1001 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1002 SPIFFS_CHECK_RES(res);
1003 objix_hdr = (spiffs_page_object_ix_header *)fs->work;
1006 SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, obj_id, 0);
1008 // change name
1009 if (name) {
1010 strncpy((char *)objix_hdr->name, (const char *)name, SPIFFS_OBJ_NAME_LEN - 1);
1012 #if SPIFFS_OBJ_META_LEN
1013 if (meta) {
1014 _SPIFFS_MEMCPY(objix_hdr->meta, meta, SPIFFS_OBJ_META_LEN);
1016 #else
1017 (void) meta;
1018 #endif
1019 if (size) {
1020 objix_hdr->size = size;
1023 // move and update page
1024 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);
1026 if (res == SPIFFS_OK) {
1027 if (new_pix) {
1028 *new_pix = new_objix_hdr_pix;
1030 // callback on object index update
1031 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,
1032 new_objix_hdr_data ? SPIFFS_EV_IX_UPD : SPIFFS_EV_IX_UPD_HDR,
1033 obj_id, objix_hdr->p_hdr.span_ix, new_objix_hdr_pix, objix_hdr->size);
1034 if (fd) fd->objix_hdr_pix = new_objix_hdr_pix; // if this is not in the registered cluster
1037 return res;
1039 #endif // !SPIFFS_READ_ONLY
1041 void spiffs_cb_object_event(
1042 spiffs *fs,
1043 spiffs_page_object_ix *objix,
1044 int ev,
1045 spiffs_obj_id obj_id_raw,
1046 spiffs_span_ix spix,
1047 spiffs_page_ix new_pix,
1048 u32_t new_size) {
1049 #if SPIFFS_IX_MAP == 0
1050 (void)objix;
1051 #endif
1052 // update index caches in all file descriptors
1053 spiffs_obj_id obj_id = obj_id_raw & ~SPIFFS_OBJ_ID_IX_FLAG;
1054 u32_t i;
1055 spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
1056 SPIFFS_DBG(" CALLBACK %s obj_id:"_SPIPRIid" spix:"_SPIPRIsp" npix:"_SPIPRIpg" nsz:"_SPIPRIi"\n", (const char *[]) {"UPD", "NEW", "DEL", "MOV", "HUP", "???"}[MIN(ev, 5)],
1057 obj_id_raw, spix, new_pix, new_size);
1058 for (i = 0; i < fs->fd_count; i++) {
1059 spiffs_fd *cur_fd = &fds[i];
1060 if ((cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue; // fd not related to updated file
1061 #if !SPIFFS_TEMPORAL_FD_CACHE
1062 if (cur_fd->file_nbr == 0) continue; // fd closed
1063 #endif
1064 if (spix == 0) { // object index header update
1065 if (ev != SPIFFS_EV_IX_DEL) {
1066 #if SPIFFS_TEMPORAL_FD_CACHE
1067 if (cur_fd->score == 0) continue; // never used fd
1068 #endif
1069 SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid"(fdoffs:"_SPIPRIi" offs:"_SPIPRIi") objix_hdr_pix to "_SPIPRIpg", size:"_SPIPRIi"\n",
1070 SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, cur_fd->fdoffset, cur_fd->offset, new_pix, new_size);
1071 cur_fd->objix_hdr_pix = new_pix;
1072 if (new_size != 0) {
1073 // update size and offsets for fds to this file
1074 cur_fd->size = new_size;
1075 u32_t act_new_size = new_size == SPIFFS_UNDEFINED_LEN ? 0 : new_size;
1076 #if SPIFFS_CACHE_WR
1077 if (act_new_size > 0 && cur_fd->cache_page) {
1078 act_new_size = MAX(act_new_size, cur_fd->cache_page->ucache.swrc.offset + cur_fd->cache_page->ucache.swrc.size);
1080 #endif
1081 if (cur_fd->offset > act_new_size) {
1082 cur_fd->offset = act_new_size;
1084 if (cur_fd->fdoffset > act_new_size) {
1085 cur_fd->fdoffset = act_new_size;
1087 #if SPIFFS_CACHE_WR
1088 if (cur_fd->cache_page && cur_fd->cache_page->ucache.swrc.offset > act_new_size + 1) {
1089 SPIFFS_CACHE_DBG("CACHE_DROP: file trunced, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix);
1090 spiffs_cache_fd_release(fs, cur_fd->cache_page);
1092 #endif
1094 } else {
1095 // removing file
1096 #if SPIFFS_CACHE_WR
1097 if (cur_fd->file_nbr && cur_fd->cache_page) {
1098 SPIFFS_CACHE_DBG("CACHE_DROP: file deleted, dropping cache page "_SPIPRIi", no writeback\n", cur_fd->cache_page->ix);
1099 spiffs_cache_fd_release(fs, cur_fd->cache_page);
1101 #endif
1102 SPIFFS_DBG(" callback: release fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix, new_pix);
1103 cur_fd->file_nbr = 0;
1104 cur_fd->obj_id = SPIFFS_OBJ_ID_DELETED;
1106 } // object index header update
1107 if (cur_fd->cursor_objix_spix == spix) {
1108 if (ev != SPIFFS_EV_IX_DEL) {
1109 SPIFFS_DBG(" callback: setting fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp" objix_pix to "_SPIPRIpg"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix, new_pix);
1110 cur_fd->cursor_objix_pix = new_pix;
1111 } else {
1112 cur_fd->cursor_objix_pix = 0;
1115 } // fd update loop
1117 #if SPIFFS_IX_MAP
1119 // update index maps
1120 if (ev == SPIFFS_EV_IX_UPD || ev == SPIFFS_EV_IX_NEW) {
1121 for (i = 0; i < fs->fd_count; i++) {
1122 spiffs_fd *cur_fd = &fds[i];
1123 // check fd opened, having ix map, match obj id
1124 if (cur_fd->file_nbr == 0 ||
1125 cur_fd->ix_map == 0 ||
1126 (cur_fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) != obj_id) continue;
1127 SPIFFS_DBG(" callback: map ix update fd "_SPIPRIfd":"_SPIPRIid" span:"_SPIPRIsp"\n", SPIFFS_FH_OFFS(fs, cur_fd->file_nbr), cur_fd->obj_id, spix);
1128 spiffs_update_ix_map(fs, cur_fd, spix, objix);
1132 #endif
1134 // callback to user if object index header
1135 if (fs->file_cb_f && spix == 0 && (obj_id_raw & SPIFFS_OBJ_ID_IX_FLAG)) {
1136 spiffs_fileop_type op;
1137 if (ev == SPIFFS_EV_IX_NEW) {
1138 op = SPIFFS_CB_CREATED;
1139 } else if (ev == SPIFFS_EV_IX_UPD ||
1140 ev == SPIFFS_EV_IX_MOV ||
1141 ev == SPIFFS_EV_IX_UPD_HDR) {
1142 op = SPIFFS_CB_UPDATED;
1143 } else if (ev == SPIFFS_EV_IX_DEL) {
1144 op = SPIFFS_CB_DELETED;
1145 } else {
1146 SPIFFS_DBG(" callback: WARNING unknown callback event "_SPIPRIi"\n", ev);
1147 return; // bail out
1149 fs->file_cb_f(fs, op, obj_id, new_pix);
1153 // Open object by id
1154 s32_t spiffs_object_open_by_id(
1155 spiffs *fs,
1156 spiffs_obj_id obj_id,
1157 spiffs_fd *fd,
1158 spiffs_flags flags,
1159 spiffs_mode mode) {
1160 s32_t res = SPIFFS_OK;
1161 spiffs_page_ix pix;
1163 res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &pix);
1164 SPIFFS_CHECK_RES(res);
1166 res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);
1168 return res;
1171 // Open object by page index
1172 s32_t spiffs_object_open_by_page(
1173 spiffs *fs,
1174 spiffs_page_ix pix,
1175 spiffs_fd *fd,
1176 spiffs_flags flags,
1177 spiffs_mode mode) {
1178 (void)mode;
1179 s32_t res = SPIFFS_OK;
1180 spiffs_page_object_ix_header oix_hdr;
1181 spiffs_obj_id obj_id;
1183 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
1184 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&oix_hdr);
1185 SPIFFS_CHECK_RES(res);
1187 spiffs_block_ix bix = SPIFFS_BLOCK_FOR_PAGE(fs, pix);
1188 int entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix);
1190 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
1191 0, SPIFFS_BLOCK_TO_PADDR(fs, bix) + entry * sizeof(spiffs_obj_id), sizeof(spiffs_obj_id), (u8_t *)&obj_id);
1193 fd->fs = fs;
1194 fd->objix_hdr_pix = pix;
1195 fd->size = oix_hdr.size;
1196 fd->offset = 0;
1197 fd->cursor_objix_pix = pix;
1198 fd->cursor_objix_spix = 0;
1199 fd->obj_id = obj_id;
1200 fd->flags = flags;
1202 SPIFFS_VALIDATE_OBJIX(oix_hdr.p_hdr, fd->obj_id, 0);
1204 SPIFFS_DBG("open: fd "_SPIPRIfd" is obj id "_SPIPRIid"\n", SPIFFS_FH_OFFS(fs, fd->file_nbr), fd->obj_id);
1206 return res;
1209 #if !SPIFFS_READ_ONLY
1210 // Append to object
1211 // keep current object index (header) page in fs->work buffer
1212 s32_t spiffs_object_append(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
1213 spiffs *fs = fd->fs;
1214 s32_t res = SPIFFS_OK;
1215 u32_t written = 0;
1217 SPIFFS_DBG("append: "_SPIPRIi" bytes @ offs "_SPIPRIi" of size "_SPIPRIi"\n", len, offset, fd->size);
1219 if (offset > fd->size) {
1220 SPIFFS_DBGF("append: offset reversed to size\n");
1221 offset = fd->size;
1224 res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs)); // add an extra page of data worth for meta
1225 if (res != SPIFFS_OK) {
1226 SPIFFS_DBG("append: gc check fail "_SPIPRIi"\n", res);
1228 SPIFFS_CHECK_RES(res);
1230 spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
1231 spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
1232 spiffs_page_header p_hdr;
1234 spiffs_span_ix cur_objix_spix = 0;
1235 spiffs_span_ix prev_objix_spix = (spiffs_span_ix) - 1;
1236 spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;
1237 spiffs_page_ix new_objix_hdr_page;
1239 spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
1240 spiffs_page_ix data_page;
1241 u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);
1243 // write all data
1244 while (res == SPIFFS_OK && written < len) {
1245 // calculate object index page span index
1246 cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
1248 // handle storing and loading of object indices
1249 if (cur_objix_spix != prev_objix_spix) {
1250 // new object index page
1251 // within this clause we return directly if something fails, object index mess-up
1252 if (written > 0) {
1253 // store previous object index page, unless first pass
1254 SPIFFS_DBG("append: "_SPIPRIid" store objix "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
1255 cur_objix_pix, prev_objix_spix, written);
1256 if (prev_objix_spix == 0) {
1257 // this is an update to object index header page
1258 objix_hdr->size = offset + written;
1259 if (offset == 0) {
1260 // was an empty object, update same page (size was 0xffffffff)
1261 res = spiffs_page_index_check(fs, fd, cur_objix_pix, 0);
1262 SPIFFS_CHECK_RES(res);
1263 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
1264 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1265 SPIFFS_CHECK_RES(res);
1266 } else {
1267 // was a nonempty object, update to new page
1268 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1269 fd->objix_hdr_pix, fs->work, 0, 0, offset + written, &new_objix_hdr_page);
1270 SPIFFS_CHECK_RES(res);
1271 SPIFFS_DBG("append: "_SPIPRIid" store new objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
1272 new_objix_hdr_page, 0, written);
1274 } else {
1275 // this is an update to an object index page
1276 res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);
1277 SPIFFS_CHECK_RES(res);
1279 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
1280 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1281 SPIFFS_CHECK_RES(res);
1282 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
1283 SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);
1284 // update length in object index header page
1285 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1286 fd->objix_hdr_pix, 0, 0, 0, offset + written, &new_objix_hdr_page);
1287 SPIFFS_CHECK_RES(res);
1288 SPIFFS_DBG("append: "_SPIPRIid" store new size I "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
1289 offset + written, new_objix_hdr_page, 0, written);
1291 fd->size = offset + written;
1292 fd->offset = offset + written;
1295 // create or load new object index page
1296 if (cur_objix_spix == 0) {
1297 // load object index header page, must always exist
1298 SPIFFS_DBG("append: "_SPIPRIid" load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", fd->obj_id, cur_objix_pix, cur_objix_spix);
1299 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
1300 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1301 SPIFFS_CHECK_RES(res);
1302 SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
1303 } else {
1304 spiffs_span_ix len_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, (fd->size - 1) / SPIFFS_DATA_PAGE_SIZE(fs));
1305 // on subsequent passes, create a new object index page
1306 if (written > 0 || cur_objix_spix > len_objix_spix) {
1307 p_hdr.obj_id = fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
1308 p_hdr.span_ix = cur_objix_spix;
1309 p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
1310 res = spiffs_page_allocate_data(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
1311 &p_hdr, 0, 0, 0, 1, &cur_objix_pix);
1312 SPIFFS_CHECK_RES(res);
1313 // quick "load" of new object index page
1314 memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
1315 _SPIFFS_MEMCPY(fs->work, &p_hdr, sizeof(spiffs_page_header));
1316 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
1317 SPIFFS_EV_IX_NEW, fd->obj_id, cur_objix_spix, cur_objix_pix, 0);
1318 SPIFFS_DBG("append: "_SPIPRIid" create objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id
1319 , cur_objix_pix, cur_objix_spix, written);
1320 } else {
1321 // on first pass, we load existing object index page
1322 spiffs_page_ix pix;
1323 SPIFFS_DBG("append: "_SPIPRIid" find objix span_ix:"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix);
1324 if (fd->cursor_objix_spix == cur_objix_spix) {
1325 pix = fd->cursor_objix_pix;
1326 } else {
1327 res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
1328 SPIFFS_CHECK_RES(res);
1330 SPIFFS_DBG("append: "_SPIPRIid" found object index at page "_SPIPRIpg" [fd size "_SPIPRIi"]\n", fd->obj_id, pix, fd->size);
1331 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
1332 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1333 SPIFFS_CHECK_RES(res);
1334 SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
1335 cur_objix_pix = pix;
1337 fd->cursor_objix_pix = cur_objix_pix;
1338 fd->cursor_objix_spix = cur_objix_spix;
1339 fd->offset = offset + written;
1340 fd->size = offset + written;
1342 prev_objix_spix = cur_objix_spix;
1345 // write data
1346 u32_t to_write = MIN(len - written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);
1347 if (page_offs == 0) {
1348 // at beginning of a page, allocate and write a new page of data
1349 p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
1350 p_hdr.span_ix = data_spix;
1351 p_hdr.flags = 0xff & ~(SPIFFS_PH_FLAG_FINAL); // finalize immediately
1352 res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
1353 &p_hdr, &data[written], to_write, page_offs, 1, &data_page);
1354 SPIFFS_DBG("append: "_SPIPRIid" store new data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id,
1355 data_page, data_spix, page_offs, to_write, written);
1356 } else {
1357 // append to existing page, fill out free data in existing page
1358 if (cur_objix_spix == 0) {
1359 // get data page from object index header page
1360 data_page = ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
1361 } else {
1362 // get data page from object index page
1363 data_page = ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
1366 res = spiffs_page_data_check(fs, fd, data_page, data_spix);
1367 SPIFFS_CHECK_RES(res);
1369 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
1370 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, data_page) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
1371 SPIFFS_DBG("append: "_SPIPRIid" store to existing data page, "_SPIPRIpg":"_SPIPRIsp" offset:"_SPIPRIi", len "_SPIPRIi", written "_SPIPRIi"\n", fd->obj_id
1372 , data_page, data_spix, page_offs, to_write, written);
1375 if (res != SPIFFS_OK) break;
1377 // update memory representation of object index page with new data page
1378 if (cur_objix_spix == 0) {
1379 // update object index header page
1380 ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_page;
1381 SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", fd->obj_id
1382 , data_page, data_spix);
1383 objix_hdr->size = offset + written;
1384 } else {
1385 // update object index page
1386 ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_page;
1387 SPIFFS_DBG("append: "_SPIPRIid" wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", fd->obj_id
1388 , data_page, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, data_spix));
1391 // update internals
1392 page_offs = 0;
1393 data_spix++;
1394 written += to_write;
1395 } // while all data
1397 fd->size = offset + written;
1398 fd->offset = offset + written;
1399 fd->cursor_objix_pix = cur_objix_pix;
1400 fd->cursor_objix_spix = cur_objix_spix;
1402 // finalize updated object indices
1403 s32_t res2 = SPIFFS_OK;
1404 if (cur_objix_spix != 0) {
1405 // wrote beyond object index header page
1406 // write last modified object index page, unless object header index page
1407 SPIFFS_DBG("append: "_SPIPRIid" store objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id,
1408 cur_objix_pix, cur_objix_spix, written);
1410 res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
1411 SPIFFS_CHECK_RES(res2);
1413 res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
1414 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1415 SPIFFS_CHECK_RES(res2);
1416 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
1417 SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, cur_objix_pix, 0);
1419 // update size in object header index page
1420 res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1421 fd->objix_hdr_pix, 0, 0, 0, offset + written, &new_objix_hdr_page);
1422 SPIFFS_DBG("append: "_SPIPRIid" store new size II "_SPIPRIi" in objix_hdr, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi", res "_SPIPRIi"\n", fd->obj_id
1423 , offset + written, new_objix_hdr_page, 0, written, res2);
1424 SPIFFS_CHECK_RES(res2);
1425 } else {
1426 // wrote within object index header page
1427 if (offset == 0) {
1428 // wrote to empty object - simply update size and write whole page
1429 objix_hdr->size = offset + written;
1430 SPIFFS_DBG("append: "_SPIPRIid" store fresh objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id
1431 , cur_objix_pix, cur_objix_spix, written);
1433 res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
1434 SPIFFS_CHECK_RES(res2);
1436 res2 = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
1437 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1438 SPIFFS_CHECK_RES(res2);
1439 // callback on object index update
1440 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
1441 SPIFFS_EV_IX_UPD_HDR, fd->obj_id, objix_hdr->p_hdr.span_ix, cur_objix_pix, objix_hdr->size);
1442 } else {
1443 // modifying object index header page, update size and make new copy
1444 res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1445 fd->objix_hdr_pix, fs->work, 0, 0, offset + written, &new_objix_hdr_page);
1446 SPIFFS_DBG("append: "_SPIPRIid" store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", fd->obj_id
1447 , new_objix_hdr_page, 0, written);
1448 SPIFFS_CHECK_RES(res2);
1452 return res;
1453 } // spiffs_object_append
1454 #endif // !SPIFFS_READ_ONLY
1456 #if !SPIFFS_READ_ONLY
1457 // Modify object
1458 // keep current object index (header) page in fs->work buffer
1459 s32_t spiffs_object_modify(spiffs_fd *fd, u32_t offset, u8_t *data, u32_t len) {
1460 spiffs *fs = fd->fs;
1461 s32_t res = SPIFFS_OK;
1462 u32_t written = 0;
1464 res = spiffs_gc_check(fs, len + SPIFFS_DATA_PAGE_SIZE(fs));
1465 SPIFFS_CHECK_RES(res);
1467 spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
1468 spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
1469 spiffs_page_header p_hdr;
1471 spiffs_span_ix cur_objix_spix = 0;
1472 spiffs_span_ix prev_objix_spix = (spiffs_span_ix) - 1;
1473 spiffs_page_ix cur_objix_pix = fd->objix_hdr_pix;
1474 spiffs_page_ix new_objix_hdr_pix;
1476 spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
1477 spiffs_page_ix data_pix;
1478 u32_t page_offs = offset % SPIFFS_DATA_PAGE_SIZE(fs);
1481 // write all data
1482 while (res == SPIFFS_OK && written < len) {
1483 // calculate object index page span index
1484 cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
1486 // handle storing and loading of object indices
1487 if (cur_objix_spix != prev_objix_spix) {
1488 // new object index page
1489 // within this clause we return directly if something fails, object index mess-up
1490 if (written > 0) {
1491 // store previous object index (header) page, unless first pass
1492 if (prev_objix_spix == 0) {
1493 // store previous object index header page
1494 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1495 fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);
1496 SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written);
1497 SPIFFS_CHECK_RES(res);
1498 } else {
1499 // store new version of previous object index page
1500 spiffs_page_ix new_objix_pix;
1502 res = spiffs_page_index_check(fs, fd, cur_objix_pix, prev_objix_spix);
1503 SPIFFS_CHECK_RES(res);
1505 res = spiffs_page_move(fs, fd->file_nbr, (u8_t *)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
1506 SPIFFS_DBG("modify: store previous modified objix page, "_SPIPRIid":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, objix->p_hdr.span_ix, written);
1507 SPIFFS_CHECK_RES(res);
1508 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,
1509 SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
1513 // load next object index page
1514 if (cur_objix_spix == 0) {
1515 // load object index header page, must exist
1516 SPIFFS_DBG("modify: load objixhdr page "_SPIPRIpg":"_SPIPRIsp"\n", cur_objix_pix, cur_objix_spix);
1517 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
1518 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, cur_objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1519 SPIFFS_CHECK_RES(res);
1520 SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
1521 } else {
1522 // load existing object index page on first pass
1523 spiffs_page_ix pix;
1524 SPIFFS_DBG("modify: find objix span_ix:"_SPIPRIsp"\n", cur_objix_spix);
1525 if (fd->cursor_objix_spix == cur_objix_spix) {
1526 pix = fd->cursor_objix_pix;
1527 } else {
1528 res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &pix);
1529 SPIFFS_CHECK_RES(res);
1531 SPIFFS_DBG("modify: found object index at page "_SPIPRIpg"\n", pix);
1532 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
1533 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1534 SPIFFS_CHECK_RES(res);
1535 SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
1536 cur_objix_pix = pix;
1538 fd->cursor_objix_pix = cur_objix_pix;
1539 fd->cursor_objix_spix = cur_objix_spix;
1540 fd->offset = offset + written;
1541 prev_objix_spix = cur_objix_spix;
1544 // write partial data
1545 u32_t to_write = MIN(len - written, SPIFFS_DATA_PAGE_SIZE(fs) - page_offs);
1546 spiffs_page_ix orig_data_pix;
1547 if (cur_objix_spix == 0) {
1548 // get data page from object index header page
1549 orig_data_pix = ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
1550 } else {
1551 // get data page from object index page
1552 orig_data_pix = ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
1555 p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
1556 p_hdr.span_ix = data_spix;
1557 p_hdr.flags = 0xff;
1558 if (page_offs == 0 && to_write == SPIFFS_DATA_PAGE_SIZE(fs)) {
1559 // a full page, allocate and write a new page of data
1560 res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
1561 &p_hdr, &data[written], to_write, page_offs, 1, &data_pix);
1562 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);
1563 if (res != SPIFFS_OK) break;
1564 } else {
1565 // write to existing page, allocate new and copy unmodified data
1567 res = spiffs_page_data_check(fs, fd, orig_data_pix, data_spix);
1568 SPIFFS_CHECK_RES(res);
1570 res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
1571 &p_hdr, 0, 0, 0, 0, &data_pix);
1572 if (res != SPIFFS_OK) break;
1574 // copy unmodified data
1575 if (page_offs > 0) {
1576 // before modification
1577 res = spiffs_phys_cpy(fs, fd->file_nbr,
1578 SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),
1579 SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header),
1580 page_offs);
1581 if (res != SPIFFS_OK) break;
1583 if (page_offs + to_write < SPIFFS_DATA_PAGE_SIZE(fs)) {
1584 // after modification
1585 res = spiffs_phys_cpy(fs, fd->file_nbr,
1586 SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,
1587 SPIFFS_PAGE_TO_PADDR(fs, orig_data_pix) + sizeof(spiffs_page_header) + page_offs + to_write,
1588 SPIFFS_DATA_PAGE_SIZE(fs) - (page_offs + to_write));
1589 if (res != SPIFFS_OK) break;
1592 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
1593 fd->file_nbr,
1594 SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + page_offs, to_write, &data[written]);
1595 if (res != SPIFFS_OK) break;
1596 p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;
1597 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
1598 fd->file_nbr,
1599 SPIFFS_PAGE_TO_PADDR(fs, data_pix) + offsetof(spiffs_page_header, flags),
1600 sizeof(u8_t),
1601 (u8_t *)&p_hdr.flags);
1602 if (res != SPIFFS_OK) break;
1604 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);
1607 // delete original data page
1608 res = spiffs_page_delete(fs, orig_data_pix);
1609 if (res != SPIFFS_OK) break;
1610 // update memory representation of object index page with new data page
1611 if (cur_objix_spix == 0) {
1612 // update object index header page
1613 ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = data_pix;
1614 SPIFFS_DBG("modify: wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", data_pix, data_spix);
1615 } else {
1616 // update object index page
1617 ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = data_pix;
1618 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));
1621 // update internals
1622 page_offs = 0;
1623 data_spix++;
1624 written += to_write;
1625 } // while all data
1627 fd->offset = offset + written;
1628 fd->cursor_objix_pix = cur_objix_pix;
1629 fd->cursor_objix_spix = cur_objix_spix;
1631 // finalize updated object indices
1632 s32_t res2 = SPIFFS_OK;
1633 if (cur_objix_spix != 0) {
1634 // wrote beyond object index header page
1635 // write last modified object index page
1636 // move and update page
1637 spiffs_page_ix new_objix_pix;
1639 res2 = spiffs_page_index_check(fs, fd, cur_objix_pix, cur_objix_spix);
1640 SPIFFS_CHECK_RES(res2);
1642 res2 = spiffs_page_move(fs, fd->file_nbr, (u8_t *)objix, fd->obj_id, 0, cur_objix_pix, &new_objix_pix);
1643 SPIFFS_DBG("modify: store modified objix page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_pix, cur_objix_spix, written);
1644 fd->cursor_objix_pix = new_objix_pix;
1645 fd->cursor_objix_spix = cur_objix_spix;
1646 SPIFFS_CHECK_RES(res2);
1647 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix,
1648 SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
1650 } else {
1651 // wrote within object index header page
1652 res2 = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1653 fd->objix_hdr_pix, fs->work, 0, 0, 0, &new_objix_hdr_pix);
1654 SPIFFS_DBG("modify: store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp", written "_SPIPRIi"\n", new_objix_hdr_pix, 0, written);
1655 SPIFFS_CHECK_RES(res2);
1658 return res;
1659 } // spiffs_object_modify
1660 #endif // !SPIFFS_READ_ONLY
1662 static s32_t spiffs_object_find_object_index_header_by_name_v(
1663 spiffs *fs,
1664 spiffs_obj_id obj_id,
1665 spiffs_block_ix bix,
1666 int ix_entry,
1667 const void *user_const_p,
1668 void *user_var_p) {
1669 (void)user_var_p;
1670 s32_t res;
1671 spiffs_page_object_ix_header objix_hdr;
1672 spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
1673 if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||
1674 (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
1675 return SPIFFS_VIS_COUNTINUE;
1677 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
1678 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
1679 SPIFFS_CHECK_RES(res);
1680 if (objix_hdr.p_hdr.span_ix == 0 &&
1681 (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
1682 (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
1683 if (strcmp((const char *)user_const_p, (char *)objix_hdr.name) == 0) {
1684 return SPIFFS_OK;
1688 return SPIFFS_VIS_COUNTINUE;
1691 // Finds object index header page by name
1692 s32_t spiffs_object_find_object_index_header_by_name(
1693 spiffs *fs,
1694 const u8_t name[SPIFFS_OBJ_NAME_LEN],
1695 spiffs_page_ix *pix) {
1696 s32_t res;
1697 spiffs_block_ix bix;
1698 int entry;
1700 res = spiffs_obj_lu_find_entry_visitor(fs,
1701 fs->cursor_block_ix,
1702 fs->cursor_obj_lu_entry,
1705 spiffs_object_find_object_index_header_by_name_v,
1706 name,
1708 &bix,
1709 &entry);
1711 if (res == SPIFFS_VIS_END) {
1712 res = SPIFFS_ERR_NOT_FOUND;
1714 SPIFFS_CHECK_RES(res);
1716 if (pix) {
1717 *pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
1720 fs->cursor_block_ix = bix;
1721 fs->cursor_obj_lu_entry = entry;
1723 return res;
1726 #if !SPIFFS_READ_ONLY
1727 // Truncates object to new size. If new size is null, object may be removed totally
1728 s32_t spiffs_object_truncate(
1729 spiffs_fd *fd,
1730 u32_t new_size,
1731 u8_t remove_full) {
1732 s32_t res = SPIFFS_OK;
1733 spiffs *fs = fd->fs;
1735 if ((fd->size == SPIFFS_UNDEFINED_LEN || fd->size == 0) && !remove_full) {
1736 // no op
1737 return res;
1740 // need 2 pages if not removing: object index page + possibly chopped data page
1741 if (remove_full == 0) {
1742 res = spiffs_gc_check(fs, SPIFFS_DATA_PAGE_SIZE(fs) * 2);
1743 SPIFFS_CHECK_RES(res);
1746 spiffs_page_ix objix_pix = fd->objix_hdr_pix;
1747 spiffs_span_ix data_spix = (fd->size > 0 ? fd->size - 1 : 0) / SPIFFS_DATA_PAGE_SIZE(fs);
1748 u32_t cur_size = fd->size == (u32_t)SPIFFS_UNDEFINED_LEN ? 0 : fd->size ;
1749 spiffs_span_ix cur_objix_spix = 0;
1750 spiffs_span_ix prev_objix_spix = (spiffs_span_ix) - 1;
1751 spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
1752 spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
1753 spiffs_page_ix data_pix;
1754 spiffs_page_ix new_objix_hdr_pix;
1756 // before truncating, check if object is to be fully removed and mark this
1757 if (remove_full && new_size == 0) {
1758 u8_t flags = ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE);
1759 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_UPDT,
1760 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, fd->objix_hdr_pix) + offsetof(spiffs_page_header, flags),
1761 sizeof(u8_t),
1762 (u8_t *)&flags);
1763 SPIFFS_CHECK_RES(res);
1766 // delete from end of object until desired len is reached
1767 while (cur_size > new_size) {
1768 cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
1770 // put object index for current data span index in work buffer
1771 if (prev_objix_spix != cur_objix_spix) {
1772 if (prev_objix_spix != (spiffs_span_ix) - 1) {
1773 // remove previous object index page
1774 SPIFFS_DBG("truncate: delete objix page "_SPIPRIpg":"_SPIPRIsp"\n", objix_pix, prev_objix_spix);
1776 res = spiffs_page_index_check(fs, fd, objix_pix, prev_objix_spix);
1777 SPIFFS_CHECK_RES(res);
1779 res = spiffs_page_delete(fs, objix_pix);
1780 SPIFFS_CHECK_RES(res);
1781 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
1782 SPIFFS_EV_IX_DEL, fd->obj_id, objix->p_hdr.span_ix, objix_pix, 0);
1783 if (prev_objix_spix > 0) {
1784 // Update object index header page, unless we totally want to remove the file.
1785 // If fully removing, we're not keeping consistency as good as when storing the header between chunks,
1786 // would we be aborted. But when removing full files, a crammed system may otherwise
1787 // report ERR_FULL a la windows. We cannot have that.
1788 // Hence, take the risk - if aborted, a file check would free the lost pages and mend things
1789 // as the file is marked as fully deleted in the beginning.
1790 if (remove_full == 0) {
1791 SPIFFS_DBG("truncate: update objix hdr page "_SPIPRIpg":"_SPIPRIsp" to size "_SPIPRIi"\n", fd->objix_hdr_pix, prev_objix_spix, cur_size);
1792 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1793 fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);
1794 SPIFFS_CHECK_RES(res);
1796 fd->size = cur_size;
1799 // load current object index (header) page
1800 if (cur_objix_spix == 0) {
1801 objix_pix = fd->objix_hdr_pix;
1802 } else {
1803 res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);
1804 SPIFFS_CHECK_RES(res);
1807 SPIFFS_DBG("truncate: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix);
1808 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
1809 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
1810 SPIFFS_CHECK_RES(res);
1811 SPIFFS_VALIDATE_OBJIX(objix_hdr->p_hdr, fd->obj_id, cur_objix_spix);
1812 fd->cursor_objix_pix = objix_pix;
1813 fd->cursor_objix_spix = cur_objix_spix;
1814 fd->offset = cur_size;
1816 prev_objix_spix = cur_objix_spix;
1819 if (cur_objix_spix == 0) {
1820 // get data page from object index header page
1821 data_pix = ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
1822 ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = SPIFFS_OBJ_ID_FREE;
1823 } else {
1824 // get data page from object index page
1825 data_pix = ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
1826 ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = SPIFFS_OBJ_ID_FREE;
1829 SPIFFS_DBG("truncate: got data pix "_SPIPRIpg"\n", data_pix);
1831 if (new_size == 0 || remove_full || cur_size - new_size >= SPIFFS_DATA_PAGE_SIZE(fs)) {
1832 // delete full data page
1833 res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
1834 if (res != SPIFFS_ERR_DELETED && res != SPIFFS_OK && res != SPIFFS_ERR_INDEX_REF_FREE) {
1835 SPIFFS_DBG("truncate: err validating data pix "_SPIPRIi"\n", res);
1836 break;
1839 if (res == SPIFFS_OK) {
1840 res = spiffs_page_delete(fs, data_pix);
1841 if (res != SPIFFS_OK) {
1842 SPIFFS_DBG("truncate: err deleting data pix "_SPIPRIi"\n", res);
1843 break;
1845 } else if (res == SPIFFS_ERR_DELETED || res == SPIFFS_ERR_INDEX_REF_FREE) {
1846 res = SPIFFS_OK;
1849 // update current size
1850 if (cur_size % SPIFFS_DATA_PAGE_SIZE(fs) == 0) {
1851 cur_size -= SPIFFS_DATA_PAGE_SIZE(fs);
1852 } else {
1853 cur_size -= cur_size % SPIFFS_DATA_PAGE_SIZE(fs);
1855 fd->size = cur_size;
1856 fd->offset = cur_size;
1857 SPIFFS_DBG("truncate: delete data page "_SPIPRIpg" for data spix:"_SPIPRIsp", cur_size:"_SPIPRIi"\n", data_pix, data_spix, cur_size);
1858 } else {
1859 // delete last page, partially
1860 spiffs_page_header p_hdr;
1861 spiffs_page_ix new_data_pix;
1862 u32_t bytes_to_remove = SPIFFS_DATA_PAGE_SIZE(fs) - (new_size % SPIFFS_DATA_PAGE_SIZE(fs));
1863 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);
1865 res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
1866 if (res != SPIFFS_OK) break;
1868 p_hdr.obj_id = fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
1869 p_hdr.span_ix = data_spix;
1870 p_hdr.flags = 0xff;
1871 // allocate new page and copy unmodified data
1872 res = spiffs_page_allocate_data(fs, fd->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
1873 &p_hdr, 0, 0, 0, 0, &new_data_pix);
1874 if (res != SPIFFS_OK) break;
1875 res = spiffs_phys_cpy(fs, 0,
1876 SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + sizeof(spiffs_page_header),
1877 SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header),
1878 SPIFFS_DATA_PAGE_SIZE(fs) - bytes_to_remove);
1879 if (res != SPIFFS_OK) break;
1880 // delete original data page
1881 res = spiffs_page_delete(fs, data_pix);
1882 if (res != SPIFFS_OK) break;
1883 p_hdr.flags &= ~SPIFFS_PH_FLAG_FINAL;
1884 res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
1885 fd->file_nbr,
1886 SPIFFS_PAGE_TO_PADDR(fs, new_data_pix) + offsetof(spiffs_page_header, flags),
1887 sizeof(u8_t),
1888 (u8_t *)&p_hdr.flags);
1889 if (res != SPIFFS_OK) break;
1891 // update memory representation of object index page with new data page
1892 if (cur_objix_spix == 0) {
1893 // update object index header page
1894 ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
1895 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));
1896 } else {
1897 // update object index page
1898 ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
1899 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));
1901 cur_size = new_size;
1902 fd->size = new_size;
1903 fd->offset = cur_size;
1904 break;
1906 data_spix--;
1907 } // while all data
1909 // update object indices
1910 if (cur_objix_spix == 0) {
1911 // update object index header page
1912 if (cur_size == 0) {
1913 if (remove_full) {
1914 // remove object altogether
1915 SPIFFS_DBG("truncate: remove object index header page "_SPIPRIpg"\n", objix_pix);
1917 res = spiffs_page_index_check(fs, fd, objix_pix, 0);
1918 SPIFFS_CHECK_RES(res);
1920 res = spiffs_page_delete(fs, objix_pix);
1921 SPIFFS_CHECK_RES(res);
1922 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
1923 SPIFFS_EV_IX_DEL, fd->obj_id, 0, objix_pix, 0);
1924 } else {
1925 // make uninitialized object
1926 SPIFFS_DBG("truncate: reset objix_hdr page "_SPIPRIpg"\n", objix_pix);
1927 memset(fs->work + sizeof(spiffs_page_object_ix_header), 0xff,
1928 SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header));
1929 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1930 objix_pix, fs->work, 0, 0, SPIFFS_UNDEFINED_LEN, &new_objix_hdr_pix);
1931 SPIFFS_CHECK_RES(res);
1933 } else {
1934 // update object index header page
1935 SPIFFS_DBGF("truncate: update object index header page with indices and size\n");
1936 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1937 objix_pix, fs->work, 0, 0, cur_size, &new_objix_hdr_pix);
1938 SPIFFS_CHECK_RES(res);
1940 } else {
1941 // update both current object index page and object index header page
1942 spiffs_page_ix new_objix_pix;
1944 res = spiffs_page_index_check(fs, fd, objix_pix, cur_objix_spix);
1945 SPIFFS_CHECK_RES(res);
1947 // move and update object index page
1948 res = spiffs_page_move(fs, fd->file_nbr, (u8_t *)objix_hdr, fd->obj_id, 0, objix_pix, &new_objix_pix);
1949 SPIFFS_CHECK_RES(res);
1950 spiffs_cb_object_event(fs, (spiffs_page_object_ix *)objix_hdr,
1951 SPIFFS_EV_IX_UPD, fd->obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
1952 SPIFFS_DBG("truncate: store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, cur_objix_spix);
1953 fd->cursor_objix_pix = new_objix_pix;
1954 fd->cursor_objix_spix = cur_objix_spix;
1955 fd->offset = cur_size;
1956 // update object index header page with new size
1957 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id,
1958 fd->objix_hdr_pix, 0, 0, 0, cur_size, &new_objix_hdr_pix);
1959 SPIFFS_CHECK_RES(res);
1961 fd->size = cur_size;
1963 return res;
1964 } // spiffs_object_truncate
1965 #endif // !SPIFFS_READ_ONLY
1967 s32_t spiffs_object_read(
1968 spiffs_fd *fd,
1969 u32_t offset,
1970 u32_t len,
1971 u8_t *dst) {
1972 s32_t res = SPIFFS_OK;
1973 spiffs *fs = fd->fs;
1974 spiffs_page_ix objix_pix;
1975 spiffs_page_ix data_pix;
1976 spiffs_span_ix data_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
1977 u32_t cur_offset = offset;
1978 spiffs_span_ix cur_objix_spix;
1979 spiffs_span_ix prev_objix_spix = (spiffs_span_ix) - 1;
1980 spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
1981 spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
1983 while (cur_offset < offset + len) {
1984 #if SPIFFS_IX_MAP
1985 // check if we have a memory, index map and if so, if we're within index map's range
1986 // and if so, if the entry is populated
1987 if (fd->ix_map && data_spix >= fd->ix_map->start_spix && data_spix <= fd->ix_map->end_spix
1988 && fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix]) {
1989 data_pix = fd->ix_map->map_buf[data_spix - fd->ix_map->start_spix];
1990 } else {
1991 #endif
1992 cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
1993 if (prev_objix_spix != cur_objix_spix) {
1994 // load current object index (header) page
1995 if (cur_objix_spix == 0) {
1996 objix_pix = fd->objix_hdr_pix;
1997 } else {
1998 SPIFFS_DBG("read: find objix "_SPIPRIid":"_SPIPRIsp"\n", fd->obj_id, cur_objix_spix);
1999 if (fd->cursor_objix_spix == cur_objix_spix) {
2000 objix_pix = fd->cursor_objix_pix;
2001 } else {
2002 res = spiffs_obj_lu_find_id_and_span(fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, cur_objix_spix, 0, &objix_pix);
2003 SPIFFS_CHECK_RES(res);
2006 SPIFFS_DBG("read: load objix page "_SPIPRIpg":"_SPIPRIsp" for data spix:"_SPIPRIsp"\n", objix_pix, cur_objix_spix, data_spix);
2007 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ,
2008 fd->file_nbr, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
2009 SPIFFS_CHECK_RES(res);
2010 SPIFFS_VALIDATE_OBJIX(objix->p_hdr, fd->obj_id, cur_objix_spix);
2012 fd->offset = cur_offset;
2013 fd->cursor_objix_pix = objix_pix;
2014 fd->cursor_objix_spix = cur_objix_spix;
2016 prev_objix_spix = cur_objix_spix;
2019 if (cur_objix_spix == 0) {
2020 // get data page from object index header page
2021 data_pix = ((spiffs_page_ix *)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[data_spix];
2022 } else {
2023 // get data page from object index page
2024 data_pix = ((spiffs_page_ix *)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)];
2026 #if SPIFFS_IX_MAP
2028 #endif
2029 // all remaining data
2030 u32_t len_to_read = offset + len - cur_offset;
2031 // remaining data in page
2032 len_to_read = MIN(len_to_read, SPIFFS_DATA_PAGE_SIZE(fs) - (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)));
2033 // remaining data in file
2034 len_to_read = MIN(len_to_read, fd->size - cur_offset);
2035 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,
2036 (u32_t)(SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs))));
2037 if (len_to_read == 0) {
2038 res = SPIFFS_ERR_END_OF_OBJECT;
2039 break;
2041 res = spiffs_page_data_check(fs, fd, data_pix, data_spix);
2042 SPIFFS_CHECK_RES(res);
2043 res = _spiffs_rd(
2044 fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_READ,
2045 fd->file_nbr,
2046 SPIFFS_PAGE_TO_PADDR(fs, data_pix) + sizeof(spiffs_page_header) + (cur_offset % SPIFFS_DATA_PAGE_SIZE(fs)),
2047 len_to_read,
2048 dst);
2049 SPIFFS_CHECK_RES(res);
2050 dst += len_to_read;
2051 cur_offset += len_to_read;
2052 fd->offset = cur_offset;
2053 data_spix++;
2056 return res;
2059 #if !SPIFFS_READ_ONLY
2060 typedef struct {
2061 spiffs_obj_id min_obj_id;
2062 spiffs_obj_id max_obj_id;
2063 u32_t compaction;
2064 const u8_t *conflicting_name;
2065 } spiffs_free_obj_id_state;
2067 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,
2068 const void *user_const_p, void *user_var_p) {
2069 if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED) {
2070 spiffs_obj_id min_obj_id = *((spiffs_obj_id *)user_var_p);
2071 const u8_t *conflicting_name = (const u8_t *)user_const_p;
2073 // if conflicting name parameter is given, also check if this name is found in object index hdrs
2074 if (conflicting_name && (id & SPIFFS_OBJ_ID_IX_FLAG)) {
2075 spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
2076 int res;
2077 spiffs_page_object_ix_header objix_hdr;
2078 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
2079 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
2080 SPIFFS_CHECK_RES(res);
2081 if (objix_hdr.p_hdr.span_ix == 0 &&
2082 (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
2083 (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
2084 if (strcmp((const char *)user_const_p, (char *)objix_hdr.name) == 0) {
2085 return SPIFFS_ERR_CONFLICTING_NAME;
2090 id &= ~SPIFFS_OBJ_ID_IX_FLAG;
2091 u32_t bit_ix = (id - min_obj_id) & 7;
2092 int byte_ix = (id - min_obj_id) >> 3;
2093 if (byte_ix >= 0 && (u32_t)byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
2094 fs->work[byte_ix] |= (1 << bit_ix);
2097 return SPIFFS_VIS_COUNTINUE;
2100 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,
2101 const void *user_const_p, void *user_var_p) {
2102 (void)user_var_p;
2103 if (id != SPIFFS_OBJ_ID_FREE && id != SPIFFS_OBJ_ID_DELETED && (id & SPIFFS_OBJ_ID_IX_FLAG)) {
2104 s32_t res;
2105 const spiffs_free_obj_id_state *state = (const spiffs_free_obj_id_state *)user_const_p;
2106 spiffs_page_object_ix_header objix_hdr;
2108 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
2109 0, SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, bix, ix_entry), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
2110 if (res == SPIFFS_OK && objix_hdr.p_hdr.span_ix == 0 &&
2111 ((objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) ==
2112 (SPIFFS_PH_FLAG_DELET))) {
2113 // ok object look up entry
2114 if (state->conflicting_name && strcmp((const char *)state->conflicting_name, (char *)objix_hdr.name) == 0) {
2115 return SPIFFS_ERR_CONFLICTING_NAME;
2118 id &= ~SPIFFS_OBJ_ID_IX_FLAG;
2119 if (id >= state->min_obj_id && id <= state->max_obj_id) {
2120 u8_t *map = (u8_t *)fs->work;
2121 int ix = (id - state->min_obj_id) / state->compaction;
2122 //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);
2123 map[ix]++;
2127 return SPIFFS_VIS_COUNTINUE;
2130 // Scans thru all object lookup for object index header pages. If total possible number of
2131 // object ids cannot fit into a work buffer, these are grouped. When a group containing free
2132 // object ids is found, the object lu is again scanned for object ids within group and bitmasked.
2133 // Finally, the bitmask is searched for a free id
2134 s32_t spiffs_obj_lu_find_free_obj_id(spiffs *fs, spiffs_obj_id *obj_id, const u8_t *conflicting_name) {
2135 s32_t res = SPIFFS_OK;
2136 u32_t max_objects = (fs->block_count * SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs)) / 2;
2137 spiffs_free_obj_id_state state;
2138 spiffs_obj_id free_obj_id = SPIFFS_OBJ_ID_FREE;
2139 state.min_obj_id = 1;
2140 state.max_obj_id = max_objects + 1;
2141 if (state.max_obj_id & SPIFFS_OBJ_ID_IX_FLAG) {
2142 state.max_obj_id = ((spiffs_obj_id) - 1) & ~SPIFFS_OBJ_ID_IX_FLAG;
2144 state.compaction = 0;
2145 state.conflicting_name = conflicting_name;
2146 while (res == SPIFFS_OK && free_obj_id == SPIFFS_OBJ_ID_FREE) {
2147 if (state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8) {
2148 // possible to represent in bitmap
2149 u32_t i, j;
2150 SPIFFS_DBG("free_obj_id: BITM min:"_SPIPRIid" max:"_SPIPRIid"\n", state.min_obj_id, state.max_obj_id);
2152 memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
2153 res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_obj_lu_find_free_obj_id_bitmap_v,
2154 conflicting_name, &state.min_obj_id, 0, 0);
2155 if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
2156 SPIFFS_CHECK_RES(res);
2157 // traverse bitmask until found free obj_id
2158 for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs); i++) {
2159 u8_t mask = fs->work[i];
2160 if (mask == 0xff) {
2161 continue;
2163 for (j = 0; j < 8; j++) {
2164 if ((mask & (1 << j)) == 0) {
2165 *obj_id = (i << 3) + j + state.min_obj_id;
2166 return SPIFFS_OK;
2170 return SPIFFS_ERR_FULL;
2171 } else {
2172 // not possible to represent all ids in range in a bitmap, compact and count
2173 if (state.compaction != 0) {
2174 // select element in compacted table, decrease range and recompact
2175 u32_t i, min_i = 0;
2176 u8_t *map = (u8_t *)fs->work;
2177 u8_t min_count = 0xff;
2179 for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t); i++) {
2180 if (map[i] < min_count) {
2181 min_count = map[i];
2182 min_i = i;
2183 if (min_count == 0) {
2184 break;
2189 if (min_count == state.compaction) {
2190 // there are no free objids!
2191 SPIFFS_DBGF("free_obj_id: compacted table is full\n");
2192 return SPIFFS_ERR_FULL;
2195 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);
2197 if (min_count == 0) {
2198 // no id in this range, skip compacting and use directly
2199 *obj_id = min_i * state.compaction + state.min_obj_id;
2200 return SPIFFS_OK;
2201 } else {
2202 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);
2203 state.min_obj_id += min_i * state.compaction;
2204 state.max_obj_id = state.min_obj_id + state.compaction;
2205 // decrease compaction
2207 if ((state.max_obj_id - state.min_obj_id <= (spiffs_obj_id)SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8)) {
2208 // no need for compacting, use bitmap
2209 continue;
2212 // in a work memory of log_page_size bytes, we may fit in log_page_size ids
2213 // todo what if compaction is > 255 - then we cannot fit it in a byte
2214 state.compaction = (state.max_obj_id - state.min_obj_id) / ((SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(u8_t)));
2215 SPIFFS_DBG("free_obj_id: COMP min:"_SPIPRIid" max:"_SPIPRIid" compact:"_SPIPRIi"\n", state.min_obj_id, state.max_obj_id, state.compaction);
2217 memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
2218 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);
2219 if (res == SPIFFS_VIS_END) res = SPIFFS_OK;
2220 SPIFFS_CHECK_RES(res);
2221 state.conflicting_name = 0; // searched for conflicting name once, no need to do it again
2225 return res;
2227 #endif // !SPIFFS_READ_ONLY
2229 #if SPIFFS_TEMPORAL_FD_CACHE
2230 // djb2 hash
2231 static u32_t spiffs_hash(spiffs *fs, const u8_t *name) {
2232 (void)fs;
2233 u32_t hash = 5381;
2234 u8_t c;
2235 int i = 0;
2236 while ((c = name[i++]) && i < SPIFFS_OBJ_NAME_LEN) {
2237 hash = (hash * 33) ^ c;
2239 return hash;
2241 #endif
2243 s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) {
2244 #if SPIFFS_TEMPORAL_FD_CACHE
2245 u32_t i;
2246 u16_t min_score = 0xffff;
2247 u32_t cand_ix = (u32_t) - 1;
2248 u32_t name_hash = name ? spiffs_hash(fs, (const u8_t *)name) : 0;
2249 spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
2251 if (name) {
2252 // first, decrease score of all closed descriptors
2253 for (i = 0; i < fs->fd_count; i++) {
2254 spiffs_fd *cur_fd = &fds[i];
2255 if (cur_fd->file_nbr == 0) {
2256 if (cur_fd->score > 1) { // score == 0 indicates never used fd
2257 cur_fd->score--;
2263 // find the free fd with least score or name match
2264 for (i = 0; i < fs->fd_count; i++) {
2265 spiffs_fd *cur_fd = &fds[i];
2266 if (cur_fd->file_nbr == 0) {
2267 if (name && cur_fd->name_hash == name_hash) {
2268 cand_ix = i;
2269 break;
2271 if (cur_fd->score < min_score) {
2272 min_score = cur_fd->score;
2273 cand_ix = i;
2278 if (cand_ix != (u32_t) - 1) {
2279 spiffs_fd *cur_fd = &fds[cand_ix];
2280 if (name) {
2281 if (cur_fd->name_hash == name_hash && cur_fd->score > 0) {
2282 // opened an fd with same name hash, assume same file
2283 // set search point to saved obj index page and hope we have a correct match directly
2284 // when start searching - if not, we will just keep searching until it is found
2285 fs->cursor_block_ix = SPIFFS_BLOCK_FOR_PAGE(fs, cur_fd->objix_hdr_pix);
2286 fs->cursor_obj_lu_entry = SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, cur_fd->objix_hdr_pix);
2287 // update score
2288 if (cur_fd->score < 0xffff - SPIFFS_TEMPORAL_CACHE_HIT_SCORE) {
2289 cur_fd->score += SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
2290 } else {
2291 cur_fd->score = 0xffff;
2293 } else {
2294 // no hash hit, restore this fd to initial state
2295 cur_fd->score = SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
2296 cur_fd->name_hash = name_hash;
2299 cur_fd->file_nbr = cand_ix + 1;
2300 *fd = cur_fd;
2301 return SPIFFS_OK;
2302 } else {
2303 return SPIFFS_ERR_OUT_OF_FILE_DESCS;
2305 #else
2306 (void)name;
2307 u32_t i;
2308 spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
2309 for (i = 0; i < fs->fd_count; i++) {
2310 spiffs_fd *cur_fd = &fds[i];
2311 if (cur_fd->file_nbr == 0) {
2312 cur_fd->file_nbr = i + 1;
2313 *fd = cur_fd;
2314 return SPIFFS_OK;
2317 return SPIFFS_ERR_OUT_OF_FILE_DESCS;
2318 #endif
2321 s32_t spiffs_fd_return(spiffs *fs, spiffs_file f) {
2322 if (f <= 0 || f > (s16_t)fs->fd_count) {
2323 return SPIFFS_ERR_BAD_DESCRIPTOR;
2325 spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
2326 spiffs_fd *fd = &fds[f - 1];
2327 if (fd->file_nbr == 0) {
2328 return SPIFFS_ERR_FILE_CLOSED;
2330 fd->file_nbr = 0;
2331 #if SPIFFS_IX_MAP
2332 fd->ix_map = 0;
2333 #endif
2334 return SPIFFS_OK;
2337 s32_t spiffs_fd_get(spiffs *fs, spiffs_file f, spiffs_fd **fd) {
2338 if (f <= 0 || f > (s16_t)fs->fd_count) {
2339 return SPIFFS_ERR_BAD_DESCRIPTOR;
2341 spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
2342 *fd = &fds[f - 1];
2343 if ((*fd)->file_nbr == 0) {
2344 return SPIFFS_ERR_FILE_CLOSED;
2346 return SPIFFS_OK;
2349 #if SPIFFS_TEMPORAL_FD_CACHE
2350 void spiffs_fd_temporal_cache_rehash(
2351 spiffs *fs,
2352 const char *old_path,
2353 const char *new_path) {
2354 u32_t i;
2355 u32_t old_hash = spiffs_hash(fs, (const u8_t *)old_path);
2356 u32_t new_hash = spiffs_hash(fs, (const u8_t *)new_path);
2357 spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
2358 for (i = 0; i < fs->fd_count; i++) {
2359 spiffs_fd *cur_fd = &fds[i];
2360 if (cur_fd->score > 0 && cur_fd->name_hash == old_hash) {
2361 cur_fd->name_hash = new_hash;
2365 #endif