2014-01-04 14:02:53 +00:00
|
|
|
/*
|
|
|
|
* This file is subject to the terms of the GFX License. If a copy of
|
|
|
|
* the license was not distributed with this file, you can obtain one at:
|
|
|
|
*
|
|
|
|
* http://ugfx.org/license.html
|
|
|
|
*/
|
|
|
|
|
2014-08-14 14:31:32 +00:00
|
|
|
/********************************************************
|
|
|
|
* The FATFS file-system
|
|
|
|
********************************************************/
|
|
|
|
|
|
|
|
#include "gfx.h"
|
2014-01-04 14:02:53 +00:00
|
|
|
|
2014-08-14 14:31:32 +00:00
|
|
|
#if GFX_USE_GFILE && GFILE_NEED_FATFS
|
|
|
|
|
|
|
|
#include "gfile_fs.h"
|
2014-09-16 23:32:09 +00:00
|
|
|
#include "gfile_fatfs_wrapper.h"
|
2014-06-25 03:23:57 +00:00
|
|
|
|
2014-01-04 14:02:53 +00:00
|
|
|
/********************************************************
|
|
|
|
* The FAT file-system VMT
|
|
|
|
********************************************************/
|
2014-06-24 03:56:13 +00:00
|
|
|
|
|
|
|
static bool_t fatfsDel(const char* fname);
|
|
|
|
static bool_t fatfsExists(const char* fname);
|
|
|
|
static long int fatfsFileSize(const char* fname);
|
|
|
|
static bool_t fatfsRename(const char* oldname, const char* newname);
|
|
|
|
static bool_t fatfsOpen(GFILE* f, const char* fname);
|
|
|
|
static void fatfsClose(GFILE* f);
|
|
|
|
static int fatfsRead(GFILE* f, void* buf, int size);
|
|
|
|
static int fatfsWrite(GFILE* f, const void* buf, int size);
|
|
|
|
static bool_t fatfsSetPos(GFILE* f, long int pos);
|
|
|
|
static long int fatfsGetSize(GFILE* f);
|
|
|
|
static bool_t fatfsEOF(GFILE* f);
|
2014-06-27 04:10:18 +00:00
|
|
|
static bool_t fatfsMount(const char* drive);
|
|
|
|
static bool_t fatfsUnmount(const char* drive);
|
2014-06-29 14:15:46 +00:00
|
|
|
static bool_t fatfsSync(GFILE* f);
|
2014-08-13 05:48:16 +00:00
|
|
|
#if GFILE_NEED_FILELISTS && _FS_MINIMIZE <= 1
|
2014-08-12 06:43:45 +00:00
|
|
|
static gfileList *fatfsFlOpen(const char *path, bool_t dirs);
|
|
|
|
static const char *fatfsFlRead(gfileList *pfl);
|
|
|
|
static void fatfsFlClose(gfileList *pfl);
|
|
|
|
#endif
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-08-14 14:31:32 +00:00
|
|
|
const GFILEVMT FsFatFSVMT = {
|
2014-06-26 22:38:46 +00:00
|
|
|
GFSFLG_WRITEABLE | GFSFLG_SEEKABLE,
|
2014-06-24 03:56:13 +00:00
|
|
|
'F',
|
|
|
|
fatfsDel,
|
|
|
|
fatfsExists,
|
|
|
|
fatfsFileSize,
|
|
|
|
fatfsRename,
|
|
|
|
fatfsOpen,
|
|
|
|
fatfsClose,
|
|
|
|
fatfsRead,
|
|
|
|
fatfsWrite,
|
|
|
|
fatfsSetPos,
|
|
|
|
fatfsGetSize,
|
2014-06-27 04:10:18 +00:00
|
|
|
fatfsEOF,
|
2014-08-12 06:43:45 +00:00
|
|
|
fatfsMount, fatfsUnmount, fatfsSync,
|
|
|
|
#if GFILE_NEED_FILELISTS
|
|
|
|
#if _FS_MINIMIZE <= 1
|
|
|
|
fatfsFlOpen, fatfsFlRead, fatfsFlClose
|
|
|
|
#else
|
|
|
|
0, 0, 0
|
|
|
|
#endif
|
|
|
|
#endif
|
2014-06-24 03:56:13 +00:00
|
|
|
};
|
|
|
|
|
2014-08-12 06:43:45 +00:00
|
|
|
// Our directory list structure
|
|
|
|
typedef struct fatfsList {
|
|
|
|
gfileList fl; // This must be the first element.
|
|
|
|
DIR dir;
|
|
|
|
FILINFO fno;
|
|
|
|
#if _USE_LFN
|
|
|
|
char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */
|
|
|
|
#endif
|
|
|
|
} fatfsList;
|
|
|
|
|
2014-06-27 04:10:18 +00:00
|
|
|
// optimize these later on. Use an array to have multiple FatFS
|
|
|
|
static bool_t fatfs_mounted = FALSE;
|
|
|
|
static FATFS fatfs_fs;
|
|
|
|
|
2014-06-27 13:04:01 +00:00
|
|
|
static BYTE fatfs_flags2mode(GFILE* f)
|
2014-06-25 03:23:57 +00:00
|
|
|
{
|
2014-06-27 13:04:01 +00:00
|
|
|
BYTE mode = 0;
|
2014-06-25 03:23:57 +00:00
|
|
|
|
2014-06-26 22:38:46 +00:00
|
|
|
if (f->flags & GFILEFLG_READ)
|
2014-06-27 13:04:01 +00:00
|
|
|
mode |= FA_READ;
|
2014-06-26 22:38:46 +00:00
|
|
|
if (f->flags & GFILEFLG_WRITE)
|
2014-06-27 13:04:01 +00:00
|
|
|
mode |= FA_WRITE;
|
2014-06-26 22:38:46 +00:00
|
|
|
if (f->flags & GFILEFLG_APPEND)
|
2014-06-27 13:04:01 +00:00
|
|
|
mode |= 0; // ToDo
|
2014-06-26 22:38:46 +00:00
|
|
|
if (f->flags & GFILEFLG_TRUNC)
|
2014-06-27 13:04:01 +00:00
|
|
|
mode |= FA_CREATE_ALWAYS;
|
2014-06-25 03:23:57 +00:00
|
|
|
|
2014-06-27 13:04:01 +00:00
|
|
|
/* ToDo - Complete */
|
|
|
|
return mode;
|
2014-06-25 03:23:57 +00:00
|
|
|
}
|
|
|
|
|
2014-06-24 03:56:13 +00:00
|
|
|
static bool_t fatfsDel(const char* fname)
|
|
|
|
{
|
2014-06-25 03:23:57 +00:00
|
|
|
FRESULT ferr;
|
|
|
|
|
|
|
|
ferr = f_unlink( (const TCHAR*)fname );
|
|
|
|
if (ferr != FR_OK)
|
|
|
|
return FALSE;
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
return TRUE;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool_t fatfsExists(const char* fname)
|
|
|
|
{
|
2014-06-26 22:38:46 +00:00
|
|
|
FRESULT ferr;
|
|
|
|
FILINFO fno;
|
2014-06-25 03:23:57 +00:00
|
|
|
|
2014-06-26 22:38:46 +00:00
|
|
|
ferr = f_stat( (const TCHAR*)fname, &fno);
|
|
|
|
if (ferr != FR_OK)
|
|
|
|
return FALSE;
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
return TRUE;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static long int fatfsFileSize(const char* fname)
|
|
|
|
{
|
2014-06-25 03:23:57 +00:00
|
|
|
FRESULT ferr;
|
|
|
|
FILINFO fno;
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
ferr = f_stat( (const TCHAR*)fname, &fno );
|
|
|
|
if (ferr != FR_OK)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (long int)fno.fsize;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool_t fatfsRename(const char* oldname, const char* newname)
|
|
|
|
{
|
2014-06-25 03:23:57 +00:00
|
|
|
FRESULT ferr;
|
|
|
|
|
|
|
|
ferr = f_rename( (const TCHAR*)oldname, (const TCHAR*)newname );
|
|
|
|
if (ferr != FR_OK)
|
|
|
|
return FALSE;
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
return TRUE;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool_t fatfsOpen(GFILE* f, const char* fname)
|
|
|
|
{
|
2014-06-26 22:38:46 +00:00
|
|
|
FIL* fd;
|
2014-06-27 13:04:01 +00:00
|
|
|
|
|
|
|
#if !GFILE_NEED_NOAUTOMOUNT
|
|
|
|
if (!fatfs_mounted && !fatfsMount(""))
|
|
|
|
return FALSE;
|
|
|
|
#endif
|
|
|
|
|
2014-06-26 22:38:46 +00:00
|
|
|
if (!(fd = gfxAlloc(sizeof(FIL))))
|
|
|
|
return FALSE;
|
|
|
|
|
2014-06-27 13:04:01 +00:00
|
|
|
if (f_open(fd, fname, fatfs_flags2mode(f)) != FR_OK) {
|
2014-06-27 04:10:18 +00:00
|
|
|
gfxFree(fd);
|
2014-06-26 22:38:46 +00:00
|
|
|
f->obj = 0;
|
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
return FALSE;
|
2014-06-26 22:38:46 +00:00
|
|
|
}
|
2014-06-25 03:23:57 +00:00
|
|
|
|
|
|
|
f->obj = (void*)fd;
|
|
|
|
|
2014-06-29 14:15:46 +00:00
|
|
|
#if !GFILE_NEED_NOAUTOSYNC
|
|
|
|
// no need to sync when not opening for write
|
|
|
|
if (f->flags & GFILEFLG_WRITE) {
|
|
|
|
f_sync( (FIL*)f->obj );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
return TRUE;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void fatfsClose(GFILE* f)
|
|
|
|
{
|
2014-06-27 04:10:18 +00:00
|
|
|
if ((FIL*)f->obj != 0) {
|
|
|
|
f_close( (FIL*)f->obj );
|
2014-08-14 16:19:23 +00:00
|
|
|
gfxFree( (FIL*)f->obj );
|
2014-06-27 04:10:18 +00:00
|
|
|
}
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int fatfsRead(GFILE* f, void* buf, int size)
|
|
|
|
{
|
2014-06-25 03:23:57 +00:00
|
|
|
int br;
|
|
|
|
|
|
|
|
f_read( (FIL*)f->obj, buf, size, (UINT*)&br);
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
return br;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int fatfsWrite(GFILE* f, const void* buf, int size)
|
|
|
|
{
|
2014-06-25 03:23:57 +00:00
|
|
|
int wr;
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
f_write( (FIL*)f->obj, buf, size, (UINT*)&wr);
|
2014-07-01 23:36:00 +00:00
|
|
|
#if !GFILE_NEED_NOAUTOSYNC
|
|
|
|
f_sync( (FIL*)f->obj );
|
|
|
|
#endif
|
2014-06-25 03:23:57 +00:00
|
|
|
|
|
|
|
return wr;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool_t fatfsSetPos(GFILE* f, long int pos)
|
|
|
|
{
|
2014-06-25 03:23:57 +00:00
|
|
|
FRESULT ferr;
|
|
|
|
|
|
|
|
ferr = f_lseek( (FIL*)f->obj, (DWORD)pos );
|
|
|
|
if (ferr != FR_OK)
|
|
|
|
return FALSE;
|
2014-06-24 03:56:13 +00:00
|
|
|
|
2014-06-25 03:23:57 +00:00
|
|
|
return TRUE;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static long int fatfsGetSize(GFILE* f)
|
|
|
|
{
|
2014-06-26 22:38:46 +00:00
|
|
|
return (long int)f_size( (FIL*)f->obj );
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool_t fatfsEOF(GFILE* f)
|
|
|
|
{
|
2014-06-25 03:23:57 +00:00
|
|
|
if ( f_eof( (FIL*)f->obj ) != 0)
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
2014-06-24 03:56:13 +00:00
|
|
|
}
|
|
|
|
|
2014-06-27 04:10:18 +00:00
|
|
|
static bool_t fatfsMount(const char* drive)
|
|
|
|
{
|
|
|
|
FRESULT ferr;
|
|
|
|
|
|
|
|
if (!fatfs_mounted) {
|
|
|
|
ferr = f_mount(&fatfs_fs, drive, 1);
|
|
|
|
if (ferr != FR_OK)
|
|
|
|
return FALSE;
|
|
|
|
fatfs_mounted = TRUE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool_t fatfsUnmount(const char* drive)
|
|
|
|
{
|
|
|
|
(void)drive;
|
|
|
|
|
|
|
|
if (fatfs_mounted) {
|
|
|
|
// FatFS does not provide an unmount routine.
|
|
|
|
fatfs_mounted = FALSE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2014-06-29 14:15:46 +00:00
|
|
|
static bool_t fatfsSync(GFILE *f)
|
|
|
|
{
|
|
|
|
FRESULT ferr;
|
|
|
|
|
|
|
|
ferr = f_sync( (FIL*)f->obj );
|
|
|
|
if (ferr != FR_OK) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2014-08-13 05:48:16 +00:00
|
|
|
#if GFILE_NEED_FILELISTS && _FS_MINIMIZE <= 1
|
2014-08-12 06:43:45 +00:00
|
|
|
static gfileList *fatfsFlOpen(const char *path, bool_t dirs) {
|
|
|
|
fatfsList *p;
|
|
|
|
(void) dirs;
|
|
|
|
|
|
|
|
if (!(p = gfxAlloc(sizeof(fatfsList))))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (f_opendir(&p->dir, path) != FR_OK) {
|
|
|
|
gfxFree(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return &p->fl;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *fatfsFlRead(gfileList *pfl) {
|
|
|
|
#define ffl ((fatfsList *)pfl)
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
#if _USE_LFN
|
|
|
|
ffl->fno.lfname = ffl->lfn;
|
|
|
|
ffl->fno.lfsize = sizeof(ffl->lfn);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Read the next entry
|
|
|
|
if (f_readdir(&ffl->dir, &ffl->fno) != FR_OK || !ffl->fno.fname[0])
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Ignore dot entries */
|
|
|
|
if (ffl->fno.fname[0] == '.') continue;
|
|
|
|
|
|
|
|
/* Is it a directory */
|
|
|
|
if (ffl->fl.dirs) {
|
|
|
|
if ((ffl->fno.fattrib & AM_DIR))
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (!(ffl->fno.fattrib & AM_DIR))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _USE_LFN
|
|
|
|
return ffl->fno.lfname[0] ? ffl->fno.lfname : ffl->fno.fname;
|
|
|
|
#else
|
|
|
|
return ffl->fno.fname;
|
|
|
|
#endif
|
|
|
|
#undef ffl
|
|
|
|
}
|
|
|
|
|
|
|
|
static void fatfsFlClose(gfileList *pfl) {
|
|
|
|
f_closedir(&((fatfsList *)pfl)->dir);
|
|
|
|
gfxFree(pfl);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2014-08-14 14:31:32 +00:00
|
|
|
|
|
|
|
#endif //GFX_USE_GFILE && GFILE_NEED_FATFS
|
|
|
|
|