/ components / spiffs / test_spiffs_host / test_spiffs.cpp
test_spiffs.cpp
  1  #include <stdio.h>
  2  #include <string.h>
  3  #include <stdint.h>
  4  #include <stdlib.h>
  5  #include <sys/mman.h>
  6  #include <sys/stat.h>
  7  #include <sys/types.h>
  8  #include <dirent.h>
  9  #include <limits.h>
 10  #include <unistd.h>
 11  
 12  #include "esp_partition.h"
 13  #include "spiffs.h"
 14  #include "spiffs_nucleus.h"
 15  #include "spiffs_api.h"
 16  
 17  #include "catch.hpp"
 18  
 19  extern "C" void _spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
 20  
 21  static void init_spiffs(spiffs *fs, uint32_t max_files)
 22  {
 23      spiffs_config cfg;
 24      s32_t spiffs_res;
 25  
 26      const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
 27      REQUIRE(partition);
 28  
 29      // Configure objects needed by SPIFFS
 30      esp_spiffs_t *user_data = (esp_spiffs_t*) calloc(1, sizeof(*user_data));
 31      user_data->partition = partition;
 32      fs->user_data = (void*)user_data;
 33  
 34      cfg.hal_erase_f = spiffs_api_erase;
 35      cfg.hal_read_f = spiffs_api_read;
 36      cfg.hal_write_f = spiffs_api_write;
 37      cfg.log_block_size = CONFIG_WL_SECTOR_SIZE;
 38      cfg.log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
 39      cfg.phys_addr = 0;
 40      cfg.phys_erase_block = CONFIG_WL_SECTOR_SIZE;
 41      cfg.phys_size = partition->size;
 42  
 43      uint32_t work_sz = cfg.log_page_size * 2;
 44      uint8_t *work = (uint8_t*) malloc(work_sz);
 45  
 46      uint32_t fds_sz = max_files * sizeof(spiffs_fd);
 47      uint8_t *fds = (uint8_t*) malloc(fds_sz);
 48  
 49  #if CONFIG_SPIFFS_CACHE
 50      uint32_t cache_sz = sizeof(spiffs_cache) + max_files * (sizeof(spiffs_cache_page)
 51                            + cfg.log_page_size);
 52      uint8_t *cache = (uint8_t*) malloc(cache_sz);
 53  #else
 54      uint32_t cache_sz = 0;
 55      uint8_t cache = NULL;
 56  #endif
 57  
 58      // Special mounting procedure: mount, format, mount as per
 59      // https://github.com/pellepl/spiffs/wiki/Using-spiffs
 60      spiffs_res = SPIFFS_mount(fs, &cfg, work, fds, fds_sz,
 61                              cache, cache_sz, spiffs_api_check);
 62  
 63      if (spiffs_res == SPIFFS_ERR_NOT_A_FS) {
 64          spiffs_res = SPIFFS_format(fs);
 65          REQUIRE(spiffs_res >= SPIFFS_OK);
 66  
 67          spiffs_res = SPIFFS_mount(fs, &cfg, work, fds, fds_sz,
 68                                  cache, cache_sz, spiffs_api_check);
 69      }
 70  
 71      REQUIRE(spiffs_res >= SPIFFS_OK);
 72  }
 73  
 74  static void deinit_spiffs(spiffs *fs)
 75  {
 76      SPIFFS_unmount(fs);
 77  
 78      free(fs->work);
 79      free(fs->user_data);
 80      free(fs->fd_space);
 81  
 82  #if CONFIG_SPIFFS_CACHE
 83      free(fs->cache);
 84  #endif
 85  }
 86  
 87  static void check_spiffs_files(spiffs *fs, const char *base_path, char* cur_path)
 88  {
 89      DIR *dir;
 90      struct dirent *entry;
 91      size_t len = strlen(cur_path);
 92  
 93      if (len == 0) {
 94          strcpy(cur_path, base_path);
 95          len = strlen(base_path);
 96      }
 97  
 98      dir = opendir(cur_path);
 99      REQUIRE(dir != 0);
100  
101      while ((entry = readdir(dir)) != NULL) {
102          char *name = entry->d_name;
103  
104          char path[PATH_MAX] = { 0 };
105  
106          // Read the file from host FS
107          strcpy(path, cur_path);
108          strcat(path, "/");
109          strcat(path, name);
110  
111          struct stat sb;
112          stat(path, &sb);
113  
114          if (S_ISDIR(sb.st_mode)) {
115              if (!strcmp(name, ".") || !strcmp(name, ".."))
116                  continue;
117              cur_path[len] = '/';
118              strcpy(cur_path + len + 1, name);
119              check_spiffs_files(fs, base_path, cur_path);
120              cur_path[len] = '\0';
121          } else {
122              FILE* f = fopen(path , "r");
123              REQUIRE(f);
124              fseek(f, 0, SEEK_END);
125              long sz = ftell(f);
126              fseek(f, 0, SEEK_SET);
127  
128              char *f_contents = (char*) malloc(sz);
129              fread(f_contents, 1, sz, f);
130              fclose(f);
131  
132              s32_t spiffs_res;
133  
134              // Read the file from SPIFFS
135              char *spiffs_path = path + strlen(base_path);
136              spiffs_res = SPIFFS_open(fs, spiffs_path, SPIFFS_RDONLY, 0);
137  
138              REQUIRE(spiffs_res > SPIFFS_OK);
139  
140              spiffs_file fd = spiffs_res;
141  
142              spiffs_stat stat;
143              spiffs_res = SPIFFS_stat(fs, spiffs_path, &stat);
144  
145              char *spiffs_f_contents = (char*) malloc(stat.size);
146              spiffs_res = SPIFFS_read(fs, fd, spiffs_f_contents, stat.size);
147              REQUIRE(spiffs_res == stat.size);
148  
149              // Compare the contents
150              REQUIRE(sz == stat.size);
151  
152              bool same = memcmp(f_contents, spiffs_f_contents, sz) == 0;
153              REQUIRE(same);
154  
155              free(f_contents);
156              free(spiffs_f_contents);
157          }
158      }
159      closedir(dir);
160  }
161  
162  TEST_CASE("format disk, open file, write and read file", "[spiffs]")
163  {
164      _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
165  
166      spiffs fs;
167      s32_t spiffs_res;
168  
169      init_spiffs(&fs, 5);
170  
171      // Open test file
172      spiffs_res = SPIFFS_open(&fs, "test.txt", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0);
173      REQUIRE(spiffs_res >= SPIFFS_OK);
174  
175      // Generate data
176      spiffs_file file = spiffs_res;
177  
178      uint32_t data_size = 100000;
179  
180      char *data = (char*) malloc(data_size);
181      char *read = (char*) malloc(data_size);
182  
183      for(uint32_t i = 0; i < data_size; i += sizeof(i))
184      {
185          *((uint32_t*)(data + i)) = i;
186      }
187  
188      // Write data to file
189      spiffs_res = SPIFFS_write(&fs, file, (void*)data, data_size);
190      REQUIRE(spiffs_res >= SPIFFS_OK);
191      REQUIRE(spiffs_res == data_size);
192  
193      // Set the file object pointer to the beginning
194      spiffs_res = SPIFFS_lseek(&fs, file, 0, SPIFFS_SEEK_SET);
195      REQUIRE(spiffs_res >= SPIFFS_OK);
196  
197      // Read the file
198      spiffs_res = SPIFFS_read(&fs, file, (void*)read, data_size);
199      REQUIRE(spiffs_res >= SPIFFS_OK);
200      REQUIRE(spiffs_res == data_size);
201  
202      // Close the test file
203      spiffs_res = SPIFFS_close(&fs, file);
204      REQUIRE(spiffs_res >= SPIFFS_OK);
205  
206      REQUIRE(memcmp(data, read, data_size) == 0);
207  
208      deinit_spiffs(&fs);
209  
210      free(read);
211      free(data);
212  }
213  
214  TEST_CASE("can read spiffs image", "[spiffs]")
215  {
216      _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
217  
218      spiffs fs;
219      s32_t spiffs_res;
220  
221      const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
222  
223      // Write the contents of the image file to partition
224      FILE* img_file = fopen("image.bin", "r");
225      REQUIRE(img_file);
226  
227      fseek(img_file, 0, SEEK_END);
228      long img_size = ftell(img_file);
229      fseek(img_file, 0, SEEK_SET);
230  
231      char *img = (char*) malloc(img_size);
232      fread(img, 1, img_size, img_file);
233      fclose(img_file);
234  
235      REQUIRE(partition->size == img_size);
236  
237      esp_partition_erase_range(partition, 0, partition->size);
238      esp_partition_write(partition, 0, img, img_size);
239  
240      free(img);
241  
242      // Mount the spiffs partition and init filesystem, using the contents of
243      // the image file
244      init_spiffs(&fs, 1024);
245  
246      // Check spiffs consistency
247      spiffs_res = SPIFFS_check(&fs);
248      REQUIRE(spiffs_res == SPIFFS_OK);
249  
250      char path_buf[PATH_MAX];
251  
252      // The image is created from the spiffs source directory. Compare the files in that
253      // directory to the files read from the SPIFFS image.
254      check_spiffs_files(&fs, "../spiffs", path_buf);
255  
256      deinit_spiffs(&fs);
257  }