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 }