vfs_fat.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. // Copyright 2015-2016 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 <string.h>
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #include <dirent.h>
  18. #include <sys/errno.h>
  19. #include <sys/fcntl.h>
  20. #include <sys/lock.h>
  21. #include "esp_vfs.h"
  22. #include "esp_log.h"
  23. #include "ff.h"
  24. #include "diskio_impl.h"
  25. typedef struct {
  26. char fat_drive[8]; /* FAT drive name */
  27. char base_path[ESP_VFS_PATH_MAX]; /* base path in VFS where partition is registered */
  28. size_t max_files; /* max number of simultaneously open files; size of files[] array */
  29. _lock_t lock; /* guard for access to this structure */
  30. FATFS fs; /* fatfs library FS structure */
  31. char tmp_path_buf[FILENAME_MAX+3]; /* temporary buffer used to prepend drive name to the path */
  32. char tmp_path_buf2[FILENAME_MAX+3]; /* as above; used in functions which take two path arguments */
  33. bool *o_append; /* O_APPEND is stored here for each max_files entries (because O_APPEND is not compatible with FA_OPEN_APPEND) */
  34. FIL files[0]; /* array with max_files entries; must be the final member of the structure */
  35. } vfs_fat_ctx_t;
  36. typedef struct {
  37. DIR dir;
  38. long offset;
  39. FF_DIR ffdir;
  40. FILINFO filinfo;
  41. struct dirent cur_dirent;
  42. } vfs_fat_dir_t;
  43. /* Date and time storage formats in FAT */
  44. typedef union {
  45. struct {
  46. uint16_t mday : 5; /* Day of month, 1 - 31 */
  47. uint16_t mon : 4; /* Month, 1 - 12 */
  48. uint16_t year : 7; /* Year, counting from 1980. E.g. 37 for 2017 */
  49. };
  50. uint16_t as_int;
  51. } fat_date_t;
  52. typedef union {
  53. struct {
  54. uint16_t sec : 5; /* Seconds divided by 2. E.g. 21 for 42 seconds */
  55. uint16_t min : 6; /* Minutes, 0 - 59 */
  56. uint16_t hour : 5; /* Hour, 0 - 23 */
  57. };
  58. uint16_t as_int;
  59. } fat_time_t;
  60. static const char* TAG = "vfs_fat";
  61. static ssize_t vfs_fat_write(void* p, int fd, const void * data, size_t size);
  62. static off_t vfs_fat_lseek(void* p, int fd, off_t size, int mode);
  63. static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size);
  64. static ssize_t vfs_fat_pread(void *ctx, int fd, void *dst, size_t size, off_t offset);
  65. static ssize_t vfs_fat_pwrite(void *ctx, int fd, const void *src, size_t size, off_t offset);
  66. static int vfs_fat_open(void* ctx, const char * path, int flags, int mode);
  67. static int vfs_fat_close(void* ctx, int fd);
  68. static int vfs_fat_fstat(void* ctx, int fd, struct stat * st);
  69. static int vfs_fat_fsync(void* ctx, int fd);
  70. #ifdef CONFIG_VFS_SUPPORT_DIR
  71. static int vfs_fat_stat(void* ctx, const char * path, struct stat * st);
  72. static int vfs_fat_link(void* ctx, const char* n1, const char* n2);
  73. static int vfs_fat_unlink(void* ctx, const char *path);
  74. static int vfs_fat_rename(void* ctx, const char *src, const char *dst);
  75. static DIR* vfs_fat_opendir(void* ctx, const char* name);
  76. static struct dirent* vfs_fat_readdir(void* ctx, DIR* pdir);
  77. static int vfs_fat_readdir_r(void* ctx, DIR* pdir, struct dirent* entry, struct dirent** out_dirent);
  78. static long vfs_fat_telldir(void* ctx, DIR* pdir);
  79. static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset);
  80. static int vfs_fat_closedir(void* ctx, DIR* pdir);
  81. static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode);
  82. static int vfs_fat_rmdir(void* ctx, const char* name);
  83. static int vfs_fat_access(void* ctx, const char *path, int amode);
  84. static int vfs_fat_truncate(void* ctx, const char *path, off_t length);
  85. static int vfs_fat_utime(void* ctx, const char *path, const struct utimbuf *times);
  86. #endif // CONFIG_VFS_SUPPORT_DIR
  87. static vfs_fat_ctx_t* s_fat_ctxs[FF_VOLUMES] = { NULL, NULL };
  88. //backwards-compatibility with esp_vfs_fat_unregister()
  89. static vfs_fat_ctx_t* s_fat_ctx = NULL;
  90. static size_t find_context_index_by_path(const char* base_path)
  91. {
  92. for(size_t i=0; i<FF_VOLUMES; i++) {
  93. if (s_fat_ctxs[i] && !strcmp(s_fat_ctxs[i]->base_path, base_path)) {
  94. return i;
  95. }
  96. }
  97. return FF_VOLUMES;
  98. }
  99. static size_t find_unused_context_index(void)
  100. {
  101. for(size_t i=0; i<FF_VOLUMES; i++) {
  102. if (!s_fat_ctxs[i]) {
  103. return i;
  104. }
  105. }
  106. return FF_VOLUMES;
  107. }
  108. esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive, size_t max_files, FATFS** out_fs)
  109. {
  110. size_t ctx = find_context_index_by_path(base_path);
  111. if (ctx < FF_VOLUMES) {
  112. return ESP_ERR_INVALID_STATE;
  113. }
  114. ctx = find_unused_context_index();
  115. if (ctx == FF_VOLUMES) {
  116. return ESP_ERR_NO_MEM;
  117. }
  118. const esp_vfs_t vfs = {
  119. .flags = ESP_VFS_FLAG_CONTEXT_PTR,
  120. .write_p = &vfs_fat_write,
  121. .lseek_p = &vfs_fat_lseek,
  122. .read_p = &vfs_fat_read,
  123. .pread_p = &vfs_fat_pread,
  124. .pwrite_p = &vfs_fat_pwrite,
  125. .open_p = &vfs_fat_open,
  126. .close_p = &vfs_fat_close,
  127. .fstat_p = &vfs_fat_fstat,
  128. .fsync_p = &vfs_fat_fsync,
  129. #ifdef CONFIG_VFS_SUPPORT_DIR
  130. .stat_p = &vfs_fat_stat,
  131. .link_p = &vfs_fat_link,
  132. .unlink_p = &vfs_fat_unlink,
  133. .rename_p = &vfs_fat_rename,
  134. .opendir_p = &vfs_fat_opendir,
  135. .closedir_p = &vfs_fat_closedir,
  136. .readdir_p = &vfs_fat_readdir,
  137. .readdir_r_p = &vfs_fat_readdir_r,
  138. .seekdir_p = &vfs_fat_seekdir,
  139. .telldir_p = &vfs_fat_telldir,
  140. .mkdir_p = &vfs_fat_mkdir,
  141. .rmdir_p = &vfs_fat_rmdir,
  142. .access_p = &vfs_fat_access,
  143. .truncate_p = &vfs_fat_truncate,
  144. .utime_p = &vfs_fat_utime,
  145. #endif // CONFIG_VFS_SUPPORT_DIR
  146. };
  147. size_t ctx_size = sizeof(vfs_fat_ctx_t) + max_files * sizeof(FIL);
  148. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ff_memalloc(ctx_size);
  149. if (fat_ctx == NULL) {
  150. return ESP_ERR_NO_MEM;
  151. }
  152. memset(fat_ctx, 0, ctx_size);
  153. fat_ctx->o_append = ff_memalloc(max_files * sizeof(bool));
  154. if (fat_ctx->o_append == NULL) {
  155. free(fat_ctx);
  156. return ESP_ERR_NO_MEM;
  157. }
  158. memset(fat_ctx->o_append, 0, max_files * sizeof(bool));
  159. fat_ctx->max_files = max_files;
  160. strlcpy(fat_ctx->fat_drive, fat_drive, sizeof(fat_ctx->fat_drive) - 1);
  161. strlcpy(fat_ctx->base_path, base_path, sizeof(fat_ctx->base_path) - 1);
  162. esp_err_t err = esp_vfs_register(base_path, &vfs, fat_ctx);
  163. if (err != ESP_OK) {
  164. free(fat_ctx->o_append);
  165. free(fat_ctx);
  166. return err;
  167. }
  168. _lock_init(&fat_ctx->lock);
  169. s_fat_ctxs[ctx] = fat_ctx;
  170. //compatibility
  171. s_fat_ctx = fat_ctx;
  172. *out_fs = &fat_ctx->fs;
  173. return ESP_OK;
  174. }
  175. esp_err_t esp_vfs_fat_unregister_path(const char* base_path)
  176. {
  177. size_t ctx = find_context_index_by_path(base_path);
  178. if (ctx == FF_VOLUMES) {
  179. return ESP_ERR_INVALID_STATE;
  180. }
  181. vfs_fat_ctx_t* fat_ctx = s_fat_ctxs[ctx];
  182. esp_err_t err = esp_vfs_unregister(fat_ctx->base_path);
  183. if (err != ESP_OK) {
  184. return err;
  185. }
  186. _lock_close(&fat_ctx->lock);
  187. free(fat_ctx->o_append);
  188. free(fat_ctx);
  189. s_fat_ctxs[ctx] = NULL;
  190. return ESP_OK;
  191. }
  192. static int get_next_fd(vfs_fat_ctx_t* fat_ctx)
  193. {
  194. for (size_t i = 0; i < fat_ctx->max_files; ++i) {
  195. if (fat_ctx->files[i].obj.fs == NULL) {
  196. return (int) i;
  197. }
  198. }
  199. return -1;
  200. }
  201. static int fat_mode_conv(int m)
  202. {
  203. int res = 0;
  204. int acc_mode = m & O_ACCMODE;
  205. if (acc_mode == O_RDONLY) {
  206. res |= FA_READ;
  207. } else if (acc_mode == O_WRONLY) {
  208. res |= FA_WRITE;
  209. } else if (acc_mode == O_RDWR) {
  210. res |= FA_READ | FA_WRITE;
  211. }
  212. if ((m & O_CREAT) && (m & O_EXCL)) {
  213. res |= FA_CREATE_NEW;
  214. } else if ((m & O_CREAT) && (m & O_TRUNC)) {
  215. res |= FA_CREATE_ALWAYS;
  216. } else if (m & O_APPEND) {
  217. res |= FA_OPEN_ALWAYS;
  218. } else {
  219. res |= FA_OPEN_EXISTING;
  220. }
  221. return res;
  222. }
  223. static int fresult_to_errno(FRESULT fr)
  224. {
  225. switch(fr) {
  226. case FR_DISK_ERR: return EIO;
  227. case FR_INT_ERR: return EIO;
  228. case FR_NOT_READY: return ENODEV;
  229. case FR_NO_FILE: return ENOENT;
  230. case FR_NO_PATH: return ENOENT;
  231. case FR_INVALID_NAME: return EINVAL;
  232. case FR_DENIED: return EACCES;
  233. case FR_EXIST: return EEXIST;
  234. case FR_INVALID_OBJECT: return EBADF;
  235. case FR_WRITE_PROTECTED: return EACCES;
  236. case FR_INVALID_DRIVE: return ENXIO;
  237. case FR_NOT_ENABLED: return ENODEV;
  238. case FR_NO_FILESYSTEM: return ENODEV;
  239. case FR_MKFS_ABORTED: return EINTR;
  240. case FR_TIMEOUT: return ETIMEDOUT;
  241. case FR_LOCKED: return EACCES;
  242. case FR_NOT_ENOUGH_CORE: return ENOMEM;
  243. case FR_TOO_MANY_OPEN_FILES: return ENFILE;
  244. case FR_INVALID_PARAMETER: return EINVAL;
  245. case FR_OK: return 0;
  246. }
  247. assert(0 && "unhandled FRESULT");
  248. return ENOTSUP;
  249. }
  250. static void file_cleanup(vfs_fat_ctx_t* ctx, int fd)
  251. {
  252. memset(&ctx->files[fd], 0, sizeof(FIL));
  253. }
  254. /**
  255. * @brief Prepend drive letters to path names
  256. * This function returns new path path pointers, pointing to a temporary buffer
  257. * inside ctx.
  258. * @note Call this function with ctx->lock acquired. Paths are valid while the
  259. * lock is held.
  260. * @param ctx vfs_fat_ctx_t context
  261. * @param[inout] path as input, pointer to the path; as output, pointer to the new path
  262. * @param[inout] path2 as input, pointer to the path; as output, pointer to the new path
  263. */
  264. static void prepend_drive_to_path(vfs_fat_ctx_t * ctx, const char ** path, const char ** path2){
  265. snprintf(ctx->tmp_path_buf, sizeof(ctx->tmp_path_buf), "%s%s", ctx->fat_drive, *path);
  266. *path = ctx->tmp_path_buf;
  267. if(path2){
  268. snprintf(ctx->tmp_path_buf2, sizeof(ctx->tmp_path_buf2), "%s%s", ((vfs_fat_ctx_t*)ctx)->fat_drive, *path2);
  269. *path2 = ctx->tmp_path_buf2;
  270. }
  271. }
  272. static int vfs_fat_open(void* ctx, const char * path, int flags, int mode)
  273. {
  274. ESP_LOGV(TAG, "%s: path=\"%s\", flags=%x, mode=%x", __func__, path, flags, mode);
  275. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  276. _lock_acquire(&fat_ctx->lock);
  277. prepend_drive_to_path(fat_ctx, &path, NULL);
  278. int fd = get_next_fd(fat_ctx);
  279. if (fd < 0) {
  280. _lock_release(&fat_ctx->lock);
  281. ESP_LOGE(TAG, "open: no free file descriptors");
  282. errno = ENFILE;
  283. return -1;
  284. }
  285. FRESULT res = f_open(&fat_ctx->files[fd], path, fat_mode_conv(flags));
  286. if (res != FR_OK) {
  287. file_cleanup(fat_ctx, fd);
  288. _lock_release(&fat_ctx->lock);
  289. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  290. errno = fresult_to_errno(res);
  291. return -1;
  292. }
  293. // O_APPEND need to be stored because it is not compatible with FA_OPEN_APPEND:
  294. // - FA_OPEN_APPEND means to jump to the end of file only after open()
  295. // - O_APPEND means to jump to the end only before each write()
  296. // Other VFS drivers handles O_APPEND well (to the best of my knowledge),
  297. // therefore this flag is stored here (at this VFS level) in order to save
  298. // memory.
  299. fat_ctx->o_append[fd] = (flags & O_APPEND) == O_APPEND;
  300. _lock_release(&fat_ctx->lock);
  301. return fd;
  302. }
  303. static ssize_t vfs_fat_write(void* ctx, int fd, const void * data, size_t size)
  304. {
  305. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  306. FIL* file = &fat_ctx->files[fd];
  307. FRESULT res;
  308. if (fat_ctx->o_append[fd]) {
  309. if ((res = f_lseek(file, f_size(file))) != FR_OK) {
  310. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  311. errno = fresult_to_errno(res);
  312. return -1;
  313. }
  314. }
  315. unsigned written = 0;
  316. res = f_write(file, data, size, &written);
  317. if (res != FR_OK) {
  318. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  319. errno = fresult_to_errno(res);
  320. if (written == 0) {
  321. return -1;
  322. }
  323. }
  324. return written;
  325. }
  326. static ssize_t vfs_fat_read(void* ctx, int fd, void * dst, size_t size)
  327. {
  328. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  329. FIL* file = &fat_ctx->files[fd];
  330. unsigned read = 0;
  331. FRESULT res = f_read(file, dst, size, &read);
  332. if (res != FR_OK) {
  333. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  334. errno = fresult_to_errno(res);
  335. if (read == 0) {
  336. return -1;
  337. }
  338. }
  339. return read;
  340. }
  341. static ssize_t vfs_fat_pread(void *ctx, int fd, void *dst, size_t size, off_t offset)
  342. {
  343. ssize_t ret = -1;
  344. vfs_fat_ctx_t *fat_ctx = (vfs_fat_ctx_t *) ctx;
  345. _lock_acquire(&fat_ctx->lock);
  346. FIL *file = &fat_ctx->files[fd];
  347. const off_t prev_pos = f_tell(file);
  348. FRESULT f_res = f_lseek(file, offset);
  349. if (f_res != FR_OK) {
  350. ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res);
  351. errno = fresult_to_errno(f_res);
  352. goto pread_release;
  353. }
  354. unsigned read = 0;
  355. f_res = f_read(file, dst, size, &read);
  356. if (f_res == FR_OK) {
  357. ret = read;
  358. } else {
  359. ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res);
  360. errno = fresult_to_errno(f_res);
  361. // No return yet - need to restore previous position
  362. }
  363. f_res = f_lseek(file, prev_pos);
  364. if (f_res != FR_OK) {
  365. ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res);
  366. if (ret >= 0) {
  367. errno = fresult_to_errno(f_res);
  368. } // else f_read failed so errno shouldn't be overwritten
  369. ret = -1; // in case the read was successful but the seek wasn't
  370. }
  371. pread_release:
  372. _lock_release(&fat_ctx->lock);
  373. return ret;
  374. }
  375. static ssize_t vfs_fat_pwrite(void *ctx, int fd, const void *src, size_t size, off_t offset)
  376. {
  377. ssize_t ret = -1;
  378. vfs_fat_ctx_t *fat_ctx = (vfs_fat_ctx_t *) ctx;
  379. _lock_acquire(&fat_ctx->lock);
  380. FIL *file = &fat_ctx->files[fd];
  381. const off_t prev_pos = f_tell(file);
  382. FRESULT f_res = f_lseek(file, offset);
  383. if (f_res != FR_OK) {
  384. ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res);
  385. errno = fresult_to_errno(f_res);
  386. goto pwrite_release;
  387. }
  388. unsigned wr = 0;
  389. f_res = f_write(file, src, size, &wr);
  390. if (f_res == FR_OK) {
  391. ret = wr;
  392. } else {
  393. ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res);
  394. errno = fresult_to_errno(f_res);
  395. // No return yet - need to restore previous position
  396. }
  397. f_res = f_lseek(file, prev_pos);
  398. if (f_res != FR_OK) {
  399. ESP_LOGD(TAG, "%s: fresult=%d", __func__, f_res);
  400. if (ret >= 0) {
  401. errno = fresult_to_errno(f_res);
  402. } // else f_write failed so errno shouldn't be overwritten
  403. ret = -1; // in case the write was successful but the seek wasn't
  404. }
  405. pwrite_release:
  406. _lock_release(&fat_ctx->lock);
  407. return ret;
  408. }
  409. static int vfs_fat_fsync(void* ctx, int fd)
  410. {
  411. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  412. _lock_acquire(&fat_ctx->lock);
  413. FIL* file = &fat_ctx->files[fd];
  414. FRESULT res = f_sync(file);
  415. _lock_release(&fat_ctx->lock);
  416. int rc = 0;
  417. if (res != FR_OK) {
  418. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  419. errno = fresult_to_errno(res);
  420. rc = -1;
  421. }
  422. return rc;
  423. }
  424. static int vfs_fat_close(void* ctx, int fd)
  425. {
  426. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  427. _lock_acquire(&fat_ctx->lock);
  428. FIL* file = &fat_ctx->files[fd];
  429. FRESULT res = f_close(file);
  430. file_cleanup(fat_ctx, fd);
  431. _lock_release(&fat_ctx->lock);
  432. int rc = 0;
  433. if (res != FR_OK) {
  434. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  435. errno = fresult_to_errno(res);
  436. rc = -1;
  437. }
  438. return rc;
  439. }
  440. static off_t vfs_fat_lseek(void* ctx, int fd, off_t offset, int mode)
  441. {
  442. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  443. FIL* file = &fat_ctx->files[fd];
  444. off_t new_pos;
  445. if (mode == SEEK_SET) {
  446. new_pos = offset;
  447. } else if (mode == SEEK_CUR) {
  448. off_t cur_pos = f_tell(file);
  449. new_pos = cur_pos + offset;
  450. } else if (mode == SEEK_END) {
  451. off_t size = f_size(file);
  452. new_pos = size + offset;
  453. } else {
  454. errno = EINVAL;
  455. return -1;
  456. }
  457. FRESULT res = f_lseek(file, new_pos);
  458. if (res != FR_OK) {
  459. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  460. errno = fresult_to_errno(res);
  461. return -1;
  462. }
  463. return new_pos;
  464. }
  465. static int vfs_fat_fstat(void* ctx, int fd, struct stat * st)
  466. {
  467. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  468. FIL* file = &fat_ctx->files[fd];
  469. st->st_size = f_size(file);
  470. st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
  471. st->st_mtime = 0;
  472. st->st_atime = 0;
  473. st->st_ctime = 0;
  474. return 0;
  475. }
  476. #ifdef CONFIG_VFS_SUPPORT_DIR
  477. static inline mode_t get_stat_mode(bool is_dir)
  478. {
  479. return S_IRWXU | S_IRWXG | S_IRWXO |
  480. ((is_dir) ? S_IFDIR : S_IFREG);
  481. }
  482. static int vfs_fat_stat(void* ctx, const char * path, struct stat * st)
  483. {
  484. if (strcmp(path, "/") == 0) {
  485. /* FatFS f_stat function does not work for the drive root.
  486. * Just pretend that this is a directory.
  487. */
  488. memset(st, 0, sizeof(*st));
  489. st->st_mode = get_stat_mode(true);
  490. return 0;
  491. }
  492. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  493. _lock_acquire(&fat_ctx->lock);
  494. prepend_drive_to_path(fat_ctx, &path, NULL);
  495. FILINFO info;
  496. FRESULT res = f_stat(path, &info);
  497. _lock_release(&fat_ctx->lock);
  498. if (res != FR_OK) {
  499. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  500. errno = fresult_to_errno(res);
  501. return -1;
  502. }
  503. memset(st, 0, sizeof(*st));
  504. st->st_size = info.fsize;
  505. st->st_mode = get_stat_mode((info.fattrib & AM_DIR) != 0);
  506. fat_date_t fdate = { .as_int = info.fdate };
  507. fat_time_t ftime = { .as_int = info.ftime };
  508. struct tm tm = {
  509. .tm_mday = fdate.mday,
  510. .tm_mon = fdate.mon - 1, /* unlike tm_mday, tm_mon is zero-based */
  511. .tm_year = fdate.year + 80,
  512. .tm_sec = ftime.sec * 2,
  513. .tm_min = ftime.min,
  514. .tm_hour = ftime.hour
  515. };
  516. st->st_mtime = mktime(&tm);
  517. st->st_atime = 0;
  518. st->st_ctime = 0;
  519. return 0;
  520. }
  521. static int vfs_fat_unlink(void* ctx, const char *path)
  522. {
  523. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  524. _lock_acquire(&fat_ctx->lock);
  525. prepend_drive_to_path(fat_ctx, &path, NULL);
  526. FRESULT res = f_unlink(path);
  527. _lock_release(&fat_ctx->lock);
  528. if (res != FR_OK) {
  529. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  530. errno = fresult_to_errno(res);
  531. return -1;
  532. }
  533. return 0;
  534. }
  535. static int vfs_fat_link(void* ctx, const char* n1, const char* n2)
  536. {
  537. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  538. _lock_acquire(&fat_ctx->lock);
  539. prepend_drive_to_path(fat_ctx, &n1, &n2);
  540. const size_t copy_buf_size = fat_ctx->fs.csize;
  541. FRESULT res;
  542. FIL* pf1 = (FIL*) ff_memalloc(sizeof(FIL));
  543. FIL* pf2 = (FIL*) ff_memalloc(sizeof(FIL));
  544. void* buf = ff_memalloc(copy_buf_size);
  545. if (buf == NULL || pf1 == NULL || pf2 == NULL) {
  546. _lock_release(&fat_ctx->lock);
  547. ESP_LOGD(TAG, "alloc failed, pf1=%p, pf2=%p, buf=%p", pf1, pf2, buf);
  548. free(pf1);
  549. free(pf2);
  550. free(buf);
  551. errno = ENOMEM;
  552. return -1;
  553. }
  554. memset(pf1, 0, sizeof(*pf1));
  555. memset(pf2, 0, sizeof(*pf2));
  556. res = f_open(pf1, n1, FA_READ | FA_OPEN_EXISTING);
  557. if (res != FR_OK) {
  558. _lock_release(&fat_ctx->lock);
  559. goto fail1;
  560. }
  561. res = f_open(pf2, n2, FA_WRITE | FA_CREATE_NEW);
  562. _lock_release(&fat_ctx->lock);
  563. if (res != FR_OK) {
  564. goto fail2;
  565. }
  566. size_t size_left = f_size(pf1);
  567. while (size_left > 0) {
  568. size_t will_copy = (size_left < copy_buf_size) ? size_left : copy_buf_size;
  569. size_t read;
  570. res = f_read(pf1, buf, will_copy, &read);
  571. if (res != FR_OK) {
  572. goto fail3;
  573. } else if (read != will_copy) {
  574. res = FR_DISK_ERR;
  575. goto fail3;
  576. }
  577. size_t written;
  578. res = f_write(pf2, buf, will_copy, &written);
  579. if (res != FR_OK) {
  580. goto fail3;
  581. } else if (written != will_copy) {
  582. res = FR_DISK_ERR;
  583. goto fail3;
  584. }
  585. size_left -= will_copy;
  586. }
  587. fail3:
  588. f_close(pf2);
  589. fail2:
  590. f_close(pf1);
  591. fail1:
  592. free(buf);
  593. free(pf2);
  594. free(pf1);
  595. if (res != FR_OK) {
  596. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  597. errno = fresult_to_errno(res);
  598. return -1;
  599. }
  600. return 0;
  601. }
  602. static int vfs_fat_rename(void* ctx, const char *src, const char *dst)
  603. {
  604. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  605. _lock_acquire(&fat_ctx->lock);
  606. prepend_drive_to_path(fat_ctx, &src, &dst);
  607. FRESULT res = f_rename(src, dst);
  608. _lock_release(&fat_ctx->lock);
  609. if (res != FR_OK) {
  610. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  611. errno = fresult_to_errno(res);
  612. return -1;
  613. }
  614. return 0;
  615. }
  616. static DIR* vfs_fat_opendir(void* ctx, const char* name)
  617. {
  618. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  619. _lock_acquire(&fat_ctx->lock);
  620. prepend_drive_to_path(fat_ctx, &name, NULL);
  621. vfs_fat_dir_t* fat_dir = ff_memalloc(sizeof(vfs_fat_dir_t));
  622. if (!fat_dir) {
  623. _lock_release(&fat_ctx->lock);
  624. errno = ENOMEM;
  625. return NULL;
  626. }
  627. memset(fat_dir, 0, sizeof(*fat_dir));
  628. FRESULT res = f_opendir(&fat_dir->ffdir, name);
  629. _lock_release(&fat_ctx->lock);
  630. if (res != FR_OK) {
  631. free(fat_dir);
  632. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  633. errno = fresult_to_errno(res);
  634. return NULL;
  635. }
  636. return (DIR*) fat_dir;
  637. }
  638. static int vfs_fat_closedir(void* ctx, DIR* pdir)
  639. {
  640. assert(pdir);
  641. vfs_fat_dir_t* fat_dir = (vfs_fat_dir_t*) pdir;
  642. FRESULT res = f_closedir(&fat_dir->ffdir);
  643. free(pdir);
  644. if (res != FR_OK) {
  645. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  646. errno = fresult_to_errno(res);
  647. return -1;
  648. }
  649. return 0;
  650. }
  651. static struct dirent* vfs_fat_readdir(void* ctx, DIR* pdir)
  652. {
  653. vfs_fat_dir_t* fat_dir = (vfs_fat_dir_t*) pdir;
  654. struct dirent* out_dirent;
  655. int err = vfs_fat_readdir_r(ctx, pdir, &fat_dir->cur_dirent, &out_dirent);
  656. if (err != 0) {
  657. errno = err;
  658. return NULL;
  659. }
  660. return out_dirent;
  661. }
  662. static int vfs_fat_readdir_r(void* ctx, DIR* pdir,
  663. struct dirent* entry, struct dirent** out_dirent)
  664. {
  665. assert(pdir);
  666. vfs_fat_dir_t* fat_dir = (vfs_fat_dir_t*) pdir;
  667. FRESULT res = f_readdir(&fat_dir->ffdir, &fat_dir->filinfo);
  668. if (res != FR_OK) {
  669. *out_dirent = NULL;
  670. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  671. return fresult_to_errno(res);
  672. }
  673. if (fat_dir->filinfo.fname[0] == 0) {
  674. // end of directory
  675. *out_dirent = NULL;
  676. return 0;
  677. }
  678. entry->d_ino = 0;
  679. if (fat_dir->filinfo.fattrib & AM_DIR) {
  680. entry->d_type = DT_DIR;
  681. } else {
  682. entry->d_type = DT_REG;
  683. }
  684. strlcpy(entry->d_name, fat_dir->filinfo.fname,
  685. sizeof(entry->d_name));
  686. fat_dir->offset++;
  687. *out_dirent = entry;
  688. return 0;
  689. }
  690. static long vfs_fat_telldir(void* ctx, DIR* pdir)
  691. {
  692. assert(pdir);
  693. vfs_fat_dir_t* fat_dir = (vfs_fat_dir_t*) pdir;
  694. return fat_dir->offset;
  695. }
  696. static void vfs_fat_seekdir(void* ctx, DIR* pdir, long offset)
  697. {
  698. assert(pdir);
  699. vfs_fat_dir_t* fat_dir = (vfs_fat_dir_t*) pdir;
  700. FRESULT res;
  701. if (offset < fat_dir->offset) {
  702. res = f_rewinddir(&fat_dir->ffdir);
  703. if (res != FR_OK) {
  704. ESP_LOGD(TAG, "%s: rewinddir fresult=%d", __func__, res);
  705. errno = fresult_to_errno(res);
  706. return;
  707. }
  708. fat_dir->offset = 0;
  709. }
  710. while (fat_dir->offset < offset) {
  711. res = f_readdir(&fat_dir->ffdir, &fat_dir->filinfo);
  712. if (res != FR_OK) {
  713. ESP_LOGD(TAG, "%s: f_readdir fresult=%d", __func__, res);
  714. errno = fresult_to_errno(res);
  715. return;
  716. }
  717. fat_dir->offset++;
  718. }
  719. }
  720. static int vfs_fat_mkdir(void* ctx, const char* name, mode_t mode)
  721. {
  722. (void) mode;
  723. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  724. _lock_acquire(&fat_ctx->lock);
  725. prepend_drive_to_path(fat_ctx, &name, NULL);
  726. FRESULT res = f_mkdir(name);
  727. _lock_release(&fat_ctx->lock);
  728. if (res != FR_OK) {
  729. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  730. errno = fresult_to_errno(res);
  731. return -1;
  732. }
  733. return 0;
  734. }
  735. static int vfs_fat_rmdir(void* ctx, const char* name)
  736. {
  737. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  738. _lock_acquire(&fat_ctx->lock);
  739. prepend_drive_to_path(fat_ctx, &name, NULL);
  740. FRESULT res = f_unlink(name);
  741. _lock_release(&fat_ctx->lock);
  742. if (res != FR_OK) {
  743. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  744. errno = fresult_to_errno(res);
  745. return -1;
  746. }
  747. return 0;
  748. }
  749. static int vfs_fat_access(void* ctx, const char *path, int amode)
  750. {
  751. FILINFO info;
  752. int ret = 0;
  753. FRESULT res;
  754. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  755. _lock_acquire(&fat_ctx->lock);
  756. prepend_drive_to_path(fat_ctx, &path, NULL);
  757. res = f_stat(path, &info);
  758. _lock_release(&fat_ctx->lock);
  759. if (res == FR_OK) {
  760. if (((amode & W_OK) == W_OK) && ((info.fattrib & AM_RDO) == AM_RDO)) {
  761. ret = -1;
  762. errno = EACCES;
  763. }
  764. // There is no flag to test readable or executable: we assume that if
  765. // it exists then it is readable and executable
  766. } else {
  767. ret = -1;
  768. errno = ENOENT;
  769. }
  770. return ret;
  771. }
  772. static int vfs_fat_truncate(void* ctx, const char *path, off_t length)
  773. {
  774. FRESULT res;
  775. FIL* file;
  776. int ret = 0;
  777. vfs_fat_ctx_t* fat_ctx = (vfs_fat_ctx_t*) ctx;
  778. _lock_acquire(&fat_ctx->lock);
  779. prepend_drive_to_path(fat_ctx, &path, NULL);
  780. file = (FIL*) ff_memalloc(sizeof(FIL));
  781. if (file == NULL) {
  782. _lock_release(&fat_ctx->lock);
  783. ESP_LOGD(TAG, "truncate alloc failed");
  784. errno = ENOMEM;
  785. ret = -1;
  786. goto out;
  787. }
  788. memset(file, 0, sizeof(*file));
  789. res = f_open(file, path, FA_WRITE);
  790. if (res != FR_OK) {
  791. _lock_release(&fat_ctx->lock);
  792. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  793. errno = fresult_to_errno(res);
  794. ret = -1;
  795. goto out;
  796. }
  797. res = f_size(file);
  798. if (res < length) {
  799. _lock_release(&fat_ctx->lock);
  800. ESP_LOGD(TAG, "truncate does not support extending size");
  801. errno = EPERM;
  802. ret = -1;
  803. goto close;
  804. }
  805. res = f_lseek(file, length);
  806. if (res != FR_OK) {
  807. _lock_release(&fat_ctx->lock);
  808. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  809. errno = fresult_to_errno(res);
  810. ret = -1;
  811. goto close;
  812. }
  813. res = f_truncate(file);
  814. _lock_release(&fat_ctx->lock);
  815. if (res != FR_OK) {
  816. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  817. errno = fresult_to_errno(res);
  818. ret = -1;
  819. }
  820. close:
  821. res = f_close(file);
  822. if (res != FR_OK) {
  823. ESP_LOGE(TAG, "closing file opened for truncate failed");
  824. // Overwrite previous errors, since not being able to close
  825. // an opened file is a more critical issue.
  826. errno = fresult_to_errno(res);
  827. ret = -1;
  828. }
  829. out:
  830. free(file);
  831. return ret;
  832. }
  833. static int vfs_fat_utime(void *ctx, const char *path, const struct utimbuf *times)
  834. {
  835. FILINFO filinfo_time;
  836. {
  837. struct tm tm_time;
  838. if (times) {
  839. localtime_r(&times->modtime, &tm_time);
  840. } else {
  841. // use current time
  842. struct timeval tv;
  843. gettimeofday(&tv, NULL);
  844. localtime_r(&tv.tv_sec, &tm_time);
  845. }
  846. if (tm_time.tm_year < 80) {
  847. // FATFS cannot handle years before 1980
  848. errno = EINVAL;
  849. return -1;
  850. }
  851. fat_date_t fdate;
  852. fat_time_t ftime;
  853. // this time transformation is esentially the reverse of the one in vfs_fat_stat()
  854. fdate.mday = tm_time.tm_mday;
  855. fdate.mon = tm_time.tm_mon + 1; // January in fdate.mon is 1, and 0 in tm_time.tm_mon
  856. fdate.year = tm_time.tm_year - 80; // tm_time.tm_year=0 is 1900, tm_time.tm_year=0 is 1980
  857. ftime.sec = tm_time.tm_sec / 2, // ftime.sec counts seconds by 2
  858. ftime.min = tm_time.tm_min;
  859. ftime.hour = tm_time.tm_hour;
  860. filinfo_time.fdate = fdate.as_int;
  861. filinfo_time.ftime = ftime.as_int;
  862. }
  863. vfs_fat_ctx_t *fat_ctx = (vfs_fat_ctx_t *) ctx;
  864. _lock_acquire(&fat_ctx->lock);
  865. prepend_drive_to_path(fat_ctx, &path, NULL);
  866. FRESULT res = f_utime(path, &filinfo_time);
  867. _lock_release(&fat_ctx->lock);
  868. if (res != FR_OK) {
  869. ESP_LOGD(TAG, "%s: fresult=%d", __func__, res);
  870. errno = fresult_to_errno(res);
  871. return -1;
  872. }
  873. return 0;
  874. }
  875. #endif // CONFIG_VFS_SUPPORT_DIR