text
[RRG-proxmark3.git] / armsrc / spiffs_hydrogen.c
bloba166c3b7a957cd349fc15e7ff9d0561d250a2e0f
1 /*
2 * spiffs_hydrogen.c
4 * Created on: Jun 16, 2013
5 * Author: petera
6 */
8 #include "spiffs.h"
9 #include "spiffs_nucleus.h"
10 #include "printf.h"
12 #if SPIFFS_CACHE == 1
13 static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh);
14 #endif
16 #if SPIFFS_BUFFER_HELP
17 u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs) {
18 return num_descs * sizeof(spiffs_fd);
20 #if SPIFFS_CACHE
21 u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages) {
22 return sizeof(spiffs_cache) + num_pages * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));
24 #endif
25 #endif
27 u8_t SPIFFS_mounted(spiffs *fs) {
28 return SPIFFS_CHECK_MOUNT(fs);
31 s32_t SPIFFS_format(spiffs *fs) {
32 #if SPIFFS_READ_ONLY
33 (void)fs;
34 return SPIFFS_ERR_RO_NOT_IMPL;
35 #else
36 SPIFFS_API_CHECK_CFG(fs);
37 if (SPIFFS_CHECK_MOUNT(fs)) {
38 fs->err_code = SPIFFS_ERR_MOUNTED;
39 return -1;
42 SPIFFS_LOCK(fs);
44 spiffs_block_ix bix = 0;
45 while (bix < fs->block_count) {
46 fs->max_erase_count = 0;
47 s32_t res = spiffs_erase_block(fs, bix);
48 if (res != SPIFFS_OK) {
49 res = SPIFFS_ERR_ERASE_FAIL;
51 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
52 bix++;
55 SPIFFS_UNLOCK(fs);
57 return 0;
58 #endif // SPIFFS_READ_ONLY
61 #if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
63 s32_t SPIFFS_probe_fs(spiffs_config *config) {
64 SPIFFS_API_DBG("%s\n", __func__);
65 s32_t res = spiffs_probe(config);
66 return res;
69 #endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
71 s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
72 u8_t *fd_space, u32_t fd_space_size,
73 void *cache, u32_t cache_size,
74 spiffs_check_callback check_cb_f) {
75 SPIFFS_API_DBG("%s "
76 " sz:"_SPIPRIi " logpgsz:"_SPIPRIi " logblksz:"_SPIPRIi " perasz:"_SPIPRIi
77 " addr:"_SPIPRIad
78 " fdsz:"_SPIPRIi " cachesz:"_SPIPRIi
79 "\n",
80 __func__,
81 SPIFFS_CFG_PHYS_SZ(fs),
82 SPIFFS_CFG_LOG_PAGE_SZ(fs),
83 SPIFFS_CFG_LOG_BLOCK_SZ(fs),
84 SPIFFS_CFG_PHYS_ERASE_SZ(fs),
85 SPIFFS_CFG_PHYS_ADDR(fs),
86 fd_space_size, cache_size);
87 void *user_data;
88 SPIFFS_LOCK(fs);
89 user_data = fs->user_data;
90 memset(fs, 0, sizeof(spiffs));
91 _SPIFFS_MEMCPY(&fs->cfg, config, sizeof(spiffs_config));
92 fs->user_data = user_data;
93 fs->block_count = SPIFFS_CFG_PHYS_SZ(fs) / SPIFFS_CFG_LOG_BLOCK_SZ(fs);
94 fs->work = &work[0];
95 fs->lu_work = &work[SPIFFS_CFG_LOG_PAGE_SZ(fs)];
96 memset(fd_space, 0, fd_space_size);
97 // align fd_space pointer to pointer size byte boundary
98 u8_t ptr_size = sizeof(void *);
99 u8_t addr_lsb = ((u8_t)(intptr_t)fd_space) & (ptr_size - 1);
100 if (addr_lsb) {
101 fd_space += (ptr_size - addr_lsb);
102 fd_space_size -= (ptr_size - addr_lsb);
104 fs->fd_space = fd_space;
105 fs->fd_count = (fd_space_size / sizeof(spiffs_fd));
107 // align cache pointer to 4 byte boundary
108 addr_lsb = ((u8_t)(intptr_t)cache) & (ptr_size - 1);
109 if (addr_lsb) {
110 u8_t *cache_8 = (u8_t *)cache;
111 cache_8 += (ptr_size - addr_lsb);
112 cache = cache_8;
113 cache_size -= (ptr_size - addr_lsb);
115 if (cache_size & (ptr_size - 1)) {
116 cache_size -= (cache_size & (ptr_size - 1));
119 #if SPIFFS_CACHE
120 fs->cache = cache;
121 fs->cache_size = (cache_size > (SPIFFS_CFG_LOG_PAGE_SZ(fs) * 32)) ? SPIFFS_CFG_LOG_PAGE_SZ(fs) * 32 : cache_size;
122 spiffs_cache_init(fs);
123 #endif
125 s32_t res;
127 #if SPIFFS_USE_MAGIC
128 res = SPIFFS_CHECK_MAGIC_POSSIBLE(fs) ? SPIFFS_OK : SPIFFS_ERR_MAGIC_NOT_POSSIBLE;
129 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
130 #endif
132 fs->config_magic = SPIFFS_CONFIG_MAGIC;
134 res = spiffs_obj_lu_scan(fs);
135 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
137 SPIFFS_DBG("page index byte len: "_SPIPRIi"\n", (u32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs));
138 SPIFFS_DBG("object lookup pages: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_LOOKUP_PAGES(fs));
139 SPIFFS_DBG("page pages per block: "_SPIPRIi"\n", (u32_t)SPIFFS_PAGES_PER_BLOCK(fs));
140 SPIFFS_DBG("page header length: "_SPIPRIi"\n", (u32_t)sizeof(spiffs_page_header));
141 SPIFFS_DBG("object header index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_HDR_IX_LEN(fs));
142 SPIFFS_DBG("object index entries: "_SPIPRIi"\n", (u32_t)SPIFFS_OBJ_IX_LEN(fs));
143 SPIFFS_DBG("available file descriptors: "_SPIPRIi"\n", (u32_t)fs->fd_count);
144 SPIFFS_DBG("free blocks: "_SPIPRIi"\n", (u32_t)fs->free_blocks);
146 fs->check_cb_f = check_cb_f;
148 fs->mounted = 1;
150 SPIFFS_UNLOCK(fs);
152 return 0;
155 void SPIFFS_unmount(spiffs *fs) {
156 SPIFFS_API_DBG("%s\n", __func__);
157 if (!SPIFFS_CHECK_CFG(fs) || !SPIFFS_CHECK_MOUNT(fs)) return;
158 SPIFFS_LOCK(fs);
159 u32_t i;
160 spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
161 for (i = 0; i < fs->fd_count; i++) {
162 spiffs_fd *cur_fd = &fds[i];
163 if (cur_fd->file_nbr != 0) {
164 #if SPIFFS_CACHE
165 (void)spiffs_fflush_cache(fs, cur_fd->file_nbr);
166 #endif
167 spiffs_fd_return(fs, cur_fd->file_nbr);
170 fs->mounted = 0;
172 SPIFFS_UNLOCK(fs);
175 s32_t SPIFFS_errno(spiffs *fs) {
176 return fs->err_code;
179 void SPIFFS_clearerr(spiffs *fs) {
180 SPIFFS_API_DBG("%s\n", __func__);
181 fs->err_code = SPIFFS_OK;
184 s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode) {
185 SPIFFS_API_DBG("%s '%s'\n", __func__, path);
186 #if SPIFFS_READ_ONLY
187 (void)fs;
188 (void)path;
189 (void)mode;
190 return SPIFFS_ERR_RO_NOT_IMPL;
191 #else
192 (void)mode;
193 SPIFFS_API_CHECK_CFG(fs);
194 SPIFFS_API_CHECK_MOUNT(fs);
195 if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
196 SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
198 SPIFFS_LOCK(fs);
199 spiffs_obj_id obj_id;
200 s32_t res;
202 res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, (const u8_t *)path);
203 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
204 res = spiffs_object_create(fs, obj_id, (const u8_t *)path, 0, SPIFFS_TYPE_FILE, 0);
205 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
206 SPIFFS_UNLOCK(fs);
207 return 0;
208 #endif // SPIFFS_READ_ONLY
211 spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode) {
212 SPIFFS_API_DBG("%s '%s' "_SPIPRIfl "\n", __func__, path, flags);
213 (void)mode;
214 SPIFFS_API_CHECK_CFG(fs);
215 SPIFFS_API_CHECK_MOUNT(fs);
216 if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
217 SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
219 SPIFFS_LOCK(fs);
221 spiffs_fd *fd;
222 spiffs_page_ix pix;
224 #if SPIFFS_READ_ONLY
225 // not valid flags in read only mode
226 flags &= ~(SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_TRUNC);
227 #endif // SPIFFS_READ_ONLY
229 s32_t res = spiffs_fd_find_new(fs, &fd, path);
230 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
232 res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t *)path, &pix);
233 if ((flags & SPIFFS_O_CREAT) == 0) {
234 if (res < SPIFFS_OK) {
235 spiffs_fd_return(fs, fd->file_nbr);
237 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
240 if (res == SPIFFS_OK &&
241 (flags & (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) == (SPIFFS_O_CREAT | SPIFFS_O_EXCL)) {
242 // creat and excl and file exists - fail
243 res = SPIFFS_ERR_FILE_EXISTS;
244 spiffs_fd_return(fs, fd->file_nbr);
245 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
248 if ((flags & SPIFFS_O_CREAT) && res == SPIFFS_ERR_NOT_FOUND) {
249 #if !SPIFFS_READ_ONLY
250 spiffs_obj_id obj_id;
251 // no need to enter conflicting name here, already looked for it above
252 res = spiffs_obj_lu_find_free_obj_id(fs, &obj_id, 0);
253 if (res < SPIFFS_OK) {
254 spiffs_fd_return(fs, fd->file_nbr);
256 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
257 res = spiffs_object_create(fs, obj_id, (const u8_t *)path, 0, SPIFFS_TYPE_FILE, &pix);
258 if (res < SPIFFS_OK) {
259 spiffs_fd_return(fs, fd->file_nbr);
261 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
262 flags &= ~SPIFFS_O_TRUNC;
263 #endif // !SPIFFS_READ_ONLY
264 } else {
265 if (res < SPIFFS_OK) {
266 spiffs_fd_return(fs, fd->file_nbr);
268 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
270 res = spiffs_object_open_by_page(fs, pix, fd, flags, mode);
271 if (res < SPIFFS_OK) {
272 spiffs_fd_return(fs, fd->file_nbr);
274 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
275 #if !SPIFFS_READ_ONLY
276 if (flags & SPIFFS_O_TRUNC) {
277 res = spiffs_object_truncate(fd, 0, 0);
278 if (res < SPIFFS_OK) {
279 spiffs_fd_return(fs, fd->file_nbr);
281 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
283 #endif // !SPIFFS_READ_ONLY
285 fd->fdoffset = 0;
287 SPIFFS_UNLOCK(fs);
289 return SPIFFS_FH_OFFS(fs, fd->file_nbr);
292 spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode) {
293 SPIFFS_API_DBG("%s '%s':"_SPIPRIid " "_SPIPRIfl "\n", __func__, e->name, e->obj_id, flags);
294 SPIFFS_API_CHECK_CFG(fs);
295 SPIFFS_API_CHECK_MOUNT(fs);
296 SPIFFS_LOCK(fs);
298 spiffs_fd *fd;
300 s32_t res = spiffs_fd_find_new(fs, &fd, 0);
301 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
303 res = spiffs_object_open_by_page(fs, e->pix, fd, flags, mode);
304 if (res < SPIFFS_OK) {
305 spiffs_fd_return(fs, fd->file_nbr);
307 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
308 #if !SPIFFS_READ_ONLY
309 if (flags & SPIFFS_O_TRUNC) {
310 res = spiffs_object_truncate(fd, 0, 0);
311 if (res < SPIFFS_OK) {
312 spiffs_fd_return(fs, fd->file_nbr);
314 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
316 #endif // !SPIFFS_READ_ONLY
318 fd->fdoffset = 0;
320 SPIFFS_UNLOCK(fs);
322 return SPIFFS_FH_OFFS(fs, fd->file_nbr);
325 spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode) {
326 SPIFFS_API_DBG("%s "_SPIPRIpg " "_SPIPRIfl "\n", __func__, page_ix, flags);
327 SPIFFS_API_CHECK_CFG(fs);
328 SPIFFS_API_CHECK_MOUNT(fs);
329 SPIFFS_LOCK(fs);
331 spiffs_fd *fd;
333 s32_t res = spiffs_fd_find_new(fs, &fd, 0);
334 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
336 if (SPIFFS_IS_LOOKUP_PAGE(fs, page_ix)) {
337 res = SPIFFS_ERR_NOT_A_FILE;
338 spiffs_fd_return(fs, fd->file_nbr);
339 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
342 res = spiffs_object_open_by_page(fs, page_ix, fd, flags, mode);
343 if (res == SPIFFS_ERR_IS_FREE ||
344 res == SPIFFS_ERR_DELETED ||
345 res == SPIFFS_ERR_NOT_FINALIZED ||
346 res == SPIFFS_ERR_NOT_INDEX ||
347 res == SPIFFS_ERR_INDEX_SPAN_MISMATCH) {
348 res = SPIFFS_ERR_NOT_A_FILE;
350 if (res < SPIFFS_OK) {
351 spiffs_fd_return(fs, fd->file_nbr);
353 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
355 #if !SPIFFS_READ_ONLY
356 if (flags & SPIFFS_O_TRUNC) {
357 res = spiffs_object_truncate(fd, 0, 0);
358 if (res < SPIFFS_OK) {
359 spiffs_fd_return(fs, fd->file_nbr);
361 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
363 #endif // !SPIFFS_READ_ONLY
365 fd->fdoffset = 0;
367 SPIFFS_UNLOCK(fs);
369 return SPIFFS_FH_OFFS(fs, fd->file_nbr);
372 static s32_t spiffs_hydro_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
373 SPIFFS_API_CHECK_CFG(fs);
374 SPIFFS_API_CHECK_MOUNT(fs);
375 SPIFFS_LOCK(fs);
377 spiffs_fd *fd;
378 s32_t res;
380 fh = SPIFFS_FH_UNOFFS(fs, fh);
381 res = spiffs_fd_get(fs, fh, &fd);
382 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
384 if ((fd->flags & SPIFFS_O_RDONLY) == 0) {
385 res = SPIFFS_ERR_NOT_READABLE;
386 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
389 if (fd->size == SPIFFS_UNDEFINED_LEN && len > 0) {
390 // special case for zero sized files
391 res = SPIFFS_ERR_END_OF_OBJECT;
392 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
395 #if SPIFFS_CACHE_WR
396 spiffs_fflush_cache(fs, fh);
397 #endif
399 if (fd->fdoffset + len >= fd->size) {
400 // reading beyond file size
401 s32_t avail = fd->size - fd->fdoffset;
402 if (avail <= 0) {
403 SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_END_OF_OBJECT);
405 res = spiffs_object_read(fd, fd->fdoffset, avail, (u8_t *)buf);
406 if (res == SPIFFS_ERR_END_OF_OBJECT) {
407 fd->fdoffset += avail;
408 SPIFFS_UNLOCK(fs);
409 return avail;
410 } else {
411 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
412 len = avail;
414 } else {
415 // reading within file size
416 res = spiffs_object_read(fd, fd->fdoffset, len, (u8_t *)buf);
417 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
419 fd->fdoffset += len;
421 SPIFFS_UNLOCK(fs);
423 return len;
426 s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
427 SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len);
428 s32_t res = spiffs_hydro_read(fs, fh, buf, len);
429 if (res == SPIFFS_ERR_END_OF_OBJECT) {
430 res = 0;
432 return res;
436 #if !SPIFFS_READ_ONLY
437 static s32_t spiffs_hydro_write(spiffs *fs, spiffs_fd *fd, void *buf, u32_t offset, s32_t len) {
438 (void)fs;
439 s32_t res = SPIFFS_OK;
440 s32_t remaining = len;
441 if (fd->size != SPIFFS_UNDEFINED_LEN && offset < fd->size) {
442 s32_t m_len = MIN((s32_t)(fd->size - offset), len);
443 res = spiffs_object_modify(fd, offset, (u8_t *)buf, m_len);
444 SPIFFS_CHECK_RES(res);
445 remaining -= m_len;
446 u8_t *buf_8 = (u8_t *)buf;
447 buf_8 += m_len;
448 buf = buf_8;
449 offset += m_len;
451 if (remaining > 0) {
452 res = spiffs_object_append(fd, offset, (u8_t *)buf, remaining);
453 SPIFFS_CHECK_RES(res);
455 return len;
458 #endif // !SPIFFS_READ_ONLY
460 s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len) {
461 SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, len);
462 #if SPIFFS_READ_ONLY
463 (void)fs;
464 (void)fh;
465 (void)buf;
466 (void)len;
467 return SPIFFS_ERR_RO_NOT_IMPL;
468 #else
469 SPIFFS_API_CHECK_CFG(fs);
470 SPIFFS_API_CHECK_MOUNT(fs);
471 SPIFFS_LOCK(fs);
473 spiffs_fd *fd;
474 s32_t res;
475 u32_t offset;
477 fh = SPIFFS_FH_UNOFFS(fs, fh);
478 res = spiffs_fd_get(fs, fh, &fd);
479 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
481 if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
482 res = SPIFFS_ERR_NOT_WRITABLE;
483 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
486 if ((fd->flags & SPIFFS_O_APPEND)) {
487 fd->fdoffset = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
489 offset = fd->fdoffset;
491 #if SPIFFS_CACHE_WR
492 if (fd->cache_page == 0) {
493 // see if object id is associated with cache already
494 fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
496 #endif
497 if (fd->flags & SPIFFS_O_APPEND) {
498 if (fd->size == SPIFFS_UNDEFINED_LEN) {
499 offset = 0;
500 } else {
501 offset = fd->size;
503 #if SPIFFS_CACHE_WR
504 if (fd->cache_page) {
505 offset = MAX(offset, fd->cache_page->ucache.swrc.offset + fd->cache_page->ucache.swrc.size);
507 #endif
510 #if SPIFFS_CACHE_WR
511 if ((fd->flags & SPIFFS_O_DIRECT) == 0) {
512 if (len < (s32_t)SPIFFS_CFG_LOG_PAGE_SZ(fs)) {
513 // small write, try to cache it
514 u8_t alloc_cpage = 1;
515 if (fd->cache_page) {
516 // have a cached page for this fd already, check cache page boundaries
517 if (offset < fd->cache_page->ucache.swrc.offset || // writing before cache
518 offset > fd->cache_page->ucache.swrc.offset + fd->cache_page->ucache.swrc.size || // writing after cache
519 offset + len > fd->cache_page->ucache.swrc.offset + SPIFFS_CFG_LOG_PAGE_SZ(fs)) { // writing beyond cache page
520 // boundary violation, write back cache first and allocate new
521 SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", boundary viol, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
522 fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->ucache.swrc.offset, fd->cache_page->ucache.swrc.size);
523 res = spiffs_hydro_write(fs, fd,
524 spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
525 fd->cache_page->ucache.swrc.offset, fd->cache_page->ucache.swrc.size);
526 spiffs_cache_fd_release(fs, fd->cache_page);
527 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
528 } else {
529 // writing within cache
530 alloc_cpage = 0;
534 if (alloc_cpage) {
535 fd->cache_page = spiffs_cache_page_allocate_by_fd(fs, fd);
536 if (fd->cache_page) {
537 fd->cache_page->ucache.swrc.offset = offset;
538 fd->cache_page->ucache.swrc.size = 0;
539 SPIFFS_CACHE_DBG("CACHE_WR_ALLO: allocating cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid"\n",
540 fd->cache_page->ix, fd->file_nbr, fd->obj_id);
544 if (fd->cache_page) {
545 u32_t offset_in_cpage = offset - fd->cache_page->ucache.swrc.offset;
546 SPIFFS_CACHE_DBG("CACHE_WR_WRITE: storing to cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", offs "_SPIPRIi":"_SPIPRIi" len "_SPIPRIi"\n",
547 fd->cache_page->ix, fd->file_nbr, fd->obj_id,
548 offset, offset_in_cpage, len);
549 spiffs_cache *cache = spiffs_get_cache(fs);
550 u8_t *cpage_data = spiffs_get_cache_page(fs, cache, fd->cache_page->ix);
551 #ifdef _SPIFFS_TEST
553 intptr_t __a1 = (u8_t *)&cpage_data[offset_in_cpage] - (u8_t *)cache;
554 intptr_t __a2 = (u8_t *)&cpage_data[offset_in_cpage] + len - (u8_t *)cache;
555 intptr_t __b = sizeof(spiffs_cache) + cache->cpage_count * (sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs));
556 if (__a1 > __b || __a2 > __b) {
557 printf("FATAL OOB: CACHE_WR: memcpy to cache buffer ixs:%4ld..%4ld of %4ld\n", __a1, __a2, __b);
558 ERREXIT();
561 #endif
562 _SPIFFS_MEMCPY(&cpage_data[offset_in_cpage], buf, len);
563 fd->cache_page->ucache.swrc.size = MAX(fd->cache_page->ucache.swrc.size, offset_in_cpage + len);
564 fd->fdoffset += len;
565 SPIFFS_UNLOCK(fs);
566 return len;
567 } else {
568 res = spiffs_hydro_write(fs, fd, buf, offset, len);
569 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
570 fd->fdoffset += len;
571 SPIFFS_UNLOCK(fs);
572 return res;
574 } else {
575 // big write, no need to cache it - but first check if there is a cached write already
576 if (fd->cache_page) {
577 // write back cache first
578 SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", big write, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
579 fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->ucache.swrc.offset, fd->cache_page->ucache.swrc.size);
580 res = spiffs_hydro_write(fs, fd,
581 spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
582 fd->cache_page->ucache.swrc.offset, fd->cache_page->ucache.swrc.size);
583 spiffs_cache_fd_release(fs, fd->cache_page);
584 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
585 // data written below
589 #endif
591 res = spiffs_hydro_write(fs, fd, buf, offset, len);
592 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
593 fd->fdoffset += len;
595 SPIFFS_UNLOCK(fs);
597 return res;
598 #endif // SPIFFS_READ_ONLY
601 s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence) {
602 SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " %s\n", __func__, fh, offs, (const char *[]) {"SET", "CUR", "END", "???"}[MIN(whence, 3)]);
603 SPIFFS_API_CHECK_CFG(fs);
604 SPIFFS_API_CHECK_MOUNT(fs);
605 SPIFFS_LOCK(fs);
607 spiffs_fd *fd;
608 s32_t res;
609 fh = SPIFFS_FH_UNOFFS(fs, fh);
610 res = spiffs_fd_get(fs, fh, &fd);
611 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
613 #if SPIFFS_CACHE_WR
614 spiffs_fflush_cache(fs, fh);
615 #endif
617 s32_t file_size = fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size;
619 switch (whence) {
620 case SPIFFS_SEEK_CUR:
621 offs = fd->fdoffset + offs;
622 break;
623 case SPIFFS_SEEK_END:
624 offs = file_size + offs;
625 break;
627 if (offs < 0) {
628 SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_SEEK_BOUNDS);
630 if (offs > file_size) {
631 fd->fdoffset = file_size;
632 res = SPIFFS_ERR_END_OF_OBJECT;
634 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
636 spiffs_span_ix data_spix = (offs > 0 ? (offs - 1) : 0) / SPIFFS_DATA_PAGE_SIZE(fs);
637 spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
638 if (fd->cursor_objix_spix != objix_spix) {
639 spiffs_page_ix pix;
640 res = spiffs_obj_lu_find_id_and_span(
641 fs, fd->obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, &pix);
642 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
643 fd->cursor_objix_spix = objix_spix;
644 fd->cursor_objix_pix = pix;
646 fd->fdoffset = offs;
648 SPIFFS_UNLOCK(fs);
650 return offs;
653 s32_t SPIFFS_remove(spiffs *fs, const char *path) {
654 SPIFFS_API_DBG("%s '%s'\n", __func__, path);
655 #if SPIFFS_READ_ONLY
656 (void)fs;
657 (void)path;
658 return SPIFFS_ERR_RO_NOT_IMPL;
659 #else
660 SPIFFS_API_CHECK_CFG(fs);
661 SPIFFS_API_CHECK_MOUNT(fs);
662 if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
663 SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
665 SPIFFS_LOCK(fs);
667 spiffs_fd *fd;
668 spiffs_page_ix pix;
669 s32_t res;
671 res = spiffs_fd_find_new(fs, &fd, 0);
672 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
674 res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t *)path, &pix);
675 if (res != SPIFFS_OK) {
676 spiffs_fd_return(fs, fd->file_nbr);
678 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
680 res = spiffs_object_open_by_page(fs, pix, fd, 0, 0);
681 if (res != SPIFFS_OK) {
682 spiffs_fd_return(fs, fd->file_nbr);
684 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
686 res = spiffs_object_truncate(fd, 0, 1);
687 if (res != SPIFFS_OK) {
688 spiffs_fd_return(fs, fd->file_nbr);
690 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
692 SPIFFS_UNLOCK(fs);
693 return 0;
694 #endif // SPIFFS_READ_ONLY
697 s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh) {
698 SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
699 #if SPIFFS_READ_ONLY
700 (void)fs;
701 (void)fh;
702 return SPIFFS_ERR_RO_NOT_IMPL;
703 #else
704 SPIFFS_API_CHECK_CFG(fs);
705 SPIFFS_API_CHECK_MOUNT(fs);
706 SPIFFS_LOCK(fs);
708 spiffs_fd *fd;
709 s32_t res;
710 fh = SPIFFS_FH_UNOFFS(fs, fh);
711 res = spiffs_fd_get(fs, fh, &fd);
712 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
714 if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
715 res = SPIFFS_ERR_NOT_WRITABLE;
716 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
719 #if SPIFFS_CACHE_WR
720 spiffs_cache_fd_release(fs, fd->cache_page);
721 #endif
723 res = spiffs_object_truncate(fd, 0, 1);
725 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
727 SPIFFS_UNLOCK(fs);
729 return 0;
730 #endif // SPIFFS_READ_ONLY
733 static s32_t spiffs_stat_pix(spiffs *fs, spiffs_page_ix pix, spiffs_file fh, spiffs_stat *s) {
734 (void)fh;
735 spiffs_page_object_ix_header objix_hdr;
736 spiffs_obj_id obj_id;
737 s32_t res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_IX | SPIFFS_OP_C_READ, fh,
738 SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
739 SPIFFS_API_CHECK_RES(fs, res);
741 u32_t obj_id_addr = SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, pix)) +
742 SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, pix) * sizeof(spiffs_obj_id);
743 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ, fh,
744 obj_id_addr, sizeof(spiffs_obj_id), (u8_t *)&obj_id);
745 SPIFFS_API_CHECK_RES(fs, res);
747 s->obj_id = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
748 s->type = objix_hdr.type;
749 s->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
750 s->pix = pix;
751 strncpy((char *)s->name, (char *)objix_hdr.name, SPIFFS_OBJ_NAME_LEN - 1);
752 #if SPIFFS_OBJ_META_LEN
753 _SPIFFS_MEMCPY(s->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
754 #endif
756 return res;
759 s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s) {
760 SPIFFS_API_DBG("%s '%s'\n", __func__, path);
761 SPIFFS_API_CHECK_CFG(fs);
762 SPIFFS_API_CHECK_MOUNT(fs);
763 if (strlen(path) > SPIFFS_OBJ_NAME_LEN - 1) {
764 SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
766 SPIFFS_LOCK(fs);
768 s32_t res;
769 spiffs_page_ix pix;
771 res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t *)path, &pix);
772 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
774 res = spiffs_stat_pix(fs, pix, 0, s);
776 SPIFFS_UNLOCK(fs);
778 return res;
781 s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s) {
782 SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
783 SPIFFS_API_CHECK_CFG(fs);
784 SPIFFS_API_CHECK_MOUNT(fs);
785 SPIFFS_LOCK(fs);
787 spiffs_fd *fd;
788 s32_t res;
790 fh = SPIFFS_FH_UNOFFS(fs, fh);
791 res = spiffs_fd_get(fs, fh, &fd);
792 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
794 #if SPIFFS_CACHE_WR
795 spiffs_fflush_cache(fs, fh);
796 #endif
798 res = spiffs_stat_pix(fs, fd->objix_hdr_pix, fh, s);
800 SPIFFS_UNLOCK(fs);
802 return res;
805 // Checks if there are any cached writes for the object id associated with
806 // given filehandle. If so, these writes are flushed.
807 #if SPIFFS_CACHE == 1
808 static s32_t spiffs_fflush_cache(spiffs *fs, spiffs_file fh) {
809 (void)fs;
810 (void)fh;
811 s32_t res = SPIFFS_OK;
812 #if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR
814 spiffs_fd *fd;
815 res = spiffs_fd_get(fs, fh, &fd);
816 SPIFFS_API_CHECK_RES(fs, res);
818 if ((fd->flags & SPIFFS_O_DIRECT) == 0) {
819 if (fd->cache_page == 0) {
820 // see if object id is associated with cache already
821 fd->cache_page = spiffs_cache_page_get_by_fd(fs, fd);
823 if (fd->cache_page) {
824 SPIFFS_CACHE_DBG("CACHE_WR_DUMP: dumping cache page "_SPIPRIi" for fd "_SPIPRIfd":"_SPIPRIid", flush, offs:"_SPIPRIi" size:"_SPIPRIi"\n",
825 fd->cache_page->ix, fd->file_nbr, fd->obj_id, fd->cache_page->ucache.swrc.offset, fd->cache_page->ucache.swrc.size);
826 res = spiffs_hydro_write(fs, fd,
827 spiffs_get_cache_page(fs, spiffs_get_cache(fs), fd->cache_page->ix),
828 fd->cache_page->ucache.swrc.offset, fd->cache_page->ucache.swrc.size);
829 if (res < SPIFFS_OK) {
830 fs->err_code = res;
832 spiffs_cache_fd_release(fs, fd->cache_page);
835 #endif
837 return res;
839 #endif
841 s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh) {
842 SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
843 (void)fh;
844 SPIFFS_API_CHECK_CFG(fs);
845 SPIFFS_API_CHECK_MOUNT(fs);
846 s32_t res = SPIFFS_OK;
847 #if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR
848 SPIFFS_LOCK(fs);
849 fh = SPIFFS_FH_UNOFFS(fs, fh);
850 res = spiffs_fflush_cache(fs, fh);
851 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
852 SPIFFS_UNLOCK(fs);
853 #endif
855 return res;
858 s32_t SPIFFS_close(spiffs *fs, spiffs_file fh) {
859 SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
860 SPIFFS_API_CHECK_CFG(fs);
861 SPIFFS_API_CHECK_MOUNT(fs);
863 s32_t res = SPIFFS_OK;
864 SPIFFS_LOCK(fs);
866 fh = SPIFFS_FH_UNOFFS(fs, fh);
867 #if SPIFFS_CACHE
868 res = spiffs_fflush_cache(fs, fh);
869 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
870 #endif
871 res = spiffs_fd_return(fs, fh);
872 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
874 SPIFFS_UNLOCK(fs);
876 return res;
879 s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path) {
880 SPIFFS_API_DBG("%s %s %s\n", __func__, old_path, new_path);
881 #if SPIFFS_READ_ONLY
882 (void)fs;
883 (void)old_path;
884 (void)new_path;
885 return SPIFFS_ERR_RO_NOT_IMPL;
886 #else
887 SPIFFS_API_CHECK_CFG(fs);
888 SPIFFS_API_CHECK_MOUNT(fs);
889 if (strlen(new_path) > SPIFFS_OBJ_NAME_LEN - 1 ||
890 strlen(old_path) > SPIFFS_OBJ_NAME_LEN - 1) {
891 SPIFFS_API_CHECK_RES(fs, SPIFFS_ERR_NAME_TOO_LONG);
893 SPIFFS_LOCK(fs);
895 spiffs_page_ix pix_old, pix_dummy;
896 spiffs_fd *fd;
898 s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t *)old_path, &pix_old);
899 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
901 res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t *)new_path, &pix_dummy);
902 if (res == SPIFFS_ERR_NOT_FOUND) {
903 res = SPIFFS_OK;
904 } else if (res == SPIFFS_OK) {
905 res = SPIFFS_ERR_CONFLICTING_NAME;
907 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
909 res = spiffs_fd_find_new(fs, &fd, 0);
910 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
912 res = spiffs_object_open_by_page(fs, pix_old, fd, 0, 0);
913 if (res != SPIFFS_OK) {
914 spiffs_fd_return(fs, fd->file_nbr);
916 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
918 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, (const u8_t *)new_path,
919 0, 0, &pix_dummy);
920 #if SPIFFS_TEMPORAL_FD_CACHE
921 if (res == SPIFFS_OK) {
922 spiffs_fd_temporal_cache_rehash(fs, old_path, new_path);
924 #endif
926 spiffs_fd_return(fs, fd->file_nbr);
928 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
930 SPIFFS_UNLOCK(fs);
932 return res;
933 #endif // SPIFFS_READ_ONLY
936 #if SPIFFS_OBJ_META_LEN
937 s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta) {
938 #if SPIFFS_READ_ONLY
939 (void)fs;
940 (void)name;
941 (void)meta;
942 return SPIFFS_ERR_RO_NOT_IMPL;
943 #else
944 SPIFFS_API_CHECK_CFG(fs);
945 SPIFFS_API_CHECK_MOUNT(fs);
946 SPIFFS_LOCK(fs);
948 spiffs_page_ix pix, pix_dummy;
949 spiffs_fd *fd;
951 s32_t res = spiffs_object_find_object_index_header_by_name(fs, (const u8_t *)name, &pix);
952 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
954 res = spiffs_fd_find_new(fs, &fd, 0);
955 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
957 res = spiffs_object_open_by_page(fs, pix, fd, 0, 0);
958 if (res != SPIFFS_OK) {
959 spiffs_fd_return(fs, fd->file_nbr);
961 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
963 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,
964 0, &pix_dummy);
966 spiffs_fd_return(fs, fd->file_nbr);
968 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
970 SPIFFS_UNLOCK(fs);
972 return res;
973 #endif // SPIFFS_READ_ONLY
976 s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta) {
977 #if SPIFFS_READ_ONLY
978 (void)fs;
979 (void)fh;
980 (void)meta;
981 return SPIFFS_ERR_RO_NOT_IMPL;
982 #else
983 SPIFFS_API_CHECK_CFG(fs);
984 SPIFFS_API_CHECK_MOUNT(fs);
985 SPIFFS_LOCK(fs);
987 s32_t res;
988 spiffs_fd *fd;
989 spiffs_page_ix pix_dummy;
991 fh = SPIFFS_FH_UNOFFS(fs, fh);
992 res = spiffs_fd_get(fs, fh, &fd);
993 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
995 if ((fd->flags & SPIFFS_O_WRONLY) == 0) {
996 res = SPIFFS_ERR_NOT_WRITABLE;
997 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1000 res = spiffs_object_update_index_hdr(fs, fd, fd->obj_id, fd->objix_hdr_pix, 0, 0, meta,
1001 0, &pix_dummy);
1003 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1005 SPIFFS_UNLOCK(fs);
1007 return res;
1008 #endif // SPIFFS_READ_ONLY
1010 #endif // SPIFFS_OBJ_META_LEN
1012 spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d) {
1013 SPIFFS_API_DBG("%s\n", __func__);
1014 (void)name;
1016 if (!SPIFFS_CHECK_CFG((fs))) {
1017 (fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED;
1018 return 0;
1021 if (!SPIFFS_CHECK_MOUNT(fs)) {
1022 fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
1023 return 0;
1026 d->fs = fs;
1027 d->block = 0;
1028 d->entry = 0;
1029 return d;
1032 static s32_t spiffs_read_dir_v(
1033 spiffs *fs,
1034 spiffs_obj_id obj_id,
1035 spiffs_block_ix bix,
1036 int ix_entry,
1037 const void *user_const_p,
1038 void *user_var_p) {
1039 (void)user_const_p;
1040 s32_t res;
1041 spiffs_page_object_ix_header objix_hdr;
1042 if (obj_id == SPIFFS_OBJ_ID_FREE || obj_id == SPIFFS_OBJ_ID_DELETED ||
1043 (obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0) {
1044 return SPIFFS_VIS_COUNTINUE;
1047 spiffs_page_ix pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, ix_entry);
1048 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
1049 0, SPIFFS_PAGE_TO_PADDR(fs, pix), sizeof(spiffs_page_object_ix_header), (u8_t *)&objix_hdr);
1050 if (res != SPIFFS_OK) return res;
1051 if ((obj_id & SPIFFS_OBJ_ID_IX_FLAG) &&
1052 objix_hdr.p_hdr.span_ix == 0 &&
1053 (objix_hdr.p_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_IXDELE)) ==
1054 (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
1055 struct spiffs_dirent *e = (struct spiffs_dirent *)user_var_p;
1056 e->obj_id = obj_id;
1057 strcpy((char *)e->name, (char *)objix_hdr.name);
1058 e->type = objix_hdr.type;
1059 e->size = objix_hdr.size == SPIFFS_UNDEFINED_LEN ? 0 : objix_hdr.size;
1060 e->pix = pix;
1061 #if SPIFFS_OBJ_META_LEN
1062 _SPIFFS_MEMCPY(e->meta, objix_hdr.meta, SPIFFS_OBJ_META_LEN);
1063 #endif
1064 return SPIFFS_OK;
1066 return SPIFFS_VIS_COUNTINUE;
1069 struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e) {
1070 SPIFFS_API_DBG("%s\n", __func__);
1071 if (!SPIFFS_CHECK_MOUNT(d->fs)) {
1072 d->fs->err_code = SPIFFS_ERR_NOT_MOUNTED;
1073 return 0;
1075 SPIFFS_LOCK(d->fs);
1077 spiffs_block_ix bix;
1078 int entry;
1079 s32_t res;
1080 struct spiffs_dirent *ret = 0;
1082 res = spiffs_obj_lu_find_entry_visitor(d->fs,
1083 d->block,
1084 d->entry,
1085 SPIFFS_VIS_NO_WRAP,
1087 spiffs_read_dir_v,
1090 &bix,
1091 &entry);
1092 if (res == SPIFFS_OK) {
1093 d->block = bix;
1094 d->entry = entry + 1;
1095 e->obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
1096 ret = e;
1097 } else {
1098 d->fs->err_code = res;
1100 SPIFFS_UNLOCK(d->fs);
1101 return ret;
1104 s32_t SPIFFS_closedir(spiffs_DIR *d) {
1105 SPIFFS_API_DBG("%s\n", __func__);
1106 SPIFFS_API_CHECK_CFG(d->fs);
1107 SPIFFS_API_CHECK_MOUNT(d->fs);
1108 return 0;
1111 s32_t SPIFFS_check(spiffs *fs) {
1112 SPIFFS_API_DBG("%s\n", __func__);
1113 #if SPIFFS_READ_ONLY
1114 (void)fs;
1115 return SPIFFS_ERR_RO_NOT_IMPL;
1116 #else
1117 s32_t res;
1118 SPIFFS_API_CHECK_CFG(fs);
1119 SPIFFS_API_CHECK_MOUNT(fs);
1120 SPIFFS_LOCK(fs);
1122 res = spiffs_lookup_consistency_check(fs, 0);
1123 (void)res;
1124 res = spiffs_object_index_consistency_check(fs);
1125 (void)res;
1126 res = spiffs_page_consistency_check(fs);
1127 (void)res;
1128 res = spiffs_obj_lu_scan(fs);
1130 SPIFFS_UNLOCK(fs);
1131 return res;
1132 #endif // SPIFFS_READ_ONLY
1135 s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used) {
1136 SPIFFS_API_DBG("%s\n", __func__);
1137 s32_t res = SPIFFS_OK;
1138 SPIFFS_API_CHECK_CFG(fs);
1139 SPIFFS_API_CHECK_MOUNT(fs);
1140 SPIFFS_LOCK(fs);
1142 u32_t pages_per_block = SPIFFS_PAGES_PER_BLOCK(fs);
1143 u32_t blocks = fs->block_count;
1144 u32_t obj_lu_pages = SPIFFS_OBJ_LOOKUP_PAGES(fs);
1145 u32_t data_page_size = SPIFFS_DATA_PAGE_SIZE(fs);
1146 u32_t total_data_pages = (blocks - 2) * (pages_per_block - obj_lu_pages) + 1; // -2 for spare blocks, +1 for emergency page
1148 if (total) {
1149 *total = total_data_pages * data_page_size;
1152 if (used) {
1153 *used = fs->stats_p_allocated * data_page_size;
1156 SPIFFS_UNLOCK(fs);
1157 return res;
1160 s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages) {
1161 SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, max_free_pages);
1162 #if SPIFFS_READ_ONLY
1163 (void)fs;
1164 (void)max_free_pages;
1165 return SPIFFS_ERR_RO_NOT_IMPL;
1166 #else
1167 s32_t res;
1168 SPIFFS_API_CHECK_CFG(fs);
1169 SPIFFS_API_CHECK_MOUNT(fs);
1170 SPIFFS_LOCK(fs);
1172 res = spiffs_gc_quick(fs, max_free_pages);
1174 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1175 SPIFFS_UNLOCK(fs);
1176 return 0;
1177 #endif // SPIFFS_READ_ONLY
1181 s32_t SPIFFS_gc(spiffs *fs, u32_t size) {
1182 SPIFFS_API_DBG("%s "_SPIPRIi "\n", __func__, size);
1183 #if SPIFFS_READ_ONLY
1184 (void)fs;
1185 (void)size;
1186 return SPIFFS_ERR_RO_NOT_IMPL;
1187 #else
1188 s32_t res;
1189 SPIFFS_API_CHECK_CFG(fs);
1190 SPIFFS_API_CHECK_MOUNT(fs);
1191 SPIFFS_LOCK(fs);
1193 res = spiffs_gc_check(fs, size);
1195 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1196 SPIFFS_UNLOCK(fs);
1197 return 0;
1198 #endif // SPIFFS_READ_ONLY
1201 s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh) {
1202 SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
1203 s32_t res;
1204 SPIFFS_API_CHECK_CFG(fs);
1205 SPIFFS_API_CHECK_MOUNT(fs);
1206 SPIFFS_LOCK(fs);
1208 fh = SPIFFS_FH_UNOFFS(fs, fh);
1210 spiffs_fd *fd;
1211 res = spiffs_fd_get(fs, fh, &fd);
1212 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1214 #if SPIFFS_CACHE_WR
1215 res = spiffs_fflush_cache(fs, fh);
1216 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1217 #endif
1219 res = (fd->fdoffset >= (fd->size == SPIFFS_UNDEFINED_LEN ? 0 : fd->size));
1221 SPIFFS_UNLOCK(fs);
1222 return res;
1225 s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh) {
1226 SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
1227 s32_t res;
1228 SPIFFS_API_CHECK_CFG(fs);
1229 SPIFFS_API_CHECK_MOUNT(fs);
1230 SPIFFS_LOCK(fs);
1232 fh = SPIFFS_FH_UNOFFS(fs, fh);
1234 spiffs_fd *fd;
1235 res = spiffs_fd_get(fs, fh, &fd);
1236 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1238 #if SPIFFS_CACHE_WR
1239 res = spiffs_fflush_cache(fs, fh);
1240 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1241 #endif
1243 res = fd->fdoffset;
1245 SPIFFS_UNLOCK(fs);
1246 return res;
1249 s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func) {
1250 SPIFFS_API_DBG("%s\n", __func__);
1251 SPIFFS_LOCK(fs);
1252 fs->file_cb_f = cb_func;
1253 SPIFFS_UNLOCK(fs);
1254 return 0;
1257 #if SPIFFS_IX_MAP
1259 s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
1260 u32_t offset, u32_t len, spiffs_page_ix *map_buf) {
1261 SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi " "_SPIPRIi "\n", __func__, fh, offset, len);
1262 s32_t res;
1263 SPIFFS_API_CHECK_CFG(fs);
1264 SPIFFS_API_CHECK_MOUNT(fs);
1265 SPIFFS_LOCK(fs);
1267 fh = SPIFFS_FH_UNOFFS(fs, fh);
1269 spiffs_fd *fd;
1270 res = spiffs_fd_get(fs, fh, &fd);
1271 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1273 if (fd->ix_map) {
1274 SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_MAPPED);
1277 map->map_buf = map_buf;
1278 map->offset = offset;
1279 // nb: spix range includes last
1280 map->start_spix = offset / SPIFFS_DATA_PAGE_SIZE(fs);
1281 map->end_spix = (offset + len) / SPIFFS_DATA_PAGE_SIZE(fs);
1282 memset(map_buf, 0, sizeof(spiffs_page_ix) * (map->end_spix - map->start_spix + 1));
1283 fd->ix_map = map;
1285 // scan for pixes
1286 res = spiffs_populate_ix_map(fs, fd, 0, map->end_spix - map->start_spix + 1);
1287 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1289 SPIFFS_UNLOCK(fs);
1290 return res;
1293 s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh) {
1294 SPIFFS_API_DBG("%s "_SPIPRIfd "\n", __func__, fh);
1295 s32_t res;
1296 SPIFFS_API_CHECK_CFG(fs);
1297 SPIFFS_API_CHECK_MOUNT(fs);
1298 SPIFFS_LOCK(fs);
1300 fh = SPIFFS_FH_UNOFFS(fs, fh);
1302 spiffs_fd *fd;
1303 res = spiffs_fd_get(fs, fh, &fd);
1304 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1306 if (fd->ix_map == 0) {
1307 SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);
1310 fd->ix_map = 0;
1312 SPIFFS_UNLOCK(fs);
1313 return res;
1316 s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset) {
1317 SPIFFS_API_DBG("%s "_SPIPRIfd " "_SPIPRIi "\n", __func__, fh, offset);
1318 s32_t res = SPIFFS_OK;
1319 SPIFFS_API_CHECK_CFG(fs);
1320 SPIFFS_API_CHECK_MOUNT(fs);
1321 SPIFFS_LOCK(fs);
1323 fh = SPIFFS_FH_UNOFFS(fs, fh);
1325 spiffs_fd *fd;
1326 res = spiffs_fd_get(fs, fh, &fd);
1327 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1329 if (fd->ix_map == 0) {
1330 SPIFFS_API_CHECK_RES_UNLOCK(fs, SPIFFS_ERR_IX_MAP_UNMAPPED);
1333 spiffs_ix_map *map = fd->ix_map;
1335 s32_t spix_diff = offset / SPIFFS_DATA_PAGE_SIZE(fs) - map->start_spix;
1336 map->offset = offset;
1338 // move existing pixes if within map offs
1339 if (spix_diff != 0) {
1340 // move vector
1341 int i;
1342 const s32_t vec_len = map->end_spix - map->start_spix + 1; // spix range includes last
1343 map->start_spix += spix_diff;
1344 map->end_spix += spix_diff;
1345 if (spix_diff >= vec_len) {
1346 // moving beyond range
1347 memset(&map->map_buf, 0, vec_len * sizeof(spiffs_page_ix));
1348 // populate_ix_map is inclusive
1349 res = spiffs_populate_ix_map(fs, fd, 0, vec_len - 1);
1350 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1351 } else if (spix_diff > 0) {
1352 // diff positive
1353 for (i = 0; i < vec_len - spix_diff; i++) {
1354 map->map_buf[i] = map->map_buf[i + spix_diff];
1356 // memset is non-inclusive
1357 memset(&map->map_buf[vec_len - spix_diff], 0, spix_diff * sizeof(spiffs_page_ix));
1358 // populate_ix_map is inclusive
1359 res = spiffs_populate_ix_map(fs, fd, vec_len - spix_diff, vec_len - 1);
1360 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1361 } else {
1362 // diff negative
1363 for (i = vec_len - 1; i >= -spix_diff; i--) {
1364 map->map_buf[i] = map->map_buf[i + spix_diff];
1366 // memset is non-inclusive
1367 memset(&map->map_buf[0], 0, -spix_diff * sizeof(spiffs_page_ix));
1368 // populate_ix_map is inclusive
1369 res = spiffs_populate_ix_map(fs, fd, 0, -spix_diff - 1);
1370 SPIFFS_API_CHECK_RES_UNLOCK(fs, res);
1375 SPIFFS_UNLOCK(fs);
1376 return res;
1379 s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes) {
1380 SPIFFS_API_CHECK_CFG(fs);
1381 // always add one extra page, the offset might change to the middle of a page
1382 return (bytes + SPIFFS_DATA_PAGE_SIZE(fs)) / SPIFFS_DATA_PAGE_SIZE(fs);
1385 s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries) {
1386 SPIFFS_API_CHECK_CFG(fs);
1387 return map_page_ix_entries * SPIFFS_DATA_PAGE_SIZE(fs);
1390 #endif // SPIFFS_IX_MAP
1392 #if SPIFFS_TEST_VISUALISATION
1393 s32_t SPIFFS_vis(spiffs *fs) {
1394 s32_t res = SPIFFS_OK;
1395 SPIFFS_API_CHECK_CFG(fs);
1396 SPIFFS_API_CHECK_MOUNT(fs);
1397 SPIFFS_LOCK(fs);
1399 int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
1400 spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
1401 spiffs_block_ix bix = 0;
1403 while (bix < fs->block_count) {
1404 // check each object lookup page
1405 int obj_lookup_page = 0;
1406 int cur_entry = 0;
1408 while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
1409 int entry_offset = obj_lookup_page * entries_per_page;
1410 res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
1411 0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
1412 // check each entry
1413 while (res == SPIFFS_OK &&
1414 cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
1415 spiffs_obj_id obj_id = obj_lu_buf[cur_entry - entry_offset];
1416 if (cur_entry == 0) {
1417 spiffs_printf(_SPIPRIbl" ", bix);
1418 } else if ((cur_entry & 0x3f) == 0) {
1419 spiffs_printf(" ");
1421 if (obj_id == SPIFFS_OBJ_ID_FREE) {
1422 spiffs_printf(SPIFFS_TEST_VIS_FREE_STR);
1423 } else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
1424 spiffs_printf(SPIFFS_TEST_VIS_DELE_STR);
1425 } else if (obj_id & SPIFFS_OBJ_ID_IX_FLAG) {
1426 spiffs_printf(SPIFFS_TEST_VIS_INDX_STR(obj_id));
1427 } else {
1428 spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id));
1430 cur_entry++;
1431 if ((cur_entry & 0x3f) == 0) {
1432 spiffs_printf("\n");
1434 } // per entry
1435 obj_lookup_page++;
1436 } // per object lookup page
1438 spiffs_obj_id erase_count;
1439 res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
1440 SPIFFS_ERASE_COUNT_PADDR(fs, bix),
1441 sizeof(spiffs_obj_id), (u8_t *)&erase_count);
1442 SPIFFS_CHECK_RES(res);
1444 if (erase_count != (spiffs_obj_id) - 1) {
1445 spiffs_printf("\tera_cnt: "_SPIPRIi"\n", erase_count);
1446 } else {
1447 spiffs_printf("\tera_cnt: N/A\n");
1450 bix++;
1451 } // per block
1453 spiffs_printf("era_cnt_max: "_SPIPRIi"\n", fs->max_erase_count);
1454 spiffs_printf("last_errno: "_SPIPRIi"\n", fs->err_code);
1455 spiffs_printf("blocks: "_SPIPRIi"\n", fs->block_count);
1456 spiffs_printf("free_blocks: "_SPIPRIi"\n", fs->free_blocks);
1457 spiffs_printf("page_alloc: "_SPIPRIi"\n", fs->stats_p_allocated);
1458 spiffs_printf("page_delet: "_SPIPRIi"\n", fs->stats_p_deleted);
1459 SPIFFS_UNLOCK(fs);
1460 u32_t total, used;
1461 SPIFFS_info(fs, &total, &used);
1462 spiffs_printf("used: "_SPIPRIi" of "_SPIPRIi"\n", used, total);
1463 return res;
1465 #endif