esp_spiffs.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  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. uint32_t flash_page_size = g_rom_flashchip.page_size;
  205. uint32_t log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
  206. if (log_page_size % flash_page_size != 0) {
  207. ESP_LOGE(TAG, "SPIFFS_PAGE_SIZE is not multiple of flash chip page size (%d)",
  208. flash_page_size);
  209. return ESP_ERR_INVALID_ARG;
  210. }
  211. esp_partition_subtype_t subtype = conf->partition_label ?
  212. ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS;
  213. const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
  214. subtype, conf->partition_label);
  215. if (!partition) {
  216. ESP_LOGE(TAG, "spiffs partition could not be found");
  217. return ESP_ERR_NOT_FOUND;
  218. }
  219. if (partition->encrypted) {
  220. ESP_LOGE(TAG, "spiffs can not run on encrypted partition");
  221. return ESP_ERR_INVALID_STATE;
  222. }
  223. esp_spiffs_t * efs = malloc(sizeof(esp_spiffs_t));
  224. if (efs == NULL) {
  225. ESP_LOGE(TAG, "esp_spiffs could not be malloced");
  226. return ESP_ERR_NO_MEM;
  227. }
  228. memset(efs, 0, sizeof(esp_spiffs_t));
  229. efs->cfg.hal_erase_f = spiffs_api_erase;
  230. efs->cfg.hal_read_f = spiffs_api_read;
  231. efs->cfg.hal_write_f = spiffs_api_write;
  232. efs->cfg.log_block_size = g_rom_flashchip.sector_size;
  233. efs->cfg.log_page_size = log_page_size;
  234. efs->cfg.phys_addr = 0;
  235. efs->cfg.phys_erase_block = g_rom_flashchip.sector_size;
  236. efs->cfg.phys_size = partition->size;
  237. efs->by_label = conf->partition_label != NULL;
  238. efs->lock = xSemaphoreCreateMutex();
  239. if (efs->lock == NULL) {
  240. ESP_LOGE(TAG, "mutex lock could not be created");
  241. esp_spiffs_free(&efs);
  242. return ESP_ERR_NO_MEM;
  243. }
  244. efs->fds_sz = conf->max_files * sizeof(spiffs_fd);
  245. efs->fds = malloc(efs->fds_sz);
  246. if (efs->fds == NULL) {
  247. ESP_LOGE(TAG, "fd buffer could not be malloced");
  248. esp_spiffs_free(&efs);
  249. return ESP_ERR_NO_MEM;
  250. }
  251. memset(efs->fds, 0, efs->fds_sz);
  252. #if SPIFFS_CACHE
  253. efs->cache_sz = sizeof(spiffs_cache) + conf->max_files * (sizeof(spiffs_cache_page)
  254. + efs->cfg.log_page_size);
  255. efs->cache = malloc(efs->cache_sz);
  256. if (efs->cache == NULL) {
  257. ESP_LOGE(TAG, "cache buffer could not be malloced");
  258. esp_spiffs_free(&efs);
  259. return ESP_ERR_NO_MEM;
  260. }
  261. memset(efs->cache, 0, efs->cache_sz);
  262. #endif
  263. const uint32_t work_sz = efs->cfg.log_page_size * 2;
  264. efs->work = malloc(work_sz);
  265. if (efs->work == NULL) {
  266. ESP_LOGE(TAG, "work buffer could not be malloced");
  267. esp_spiffs_free(&efs);
  268. return ESP_ERR_NO_MEM;
  269. }
  270. memset(efs->work, 0, work_sz);
  271. efs->fs = malloc(sizeof(spiffs));
  272. if (efs->fs == NULL) {
  273. ESP_LOGE(TAG, "spiffs could not be malloced");
  274. esp_spiffs_free(&efs);
  275. return ESP_ERR_NO_MEM;
  276. }
  277. memset(efs->fs, 0, sizeof(spiffs));
  278. efs->fs->user_data = (void *)efs;
  279. efs->partition = partition;
  280. s32_t res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
  281. efs->cache, efs->cache_sz, spiffs_api_check);
  282. if (conf->format_if_mount_failed && res != SPIFFS_OK) {
  283. ESP_LOGW(TAG, "mount failed, %i. formatting...", SPIFFS_errno(efs->fs));
  284. SPIFFS_clearerr(efs->fs);
  285. res = SPIFFS_format(efs->fs);
  286. if (res != SPIFFS_OK) {
  287. ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(efs->fs));
  288. SPIFFS_clearerr(efs->fs);
  289. esp_spiffs_free(&efs);
  290. return ESP_FAIL;
  291. }
  292. res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
  293. efs->cache, efs->cache_sz, spiffs_api_check);
  294. }
  295. if (res != SPIFFS_OK) {
  296. ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(efs->fs));
  297. SPIFFS_clearerr(efs->fs);
  298. esp_spiffs_free(&efs);
  299. return ESP_FAIL;
  300. }
  301. _efs[index] = efs;
  302. return ESP_OK;
  303. }
  304. bool esp_spiffs_mounted(const char* partition_label)
  305. {
  306. int index;
  307. if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
  308. return false;
  309. }
  310. return (SPIFFS_mounted(_efs[index]->fs));
  311. }
  312. esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes)
  313. {
  314. int index;
  315. if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
  316. return ESP_ERR_INVALID_STATE;
  317. }
  318. SPIFFS_info(_efs[index]->fs, total_bytes, used_bytes);
  319. return ESP_OK;
  320. }
  321. esp_err_t esp_spiffs_format(const char* partition_label)
  322. {
  323. bool partition_was_mounted = false;
  324. int index;
  325. /* If the partition is not mounted, need to create SPIFFS structures
  326. * and mount the partition, unmount, format, delete SPIFFS structures.
  327. * See SPIFFS wiki for the reason why.
  328. */
  329. esp_err_t err = esp_spiffs_by_label(partition_label, &index);
  330. if (err != ESP_OK) {
  331. esp_vfs_spiffs_conf_t conf = {
  332. .format_if_mount_failed = true,
  333. .partition_label = partition_label,
  334. .max_files = 1
  335. };
  336. err = esp_spiffs_init(&conf);
  337. if (err != ESP_OK) {
  338. return err;
  339. }
  340. err = esp_spiffs_by_label(partition_label, &index);
  341. assert(err == ESP_OK && "failed to get index of the partition just mounted");
  342. } else if (SPIFFS_mounted(_efs[index]->fs)) {
  343. partition_was_mounted = true;
  344. }
  345. SPIFFS_unmount(_efs[index]->fs);
  346. s32_t res = SPIFFS_format(_efs[index]->fs);
  347. if (res != SPIFFS_OK) {
  348. ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(_efs[index]->fs));
  349. SPIFFS_clearerr(_efs[index]->fs);
  350. /* If the partition was previously mounted, but format failed, don't
  351. * try to mount the partition back (it will probably fail). On the
  352. * other hand, if it was not mounted, need to clean up.
  353. */
  354. if (!partition_was_mounted) {
  355. esp_spiffs_free(&_efs[index]);
  356. }
  357. return ESP_FAIL;
  358. }
  359. if (partition_was_mounted) {
  360. res = SPIFFS_mount(_efs[index]->fs, &_efs[index]->cfg, _efs[index]->work,
  361. _efs[index]->fds, _efs[index]->fds_sz, _efs[index]->cache,
  362. _efs[index]->cache_sz, spiffs_api_check);
  363. if (res != SPIFFS_OK) {
  364. ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(_efs[index]->fs));
  365. SPIFFS_clearerr(_efs[index]->fs);
  366. return ESP_FAIL;
  367. }
  368. } else {
  369. esp_spiffs_free(&_efs[index]);
  370. }
  371. return ESP_OK;
  372. }
  373. esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf)
  374. {
  375. assert(conf->base_path);
  376. const esp_vfs_t vfs = {
  377. .flags = ESP_VFS_FLAG_CONTEXT_PTR,
  378. .write_p = &vfs_spiffs_write,
  379. .lseek_p = &vfs_spiffs_lseek,
  380. .read_p = &vfs_spiffs_read,
  381. .open_p = &vfs_spiffs_open,
  382. .close_p = &vfs_spiffs_close,
  383. .fstat_p = &vfs_spiffs_fstat,
  384. .stat_p = &vfs_spiffs_stat,
  385. .link_p = &vfs_spiffs_link,
  386. .unlink_p = &vfs_spiffs_unlink,
  387. .rename_p = &vfs_spiffs_rename,
  388. .opendir_p = &vfs_spiffs_opendir,
  389. .closedir_p = &vfs_spiffs_closedir,
  390. .readdir_p = &vfs_spiffs_readdir,
  391. .readdir_r_p = &vfs_spiffs_readdir_r,
  392. .seekdir_p = &vfs_spiffs_seekdir,
  393. .telldir_p = &vfs_spiffs_telldir,
  394. .mkdir_p = &vfs_spiffs_mkdir,
  395. .rmdir_p = &vfs_spiffs_rmdir
  396. };
  397. esp_err_t err = esp_spiffs_init(conf);
  398. if (err != ESP_OK) {
  399. return err;
  400. }
  401. int index;
  402. if (esp_spiffs_by_label(conf->partition_label, &index) != ESP_OK) {
  403. return ESP_ERR_INVALID_STATE;
  404. }
  405. strlcat(_efs[index]->base_path, conf->base_path, ESP_VFS_PATH_MAX + 1);
  406. err = esp_vfs_register(conf->base_path, &vfs, _efs[index]);
  407. if (err != ESP_OK) {
  408. esp_spiffs_free(&_efs[index]);
  409. return err;
  410. }
  411. return ESP_OK;
  412. }
  413. esp_err_t esp_vfs_spiffs_unregister(const char* partition_label)
  414. {
  415. int index;
  416. if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
  417. return ESP_ERR_INVALID_STATE;
  418. }
  419. esp_err_t err = esp_vfs_unregister(_efs[index]->base_path);
  420. if (err != ESP_OK) {
  421. return err;
  422. }
  423. esp_spiffs_free(&_efs[index]);
  424. return ESP_OK;
  425. }
  426. static int spiffs_res_to_errno(s32_t fr)
  427. {
  428. switch(fr) {
  429. case SPIFFS_OK :
  430. return 0;
  431. case SPIFFS_ERR_NOT_MOUNTED :
  432. return ENODEV;
  433. case SPIFFS_ERR_NOT_A_FS :
  434. return ENODEV;
  435. case SPIFFS_ERR_FULL :
  436. return ENOSPC;
  437. case SPIFFS_ERR_BAD_DESCRIPTOR :
  438. return EBADF;
  439. case SPIFFS_ERR_MOUNTED :
  440. return EEXIST;
  441. case SPIFFS_ERR_FILE_EXISTS :
  442. return EEXIST;
  443. case SPIFFS_ERR_NOT_FOUND :
  444. return ENOENT;
  445. case SPIFFS_ERR_NOT_A_FILE :
  446. return ENOENT;
  447. case SPIFFS_ERR_DELETED :
  448. return ENOENT;
  449. case SPIFFS_ERR_FILE_DELETED :
  450. return ENOENT;
  451. case SPIFFS_ERR_NAME_TOO_LONG :
  452. return ENAMETOOLONG;
  453. case SPIFFS_ERR_RO_NOT_IMPL :
  454. return EROFS;
  455. case SPIFFS_ERR_RO_ABORTED_OPERATION :
  456. return EROFS;
  457. default :
  458. return EIO;
  459. }
  460. return ENOTSUP;
  461. }
  462. static int spiffs_mode_conv(int m)
  463. {
  464. int res = 0;
  465. int acc_mode = m & O_ACCMODE;
  466. if (acc_mode == O_RDONLY) {
  467. res |= SPIFFS_O_RDONLY;
  468. } else if (acc_mode == O_WRONLY) {
  469. res |= SPIFFS_O_WRONLY;
  470. } else if (acc_mode == O_RDWR) {
  471. res |= SPIFFS_O_RDWR;
  472. }
  473. if ((m & O_CREAT) && (m & O_EXCL)) {
  474. res |= SPIFFS_O_CREAT | SPIFFS_O_EXCL;
  475. } else if ((m & O_CREAT) && (m & O_TRUNC)) {
  476. res |= SPIFFS_O_CREAT | SPIFFS_O_TRUNC;
  477. }
  478. if (m & O_APPEND) {
  479. res |= SPIFFS_O_CREAT | SPIFFS_O_APPEND;
  480. }
  481. return res;
  482. }
  483. static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode)
  484. {
  485. assert(path);
  486. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  487. int spiffs_flags = spiffs_mode_conv(flags);
  488. int fd = SPIFFS_open(efs->fs, path, spiffs_flags, mode);
  489. if (fd < 0) {
  490. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  491. SPIFFS_clearerr(efs->fs);
  492. return -1;
  493. }
  494. if (!(spiffs_flags & SPIFFS_RDONLY)) {
  495. vfs_spiffs_update_mtime(efs->fs, fd);
  496. }
  497. return fd;
  498. }
  499. static ssize_t vfs_spiffs_write(void* ctx, int fd, const void * data, size_t size)
  500. {
  501. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  502. ssize_t res = SPIFFS_write(efs->fs, fd, (void *)data, size);
  503. if (res < 0) {
  504. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  505. SPIFFS_clearerr(efs->fs);
  506. return -1;
  507. }
  508. return res;
  509. }
  510. static ssize_t vfs_spiffs_read(void* ctx, int fd, void * dst, size_t size)
  511. {
  512. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  513. ssize_t res = SPIFFS_read(efs->fs, fd, dst, size);
  514. if (res < 0) {
  515. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  516. SPIFFS_clearerr(efs->fs);
  517. return -1;
  518. }
  519. return res;
  520. }
  521. static int vfs_spiffs_close(void* ctx, int fd)
  522. {
  523. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  524. int res = SPIFFS_close(efs->fs, fd);
  525. if (res < 0) {
  526. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  527. SPIFFS_clearerr(efs->fs);
  528. return -1;
  529. }
  530. return res;
  531. }
  532. static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode)
  533. {
  534. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  535. off_t res = SPIFFS_lseek(efs->fs, fd, offset, mode);
  536. if (res < 0) {
  537. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  538. SPIFFS_clearerr(efs->fs);
  539. return -1;
  540. }
  541. return res;
  542. }
  543. static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
  544. {
  545. assert(st);
  546. spiffs_stat s;
  547. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  548. off_t res = SPIFFS_fstat(efs->fs, fd, &s);
  549. if (res < 0) {
  550. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  551. SPIFFS_clearerr(efs->fs);
  552. return -1;
  553. }
  554. st->st_size = s.size;
  555. st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
  556. st->st_mtime = vfs_spiffs_get_mtime(&s);
  557. st->st_atime = 0;
  558. st->st_ctime = 0;
  559. return res;
  560. }
  561. static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st)
  562. {
  563. assert(path);
  564. assert(st);
  565. spiffs_stat s;
  566. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  567. off_t res = SPIFFS_stat(efs->fs, path, &s);
  568. if (res < 0) {
  569. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  570. SPIFFS_clearerr(efs->fs);
  571. return -1;
  572. }
  573. st->st_size = s.size;
  574. st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
  575. st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG;
  576. st->st_mtime = vfs_spiffs_get_mtime(&s);
  577. st->st_atime = 0;
  578. st->st_ctime = 0;
  579. return res;
  580. }
  581. static int vfs_spiffs_rename(void* ctx, const char *src, const char *dst)
  582. {
  583. assert(src);
  584. assert(dst);
  585. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  586. int res = SPIFFS_rename(efs->fs, src, dst);
  587. if (res < 0) {
  588. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  589. SPIFFS_clearerr(efs->fs);
  590. return -1;
  591. }
  592. return res;
  593. }
  594. static int vfs_spiffs_unlink(void* ctx, const char *path)
  595. {
  596. assert(path);
  597. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  598. int res = SPIFFS_remove(efs->fs, path);
  599. if (res < 0) {
  600. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  601. SPIFFS_clearerr(efs->fs);
  602. return -1;
  603. }
  604. return res;
  605. }
  606. static DIR* vfs_spiffs_opendir(void* ctx, const char* name)
  607. {
  608. assert(name);
  609. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  610. vfs_spiffs_dir_t * dir = calloc(1, sizeof(vfs_spiffs_dir_t));
  611. if (!dir) {
  612. errno = ENOMEM;
  613. return NULL;
  614. }
  615. if (!SPIFFS_opendir(efs->fs, name, &dir->d)) {
  616. free(dir);
  617. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  618. SPIFFS_clearerr(efs->fs);
  619. return NULL;
  620. }
  621. dir->offset = 0;
  622. strlcpy(dir->path, name, SPIFFS_OBJ_NAME_LEN);
  623. return (DIR*) dir;
  624. }
  625. static int vfs_spiffs_closedir(void* ctx, DIR* pdir)
  626. {
  627. assert(pdir);
  628. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  629. vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
  630. int res = SPIFFS_closedir(&dir->d);
  631. free(dir);
  632. if (res < 0) {
  633. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  634. SPIFFS_clearerr(efs->fs);
  635. return -1;
  636. }
  637. return res;
  638. }
  639. static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir)
  640. {
  641. assert(pdir);
  642. vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
  643. struct dirent* out_dirent;
  644. int err = vfs_spiffs_readdir_r(ctx, pdir, &dir->e, &out_dirent);
  645. if (err != 0) {
  646. errno = err;
  647. return NULL;
  648. }
  649. return out_dirent;
  650. }
  651. static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry,
  652. struct dirent** out_dirent)
  653. {
  654. assert(pdir);
  655. esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
  656. vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
  657. struct spiffs_dirent out;
  658. if (SPIFFS_readdir(&dir->d, &out) == 0) {
  659. errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
  660. SPIFFS_clearerr(efs->fs);
  661. if (!errno) {
  662. *out_dirent = NULL;
  663. }
  664. return errno;
  665. }
  666. const char * item_name = (const char *)out.name;
  667. size_t plen = strlen(dir->path);
  668. if (plen > 1) {
  669. if (strncasecmp(dir->path, (const char *)out.name, plen) || out.name[plen] != '/' || !out.name[plen+1]) {
  670. return vfs_spiffs_readdir_r(ctx, pdir, entry, out_dirent);
  671. }
  672. item_name += plen + 1;
  673. } else if (item_name[0] == '/') {
  674. item_name++;
  675. }
  676. entry->d_ino = 0;
  677. entry->d_type = out.type;
  678. snprintf(entry->d_name, SPIFFS_OBJ_NAME_LEN, "%s", item_name);
  679. dir->offset++;
  680. *out_dirent = entry;
  681. return 0;
  682. }
  683. static long vfs_spiffs_telldir(void* ctx, DIR* pdir)
  684. {
  685. assert(pdir);
  686. vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
  687. return dir->offset;
  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. static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode)
  721. {
  722. errno = ENOTSUP;
  723. return -1;
  724. }
  725. static int vfs_spiffs_rmdir(void* ctx, const char* name)
  726. {
  727. errno = ENOTSUP;
  728. return -1;
  729. }
  730. static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2)
  731. {
  732. errno = ENOTSUP;
  733. return -1;
  734. }
  735. static void vfs_spiffs_update_mtime(spiffs *fs, spiffs_file fd)
  736. {
  737. #ifdef CONFIG_SPIFFS_USE_MTIME
  738. time_t t = time(NULL);
  739. spiffs_stat s;
  740. int ret = SPIFFS_OK;
  741. if (CONFIG_SPIFFS_META_LENGTH > sizeof(t)) {
  742. ret = SPIFFS_fstat(fs, fd, &s);
  743. }
  744. if (ret == SPIFFS_OK) {
  745. memcpy(s.meta, &t, sizeof(t));
  746. ret = SPIFFS_fupdate_meta(fs, fd, s.meta);
  747. }
  748. if (ret != SPIFFS_OK) {
  749. ESP_LOGW(TAG, "Failed to update mtime (%d)", ret);
  750. }
  751. #endif //CONFIG_SPIFFS_USE_MTIME
  752. }
  753. static time_t vfs_spiffs_get_mtime(const spiffs_stat* s)
  754. {
  755. time_t t = 0;
  756. #ifdef CONFIG_SPIFFS_USE_MTIME
  757. memcpy(&t, s->meta, sizeof(t));
  758. #endif
  759. return t;
  760. }