fat_fs.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /*
  2. * Copyright (c) 2016 Intel Corporation.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <kernel.h>
  9. #include <zephyr/types.h>
  10. #include <errno.h>
  11. #include <init.h>
  12. #include <fs/fs.h>
  13. #include <fs/fs_sys.h>
  14. #include <sys/__assert.h>
  15. #include <ff.h>
  16. /* Quick truncate: do not fill data */
  17. #define FATFS_QUICK_TRUNCATE
  18. #define FATFS_MAX_FILE_NAME 12 /* Uses 8.3 SFN */
  19. /* Memory pool for FatFs directory objects */
  20. K_MEM_SLAB_DEFINE(fatfs_dirp_pool, sizeof(DIR),
  21. CONFIG_FS_FATFS_NUM_DIRS, 4);
  22. /* Memory pool for FatFs file objects */
  23. K_MEM_SLAB_DEFINE(fatfs_filep_pool, sizeof(FIL),
  24. CONFIG_FS_FATFS_NUM_FILES, 4);
  25. static int translate_error(int error)
  26. {
  27. switch (error) {
  28. case FR_OK:
  29. return 0;
  30. case FR_NO_FILE:
  31. case FR_NO_PATH:
  32. case FR_INVALID_NAME:
  33. return -ENOENT;
  34. case FR_DENIED:
  35. return -EACCES;
  36. case FR_EXIST:
  37. return -EEXIST;
  38. case FR_INVALID_OBJECT:
  39. return -EBADF;
  40. case FR_WRITE_PROTECTED:
  41. return -EROFS;
  42. case FR_INVALID_DRIVE:
  43. case FR_NOT_ENABLED:
  44. case FR_NO_FILESYSTEM:
  45. return -ENODEV;
  46. case FR_NOT_ENOUGH_CORE:
  47. return -ENOMEM;
  48. case FR_TOO_MANY_OPEN_FILES:
  49. return -EMFILE;
  50. case FR_INVALID_PARAMETER:
  51. return -EINVAL;
  52. case FR_LOCKED:
  53. case FR_TIMEOUT:
  54. case FR_MKFS_ABORTED:
  55. case FR_DISK_ERR:
  56. case FR_INT_ERR:
  57. case FR_NOT_READY:
  58. return -EIO;
  59. }
  60. return -EIO;
  61. }
  62. static uint8_t translate_flags(fs_mode_t flags)
  63. {
  64. uint8_t fat_mode = 0;
  65. fat_mode |= (flags & FS_O_READ) ? FA_READ : 0;
  66. fat_mode |= (flags & FS_O_WRITE) ? FA_WRITE : 0;
  67. fat_mode |= (flags & FS_O_CREATE) ? FA_OPEN_ALWAYS : 0;
  68. /* NOTE: FA_APPEND is not translated because FAT FS does not
  69. * support append semantics of the Zephyr, where file position
  70. * is forwarded to the end before each write, the fatfs_write
  71. * will be tasked with setting a file position to the end,
  72. * if FA_APPEND flag is present.
  73. */
  74. return fat_mode;
  75. }
  76. static int fatfs_open(struct fs_file_t *zfp, const char *file_name,
  77. fs_mode_t mode)
  78. {
  79. FRESULT res;
  80. uint8_t fs_mode;
  81. void *ptr;
  82. if (k_mem_slab_alloc(&fatfs_filep_pool, &ptr, K_NO_WAIT) == 0) {
  83. (void)memset(ptr, 0, sizeof(FIL));
  84. zfp->filep = ptr;
  85. } else {
  86. return -ENOMEM;
  87. }
  88. fs_mode = translate_flags(mode);
  89. res = f_open(zfp->filep, &file_name[1], fs_mode);
  90. if (res != FR_OK) {
  91. k_mem_slab_free(&fatfs_filep_pool, &ptr);
  92. zfp->filep = NULL;
  93. }
  94. return translate_error(res);
  95. }
  96. static int fatfs_close(struct fs_file_t *zfp)
  97. {
  98. FRESULT res;
  99. res = f_close(zfp->filep);
  100. /* Free file ptr memory */
  101. k_mem_slab_free(&fatfs_filep_pool, &zfp->filep);
  102. zfp->filep = NULL;
  103. return translate_error(res);
  104. }
  105. static int fatfs_unlink(struct fs_mount_t *mountp, const char *path)
  106. {
  107. int res = -ENOTSUP;
  108. #if !defined(CONFIG_FS_FATFS_READ_ONLY)
  109. res = f_unlink(&path[1]);
  110. res = translate_error(res);
  111. #endif
  112. return res;
  113. }
  114. static int fatfs_rename(struct fs_mount_t *mountp, const char *from,
  115. const char *to)
  116. {
  117. int res = -ENOTSUP;
  118. #if !defined(CONFIG_FS_FATFS_READ_ONLY)
  119. FILINFO fno;
  120. /* Check if 'to' path exists; remove it if it does */
  121. res = f_stat(&to[1], &fno);
  122. if (FR_OK == res) {
  123. res = f_unlink(&to[1]);
  124. if (FR_OK != res)
  125. return translate_error(res);
  126. }
  127. res = f_rename(&from[1], &to[1]);
  128. res = translate_error(res);
  129. #endif
  130. return res;
  131. }
  132. static ssize_t fatfs_read(struct fs_file_t *zfp, void *ptr, size_t size)
  133. {
  134. FRESULT res;
  135. unsigned int br;
  136. res = f_read(zfp->filep, ptr, size, &br);
  137. if (res != FR_OK) {
  138. return translate_error(res);
  139. }
  140. return br;
  141. }
  142. static ssize_t fatfs_write(struct fs_file_t *zfp, const void *ptr, size_t size)
  143. {
  144. int res = -ENOTSUP;
  145. #if !defined(CONFIG_FS_FATFS_READ_ONLY)
  146. unsigned int bw;
  147. off_t pos = f_size((FIL *)zfp->filep);
  148. res = FR_OK;
  149. /* FA_APPEND flag means that file has been opened for append.
  150. * The FAT FS write does not support the POSIX append semantics,
  151. * to always write at the end of file, so set file position
  152. * at the end before each write if FA_APPEND is set.
  153. */
  154. if (zfp->flags & FS_O_APPEND) {
  155. res = f_lseek(zfp->filep, pos);
  156. }
  157. if (res == FR_OK) {
  158. res = f_write(zfp->filep, ptr, size, &bw);
  159. }
  160. if (res != FR_OK) {
  161. res = translate_error(res);
  162. } else {
  163. res = bw;
  164. }
  165. #endif
  166. return res;
  167. }
  168. static int fatfs_seek(struct fs_file_t *zfp, off_t offset, int whence)
  169. {
  170. FRESULT res = FR_OK;
  171. off_t pos;
  172. switch (whence) {
  173. case FS_SEEK_SET:
  174. pos = offset;
  175. break;
  176. case FS_SEEK_CUR:
  177. pos = f_tell((FIL *)zfp->filep) + offset;
  178. break;
  179. case FS_SEEK_END:
  180. pos = f_size((FIL *)zfp->filep) + offset;
  181. break;
  182. default:
  183. return -EINVAL;
  184. }
  185. if ((pos < 0) || (pos > f_size((FIL *)zfp->filep))) {
  186. return -EINVAL;
  187. }
  188. res = f_lseek(zfp->filep, pos);
  189. return translate_error(res);
  190. }
  191. static off_t fatfs_tell(struct fs_file_t *zfp)
  192. {
  193. return f_tell((FIL *)zfp->filep);
  194. }
  195. static int fatfs_truncate(struct fs_file_t *zfp, off_t length)
  196. {
  197. int res = -ENOTSUP;
  198. #if !defined(CONFIG_FS_FATFS_READ_ONLY)
  199. off_t cur_length = f_size((FIL *)zfp->filep);
  200. #ifdef FATFS_QUICK_TRUNCATE
  201. /* Optimize: No need to do any operation */
  202. if (cur_length == length) {
  203. return translate_error(res);
  204. }
  205. #endif
  206. /* f_lseek expands file if new position is larger than file size */
  207. res = f_lseek(zfp->filep, length);
  208. if (res != FR_OK) {
  209. return translate_error(res);
  210. }
  211. if (length < cur_length) {
  212. res = f_truncate(zfp->filep);
  213. } else {
  214. #ifdef FATFS_QUICK_TRUNCATE
  215. /*
  216. * Optimize: Do sync instead of filling the whole
  217. * expanded region with zeroes.
  218. */
  219. res = f_sync(zfp->filep);
  220. #else
  221. /*
  222. * Get actual length after expansion. This could be
  223. * less if there was not enough space in the volume
  224. * to expand to the requested length
  225. */
  226. length = f_tell((FIL *)zfp->filep);
  227. res = f_lseek(zfp->filep, cur_length);
  228. if (res != FR_OK) {
  229. return translate_error(res);
  230. }
  231. /*
  232. * The FS module does caching and optimization of
  233. * writes. Here we write 1 byte at a time to avoid
  234. * using additional code and memory for doing any
  235. * optimization.
  236. */
  237. unsigned int bw;
  238. uint8_t c = 0U;
  239. for (int i = cur_length; i < length; i++) {
  240. res = f_write(zfp->filep, &c, 1, &bw);
  241. if (res != FR_OK) {
  242. break;
  243. }
  244. }
  245. #endif
  246. }
  247. res = translate_error(res);
  248. #endif
  249. return res;
  250. }
  251. static int fatfs_sync(struct fs_file_t *zfp)
  252. {
  253. int res = -ENOTSUP;
  254. #if !defined(CONFIG_FS_FATFS_READ_ONLY)
  255. res = f_sync(zfp->filep);
  256. res = translate_error(res);
  257. #endif
  258. return res;
  259. }
  260. static int fatfs_mkdir(struct fs_mount_t *mountp, const char *path)
  261. {
  262. int res = -ENOTSUP;
  263. #if !defined(CONFIG_FS_FATFS_READ_ONLY)
  264. res = f_mkdir(&path[1]);
  265. res = translate_error(res);
  266. #endif
  267. return res;
  268. }
  269. static int fatfs_opendir(struct fs_dir_t *zdp, const char *path)
  270. {
  271. FRESULT res;
  272. void *ptr;
  273. if (k_mem_slab_alloc(&fatfs_dirp_pool, &ptr, K_NO_WAIT) == 0) {
  274. (void)memset(ptr, 0, sizeof(DIR));
  275. zdp->dirp = ptr;
  276. } else {
  277. return -ENOMEM;
  278. }
  279. res = f_opendir(zdp->dirp, &path[1]);
  280. if (res != FR_OK) {
  281. k_mem_slab_free(&fatfs_dirp_pool, &ptr);
  282. zdp->dirp = NULL;
  283. }
  284. return translate_error(res);
  285. }
  286. static int fatfs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry)
  287. {
  288. FRESULT res;
  289. FILINFO fno;
  290. res = f_readdir(zdp->dirp, &fno);
  291. if (res == FR_OK) {
  292. strcpy(entry->name, fno.fname);
  293. if (entry->name[0] != 0) {
  294. entry->type = ((fno.fattrib & AM_DIR) ?
  295. FS_DIR_ENTRY_DIR : FS_DIR_ENTRY_FILE);
  296. entry->size = fno.fsize;
  297. }
  298. }
  299. return translate_error(res);
  300. }
  301. static int fatfs_closedir(struct fs_dir_t *zdp)
  302. {
  303. FRESULT res;
  304. res = f_closedir(zdp->dirp);
  305. /* Free file ptr memory */
  306. k_mem_slab_free(&fatfs_dirp_pool, &zdp->dirp);
  307. return translate_error(res);
  308. }
  309. static int fatfs_stat(struct fs_mount_t *mountp,
  310. const char *path, struct fs_dirent *entry)
  311. {
  312. FRESULT res;
  313. FILINFO fno;
  314. res = f_stat(&path[1], &fno);
  315. if (res == FR_OK) {
  316. entry->type = ((fno.fattrib & AM_DIR) ?
  317. FS_DIR_ENTRY_DIR : FS_DIR_ENTRY_FILE);
  318. strcpy(entry->name, fno.fname);
  319. entry->size = fno.fsize;
  320. }
  321. return translate_error(res);
  322. }
  323. static int fatfs_statvfs(struct fs_mount_t *mountp,
  324. const char *path, struct fs_statvfs *stat)
  325. {
  326. int res = -ENOTSUP;
  327. #if !defined(CONFIG_FS_FATFS_READ_ONLY)
  328. FATFS *fs;
  329. res = f_getfree(&mountp->mnt_point[1], &stat->f_bfree, &fs);
  330. if (res != FR_OK) {
  331. return -EIO;
  332. }
  333. /*
  334. * _MIN_SS holds the sector size. It is one of the configuration
  335. * constants used by the FS module
  336. */
  337. stat->f_bsize = _MIN_SS;
  338. stat->f_frsize = fs->csize * stat->f_bsize;
  339. stat->f_blocks = (fs->n_fatent - 2);
  340. res = translate_error(res);
  341. #endif
  342. return res;
  343. }
  344. static int fatfs_mount(struct fs_mount_t *mountp)
  345. {
  346. FRESULT res;
  347. res = f_mount((FATFS *)mountp->fs_data, &mountp->mnt_point[1], 1);
  348. #if defined(CONFIG_FS_FATFS_MOUNT_MKFS)
  349. if (res == FR_NO_FILESYSTEM &&
  350. (mountp->flags & FS_MOUNT_FLAG_READ_ONLY) != 0) {
  351. return -EROFS;
  352. }
  353. /* If no file system found then create one */
  354. if (res == FR_NO_FILESYSTEM &&
  355. (mountp->flags & FS_MOUNT_FLAG_NO_FORMAT) == 0) {
  356. uint8_t work[_MAX_SS];
  357. res = f_mkfs(&mountp->mnt_point[1],
  358. (FM_FAT | FM_SFD), 0, work, sizeof(work));
  359. if (res == FR_OK) {
  360. res = f_mount((FATFS *)mountp->fs_data,
  361. &mountp->mnt_point[1], 1);
  362. }
  363. }
  364. #endif /* CONFIG_FS_FATFS_MOUNT_MKFS */
  365. return translate_error(res);
  366. }
  367. static int fatfs_unmount(struct fs_mount_t *mountp)
  368. {
  369. FRESULT res;
  370. res = f_mount(NULL, &mountp->mnt_point[1], 0);
  371. return translate_error(res);
  372. }
  373. /* detect disk add or remove */
  374. static int fatfs_disk_detect(struct fs_mount_t *mountp, const char *path, uint8_t *state)
  375. {
  376. return f_disk_detect(path + 1, state);/*filter'/'*/
  377. }
  378. static int fatfs_open_cluster(struct fs_file_t *zfp, char *dir, uint32_t cluster, uint32_t blk_ofs)
  379. {
  380. FRESULT res;
  381. uint8_t fs_mode;
  382. void *ptr;
  383. if (k_mem_slab_alloc(&fatfs_filep_pool, &ptr, K_NO_WAIT) == 0) {
  384. (void)memset(ptr, 0, sizeof(FIL));
  385. zfp->filep = ptr;
  386. } else {
  387. return -ENOMEM;
  388. }
  389. fs_mode = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
  390. res = f_open_cluster(zfp->filep, dir + 1, cluster, blk_ofs, fs_mode);/*filter'/'*/
  391. return translate_error(res);
  392. }
  393. static int fatfs_opendir_cluster(struct fs_dir_t *zdp, const char *path, unsigned int cluster, unsigned int blk_ofs)
  394. {
  395. FRESULT res;
  396. void *ptr;
  397. if (k_mem_slab_alloc(&fatfs_dirp_pool, &ptr, K_NO_WAIT) == 0) {
  398. (void)memset(ptr, 0, sizeof(DIR));
  399. zdp->dirp = ptr;
  400. } else {
  401. return -ENOMEM;
  402. }
  403. res = f_opendir_cluster(zdp->dirp, path + 1, cluster, blk_ofs);/*filter'/'*/
  404. return translate_error(res);
  405. }
  406. /* File system interface */
  407. static const struct fs_file_system_t fatfs_fs = {
  408. .open = fatfs_open,
  409. .close = fatfs_close,
  410. .read = fatfs_read,
  411. .write = fatfs_write,
  412. .lseek = fatfs_seek,
  413. .tell = fatfs_tell,
  414. .truncate = fatfs_truncate,
  415. .sync = fatfs_sync,
  416. .opendir = fatfs_opendir,
  417. .readdir = fatfs_readdir,
  418. .closedir = fatfs_closedir,
  419. .mount = fatfs_mount,
  420. .unmount = fatfs_unmount,
  421. .unlink = fatfs_unlink,
  422. .rename = fatfs_rename,
  423. .mkdir = fatfs_mkdir,
  424. .stat = fatfs_stat,
  425. .statvfs = fatfs_statvfs,
  426. .disk_detect = fatfs_disk_detect,
  427. .open_cluster = fatfs_open_cluster,
  428. .opendir_cluster = fatfs_opendir_cluster,
  429. };
  430. static int fatfs_init(const struct device *dev)
  431. {
  432. ARG_UNUSED(dev);
  433. return fs_register(FS_FATFS, &fatfs_fs);
  434. }
  435. SYS_INIT(fatfs_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);