esp_spiffs.c 24 KB

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