4 * Created on: Jun 16, 2013
9 #include "spiffs_nucleus.h"
13 static s32_t
spiffs_fflush_cache(spiffs
*fs
, spiffs_file fh
);
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
);
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
));
27 u8_t
SPIFFS_mounted(spiffs
*fs
) {
28 return SPIFFS_CHECK_MOUNT(fs
);
31 s32_t
SPIFFS_format(spiffs
*fs
) {
34 return SPIFFS_ERR_RO_NOT_IMPL
;
36 SPIFFS_API_CHECK_CFG(fs
);
37 if (SPIFFS_CHECK_MOUNT(fs
)) {
38 fs
->err_code
= SPIFFS_ERR_MOUNTED
;
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
);
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
);
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
) {
76 " sz:"_SPIPRIi
" logpgsz:"_SPIPRIi
" logblksz:"_SPIPRIi
" perasz:"_SPIPRIi
78 " fdsz:"_SPIPRIi
" cachesz:"_SPIPRIi
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
);
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
);
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);
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);
110 u8_t
*cache_8
= (u8_t
*)cache
;
111 cache_8
+= (ptr_size
- addr_lsb
);
113 cache_size
-= (ptr_size
- addr_lsb
);
115 if (cache_size
& (ptr_size
- 1)) {
116 cache_size
-= (cache_size
& (ptr_size
- 1));
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
);
128 res
= SPIFFS_CHECK_MAGIC_POSSIBLE(fs
) ? SPIFFS_OK
: SPIFFS_ERR_MAGIC_NOT_POSSIBLE
;
129 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
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
;
155 void SPIFFS_unmount(spiffs
*fs
) {
156 SPIFFS_API_DBG("%s\n", __func__
);
157 if (!SPIFFS_CHECK_CFG(fs
) || !SPIFFS_CHECK_MOUNT(fs
)) return;
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) {
165 (void)spiffs_fflush_cache(fs
, cur_fd
->file_nbr
);
167 spiffs_fd_return(fs
, cur_fd
->file_nbr
);
175 s32_t
SPIFFS_errno(spiffs
*fs
) {
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
);
190 return SPIFFS_ERR_RO_NOT_IMPL
;
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
);
199 spiffs_obj_id obj_id
;
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
);
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
);
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
);
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
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
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
);
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
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
);
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
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
);
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
);
396 spiffs_fflush_cache(fs
, fh
);
399 if (fd
->fdoffset
+ len
>= fd
->size
) {
400 // reading beyond file size
401 s32_t avail
= fd
->size
- fd
->fdoffset
;
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
;
411 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
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
);
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
) {
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
) {
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
);
446 u8_t
*buf_8
= (u8_t
*)buf
;
452 res
= spiffs_object_append(fd
, offset
, (u8_t
*)buf
, remaining
);
453 SPIFFS_CHECK_RES(res
);
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
);
467 return SPIFFS_ERR_RO_NOT_IMPL
;
469 SPIFFS_API_CHECK_CFG(fs
);
470 SPIFFS_API_CHECK_MOUNT(fs
);
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
;
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
);
497 if (fd
->flags
& SPIFFS_O_APPEND
) {
498 if (fd
->size
== SPIFFS_UNDEFINED_LEN
) {
504 if (fd
->cache_page
) {
505 offset
= MAX(offset
, fd
->cache_page
->ucache
.swrc
.offset
+ fd
->cache_page
->ucache
.swrc
.size
);
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
);
529 // writing within cache
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
);
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
);
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
);
568 res
= spiffs_hydro_write(fs
, fd
, buf
, offset
, len
);
569 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
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
591 res
= spiffs_hydro_write(fs
, fd
, buf
, offset
, len
);
592 SPIFFS_API_CHECK_RES_UNLOCK(fs
, 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
);
609 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
610 res
= spiffs_fd_get(fs
, fh
, &fd
);
611 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
614 spiffs_fflush_cache(fs
, fh
);
617 s32_t file_size
= fd
->size
== SPIFFS_UNDEFINED_LEN
? 0 : fd
->size
;
620 case SPIFFS_SEEK_CUR
:
621 offs
= fd
->fdoffset
+ offs
;
623 case SPIFFS_SEEK_END
:
624 offs
= file_size
+ offs
;
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
) {
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
;
653 s32_t
SPIFFS_remove(spiffs
*fs
, const char *path
) {
654 SPIFFS_API_DBG("%s '%s'\n", __func__
, path
);
658 return SPIFFS_ERR_RO_NOT_IMPL
;
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
);
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
);
694 #endif // SPIFFS_READ_ONLY
697 s32_t
SPIFFS_fremove(spiffs
*fs
, spiffs_file fh
) {
698 SPIFFS_API_DBG("%s "_SPIPRIfd
"\n", __func__
, fh
);
702 return SPIFFS_ERR_RO_NOT_IMPL
;
704 SPIFFS_API_CHECK_CFG(fs
);
705 SPIFFS_API_CHECK_MOUNT(fs
);
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
);
720 spiffs_cache_fd_release(fs
, fd
->cache_page
);
723 res
= spiffs_object_truncate(fd
, 0, 1);
725 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
730 #endif // SPIFFS_READ_ONLY
733 static s32_t
spiffs_stat_pix(spiffs
*fs
, spiffs_page_ix pix
, spiffs_file fh
, spiffs_stat
*s
) {
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
;
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
);
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
);
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
);
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
);
790 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
791 res
= spiffs_fd_get(fs
, fh
, &fd
);
792 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
795 spiffs_fflush_cache(fs
, fh
);
798 res
= spiffs_stat_pix(fs
, fd
->objix_hdr_pix
, fh
, s
);
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
) {
811 s32_t res
= SPIFFS_OK
;
812 #if !SPIFFS_READ_ONLY && SPIFFS_CACHE_WR
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
) {
832 spiffs_cache_fd_release(fs
, fd
->cache_page
);
841 s32_t
SPIFFS_fflush(spiffs
*fs
, spiffs_file fh
) {
842 SPIFFS_API_DBG("%s "_SPIPRIfd
"\n", __func__
, 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
849 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
850 res
= spiffs_fflush_cache(fs
, fh
);
851 SPIFFS_API_CHECK_RES_UNLOCK(fs
, 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
;
866 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
868 res
= spiffs_fflush_cache(fs
, fh
);
869 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
871 res
= spiffs_fd_return(fs
, fh
);
872 SPIFFS_API_CHECK_RES_UNLOCK(fs
, 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
);
885 return SPIFFS_ERR_RO_NOT_IMPL
;
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
);
895 spiffs_page_ix pix_old
, pix_dummy
;
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
) {
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
,
920 #if SPIFFS_TEMPORAL_FD_CACHE
921 if (res
== SPIFFS_OK
) {
922 spiffs_fd_temporal_cache_rehash(fs
, old_path
, new_path
);
926 spiffs_fd_return(fs
, fd
->file_nbr
);
928 SPIFFS_API_CHECK_RES_UNLOCK(fs
, 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
) {
942 return SPIFFS_ERR_RO_NOT_IMPL
;
944 SPIFFS_API_CHECK_CFG(fs
);
945 SPIFFS_API_CHECK_MOUNT(fs
);
948 spiffs_page_ix pix
, pix_dummy
;
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
,
966 spiffs_fd_return(fs
, fd
->file_nbr
);
968 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
973 #endif // SPIFFS_READ_ONLY
976 s32_t
SPIFFS_fupdate_meta(spiffs
*fs
, spiffs_file fh
, const void *meta
) {
981 return SPIFFS_ERR_RO_NOT_IMPL
;
983 SPIFFS_API_CHECK_CFG(fs
);
984 SPIFFS_API_CHECK_MOUNT(fs
);
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
,
1003 SPIFFS_API_CHECK_RES_UNLOCK(fs
, 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__
);
1016 if (!SPIFFS_CHECK_CFG((fs
))) {
1017 (fs
)->err_code
= SPIFFS_ERR_NOT_CONFIGURED
;
1021 if (!SPIFFS_CHECK_MOUNT(fs
)) {
1022 fs
->err_code
= SPIFFS_ERR_NOT_MOUNTED
;
1032 static s32_t
spiffs_read_dir_v(
1034 spiffs_obj_id obj_id
,
1035 spiffs_block_ix bix
,
1037 const void *user_const_p
,
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
;
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
;
1061 #if SPIFFS_OBJ_META_LEN
1062 _SPIFFS_MEMCPY(e
->meta
, objix_hdr
.meta
, SPIFFS_OBJ_META_LEN
);
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
;
1077 spiffs_block_ix bix
;
1080 struct spiffs_dirent
*ret
= 0;
1082 res
= spiffs_obj_lu_find_entry_visitor(d
->fs
,
1092 if (res
== SPIFFS_OK
) {
1094 d
->entry
= entry
+ 1;
1095 e
->obj_id
&= ~SPIFFS_OBJ_ID_IX_FLAG
;
1098 d
->fs
->err_code
= res
;
1100 SPIFFS_UNLOCK(d
->fs
);
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
);
1111 s32_t
SPIFFS_check(spiffs
*fs
) {
1112 SPIFFS_API_DBG("%s\n", __func__
);
1113 #if SPIFFS_READ_ONLY
1115 return SPIFFS_ERR_RO_NOT_IMPL
;
1118 SPIFFS_API_CHECK_CFG(fs
);
1119 SPIFFS_API_CHECK_MOUNT(fs
);
1122 res
= spiffs_lookup_consistency_check(fs
, 0);
1124 res
= spiffs_object_index_consistency_check(fs
);
1126 res
= spiffs_page_consistency_check(fs
);
1128 res
= spiffs_obj_lu_scan(fs
);
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
);
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
1149 *total
= total_data_pages
* data_page_size
;
1153 *used
= fs
->stats_p_allocated
* data_page_size
;
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
1164 (void)max_free_pages
;
1165 return SPIFFS_ERR_RO_NOT_IMPL
;
1168 SPIFFS_API_CHECK_CFG(fs
);
1169 SPIFFS_API_CHECK_MOUNT(fs
);
1172 res
= spiffs_gc_quick(fs
, max_free_pages
);
1174 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
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
1186 return SPIFFS_ERR_RO_NOT_IMPL
;
1189 SPIFFS_API_CHECK_CFG(fs
);
1190 SPIFFS_API_CHECK_MOUNT(fs
);
1193 res
= spiffs_gc_check(fs
, size
);
1195 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
1198 #endif // SPIFFS_READ_ONLY
1201 s32_t
SPIFFS_eof(spiffs
*fs
, spiffs_file fh
) {
1202 SPIFFS_API_DBG("%s "_SPIPRIfd
"\n", __func__
, fh
);
1204 SPIFFS_API_CHECK_CFG(fs
);
1205 SPIFFS_API_CHECK_MOUNT(fs
);
1208 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
1211 res
= spiffs_fd_get(fs
, fh
, &fd
);
1212 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
1215 res
= spiffs_fflush_cache(fs
, fh
);
1216 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
1219 res
= (fd
->fdoffset
>= (fd
->size
== SPIFFS_UNDEFINED_LEN
? 0 : fd
->size
));
1225 s32_t
SPIFFS_tell(spiffs
*fs
, spiffs_file fh
) {
1226 SPIFFS_API_DBG("%s "_SPIPRIfd
"\n", __func__
, fh
);
1228 SPIFFS_API_CHECK_CFG(fs
);
1229 SPIFFS_API_CHECK_MOUNT(fs
);
1232 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
1235 res
= spiffs_fd_get(fs
, fh
, &fd
);
1236 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
1239 res
= spiffs_fflush_cache(fs
, fh
);
1240 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
1249 s32_t
SPIFFS_set_file_callback_func(spiffs
*fs
, spiffs_file_callback cb_func
) {
1250 SPIFFS_API_DBG("%s\n", __func__
);
1252 fs
->file_cb_f
= cb_func
;
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
);
1263 SPIFFS_API_CHECK_CFG(fs
);
1264 SPIFFS_API_CHECK_MOUNT(fs
);
1267 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
1270 res
= spiffs_fd_get(fs
, fh
, &fd
);
1271 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
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));
1286 res
= spiffs_populate_ix_map(fs
, fd
, 0, map
->end_spix
- map
->start_spix
+ 1);
1287 SPIFFS_API_CHECK_RES_UNLOCK(fs
, res
);
1293 s32_t
SPIFFS_ix_unmap(spiffs
*fs
, spiffs_file fh
) {
1294 SPIFFS_API_DBG("%s "_SPIPRIfd
"\n", __func__
, fh
);
1296 SPIFFS_API_CHECK_CFG(fs
);
1297 SPIFFS_API_CHECK_MOUNT(fs
);
1300 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
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
);
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
);
1323 fh
= SPIFFS_FH_UNOFFS(fs
, fh
);
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) {
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) {
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
);
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
);
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
);
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;
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
);
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) {
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
));
1428 spiffs_printf(SPIFFS_TEST_VIS_DATA_STR(obj_id
));
1431 if ((cur_entry
& 0x3f) == 0) {
1432 spiffs_printf("\n");
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
);
1447 spiffs_printf("\tera_cnt: N/A\n");
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
);
1461 SPIFFS_info(fs
, &total
, &used
);
1462 spiffs_printf("used: "_SPIPRIi
" of "_SPIPRIi
"\n", used
, total
);