Skip to content

Using spiffs

Peter Andersson edited this page Aug 1, 2015 · 22 revisions

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.

  1. 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.

  2. 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. Call SPIFFS_format and try mounting again.

  3. 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:

  1. Just call a mass erase of the spi flash yourself, not involving spiffs. Then mount.

  2. 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:

  1. Call SPIFFS_mount

  2. If SPIFFS_mount fails with SPIFFS_ERR_NOT_A_FS, keep going. Otherwise, call SPIFFS_unmount

  3. Call SPIFFS_format

  4. 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);

SPIFFS_creat function?

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.

What are the flags SPIFFS_CREAT, SPIFFS_TRUNC etc?

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

Clone this wiki locally