myfatfs.c 13 KB

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