myfatfs.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdbool.h>
  4. #include "vfs_int.h"
  5. #include "fatfs_prefix_lib.h"
  6. #include "ff.h"
  7. #include "fatfs_config.h"
  8. static FRESULT last_result = FR_OK;
  9. static const char* const volstr[FF_VOLUMES] = {FF_VOLUME_STRS};
  10. static int is_current_drive = false;
  11. // forward declarations
  12. static int32_t myfatfs_close( const struct vfs_file *fd );
  13. static int32_t myfatfs_read( const struct vfs_file *fd, void *ptr, size_t len );
  14. static int32_t myfatfs_write( const struct vfs_file *fd, const void *ptr, size_t len );
  15. static int32_t myfatfs_lseek( const struct vfs_file *fd, int32_t off, int whence );
  16. static int32_t myfatfs_eof( const struct vfs_file *fd );
  17. static int32_t myfatfs_tell( const struct vfs_file *fd );
  18. static int32_t myfatfs_flush( const struct vfs_file *fd );
  19. static uint32_t myfatfs_fsize( const struct vfs_file *fd );
  20. static int32_t myfatfs_ferrno( const struct vfs_file *fd );
  21. static int32_t myfatfs_closedir( const struct vfs_dir *dd );
  22. static int32_t myfatfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf );
  23. static vfs_vol *myfatfs_mount( const char *name, int num );
  24. static vfs_file *myfatfs_open( const char *name, const char *mode );
  25. static vfs_dir *myfatfs_opendir( const char *name );
  26. static int32_t myfatfs_stat( const char *name, struct vfs_stat *buf );
  27. static int32_t myfatfs_remove( const char *name );
  28. static int32_t myfatfs_rename( const char *oldname, const char *newname );
  29. static int32_t myfatfs_mkdir( const char *name );
  30. static int32_t myfatfs_fsinfo( uint32_t *total, uint32_t *used );
  31. static int32_t myfatfs_chdrive( const char *name );
  32. static int32_t myfatfs_chdir( const char *name );
  33. static int32_t myfatfs_errno( void );
  34. static void myfatfs_clearerr( void );
  35. static int32_t myfatfs_umount( const struct vfs_vol *vol );
  36. // ---------------------------------------------------------------------------
  37. // function tables
  38. //
  39. static vfs_fs_fns myfatfs_fs_fns = {
  40. .mount = myfatfs_mount,
  41. .open = myfatfs_open,
  42. .opendir = myfatfs_opendir,
  43. .stat = myfatfs_stat,
  44. .remove = myfatfs_remove,
  45. .rename = myfatfs_rename,
  46. .mkdir = myfatfs_mkdir,
  47. .fsinfo = myfatfs_fsinfo,
  48. .fscfg = NULL,
  49. .format = NULL,
  50. .chdrive = myfatfs_chdrive,
  51. .chdir = myfatfs_chdir,
  52. .ferrno = myfatfs_errno,
  53. .clearerr = myfatfs_clearerr
  54. };
  55. static vfs_file_fns myfatfs_file_fns = {
  56. .close = myfatfs_close,
  57. .read = myfatfs_read,
  58. .write = myfatfs_write,
  59. .lseek = myfatfs_lseek,
  60. .eof = myfatfs_eof,
  61. .tell = myfatfs_tell,
  62. .flush = myfatfs_flush,
  63. .size = myfatfs_fsize,
  64. .ferrno = myfatfs_ferrno
  65. };
  66. static vfs_dir_fns myfatfs_dir_fns = {
  67. .close = myfatfs_closedir,
  68. .readdir = myfatfs_readdir
  69. };
  70. static vfs_vol_fns myfatfs_vol_fns = {
  71. .umount = myfatfs_umount
  72. };
  73. // ---------------------------------------------------------------------------
  74. // specific struct extensions
  75. //
  76. struct myvfs_vol {
  77. struct vfs_vol vfs_vol;
  78. char *ldrname;
  79. FATFS fs;
  80. };
  81. struct myvfs_file {
  82. struct vfs_file vfs_file;
  83. FIL fp;
  84. };
  85. struct myvfs_dir {
  86. struct vfs_dir vfs_dir;
  87. DIR dp;
  88. };
  89. // ---------------------------------------------------------------------------
  90. // exported helper functions for FatFS
  91. //
  92. void *ff_memalloc( UINT size )
  93. {
  94. return malloc( size );
  95. }
  96. void ff_memfree( void *mblock )
  97. {
  98. free( mblock );
  99. }
  100. // TODO
  101. DWORD get_fattime( void )
  102. {
  103. DWORD stamp;
  104. vfs_time tm;
  105. if (VFS_RES_OK == vfs_get_rtc( &tm )) {
  106. // sanity checks
  107. tm.year = (tm.year >= 1980) && (tm.year < 2108) ? tm.year : 1980;
  108. tm.mon = (tm.mon >= 1) && (tm.mon <= 12) ? tm.mon : 1;
  109. tm.day = (tm.day >= 1) && (tm.day <= 31) ? tm.day : 1;
  110. tm.hour = (tm.hour >= 0) && (tm.hour <= 23) ? tm.hour : 0;
  111. tm.min = (tm.min >= 0) && (tm.min <= 59) ? tm.min : 0;
  112. tm.sec = (tm.sec >= 0) && (tm.sec <= 59) ? tm.sec : 0;
  113. stamp = (tm.year-1980) << 25 | tm.mon << 21 | tm.day << 16 |
  114. tm.hour << 11 | tm.min << 5 | tm.sec;
  115. } else {
  116. // default time stamp derived from ffconf.h
  117. stamp = ((DWORD)(FF_NORTC_YEAR - 1980) << 25 | (DWORD)FF_NORTC_MON << 21 | (DWORD)FF_NORTC_MDAY << 16);
  118. }
  119. return stamp;
  120. }
  121. // ---------------------------------------------------------------------------
  122. // volume functions
  123. //
  124. #define GET_FATFS_FS(descr) \
  125. const struct myvfs_vol *myvol = (const struct myvfs_vol *)descr; \
  126. FATFS *fs = (FATFS *)&(myvol->fs);
  127. static int32_t myfatfs_umount( const struct vfs_vol *vol )
  128. {
  129. GET_FATFS_FS(vol);
  130. last_result = f_mount( NULL, myvol->ldrname, 0 );
  131. free( myvol->ldrname );
  132. free( (void *)vol );
  133. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  134. }
  135. // ---------------------------------------------------------------------------
  136. // file functions
  137. //
  138. #define GET_FIL_FP(descr) \
  139. const struct myvfs_file *myfd = (const struct myvfs_file *)descr; \
  140. FIL *fp = (FIL *)&(myfd->fp);
  141. static int32_t myfatfs_close( const struct vfs_file *fd )
  142. {
  143. GET_FIL_FP(fd)
  144. last_result = f_close( fp );
  145. // free descriptor memory
  146. free( (void *)fd );
  147. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  148. }
  149. static int32_t myfatfs_read( const struct vfs_file *fd, void *ptr, size_t len )
  150. {
  151. GET_FIL_FP(fd);
  152. UINT act_read;
  153. last_result = f_read( fp, ptr, len, &act_read );
  154. return last_result == FR_OK ? act_read : VFS_RES_ERR;
  155. }
  156. static int32_t myfatfs_write( const struct vfs_file *fd, const void *ptr, size_t len )
  157. {
  158. GET_FIL_FP(fd);
  159. UINT act_written;
  160. last_result = f_write( fp, ptr, len, &act_written );
  161. return last_result == FR_OK ? act_written : VFS_RES_ERR;
  162. }
  163. static int32_t myfatfs_lseek( const struct vfs_file *fd, int32_t off, int whence )
  164. {
  165. GET_FIL_FP(fd);
  166. FSIZE_t new_pos;
  167. switch (whence) {
  168. default:
  169. case VFS_SEEK_SET:
  170. new_pos = off > 0 ? off : 0;
  171. break;
  172. case VFS_SEEK_CUR:
  173. new_pos = f_tell( fp );
  174. new_pos += off;
  175. break;
  176. case VFS_SEEK_END:
  177. new_pos = f_size( fp );
  178. new_pos += off < 0 ? off : 0;
  179. break;
  180. };
  181. last_result = f_lseek( fp, new_pos );
  182. new_pos = f_tell( fp );
  183. return last_result == FR_OK ? new_pos : VFS_RES_ERR;
  184. }
  185. static int32_t myfatfs_eof( const struct vfs_file *fd )
  186. {
  187. GET_FIL_FP(fd);
  188. last_result = FR_OK;
  189. return f_eof( fp );
  190. }
  191. static int32_t myfatfs_tell( const struct vfs_file *fd )
  192. {
  193. GET_FIL_FP(fd);
  194. last_result = FR_OK;
  195. return f_tell( fp );
  196. }
  197. static int32_t myfatfs_flush( const struct vfs_file *fd )
  198. {
  199. GET_FIL_FP(fd);
  200. last_result = f_sync( fp );
  201. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  202. }
  203. static uint32_t myfatfs_fsize( const struct vfs_file *fd )
  204. {
  205. GET_FIL_FP(fd);
  206. last_result = FR_OK;
  207. return f_size( fp );
  208. }
  209. static int32_t myfatfs_ferrno( const struct vfs_file *fd )
  210. {
  211. return -last_result;
  212. }
  213. // ---------------------------------------------------------------------------
  214. // dir functions
  215. //
  216. #define GET_DIR_DP(descr) \
  217. const struct myvfs_dir *mydd = (const struct myvfs_dir *)descr; \
  218. DIR *dp = (DIR *)&(mydd->dp);
  219. static int32_t myfatfs_closedir( const struct vfs_dir *dd )
  220. {
  221. GET_DIR_DP(dd);
  222. last_result = f_closedir( dp );
  223. // free descriptor memory
  224. free( (void *)dd );
  225. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  226. }
  227. static void myfatfs_fill_stat( const FILINFO *fno, struct vfs_stat *buf )
  228. {
  229. memset( buf, 0, sizeof( struct vfs_stat ) );
  230. // fill in supported stat entries
  231. strncpy( buf->name, fno->fname, FS_OBJ_NAME_LEN+1 );
  232. buf->name[FS_OBJ_NAME_LEN] = '\0';
  233. buf->size = fno->fsize;
  234. buf->is_dir = fno->fattrib & AM_DIR ? 1 : 0;
  235. buf->is_rdonly = fno->fattrib & AM_RDO ? 1 : 0;
  236. buf->is_hidden = fno->fattrib & AM_HID ? 1 : 0;
  237. buf->is_sys = fno->fattrib & AM_SYS ? 1 : 0;
  238. buf->is_arch = fno->fattrib & AM_ARC ? 1 : 0;
  239. struct vfs_time *tm = &(buf->tm);
  240. tm->year = (fno->fdate >> 9) + 1980;
  241. tm->mon = (fno->fdate >> 5) & 0x0f;
  242. tm->day = fno->fdate & 0x1f;
  243. tm->hour = (fno->ftime >> 11);
  244. tm->min = (fno->ftime >> 5) & 0x3f;
  245. tm->sec = fno->ftime & 0x3f;
  246. buf->tm_valid = 1;
  247. }
  248. static int32_t myfatfs_readdir( const struct vfs_dir *dd, struct vfs_stat *buf )
  249. {
  250. GET_DIR_DP(dd);
  251. FILINFO fno;
  252. if (FR_OK == (last_result = f_readdir( dp, &fno ))) {
  253. // condition "no further item" is signalled with empty name
  254. if (fno.fname[0] != '\0') {
  255. myfatfs_fill_stat( &fno, buf );
  256. return VFS_RES_OK;
  257. }
  258. }
  259. return VFS_RES_ERR;
  260. }
  261. // ---------------------------------------------------------------------------
  262. // filesystem functions
  263. //
  264. static vfs_vol *myfatfs_mount( const char *name, int num )
  265. {
  266. struct myvfs_vol *vol;
  267. const size_t len = strlen( name );
  268. // num argument specifies the physical driver = SS/CS pin number for this sd card
  269. if (num >= 0) {
  270. for (int i = 0; i < NUM_LOGICAL_DRIVES; i++) {
  271. if (0 == strncmp( name, volstr[i], strlen( volstr[i] ) )) {
  272. VolToPart[i].pd = num;
  273. }
  274. }
  275. }
  276. if (vol = malloc( sizeof( struct myvfs_vol ) )) {
  277. if (vol->ldrname = strdup( name )) {
  278. if (FR_OK == (last_result = f_mount( &(vol->fs), name, 1 ))) {
  279. vol->vfs_vol.fs_type = VFS_FS_FATFS;
  280. vol->vfs_vol.fns = &myfatfs_vol_fns;
  281. return (vfs_vol *)vol;
  282. }
  283. }
  284. }
  285. if (vol) {
  286. if (vol->ldrname) free( vol->ldrname );
  287. free( vol );
  288. }
  289. return NULL;
  290. }
  291. static BYTE myfatfs_mode2flag( const char *mode )
  292. {
  293. if (strlen( mode ) == 1) {
  294. if(strcmp( mode, "w" ) == 0)
  295. return FA_WRITE | FA_CREATE_ALWAYS;
  296. else if (strcmp( mode, "r" ) == 0)
  297. return FA_READ | FA_OPEN_EXISTING;
  298. else if (strcmp( mode, "a" ) == 0)
  299. return FA_WRITE | FA_OPEN_ALWAYS;
  300. else
  301. return FA_READ | FA_OPEN_EXISTING;
  302. } else if (strlen( mode ) == 2) {
  303. if (strcmp( mode, "r+" ) == 0)
  304. return FA_READ | FA_WRITE | FA_OPEN_EXISTING;
  305. else if (strcmp( mode, "w+" ) == 0)
  306. return FA_READ | FA_WRITE | FA_CREATE_ALWAYS;
  307. else if (strcmp( mode, "a+" ) ==0 )
  308. return FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
  309. else
  310. return FA_READ | FA_OPEN_EXISTING;
  311. } else {
  312. return FA_READ | FA_OPEN_EXISTING;
  313. }
  314. }
  315. static vfs_file *myfatfs_open( const char *name, const char *mode )
  316. {
  317. struct myvfs_file *fd;
  318. const BYTE flags = myfatfs_mode2flag( mode );
  319. if (fd = malloc( sizeof( struct myvfs_file ) )) {
  320. if (FR_OK == (last_result = f_open( &(fd->fp), name, flags ))) {
  321. // skip to end of file for append mode
  322. if (flags & FA_OPEN_ALWAYS)
  323. f_lseek( &(fd->fp), f_size( &(fd->fp) ) );
  324. fd->vfs_file.fs_type = VFS_FS_FATFS;
  325. fd->vfs_file.fns = &myfatfs_file_fns;
  326. return (vfs_file *)fd;
  327. } else {
  328. free( fd );
  329. }
  330. }
  331. return NULL;
  332. }
  333. static vfs_dir *myfatfs_opendir( const char *name )
  334. {
  335. struct myvfs_dir *dd;
  336. if (dd = malloc( sizeof( struct myvfs_dir ) )) {
  337. if (FR_OK == (last_result = f_opendir( &(dd->dp), name ))) {
  338. dd->vfs_dir.fs_type = VFS_FS_FATFS;
  339. dd->vfs_dir.fns = &myfatfs_dir_fns;
  340. return (vfs_dir *)dd;
  341. } else {
  342. free( dd );
  343. }
  344. }
  345. return NULL;
  346. }
  347. static int32_t myfatfs_stat( const char *name, struct vfs_stat *buf )
  348. {
  349. FILINFO fno;
  350. if (FR_OK == (last_result = f_stat( name, &fno ))) {
  351. myfatfs_fill_stat( &fno, buf );
  352. return VFS_RES_OK;
  353. } else {
  354. return VFS_RES_ERR;
  355. }
  356. }
  357. static int32_t myfatfs_remove( const char *name )
  358. {
  359. last_result = f_unlink( name );
  360. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  361. }
  362. static int32_t myfatfs_rename( const char *oldname, const char *newname )
  363. {
  364. last_result = f_rename( oldname, newname );
  365. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  366. }
  367. static int32_t myfatfs_mkdir( const char *name )
  368. {
  369. last_result = f_mkdir( name );
  370. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  371. }
  372. static int32_t myfatfs_fsinfo( uint32_t *total, uint32_t *used )
  373. {
  374. DWORD free_clusters;
  375. FATFS *fatfs;
  376. if ((last_result = f_getfree( "", &free_clusters, &fatfs )) == FR_OK) {
  377. // provide information in kByte since uint32_t would clip to 4 GByte
  378. *total = (fatfs->n_fatent * fatfs->csize) / (1024 / FF_MAX_SS);
  379. *used = *total - (free_clusters * fatfs->csize) / (1024 / FF_MAX_SS);
  380. }
  381. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  382. }
  383. static int32_t myfatfs_chdrive( const char *name )
  384. {
  385. last_result = f_chdrive( name );
  386. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  387. }
  388. static int32_t myfatfs_chdir( const char *name )
  389. {
  390. last_result = f_chdir( name );
  391. return last_result == FR_OK ? VFS_RES_OK : VFS_RES_ERR;
  392. }
  393. static int32_t myfatfs_errno( void )
  394. {
  395. return -last_result;
  396. }
  397. static void myfatfs_clearerr( void )
  398. {
  399. last_result = FR_OK;
  400. }
  401. // ---------------------------------------------------------------------------
  402. // VFS interface functions
  403. //
  404. vfs_fs_fns *myfatfs_realm( const char *inname, char **outname, int set_current_drive )
  405. {
  406. if (inname[0] == '/') {
  407. char *oname;
  408. // logical drive is specified, check if it's one of ours
  409. for (int i = 0; i < FF_VOLUMES; i++) {
  410. size_t volstr_len = strlen( volstr[i] );
  411. if (0 == strncmp( &(inname[1]), volstr[i], volstr_len )) {
  412. oname = strdup( inname );
  413. strcpy( oname, volstr[i] );
  414. oname[volstr_len] = ':';
  415. *outname = oname;
  416. if (set_current_drive) is_current_drive = TRUE;
  417. return &myfatfs_fs_fns;
  418. }
  419. }
  420. } else {
  421. // no logical drive in patchspec, are we current drive?
  422. if (is_current_drive) {
  423. *outname = strdup( inname );
  424. return &myfatfs_fs_fns;
  425. }
  426. }
  427. if (set_current_drive) is_current_drive = false;
  428. return NULL;
  429. }