-
Notifications
You must be signed in to change notification settings - Fork 402
Using spiffs
Spiffs' API is posix-like, but not fully posix compliant. That said, there's still a lot to be learned from resources and examples on posix file handling on the internet. I will not try to educate in posix here. This is more of a 'Getting started' page. In these examples, it is assumed that spiffs is successfully configured (see Configure spiffs).
#First of all#
##Checking errors# All api functions returns something positive (or zero) when everything is ok and something negative when something is bad.
To get the specific error code for the last failure, SPIFFS_errno
can be called.
The error codes are defined in spiffs.h.
Do check the result from each spiffs call. Really. Not doing so, and considering happy-flow only, will lure out problems that are hard to detect and even might corrupt your fs. I know, it's dead boring, it makes the code dead ugly, it's a pain in the a--e.
But it's worth it.
##Mounting#
Mounting spiffs is equal to configuring the run-time parts. One simply calls SPIFFS_mount
with correct parameters and hopes that the return code is ok. See corresponding mount function in spiffs.h for details.
Mounting can behave differently depending on if the compile-time configuration SPIFFS_USE_MAGIC
is enabled or not. If enabled, this configuration will put a magic number somewhere in each block in order to validate that the underlying flash structure is indeed a spiffs file system.
If SPIFFS_USE_MAGIC
is disabled, spiffs simply assumes that the underlying flash is prepared and fine, and will return ok without even actual looking at the flash. Due to the memory restriction, everything is lazily checked in spiffs.
However, if SPIFFS_USE_MAGIC
is enabled, three things can happen.
-
You'll get error
SPIFFS_ERR_MAGIC_NOT_POSSIBLE
. This means that with your current configuration, there simply is no space in the blocks to put the magic in. This is positive in a way, because you have managed to configure spiffs to waste no bits at all. To overcome this one can try another page size or block size. -
You'll get error
SPIFFS_ERR_NOT_A_FS
. This means that the underlying structure was checked, but spiffs found more than one block not having the magic. Spiffs allows one block without magic, would there be a power loss during an erase. CallSPIFFS_format
and try mounting again. -
You'll get ok. Yay.
##Formatting#
First of all: spiffs must be unmounted when formatting flash.
Unfortunately, the formatting in spiffs became a bit awkward. The problem is that spiffs must be unmounted prior to formatting, but must be run-time configured for SPIFFS_format
. Because I'm stupid, I never made a SPIFFS_config
in the beginning. So you will have to mount, unmount, format, and mount again. Reasons? As stated before, I'm stupid, and because there was no formatting in the beginning. One just called a mass erase of the flash. Well, read on.
Formatting is dependent on if the compile-time configuration SPIFFS_USE_MAGIC
is enabled or not.
If SPIFFS_USE_MAGIC
is disabled, spiffs expects a fresh flash where all bits are set. You have two options:
-
Just call a mass erase of the spi flash yourself, not involving spiffs. Then mount.
-
Mount (to configure the run-time parts), unmount, call
SPIFFS_format
, and mount again (sigh).
If SPIFFS_USE_MAGIC
is enabled, mounting procedure will look for magic. Recommended formatting procedure is as point two above. Recapped:
-
Call
SPIFFS_mount
-
If
SPIFFS_mount
fails withSPIFFS_ERR_NOT_A_FS
, keep going. Otherwise, callSPIFFS_unmount
-
Call
SPIFFS_format
-
Call
SPIFFS_mount
again.
Again, in all cases: spiffs must be unmounted when formatting flash. Bad things will happen otherwise.
#Simple examples#
In following examples, I assume you have a fully working spiffs, configured and mounted. The spiffs
struct is the variable fs
.
##Create a file and read it back#
char buf[12];
// create a file, delete previous if it already exists, and open it for reading and writing
spiffs_file fd = SPIFFS_open(&fs, "my_file", SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
if (fd < 0) {
printf("errno %i\n", SPIFFS_errno(&fs));
return;
}
// write to it
if (SPIFFS_write(&fs, fd, (u8_t *)"Hello world", 12) < 0) {
printf("errno %i\n", SPIFFS_errno(&fs));
return;
}
// close it
SPIFFS_close(&fs, fd);
// open it
fd = SPIFFS_open(&fs, "my_file", SPIFFS_RDWR, 0);
if (fd < 0) {
printf("errno %i\n", SPIFFS_errno(&fs));
return;
}
// read it
if (SPIFFS_read(&fs, fd, (u8_t *)buf, 12) < 0) {
printf("errno %i\n", SPIFFS_errno(&fs));
return;
}
// close it
SPIFFS_close(&fs, fd);
// check it
printf("--> %s <--\n", buf);
Why is there a SPIFFS_creat
? Well, you could create files this way also. This is a posix thing. It is a lot more convenient to create and open it in the same call using SPIFFS_open
. There's not many cases where one want to create a file and do nothing more.
As for the flags to SPIFFS_open
, have a look in spiffs.h, or even better, here. Just remember, all posix flags are not implemented in spiffs.
##List contents#
spiffs_DIR d;
struct spiffs_dirent e;
struct spiffs_dirent *pe = &e;
SPIFFS_opendir(&fs, "/", &d);
while ((pe = SPIFFS_readdir(&d, pe))) {
printf("%s [%04x] size:%i\n", pe->name, pe->obj_id, pe->size);
}
SPIFFS_closedir(&d);
##Find a file by name and open it#
As spiffs is inherently slow there is a non-posix way of doing this, using SPIFFS_open_by_dirent
. This example in itself is pretty weird, as one could just call SPIFFS_open
with the filename directly. However, when e.g. opening all files with some prefix it is pretty handy.
char *search = "myfile.txt";
spiffs_DIR d;
struct spiffs_dirent e;
struct spiffs_dirent *pe = &e;
spiffs_file fd = -1;
SPIFFS_opendir(&fs, "/", &d);
while ((pe = SPIFFS_readdir(&d, pe))) {
if (0 == strcmp(search, (char*)pe->name)) {
// found it
fd = SPIFFS_open_by_dirent(&fs, pe, SPIFFS_RDWR, 0);
break;
}
}
SPIFFS_closedir(&d);
if (fd < 0) {
// not found or couldn't open it
printf("errno %i\n", SPIFFS_errno(&fs));
return;
}
// use it somehow
...
// close it
SPIFFS_close(&fs, fd);
##Seeking in a file#
As opposed to posix, spiffs cannot create gaps in files. Sorry. You can seek around, but seeking beyond file end will promptly put the offset at the file end.
u8_t buf[128];
int i, res;
u8_t test;
#define SPIFFS_CHECK(x) \
if ((x) < 0) { printf("errno:%i\n", SPIFFS_errno(FS)); return; }
for (i = 0; i < 128; i++) buf[i] = i;
// create a file with some data in it
spiffs_file fd = SPIFFS_open(&fs, "somedata", SPIFFS_CREAT | SPIFFS_RDWR, 0);
SPIFFS_CHECK(fd);
res = SPIFFS_write(&fs, fd, buf, 128);
SPIFFS_CHECK(res);
SPIFFS_close(&fs, fd);
// open for reading
fd = SPIFFS_open(&fs, "somedata", SPIFFS_CREAT | SPIFFS_RDONLY, 0);
SPIFFS_CHECK(fd);
// read the last byte of the file
res = SPIFFS_lseek(&fs, fd, -1, SPIFFS_SEEK_END);
SPIFFS_CHECK(res);
res = SPIFFS_read(&fs, fd, &test, 1);
SPIFFS_CHECK(res);
printf("last byte:%i\n", test); // prints "last byte:127"
// read the middle byte of the file
res = SPIFFS_lseek(&fs, fd, 64, SPIFFS_SEEK_SET);
SPIFFS_CHECK(res);
res = SPIFFS_read(&fs, fd, &test, 1);
SPIFFS_CHECK(res);
printf("middle byte:%i\n", test); // prints "middle byte:64"
// skip 3 bytes from current offset and read next byte (NB we read one byte previously also)
res = SPIFFS_lseek(&fs, fd, 3, SPIFFS_SEEK_CUR);
SPIFFS_CHECK(res);
res = SPIFFS_read(&fs, fd, &test, 1);
SPIFFS_CHECK(res);
printf("middle+4 byte:%i\n", test); // prints "middle+4 byte:68"
SPIFFS_close(&fs, fd);
##Remove file# You got to options: either by name or by file handle. Pretty self-explanatory.
res = SPIFFS_remove(&fs, "supersecret");
or
spiffs_file fd = SPIFFS_open(&fs, "supersecret", SPIFFS_RDWR, 0);
.. check fd obviously..
res = SPIFFS_fremove(&fs, fd);
.. check res obviously..
SPIFFS_close(&fs, fd);
The latter will invalidate the file-handle fd
but it still needs to be closed to release resources.
##Checking files# To check file info, one either calls by name or by file handle:
spiffs_stat s;
res = SPIFFS_stat(&fs, "foo");
or
spiffs_stat s;
res = SPIFFS_fstat(&fs, fd);
The spiffs_stat
struct contains name
(file name) and size
(file length). The struct also contains obj_id
, the object id, sort of an inode number. type
is not used for now.
##Rename files# Simply call:
res = SPIFFS_rename(&fs, "oldfoo", "newfoo");
##Flushing files#
If any of build time configurations SPIFFS_CACHE
or SPIFFS_CACHE_WR
are disabled, this is a no op. Otherwise flushing will store any writes being currently cached to flash.
res = SPIFFS_fflush(&fs, fd);
##Checking filesystem# To get an indication of how much spare room there is on the flash, call