esp_spiffs.c
1 // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "esp_spiffs.h" 16 #include "spiffs.h" 17 #include "spiffs_nucleus.h" 18 #include "esp_log.h" 19 #include "esp_partition.h" 20 #include "esp_spi_flash.h" 21 #include "esp_image_format.h" 22 #include "freertos/FreeRTOS.h" 23 #include "freertos/task.h" 24 #include "freertos/semphr.h" 25 #include <unistd.h> 26 #include <dirent.h> 27 #include <sys/errno.h> 28 #include <sys/fcntl.h> 29 #include <sys/lock.h> 30 #include "esp_vfs.h" 31 #include "esp_err.h" 32 #include "esp32/rom/spi_flash.h" 33 #include "spiffs_api.h" 34 35 static const char* TAG = "SPIFFS"; 36 37 #ifdef CONFIG_SPIFFS_USE_MTIME 38 #ifdef CONFIG_SPIFFS_MTIME_WIDE_64_BITS 39 typedef time_t spiffs_time_t; 40 #else 41 typedef unsigned long spiffs_time_t; 42 #endif 43 _Static_assert(CONFIG_SPIFFS_META_LENGTH >= sizeof(spiffs_time_t), 44 "SPIFFS_META_LENGTH size should be >= sizeof(spiffs_time_t)"); 45 #endif //CONFIG_SPIFFS_USE_MTIME 46 47 /** 48 * @brief SPIFFS DIR structure 49 */ 50 typedef struct { 51 DIR dir; /*!< VFS DIR struct */ 52 spiffs_DIR d; /*!< SPIFFS DIR struct */ 53 struct dirent e; /*!< Last open dirent */ 54 long offset; /*!< Offset of the current dirent */ 55 char path[SPIFFS_OBJ_NAME_LEN]; /*!< Requested directory name */ 56 } vfs_spiffs_dir_t; 57 58 static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode); 59 static ssize_t vfs_spiffs_write(void* ctx, int fd, const void * data, size_t size); 60 static ssize_t vfs_spiffs_read(void* ctx, int fd, void * dst, size_t size); 61 static int vfs_spiffs_close(void* ctx, int fd); 62 static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode); 63 static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st); 64 #ifdef CONFIG_VFS_SUPPORT_DIR 65 static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st); 66 static int vfs_spiffs_unlink(void* ctx, const char *path); 67 static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2); 68 static int vfs_spiffs_rename(void* ctx, const char *src, const char *dst); 69 static DIR* vfs_spiffs_opendir(void* ctx, const char* name); 70 static int vfs_spiffs_closedir(void* ctx, DIR* pdir); 71 static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir); 72 static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, 73 struct dirent* entry, struct dirent** out_dirent); 74 static long vfs_spiffs_telldir(void* ctx, DIR* pdir); 75 static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset); 76 static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode); 77 static int vfs_spiffs_rmdir(void* ctx, const char* name); 78 #ifdef CONFIG_SPIFFS_USE_MTIME 79 static int vfs_spiffs_utime(void *ctx, const char *path, const struct utimbuf *times); 80 #endif // CONFIG_SPIFFS_USE_MTIME 81 #endif // CONFIG_VFS_SUPPORT_DIR 82 static void vfs_spiffs_update_mtime(spiffs *fs, spiffs_file f); 83 static time_t vfs_spiffs_get_mtime(const spiffs_stat* s); 84 85 static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS]; 86 87 static void esp_spiffs_free(esp_spiffs_t ** efs) 88 { 89 esp_spiffs_t * e = *efs; 90 if (*efs == NULL) { 91 return; 92 } 93 *efs = NULL; 94 95 if (e->fs) { 96 SPIFFS_unmount(e->fs); 97 free(e->fs); 98 } 99 vSemaphoreDelete(e->lock); 100 free(e->fds); 101 free(e->cache); 102 free(e->work); 103 free(e); 104 } 105 106 static esp_err_t esp_spiffs_by_label(const char* label, int * index){ 107 int i; 108 esp_spiffs_t * p; 109 for (i = 0; i < CONFIG_SPIFFS_MAX_PARTITIONS; i++) { 110 p = _efs[i]; 111 if (p) { 112 if (!label && !p->by_label) { 113 *index = i; 114 return ESP_OK; 115 } 116 if (label && p->by_label && strncmp(label, p->partition->label, 17) == 0) { 117 *index = i; 118 return ESP_OK; 119 } 120 } 121 } 122 return ESP_ERR_NOT_FOUND; 123 } 124 125 static esp_err_t esp_spiffs_get_empty(int * index){ 126 int i; 127 for (i = 0; i < CONFIG_SPIFFS_MAX_PARTITIONS; i++) { 128 if (_efs[i] == NULL) { 129 *index = i; 130 return ESP_OK; 131 } 132 } 133 return ESP_ERR_NOT_FOUND; 134 } 135 136 static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf) 137 { 138 int index; 139 //find if such partition is already mounted 140 if (esp_spiffs_by_label(conf->partition_label, &index) == ESP_OK) { 141 return ESP_ERR_INVALID_STATE; 142 } 143 144 if (esp_spiffs_get_empty(&index) != ESP_OK) { 145 ESP_LOGE(TAG, "max mounted partitions reached"); 146 return ESP_ERR_INVALID_STATE; 147 } 148 149 uint32_t flash_page_size = g_rom_flashchip.page_size; 150 uint32_t log_page_size = CONFIG_SPIFFS_PAGE_SIZE; 151 if (log_page_size % flash_page_size != 0) { 152 ESP_LOGE(TAG, "SPIFFS_PAGE_SIZE is not multiple of flash chip page size (%d)", 153 flash_page_size); 154 return ESP_ERR_INVALID_ARG; 155 } 156 157 esp_partition_subtype_t subtype = conf->partition_label ? 158 ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS; 159 const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, 160 subtype, conf->partition_label); 161 if (!partition) { 162 ESP_LOGE(TAG, "spiffs partition could not be found"); 163 return ESP_ERR_NOT_FOUND; 164 } 165 166 if (partition->encrypted) { 167 ESP_LOGE(TAG, "spiffs can not run on encrypted partition"); 168 return ESP_ERR_INVALID_STATE; 169 } 170 171 esp_spiffs_t * efs = malloc(sizeof(esp_spiffs_t)); 172 if (efs == NULL) { 173 ESP_LOGE(TAG, "esp_spiffs could not be malloced"); 174 return ESP_ERR_NO_MEM; 175 } 176 memset(efs, 0, sizeof(esp_spiffs_t)); 177 178 efs->cfg.hal_erase_f = spiffs_api_erase; 179 efs->cfg.hal_read_f = spiffs_api_read; 180 efs->cfg.hal_write_f = spiffs_api_write; 181 efs->cfg.log_block_size = g_rom_flashchip.sector_size; 182 efs->cfg.log_page_size = log_page_size; 183 efs->cfg.phys_addr = 0; 184 efs->cfg.phys_erase_block = g_rom_flashchip.sector_size; 185 efs->cfg.phys_size = partition->size; 186 187 efs->by_label = conf->partition_label != NULL; 188 189 efs->lock = xSemaphoreCreateMutex(); 190 if (efs->lock == NULL) { 191 ESP_LOGE(TAG, "mutex lock could not be created"); 192 esp_spiffs_free(&efs); 193 return ESP_ERR_NO_MEM; 194 } 195 196 efs->fds_sz = conf->max_files * sizeof(spiffs_fd); 197 efs->fds = malloc(efs->fds_sz); 198 if (efs->fds == NULL) { 199 ESP_LOGE(TAG, "fd buffer could not be malloced"); 200 esp_spiffs_free(&efs); 201 return ESP_ERR_NO_MEM; 202 } 203 memset(efs->fds, 0, efs->fds_sz); 204 205 #if SPIFFS_CACHE 206 efs->cache_sz = sizeof(spiffs_cache) + conf->max_files * (sizeof(spiffs_cache_page) 207 + efs->cfg.log_page_size); 208 efs->cache = malloc(efs->cache_sz); 209 if (efs->cache == NULL) { 210 ESP_LOGE(TAG, "cache buffer could not be malloced"); 211 esp_spiffs_free(&efs); 212 return ESP_ERR_NO_MEM; 213 } 214 memset(efs->cache, 0, efs->cache_sz); 215 #endif 216 217 const uint32_t work_sz = efs->cfg.log_page_size * 2; 218 efs->work = malloc(work_sz); 219 if (efs->work == NULL) { 220 ESP_LOGE(TAG, "work buffer could not be malloced"); 221 esp_spiffs_free(&efs); 222 return ESP_ERR_NO_MEM; 223 } 224 memset(efs->work, 0, work_sz); 225 226 efs->fs = malloc(sizeof(spiffs)); 227 if (efs->fs == NULL) { 228 ESP_LOGE(TAG, "spiffs could not be malloced"); 229 esp_spiffs_free(&efs); 230 return ESP_ERR_NO_MEM; 231 } 232 memset(efs->fs, 0, sizeof(spiffs)); 233 234 efs->fs->user_data = (void *)efs; 235 efs->partition = partition; 236 237 s32_t res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz, 238 efs->cache, efs->cache_sz, spiffs_api_check); 239 240 if (conf->format_if_mount_failed && res != SPIFFS_OK) { 241 ESP_LOGW(TAG, "mount failed, %i. formatting...", SPIFFS_errno(efs->fs)); 242 SPIFFS_clearerr(efs->fs); 243 res = SPIFFS_format(efs->fs); 244 if (res != SPIFFS_OK) { 245 ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(efs->fs)); 246 SPIFFS_clearerr(efs->fs); 247 esp_spiffs_free(&efs); 248 return ESP_FAIL; 249 } 250 res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz, 251 efs->cache, efs->cache_sz, spiffs_api_check); 252 } 253 if (res != SPIFFS_OK) { 254 ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(efs->fs)); 255 SPIFFS_clearerr(efs->fs); 256 esp_spiffs_free(&efs); 257 return ESP_FAIL; 258 } 259 _efs[index] = efs; 260 return ESP_OK; 261 } 262 263 bool esp_spiffs_mounted(const char* partition_label) 264 { 265 int index; 266 if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) { 267 return false; 268 } 269 return (SPIFFS_mounted(_efs[index]->fs)); 270 } 271 272 esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes) 273 { 274 int index; 275 if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) { 276 return ESP_ERR_INVALID_STATE; 277 } 278 SPIFFS_info(_efs[index]->fs, total_bytes, used_bytes); 279 return ESP_OK; 280 } 281 282 esp_err_t esp_spiffs_format(const char* partition_label) 283 { 284 bool partition_was_mounted = false; 285 int index; 286 /* If the partition is not mounted, need to create SPIFFS structures 287 * and mount the partition, unmount, format, delete SPIFFS structures. 288 * See SPIFFS wiki for the reason why. 289 */ 290 esp_err_t err = esp_spiffs_by_label(partition_label, &index); 291 if (err != ESP_OK) { 292 esp_vfs_spiffs_conf_t conf = { 293 .format_if_mount_failed = true, 294 .partition_label = partition_label, 295 .max_files = 1 296 }; 297 err = esp_spiffs_init(&conf); 298 if (err != ESP_OK) { 299 return err; 300 } 301 err = esp_spiffs_by_label(partition_label, &index); 302 assert(err == ESP_OK && "failed to get index of the partition just mounted"); 303 } else if (SPIFFS_mounted(_efs[index]->fs)) { 304 partition_was_mounted = true; 305 } 306 307 SPIFFS_unmount(_efs[index]->fs); 308 309 s32_t res = SPIFFS_format(_efs[index]->fs); 310 if (res != SPIFFS_OK) { 311 ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(_efs[index]->fs)); 312 SPIFFS_clearerr(_efs[index]->fs); 313 /* If the partition was previously mounted, but format failed, don't 314 * try to mount the partition back (it will probably fail). On the 315 * other hand, if it was not mounted, need to clean up. 316 */ 317 if (!partition_was_mounted) { 318 esp_spiffs_free(&_efs[index]); 319 } 320 return ESP_FAIL; 321 } 322 323 if (partition_was_mounted) { 324 res = SPIFFS_mount(_efs[index]->fs, &_efs[index]->cfg, _efs[index]->work, 325 _efs[index]->fds, _efs[index]->fds_sz, _efs[index]->cache, 326 _efs[index]->cache_sz, spiffs_api_check); 327 if (res != SPIFFS_OK) { 328 ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(_efs[index]->fs)); 329 SPIFFS_clearerr(_efs[index]->fs); 330 return ESP_FAIL; 331 } 332 } else { 333 esp_spiffs_free(&_efs[index]); 334 } 335 return ESP_OK; 336 } 337 338 esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf) 339 { 340 assert(conf->base_path); 341 const esp_vfs_t vfs = { 342 .flags = ESP_VFS_FLAG_CONTEXT_PTR, 343 .write_p = &vfs_spiffs_write, 344 .lseek_p = &vfs_spiffs_lseek, 345 .read_p = &vfs_spiffs_read, 346 .open_p = &vfs_spiffs_open, 347 .close_p = &vfs_spiffs_close, 348 .fstat_p = &vfs_spiffs_fstat, 349 #ifdef CONFIG_VFS_SUPPORT_DIR 350 .stat_p = &vfs_spiffs_stat, 351 .link_p = &vfs_spiffs_link, 352 .unlink_p = &vfs_spiffs_unlink, 353 .rename_p = &vfs_spiffs_rename, 354 .opendir_p = &vfs_spiffs_opendir, 355 .closedir_p = &vfs_spiffs_closedir, 356 .readdir_p = &vfs_spiffs_readdir, 357 .readdir_r_p = &vfs_spiffs_readdir_r, 358 .seekdir_p = &vfs_spiffs_seekdir, 359 .telldir_p = &vfs_spiffs_telldir, 360 .mkdir_p = &vfs_spiffs_mkdir, 361 .rmdir_p = &vfs_spiffs_rmdir, 362 #ifdef CONFIG_SPIFFS_USE_MTIME 363 .utime_p = &vfs_spiffs_utime, 364 #else 365 .utime_p = NULL, 366 #endif // CONFIG_SPIFFS_USE_MTIME 367 #endif // CONFIG_VFS_SUPPORT_DIR 368 }; 369 370 esp_err_t err = esp_spiffs_init(conf); 371 if (err != ESP_OK) { 372 return err; 373 } 374 375 int index; 376 if (esp_spiffs_by_label(conf->partition_label, &index) != ESP_OK) { 377 return ESP_ERR_INVALID_STATE; 378 } 379 380 strlcat(_efs[index]->base_path, conf->base_path, ESP_VFS_PATH_MAX + 1); 381 err = esp_vfs_register(conf->base_path, &vfs, _efs[index]); 382 if (err != ESP_OK) { 383 esp_spiffs_free(&_efs[index]); 384 return err; 385 } 386 387 return ESP_OK; 388 } 389 390 esp_err_t esp_vfs_spiffs_unregister(const char* partition_label) 391 { 392 int index; 393 if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) { 394 return ESP_ERR_INVALID_STATE; 395 } 396 esp_err_t err = esp_vfs_unregister(_efs[index]->base_path); 397 if (err != ESP_OK) { 398 return err; 399 } 400 esp_spiffs_free(&_efs[index]); 401 return ESP_OK; 402 } 403 404 static int spiffs_res_to_errno(s32_t fr) 405 { 406 switch(fr) { 407 case SPIFFS_OK : 408 return 0; 409 case SPIFFS_ERR_NOT_MOUNTED : 410 return ENODEV; 411 case SPIFFS_ERR_NOT_A_FS : 412 return ENODEV; 413 case SPIFFS_ERR_FULL : 414 return ENOSPC; 415 case SPIFFS_ERR_BAD_DESCRIPTOR : 416 return EBADF; 417 case SPIFFS_ERR_MOUNTED : 418 return EEXIST; 419 case SPIFFS_ERR_FILE_EXISTS : 420 return EEXIST; 421 case SPIFFS_ERR_NOT_FOUND : 422 return ENOENT; 423 case SPIFFS_ERR_NOT_A_FILE : 424 return ENOENT; 425 case SPIFFS_ERR_DELETED : 426 return ENOENT; 427 case SPIFFS_ERR_FILE_DELETED : 428 return ENOENT; 429 case SPIFFS_ERR_NAME_TOO_LONG : 430 return ENAMETOOLONG; 431 case SPIFFS_ERR_RO_NOT_IMPL : 432 return EROFS; 433 case SPIFFS_ERR_RO_ABORTED_OPERATION : 434 return EROFS; 435 default : 436 return EIO; 437 } 438 return ENOTSUP; 439 } 440 441 static int spiffs_mode_conv(int m) 442 { 443 int res = 0; 444 int acc_mode = m & O_ACCMODE; 445 if (acc_mode == O_RDONLY) { 446 res |= SPIFFS_O_RDONLY; 447 } else if (acc_mode == O_WRONLY) { 448 res |= SPIFFS_O_WRONLY; 449 } else if (acc_mode == O_RDWR) { 450 res |= SPIFFS_O_RDWR; 451 } 452 if ((m & O_CREAT) && (m & O_EXCL)) { 453 res |= SPIFFS_O_CREAT | SPIFFS_O_EXCL; 454 } else if ((m & O_CREAT) && (m & O_TRUNC)) { 455 res |= SPIFFS_O_CREAT | SPIFFS_O_TRUNC; 456 } 457 if (m & O_APPEND) { 458 res |= SPIFFS_O_CREAT | SPIFFS_O_APPEND; 459 } 460 return res; 461 } 462 463 static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode) 464 { 465 assert(path); 466 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 467 int spiffs_flags = spiffs_mode_conv(flags); 468 int fd = SPIFFS_open(efs->fs, path, spiffs_flags, mode); 469 if (fd < 0) { 470 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 471 SPIFFS_clearerr(efs->fs); 472 return -1; 473 } 474 if (!(spiffs_flags & SPIFFS_RDONLY)) { 475 vfs_spiffs_update_mtime(efs->fs, fd); 476 } 477 return fd; 478 } 479 480 static ssize_t vfs_spiffs_write(void* ctx, int fd, const void * data, size_t size) 481 { 482 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 483 ssize_t res = SPIFFS_write(efs->fs, fd, (void *)data, size); 484 if (res < 0) { 485 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 486 SPIFFS_clearerr(efs->fs); 487 return -1; 488 } 489 return res; 490 } 491 492 static ssize_t vfs_spiffs_read(void* ctx, int fd, void * dst, size_t size) 493 { 494 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 495 ssize_t res = SPIFFS_read(efs->fs, fd, dst, size); 496 if (res < 0) { 497 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 498 SPIFFS_clearerr(efs->fs); 499 return -1; 500 } 501 return res; 502 } 503 504 static int vfs_spiffs_close(void* ctx, int fd) 505 { 506 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 507 int res = SPIFFS_close(efs->fs, fd); 508 if (res < 0) { 509 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 510 SPIFFS_clearerr(efs->fs); 511 return -1; 512 } 513 return res; 514 } 515 516 static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode) 517 { 518 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 519 off_t res = SPIFFS_lseek(efs->fs, fd, offset, mode); 520 if (res < 0) { 521 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 522 SPIFFS_clearerr(efs->fs); 523 return -1; 524 } 525 return res; 526 } 527 528 static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st) 529 { 530 assert(st); 531 spiffs_stat s; 532 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 533 off_t res = SPIFFS_fstat(efs->fs, fd, &s); 534 if (res < 0) { 535 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 536 SPIFFS_clearerr(efs->fs); 537 return -1; 538 } 539 st->st_size = s.size; 540 st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG; 541 st->st_mtime = vfs_spiffs_get_mtime(&s); 542 st->st_atime = 0; 543 st->st_ctime = 0; 544 return res; 545 } 546 547 #ifdef CONFIG_VFS_SUPPORT_DIR 548 549 static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st) 550 { 551 assert(path); 552 assert(st); 553 spiffs_stat s; 554 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 555 off_t res = SPIFFS_stat(efs->fs, path, &s); 556 if (res < 0) { 557 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 558 SPIFFS_clearerr(efs->fs); 559 return -1; 560 } 561 562 st->st_size = s.size; 563 st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO; 564 st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG; 565 st->st_mtime = vfs_spiffs_get_mtime(&s); 566 st->st_atime = 0; 567 st->st_ctime = 0; 568 return res; 569 } 570 571 static int vfs_spiffs_rename(void* ctx, const char *src, const char *dst) 572 { 573 assert(src); 574 assert(dst); 575 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 576 int res = SPIFFS_rename(efs->fs, src, dst); 577 if (res < 0) { 578 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 579 SPIFFS_clearerr(efs->fs); 580 return -1; 581 } 582 return res; 583 } 584 585 static int vfs_spiffs_unlink(void* ctx, const char *path) 586 { 587 assert(path); 588 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 589 int res = SPIFFS_remove(efs->fs, path); 590 if (res < 0) { 591 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 592 SPIFFS_clearerr(efs->fs); 593 return -1; 594 } 595 return res; 596 } 597 598 static DIR* vfs_spiffs_opendir(void* ctx, const char* name) 599 { 600 assert(name); 601 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 602 vfs_spiffs_dir_t * dir = calloc(1, sizeof(vfs_spiffs_dir_t)); 603 if (!dir) { 604 errno = ENOMEM; 605 return NULL; 606 } 607 if (!SPIFFS_opendir(efs->fs, name, &dir->d)) { 608 free(dir); 609 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 610 SPIFFS_clearerr(efs->fs); 611 return NULL; 612 } 613 dir->offset = 0; 614 strlcpy(dir->path, name, SPIFFS_OBJ_NAME_LEN); 615 return (DIR*) dir; 616 } 617 618 static int vfs_spiffs_closedir(void* ctx, DIR* pdir) 619 { 620 assert(pdir); 621 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 622 vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir; 623 int res = SPIFFS_closedir(&dir->d); 624 free(dir); 625 if (res < 0) { 626 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 627 SPIFFS_clearerr(efs->fs); 628 return -1; 629 } 630 return res; 631 } 632 633 static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir) 634 { 635 assert(pdir); 636 vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir; 637 struct dirent* out_dirent; 638 int err = vfs_spiffs_readdir_r(ctx, pdir, &dir->e, &out_dirent); 639 if (err != 0) { 640 errno = err; 641 return NULL; 642 } 643 return out_dirent; 644 } 645 646 static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry, 647 struct dirent** out_dirent) 648 { 649 assert(pdir); 650 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 651 vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir; 652 struct spiffs_dirent out; 653 size_t plen; 654 char * item_name; 655 do { 656 if (SPIFFS_readdir(&dir->d, &out) == 0) { 657 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 658 SPIFFS_clearerr(efs->fs); 659 if (!errno) { 660 *out_dirent = NULL; 661 } 662 return errno; 663 } 664 item_name = (char *)out.name; 665 plen = strlen(dir->path); 666 667 } while ((plen > 1) && (strncasecmp(dir->path, (const char*)out.name, plen) || out.name[plen] != '/' || !out.name[plen + 1])); 668 669 if (plen > 1) { 670 item_name += plen + 1; 671 } else if (item_name[0] == '/') { 672 item_name++; 673 } 674 entry->d_ino = 0; 675 entry->d_type = out.type; 676 snprintf(entry->d_name, SPIFFS_OBJ_NAME_LEN, "%s", item_name); 677 dir->offset++; 678 *out_dirent = entry; 679 return 0; 680 } 681 682 static long vfs_spiffs_telldir(void* ctx, DIR* pdir) 683 { 684 assert(pdir); 685 vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir; 686 return dir->offset; 687 } 688 689 static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset) 690 { 691 assert(pdir); 692 esp_spiffs_t * efs = (esp_spiffs_t *)ctx; 693 vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir; 694 struct spiffs_dirent tmp; 695 if (offset < dir->offset) { 696 //rewind dir 697 SPIFFS_closedir(&dir->d); 698 if (!SPIFFS_opendir(efs->fs, NULL, &dir->d)) { 699 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 700 SPIFFS_clearerr(efs->fs); 701 return; 702 } 703 dir->offset = 0; 704 } 705 while (dir->offset < offset) { 706 if (SPIFFS_readdir(&dir->d, &tmp) == 0) { 707 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 708 SPIFFS_clearerr(efs->fs); 709 return; 710 } 711 size_t plen = strlen(dir->path); 712 if (plen > 1) { 713 if (strncasecmp(dir->path, (const char *)tmp.name, plen) || tmp.name[plen] != '/' || !tmp.name[plen+1]) { 714 continue; 715 } 716 } 717 dir->offset++; 718 } 719 } 720 721 static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode) 722 { 723 errno = ENOTSUP; 724 return -1; 725 } 726 727 static int vfs_spiffs_rmdir(void* ctx, const char* name) 728 { 729 errno = ENOTSUP; 730 return -1; 731 } 732 733 static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2) 734 { 735 errno = ENOTSUP; 736 return -1; 737 } 738 739 #ifdef CONFIG_SPIFFS_USE_MTIME 740 static int vfs_spiffs_update_mtime_value(spiffs *fs, const char *path, spiffs_time_t t) 741 { 742 int ret = SPIFFS_OK; 743 spiffs_stat s; 744 if (CONFIG_SPIFFS_META_LENGTH > sizeof(t)) { 745 ret = SPIFFS_stat(fs, path, &s); 746 } 747 if (ret == SPIFFS_OK) { 748 memcpy(s.meta, &t, sizeof(t)); 749 ret = SPIFFS_update_meta(fs, path, s.meta); 750 } 751 if (ret != SPIFFS_OK) { 752 ESP_LOGW(TAG, "Failed to update mtime (%d)", ret); 753 } 754 return ret; 755 } 756 #endif //CONFIG_SPIFFS_USE_MTIME 757 758 #ifdef CONFIG_SPIFFS_USE_MTIME 759 static int vfs_spiffs_utime(void *ctx, const char *path, const struct utimbuf *times) 760 { 761 assert(path); 762 763 esp_spiffs_t *efs = (esp_spiffs_t *) ctx; 764 spiffs_time_t t; 765 766 if (times) { 767 t = (spiffs_time_t)times->modtime; 768 } else { 769 // use current time 770 t = (spiffs_time_t)time(NULL); 771 } 772 773 int ret = vfs_spiffs_update_mtime_value(efs->fs, path, t); 774 775 if (ret != SPIFFS_OK) { 776 errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs)); 777 SPIFFS_clearerr(efs->fs); 778 return -1; 779 } 780 781 return 0; 782 } 783 #endif //CONFIG_SPIFFS_USE_MTIME 784 785 #endif // CONFIG_VFS_SUPPORT_DIR 786 787 static void vfs_spiffs_update_mtime(spiffs *fs, spiffs_file fd) 788 { 789 #ifdef CONFIG_SPIFFS_USE_MTIME 790 spiffs_time_t t = (spiffs_time_t)time(NULL); 791 spiffs_stat s; 792 int ret = SPIFFS_OK; 793 if (CONFIG_SPIFFS_META_LENGTH > sizeof(t)) { 794 ret = SPIFFS_fstat(fs, fd, &s); 795 } 796 if (ret == SPIFFS_OK) { 797 memcpy(s.meta, &t, sizeof(t)); 798 ret = SPIFFS_fupdate_meta(fs, fd, s.meta); 799 } 800 if (ret != SPIFFS_OK) { 801 ESP_LOGW(TAG, "Failed to update mtime (%d)", ret); 802 } 803 #endif //CONFIG_SPIFFS_USE_MTIME 804 } 805 806 static time_t vfs_spiffs_get_mtime(const spiffs_stat* s) 807 { 808 #ifdef CONFIG_SPIFFS_USE_MTIME 809 spiffs_time_t t = 0; 810 memcpy(&t, s->meta, sizeof(t)); 811 #else 812 time_t t = 0; 813 #endif 814 return (time_t)t; 815 }