You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

879 line
20 KiB

  1. /*
  2. * spiffs VFS operations
  3. *
  4. * Author: LoBo (loboris@gmail.com / https://github.com/loboris)
  5. *
  6. * Part of this code is copied from or inspired by LUA-RTOS_ESP32 project:
  7. *
  8. * https://github.com/whitecatboard/Lua-RTOS-ESP32
  9. * IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
  10. * Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
  11. *
  12. */
  13. #include <freertos/FreeRTOS.h>
  14. #include <string.h>
  15. #include <stdio.h>
  16. #include <limits.h>
  17. #include "esp_log.h"
  18. #include <sys/stat.h>
  19. #include "esp_vfs.h"
  20. #include "esp_attr.h"
  21. #include <errno.h>
  22. #include <spiffs_vfs.h>
  23. #include <spiffs.h>
  24. #include <esp_spiffs.h>
  25. #include <spiffs_nucleus.h>
  26. #include "list.h"
  27. #include <sys/fcntl.h>
  28. #include <sys/dirent.h>
  29. #include "sdkconfig.h"
  30. #ifdef PATH_MAX
  31. #undef PATH_MAX
  32. #endif
  33. #define PATH_MAX MAXNAMLEN+8
  34. #define SPIFFS_ERASE_SIZE 4096
  35. int spiffs_is_registered = 0;
  36. int spiffs_is_mounted = 0;
  37. QueueHandle_t spiffs_mutex = NULL;
  38. static int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode);
  39. static ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size);
  40. static ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size);
  41. static int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st);
  42. static int IRAM_ATTR vfs_spiffs_close(int fd);
  43. static off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode);
  44. typedef struct {
  45. DIR dir;
  46. spiffs_DIR spiffs_dir;
  47. char path[MAXNAMLEN + 1];
  48. struct dirent ent;
  49. uint8_t read_mount;
  50. } vfs_spiffs_dir_t;
  51. typedef struct {
  52. spiffs_file spiffs_file;
  53. char path[MAXNAMLEN + 1];
  54. uint8_t is_dir;
  55. } vfs_spiffs_file_t;
  56. typedef struct {
  57. time_t mtime;
  58. time_t ctime;
  59. time_t atime;
  60. uint8_t spare[SPIFFS_OBJ_META_LEN - (sizeof(time_t)*3)];
  61. } spiffs_metadata_t;
  62. static spiffs fs;
  63. static struct list files;
  64. static u8_t *my_spiffs_work_buf;
  65. static u8_t *my_spiffs_fds;
  66. static u8_t *my_spiffs_cache;
  67. /*
  68. * ########################################
  69. * file names/paths passed to the functions
  70. * do not contain '/spiffs' prefix
  71. * ########################################
  72. */
  73. //----------------------------------------------------
  74. void spiffs_fs_stat(uint32_t *total, uint32_t *used) {
  75. if (SPIFFS_info(&fs, total, used) != SPIFFS_OK) {
  76. *total = 0;
  77. *used = 0;
  78. }
  79. }
  80. /*
  81. * Test if path corresponds to a directory. Return 0 if is not a directory,
  82. * 1 if it's a directory.
  83. *
  84. */
  85. //-----------------------------------
  86. static int is_dir(const char *path) {
  87. spiffs_DIR d;
  88. char npath[PATH_MAX + 1];
  89. int res = 0;
  90. struct spiffs_dirent e;
  91. // Add /. to path
  92. strlcpy(npath, path, PATH_MAX);
  93. if (strcmp(path,"/") != 0) {
  94. strlcat(npath,"/.", PATH_MAX);
  95. } else {
  96. strlcat(npath,".", PATH_MAX);
  97. }
  98. SPIFFS_opendir(&fs, "/", &d);
  99. while (SPIFFS_readdir(&d, &e)) {
  100. if (strncmp(npath, (const char *)e.name, strlen(npath)) == 0) {
  101. res = 1;
  102. break;
  103. }
  104. }
  105. SPIFFS_closedir(&d);
  106. return res;
  107. }
  108. /*
  109. * This function translate error codes from SPIFFS to errno error codes
  110. *
  111. */
  112. //-------------------------------
  113. static int spiffs_result(int res) {
  114. switch (res) {
  115. case SPIFFS_OK:
  116. case SPIFFS_ERR_END_OF_OBJECT:
  117. return 0;
  118. case SPIFFS_ERR_NOT_FOUND:
  119. case SPIFFS_ERR_CONFLICTING_NAME:
  120. return ENOENT;
  121. case SPIFFS_ERR_NOT_WRITABLE:
  122. case SPIFFS_ERR_NOT_READABLE:
  123. return EACCES;
  124. case SPIFFS_ERR_FILE_EXISTS:
  125. return EEXIST;
  126. default:
  127. return res;
  128. }
  129. }
  130. //-----------------------------------------------------------------------------------------------------
  131. static int IRAM_ATTR vfs_spiffs_getstat(spiffs_file fd, spiffs_stat *st, spiffs_metadata_t *metadata) {
  132. int res = SPIFFS_fstat(&fs, fd, st);
  133. if (res == SPIFFS_OK) {
  134. // Get file's time information from metadata
  135. memcpy(metadata, st->meta, sizeof(spiffs_metadata_t));
  136. }
  137. return res;
  138. }
  139. // ## path does not contain '/spiffs' prefix !
  140. //---------------------------------------------------------------------------
  141. static int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode) {
  142. int fd, result = 0, exists = 0;
  143. spiffs_stat stat;
  144. spiffs_metadata_t meta;
  145. // Allocate new file
  146. vfs_spiffs_file_t *file = calloc(1, sizeof(vfs_spiffs_file_t));
  147. if (!file) {
  148. errno = ENOMEM;
  149. return -1;
  150. }
  151. // Add file to file list. List index is file descriptor.
  152. int res = list_add(&files, file, &fd);
  153. if (res) {
  154. free(file);
  155. errno = res;
  156. return -1;
  157. }
  158. // Check if file exists
  159. if (SPIFFS_stat(&fs, path, &stat) == SPIFFS_OK) exists = 1;
  160. // Make a copy of path
  161. strlcpy(file->path, path, MAXNAMLEN);
  162. // Open file
  163. spiffs_flags spiffs_mode = 0;
  164. // Translate flags to SPIFFS flags
  165. if (flags == O_RDONLY)
  166. spiffs_mode |= SPIFFS_RDONLY;
  167. if (flags & O_WRONLY)
  168. spiffs_mode |= SPIFFS_WRONLY;
  169. if (flags & O_RDWR)
  170. spiffs_mode = SPIFFS_RDWR;
  171. if (flags & O_EXCL)
  172. spiffs_mode |= SPIFFS_EXCL;
  173. if (flags & O_CREAT)
  174. spiffs_mode |= SPIFFS_CREAT;
  175. if (flags & O_TRUNC)
  176. spiffs_mode |= SPIFFS_TRUNC;
  177. if (is_dir(path)) {
  178. char npath[PATH_MAX + 1];
  179. // Add /. to path
  180. strlcpy(npath, path, PATH_MAX);
  181. if (strcmp(path,"/") != 0) {
  182. strlcat(npath,"/.", PATH_MAX);
  183. } else {
  184. strlcat(npath,".", PATH_MAX);
  185. }
  186. // Open SPIFFS file
  187. file->spiffs_file = SPIFFS_open(&fs, npath, spiffs_mode, 0);
  188. if (file->spiffs_file < 0) {
  189. result = spiffs_result(fs.err_code);
  190. }
  191. file->is_dir = 1;
  192. } else {
  193. // Open SPIFFS file
  194. file->spiffs_file = SPIFFS_open(&fs, path, spiffs_mode, 0);
  195. if (file->spiffs_file < 0) {
  196. result = spiffs_result(fs.err_code);
  197. }
  198. }
  199. if (result != 0) {
  200. list_remove(&files, fd, 1);
  201. errno = result;
  202. return -1;
  203. }
  204. res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);
  205. if (res == SPIFFS_OK) {
  206. // update file's time information
  207. meta.atime = time(NULL); // Get the system time to access time
  208. if (!exists) meta.ctime = meta.atime;
  209. if (spiffs_mode != SPIFFS_RDONLY) meta.mtime = meta.atime;
  210. SPIFFS_fupdate_meta(&fs, file->spiffs_file, &meta);
  211. }
  212. return fd;
  213. }
  214. //--------------------------------------------------------------------------------
  215. static ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size) {
  216. vfs_spiffs_file_t *file;
  217. int res;
  218. res = list_get(&files, fd, (void **)&file);
  219. if (res) {
  220. errno = EBADF;
  221. return -1;
  222. }
  223. if (file->is_dir) {
  224. errno = EBADF;
  225. return -1;
  226. }
  227. // Write SPIFFS file
  228. res = SPIFFS_write(&fs, file->spiffs_file, (void *)data, size);
  229. if (res >= 0) {
  230. return res;
  231. } else {
  232. res = spiffs_result(fs.err_code);
  233. if (res != 0) {
  234. errno = res;
  235. return -1;
  236. }
  237. }
  238. return -1;
  239. }
  240. //-------------------------------------------------------------------------
  241. static ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size) {
  242. vfs_spiffs_file_t *file;
  243. int res;
  244. res = list_get(&files, fd, (void **)&file);
  245. if (res) {
  246. errno = EBADF;
  247. return -1;
  248. }
  249. if (file->is_dir) {
  250. errno = EBADF;
  251. return -1;
  252. }
  253. // Read SPIFFS file
  254. res = SPIFFS_read(&fs, file->spiffs_file, dst, size);
  255. if (res >= 0) {
  256. return res;
  257. } else {
  258. res = spiffs_result(fs.err_code);
  259. if (res != 0) {
  260. errno = res;
  261. return -1;
  262. }
  263. // EOF
  264. return 0;
  265. }
  266. return -1;
  267. }
  268. //---------------------------------------------------------------
  269. static int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st) {
  270. vfs_spiffs_file_t *file;
  271. spiffs_stat stat;
  272. int res;
  273. spiffs_metadata_t meta;
  274. res = list_get(&files, fd, (void **)&file);
  275. if (res) {
  276. errno = EBADF;
  277. return -1;
  278. }
  279. // Set block size for this file system
  280. st->st_blksize = CONFIG_SPIFFS_LOG_PAGE_SIZE;
  281. // Get file/directory statistics
  282. res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);
  283. if (res == SPIFFS_OK) {
  284. // Set file's time information from metadata
  285. st->st_mtime = meta.mtime;
  286. st->st_ctime = meta.ctime;
  287. st->st_atime = meta.atime;
  288. st->st_size = stat.size;
  289. } else {
  290. st->st_mtime = 0;
  291. st->st_ctime = 0;
  292. st->st_atime = 0;
  293. st->st_size = 0;
  294. errno = spiffs_result(fs.err_code);
  295. //printf("SPIFFS_STAT: error %d\r\n", res);
  296. return -1;
  297. }
  298. // Test if it's a directory entry
  299. if (file->is_dir) st->st_mode = S_IFDIR;
  300. else st->st_mode = S_IFREG;
  301. return 0;
  302. }
  303. //---------------------------------------------
  304. static int IRAM_ATTR vfs_spiffs_close(int fd) {
  305. vfs_spiffs_file_t *file;
  306. int res;
  307. res = list_get(&files, fd, (void **)&file);
  308. if (res) {
  309. errno = EBADF;
  310. return -1;
  311. }
  312. res = SPIFFS_close(&fs, file->spiffs_file);
  313. if (res) {
  314. res = spiffs_result(fs.err_code);
  315. }
  316. if (res < 0) {
  317. errno = res;
  318. return -1;
  319. }
  320. list_remove(&files, fd, 1);
  321. return 0;
  322. }
  323. //---------------------------------------------------------------------
  324. static off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode) {
  325. vfs_spiffs_file_t *file;
  326. int res;
  327. res = list_get(&files, fd, (void **)&file);
  328. if (res) {
  329. errno = EBADF;
  330. return -1;
  331. }
  332. if (file->is_dir) {
  333. errno = EBADF;
  334. return -1;
  335. }
  336. int whence = SPIFFS_SEEK_CUR;
  337. switch (mode) {
  338. case SEEK_SET: whence = SPIFFS_SEEK_SET;break;
  339. case SEEK_CUR: whence = SPIFFS_SEEK_CUR;break;
  340. case SEEK_END: whence = SPIFFS_SEEK_END;break;
  341. }
  342. res = SPIFFS_lseek(&fs, file->spiffs_file, size, whence);
  343. if (res < 0) {
  344. res = spiffs_result(fs.err_code);
  345. errno = res;
  346. return -1;
  347. }
  348. return res;
  349. }
  350. //-------------------------------------------------------------------------
  351. static int IRAM_ATTR vfs_spiffs_stat(const char * path, struct stat * st) {
  352. int fd;
  353. int res;
  354. fd = vfs_spiffs_open(path, 0, 0);
  355. res = vfs_spiffs_fstat(fd, st);
  356. vfs_spiffs_close(fd);
  357. return res;
  358. }
  359. //--------------------------------------------------------
  360. static int IRAM_ATTR vfs_spiffs_unlink(const char *path) {
  361. char npath[PATH_MAX + 1];
  362. strlcpy(npath, path, PATH_MAX);
  363. if (is_dir(path)) {
  364. // Check if directory is empty
  365. int nument = 0;
  366. sprintf(npath, "/spiffs");
  367. strlcat(npath, path, PATH_MAX);
  368. DIR *dir = opendir(npath);
  369. if (dir) {
  370. struct dirent *ent;
  371. // Read directory entries
  372. while ((ent = readdir(dir)) != NULL) {
  373. nument++;
  374. }
  375. }
  376. else {
  377. errno = ENOTEMPTY;
  378. return -1;
  379. }
  380. closedir(dir);
  381. if (nument > 0) {
  382. // Directory not empty, cannot remove
  383. errno = ENOTEMPTY;
  384. return -1;
  385. }
  386. strlcpy(npath, path, PATH_MAX);
  387. // Add /. to path
  388. if (strcmp(path,"/") != 0) {
  389. strlcat(npath,"/.", PATH_MAX);
  390. }
  391. }
  392. // Open SPIFFS file
  393. spiffs_file FP = SPIFFS_open(&fs, npath, SPIFFS_RDWR, 0);
  394. if (FP < 0) {
  395. errno = spiffs_result(fs.err_code);
  396. return -1;
  397. }
  398. // Remove SPIFSS file
  399. if (SPIFFS_fremove(&fs, FP) < 0) {
  400. errno = spiffs_result(fs.err_code);
  401. SPIFFS_close(&fs, FP);
  402. return -1;
  403. }
  404. SPIFFS_close(&fs, FP);
  405. return 0;
  406. }
  407. //------------------------------------------------------------------------
  408. static int IRAM_ATTR vfs_spiffs_rename(const char *src, const char *dst) {
  409. if (SPIFFS_rename(&fs, src, dst) < 0) {
  410. errno = spiffs_result(fs.err_code);
  411. return -1;
  412. }
  413. return 0;
  414. }
  415. //------------------------------------------------
  416. static DIR* vfs_spiffs_opendir(const char* name) {
  417. struct stat st;
  418. if (strcmp(name, "/") != 0) {
  419. // Not on root
  420. if (vfs_spiffs_stat(name, &st)) {
  421. // Not found
  422. errno = ENOENT;
  423. return NULL;
  424. }
  425. if (!S_ISDIR(st.st_mode)) {
  426. // Not a directory
  427. errno = ENOTDIR;
  428. return NULL;
  429. }
  430. }
  431. vfs_spiffs_dir_t *dir = calloc(1, sizeof(vfs_spiffs_dir_t));
  432. if (!dir) {
  433. errno = ENOMEM;
  434. return NULL;
  435. }
  436. if (!SPIFFS_opendir(&fs, name, &dir->spiffs_dir)) {
  437. free(dir);
  438. errno = spiffs_result(fs.err_code);
  439. return NULL;
  440. }
  441. strlcpy(dir->path, name, MAXNAMLEN);
  442. return (DIR *)dir;
  443. }
  444. //---------------------------------------------------
  445. static struct dirent* vfs_spiffs_readdir(DIR* pdir) {
  446. int res = 0, len = 0, entries = 0;
  447. vfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;
  448. struct spiffs_dirent e;
  449. struct spiffs_dirent *pe = &e;
  450. struct dirent *ent = &dir->ent;
  451. char *fn;
  452. // Clear current dirent
  453. memset(ent,0,sizeof(struct dirent));
  454. // If this is the first call to readdir for pdir, and
  455. // directory is the root path, return the mounted point if any
  456. if (!dir->read_mount) {
  457. if (strcmp(dir->path,"/") == 0) {
  458. strlcpy(ent->d_name, "/spiffs", PATH_MAX);
  459. ent->d_type = DT_DIR;
  460. dir->read_mount = 1;
  461. return ent;
  462. }
  463. dir->read_mount = 1;
  464. }
  465. // Search for next entry
  466. for(;;) {
  467. // Read directory
  468. pe = SPIFFS_readdir(&dir->spiffs_dir, pe);
  469. if (!pe) {
  470. res = spiffs_result(fs.err_code);
  471. errno = res;
  472. break;
  473. }
  474. // Break condition
  475. if (pe->name[0] == 0) break;
  476. // Get name and length
  477. fn = (char *)pe->name;
  478. len = strlen(fn);
  479. // Get entry type and size
  480. ent->d_type = DT_REG;
  481. if (len >= 2) {
  482. if (fn[len - 1] == '.') {
  483. if (fn[len - 2] == '/') {
  484. ent->d_type = DT_DIR;
  485. fn[len - 2] = '\0';
  486. len = strlen(fn);
  487. // Skip root dir
  488. if (len == 0) {
  489. continue;
  490. }
  491. }
  492. }
  493. }
  494. // Skip entries not belonged to path
  495. if (strncmp(fn, dir->path, strlen(dir->path)) != 0) {
  496. continue;
  497. }
  498. if (strlen(dir->path) > 1) {
  499. if (*(fn + strlen(dir->path)) != '/') {
  500. continue;
  501. }
  502. }
  503. // Skip root directory
  504. fn = fn + strlen(dir->path);
  505. len = strlen(fn);
  506. if (len == 0) {
  507. continue;
  508. }
  509. // Skip initial /
  510. if (len > 1) {
  511. if (*fn == '/') {
  512. fn = fn + 1;
  513. len--;
  514. }
  515. }
  516. // Skip subdirectories
  517. if (strchr(fn,'/')) {
  518. continue;
  519. }
  520. //ent->d_fsize = pe->size;
  521. strlcpy(ent->d_name, fn, MAXNAMLEN);
  522. entries++;
  523. break;
  524. }
  525. if (entries > 0) {
  526. return ent;
  527. } else {
  528. return NULL;
  529. }
  530. }
  531. //--------------------------------------------------
  532. static int IRAM_ATTR vfs_piffs_closedir(DIR* pdir) {
  533. vfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;
  534. int res;
  535. if (!pdir) {
  536. errno = EBADF;
  537. return -1;
  538. }
  539. if ((res = SPIFFS_closedir(&dir->spiffs_dir)) < 0) {
  540. errno = spiffs_result(fs.err_code);;
  541. return -1;
  542. }
  543. free(dir);
  544. return 0;
  545. }
  546. //--------------------------------------------------------------------
  547. static int IRAM_ATTR vfs_spiffs_mkdir(const char *path, mode_t mode) {
  548. char npath[PATH_MAX + 1];
  549. int res;
  550. // Add /. to path
  551. strlcpy(npath, path, PATH_MAX);
  552. if ((strcmp(path,"/") != 0) && (strcmp(path,"/.") != 0)) {
  553. strlcat(npath,"/.", PATH_MAX);
  554. }
  555. spiffs_file fd = SPIFFS_open(&fs, npath, SPIFFS_CREAT, 0);
  556. if (fd < 0) {
  557. res = spiffs_result(fs.err_code);
  558. errno = res;
  559. return -1;
  560. }
  561. if (SPIFFS_close(&fs, fd) < 0) {
  562. res = spiffs_result(fs.err_code);
  563. errno = res;
  564. return -1;
  565. }
  566. spiffs_metadata_t meta;
  567. meta.atime = time(NULL); // Get the system time to access time
  568. meta.ctime = meta.atime;
  569. meta.mtime = meta.atime;
  570. SPIFFS_update_meta(&fs, npath, &meta);
  571. return 0;
  572. }
  573. static const char tag[] = "[SPIFFS]";
  574. //==================
  575. int spiffs_mount() {
  576. if (!spiffs_is_registered) return 0;
  577. if (spiffs_is_mounted) return 1;
  578. spiffs_config cfg;
  579. int res = 0;
  580. int retries = 0;
  581. int err = 0;
  582. ESP_LOGI(tag, "Mounting SPIFFS files system");
  583. cfg.phys_addr = CONFIG_SPIFFS_BASE_ADDR;
  584. cfg.phys_size = CONFIG_SPIFFS_SIZE;
  585. cfg.phys_erase_block = SPIFFS_ERASE_SIZE;
  586. cfg.log_page_size = CONFIG_SPIFFS_LOG_PAGE_SIZE;
  587. cfg.log_block_size = CONFIG_SPIFFS_LOG_BLOCK_SIZE;
  588. cfg.hal_read_f = (spiffs_read)low_spiffs_read;
  589. cfg.hal_write_f = (spiffs_write)low_spiffs_write;
  590. cfg.hal_erase_f = (spiffs_erase)low_spiffs_erase;
  591. my_spiffs_work_buf = malloc(cfg.log_page_size * 8);
  592. if (!my_spiffs_work_buf) {
  593. err = 1;
  594. goto err_exit;
  595. }
  596. int fds_len = sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
  597. my_spiffs_fds = malloc(fds_len);
  598. if (!my_spiffs_fds) {
  599. free(my_spiffs_work_buf);
  600. err = 2;
  601. goto err_exit;
  602. }
  603. int cache_len = cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
  604. my_spiffs_cache = malloc(cache_len);
  605. if (!my_spiffs_cache) {
  606. free(my_spiffs_work_buf);
  607. free(my_spiffs_fds);
  608. err = 3;
  609. goto err_exit;
  610. }
  611. ESP_LOGI(tag, "Start address: 0x%x; Size %d KB", cfg.phys_addr, cfg.phys_size / 1024);
  612. ESP_LOGI(tag, " Work buffer: %d B", cfg.log_page_size * 8);
  613. ESP_LOGI(tag, " FDS buffer: %d B", sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);
  614. ESP_LOGI(tag, " Cache size: %d B", cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);
  615. while (retries < 2) {
  616. res = SPIFFS_mount(
  617. &fs, &cfg, my_spiffs_work_buf, my_spiffs_fds,
  618. fds_len, my_spiffs_cache, cache_len, NULL
  619. );
  620. if (res < 0) {
  621. if (fs.err_code == SPIFFS_ERR_NOT_A_FS) {
  622. ESP_LOGW(tag, "No file system detected, formating...");
  623. SPIFFS_unmount(&fs);
  624. res = SPIFFS_format(&fs);
  625. if (res < 0) {
  626. free(my_spiffs_work_buf);
  627. free(my_spiffs_fds);
  628. free(my_spiffs_cache);
  629. ESP_LOGE(tag, "Format error");
  630. goto exit;
  631. }
  632. }
  633. else {
  634. free(my_spiffs_work_buf);
  635. free(my_spiffs_fds);
  636. free(my_spiffs_cache);
  637. ESP_LOGE(tag, "Error mounting fs (%d)", res);
  638. goto exit;
  639. }
  640. }
  641. else break;
  642. retries++;
  643. }
  644. if (retries > 1) {
  645. free(my_spiffs_work_buf);
  646. free(my_spiffs_fds);
  647. free(my_spiffs_cache);
  648. ESP_LOGE(tag, "Can't mount");
  649. goto exit;
  650. }
  651. list_init(&files, 0);
  652. ESP_LOGI(tag, "Mounted");
  653. spiffs_is_mounted = 1;
  654. return 1;
  655. err_exit:
  656. ESP_LOGE(tag, "Error allocating fs structures (%d)", err);
  657. exit:
  658. esp_vfs_unregister("/spiffs");
  659. spiffs_is_registered = 0;
  660. return 0;
  661. }
  662. //==========================
  663. void vfs_spiffs_register() {
  664. if (spiffs_is_registered) return;
  665. if (spiffs_mutex == NULL) {
  666. spiffs_mutex = xSemaphoreCreateMutex();
  667. if (spiffs_mutex == NULL) {
  668. ESP_LOGE(tag, "Error creating SPIFFS mutex");
  669. return;
  670. }
  671. }
  672. esp_vfs_t vfs = {
  673. //.fd_offset = 0, // not available in latest esp-idf
  674. .flags = ESP_VFS_FLAG_DEFAULT,
  675. .write = &vfs_spiffs_write,
  676. .open = &vfs_spiffs_open,
  677. .fstat = &vfs_spiffs_fstat,
  678. .close = &vfs_spiffs_close,
  679. .read = &vfs_spiffs_read,
  680. .lseek = &vfs_spiffs_lseek,
  681. .stat = &vfs_spiffs_stat,
  682. .link = NULL,
  683. .unlink = &vfs_spiffs_unlink,
  684. .rename = &vfs_spiffs_rename,
  685. .mkdir = &vfs_spiffs_mkdir,
  686. .opendir = &vfs_spiffs_opendir,
  687. .readdir = &vfs_spiffs_readdir,
  688. .closedir = &vfs_piffs_closedir,
  689. };
  690. ESP_LOGI(tag, "Registering SPIFFS file system");
  691. esp_err_t res = esp_vfs_register(SPIFFS_BASE_PATH, &vfs, NULL);
  692. if (res != ESP_OK) {
  693. ESP_LOGE(tag, "Error, SPIFFS file system not registered");
  694. return;
  695. }
  696. spiffs_is_registered = 1;
  697. spiffs_mount();
  698. }
  699. //=============================
  700. int spiffs_unmount(int unreg) {
  701. if (!spiffs_is_mounted) return 0;
  702. SPIFFS_unmount(&fs);
  703. spiffs_is_mounted = 0;
  704. if (unreg) {
  705. esp_vfs_unregister("/spiffs");
  706. spiffs_is_registered = 0;
  707. }
  708. return 1;
  709. }