µGFX  2.9
version 2.9
gfile_fs_fatfs.c
1 /*
2  * This file is subject to the terms of the GFX License. If a copy of
3  * the license was not distributed with this file, you can obtain one at:
4  *
5  * http://ugfx.io/license.html
6  */
7 
8 /********************************************************
9  * The FATFS file-system
10  ********************************************************/
11 
12 #include "../../gfx.h"
13 
14 #if GFX_USE_GFILE && GFILE_NEED_FATFS
15 
16 #include "gfile_fs.h"
17 #include "gfile_fatfs_wrapper.h"
18 
19 /********************************************************
20  * The FAT file-system VMT
21  ********************************************************/
22 
23 static gBool fatfsDel(const char* fname);
24 static gBool fatfsExists(const char* fname);
25 static gFileSize fatfsFileSize(const char* fname);
26 static gBool fatfsRename(const char* oldname, const char* newname);
27 static gBool fatfsOpen(GFILE* f, const char* fname);
28 static void fatfsClose(GFILE* f);
29 static int fatfsRead(GFILE* f, void* buf, int size);
30 static int fatfsWrite(GFILE* f, const void* buf, int size);
31 static gBool fatfsSetPos(GFILE* f, gFileSize pos);
32 static gFileSize fatfsGetSize(GFILE* f);
33 static gBool fatfsEOF(GFILE* f);
34 static gBool fatfsMount(const char* drive);
35 static gBool fatfsUnmount(const char* drive);
36 static gBool fatfsSync(GFILE* f);
37 #if GFILE_NEED_FILELISTS && _FS_MINIMIZE <= 1
38  static gfileList *fatfsFlOpen(const char *path, gBool dirs);
39  static const char *fatfsFlRead(gfileList *pfl);
40  static void fatfsFlClose(gfileList *pfl);
41 #endif
42 
43 const GFILEVMT FsFatFSVMT = {
44  GFSFLG_WRITEABLE | GFSFLG_SEEKABLE,
45  'F',
46  fatfsDel,
47  fatfsExists,
48  fatfsFileSize,
49  fatfsRename,
50  fatfsOpen,
51  fatfsClose,
52  fatfsRead,
53  fatfsWrite,
54  fatfsSetPos,
55  fatfsGetSize,
56  fatfsEOF,
57  fatfsMount, fatfsUnmount, fatfsSync,
58  #if GFILE_NEED_FILELISTS
59  #if _FS_MINIMIZE <= 1
60  fatfsFlOpen, fatfsFlRead, fatfsFlClose
61  #else
62  0, 0, 0
63  #endif
64  #endif
65 };
66 
67 // Our directory list structure
68 typedef struct fatfsList {
69  gfileList fl; // This must be the first element.
70  DIR dir;
71  FILINFO fno;
72  #if _USE_LFN
73  char lfn[_MAX_LFN + 1]; /* Buffer to store the LFN */
74  #endif
75 } fatfsList;
76 
77 // optimize these later on. Use an array to have multiple FatFS
78 static gBool fatfs_mounted = gFalse;
79 static FATFS fatfs_fs;
80 
81 static BYTE fatfs_flags2mode(GFILE* f)
82 {
83  BYTE mode = 0;
84 
85  if (f->flags & GFILEFLG_READ)
86  mode |= FA_READ;
87  if (f->flags & GFILEFLG_WRITE)
88  mode |= FA_WRITE;
89  if (f->flags & GFILEFLG_APPEND)
90  mode |= FA_OPEN_APPEND;
91  if (f->flags & GFILEFLG_TRUNC)
92  mode |= FA_CREATE_ALWAYS;
93 
94  /* ToDo - Complete */
95  return mode;
96 }
97 
98 static gBool fatfsDel(const char* fname)
99 {
100  FRESULT ferr;
101 
102  ferr = f_unlink( (const TCHAR*)fname );
103  if (ferr != FR_OK)
104  return gFalse;
105 
106  return gTrue;
107 }
108 
109 static gBool fatfsExists(const char* fname)
110 {
111  FRESULT ferr;
112  FILINFO fno;
113 
114  ferr = f_stat( (const TCHAR*)fname, &fno);
115  if (ferr != FR_OK)
116  return gFalse;
117 
118  return gTrue;
119 }
120 
121 static gFileSize fatfsFileSize(const char* fname)
122 {
123  FRESULT ferr;
124  FILINFO fno;
125 
126  ferr = f_stat( (const TCHAR*)fname, &fno );
127  if (ferr != FR_OK)
128  return 0;
129 
130  return (gFileSize)fno.fsize;
131 }
132 
133 static gBool fatfsRename(const char* oldname, const char* newname)
134 {
135  FRESULT ferr;
136 
137  ferr = f_rename( (const TCHAR*)oldname, (const TCHAR*)newname );
138  if (ferr != FR_OK)
139  return gFalse;
140 
141  return gTrue;
142 }
143 
144 static gBool fatfsOpen(GFILE* f, const char* fname)
145 {
146  FIL* fd;
147 
148  #if !GFILE_NEED_NOAUTOMOUNT
149  if (!fatfs_mounted && !fatfsMount(""))
150  return gFalse;
151  #endif
152 
153  if (!(fd = gfxAlloc(sizeof(FIL))))
154  return gFalse;
155 
156  if (f_open(fd, fname, fatfs_flags2mode(f)) != FR_OK) {
157  gfxFree(fd);
158  f->obj = 0;
159 
160  return gFalse;
161  }
162 
163  f->obj = (void*)fd;
164 
165  #if !GFILE_NEED_NOAUTOSYNC
166  // no need to sync when not opening for write
167  if (f->flags & GFILEFLG_WRITE) {
168  f_sync( (FIL*)f->obj );
169  }
170  #endif
171 
172  return gTrue;
173 }
174 
175 static void fatfsClose(GFILE* f)
176 {
177  if ((FIL*)f->obj != 0) {
178  f_close( (FIL*)f->obj );
179  gfxFree( (FIL*)f->obj );
180  }
181 }
182 
183 static int fatfsRead(GFILE* f, void* buf, int size)
184 {
185  int br;
186 
187  f_read( (FIL*)f->obj, buf, size, (UINT*)&br);
188 
189  return br;
190 }
191 
192 static int fatfsWrite(GFILE* f, const void* buf, int size)
193 {
194  int wr;
195 
196  f_write( (FIL*)f->obj, buf, size, (UINT*)&wr);
197  #if !GFILE_NEED_NOAUTOSYNC
198  f_sync( (FIL*)f->obj );
199  #endif
200 
201  return wr;
202 }
203 
204 static gBool fatfsSetPos(GFILE* f, gFileSize pos)
205 {
206  FRESULT ferr;
207 
208  ferr = f_lseek( (FIL*)f->obj, (DWORD)pos );
209  if (ferr != FR_OK)
210  return gFalse;
211 
212  return gTrue;
213 }
214 
215 static gFileSize fatfsGetSize(GFILE* f)
216 {
217  return (gFileSize)f_size( (FIL*)f->obj );
218 }
219 
220 static gBool fatfsEOF(GFILE* f)
221 {
222  if ( f_eof( (FIL*)f->obj ) != 0)
223  return gTrue;
224  else
225  return gFalse;
226 }
227 
228 static gBool fatfsMount(const char* drive)
229 {
230  FRESULT ferr;
231 
232  if (!fatfs_mounted) {
233  ferr = f_mount(&fatfs_fs, drive, 1);
234  if (ferr != FR_OK)
235  return gFalse;
236  fatfs_mounted = gTrue;
237  return gTrue;
238  }
239 
240  return gFalse;
241 }
242 
243 static gBool fatfsUnmount(const char* drive)
244 {
245  (void)drive;
246 
247  if (fatfs_mounted) {
248  // FatFS does not provide an unmount routine.
249  fatfs_mounted = gFalse;
250  return gTrue;
251  }
252 
253  return gFalse;
254 }
255 
256 static gBool fatfsSync(GFILE *f)
257 {
258  FRESULT ferr;
259 
260  ferr = f_sync( (FIL*)f->obj );
261  if (ferr != FR_OK) {
262  return gFalse;
263  }
264 
265  return gTrue;
266 }
267 
268 #if GFILE_NEED_FILELISTS && _FS_MINIMIZE <= 1
269  static gfileList *fatfsFlOpen(const char *path, gBool dirs) {
270  fatfsList *p;
271  (void) dirs;
272 
273  if (!(p = gfxAlloc(sizeof(fatfsList))))
274  return 0;
275 
276  if (f_opendir(&p->dir, path) != FR_OK) {
277  gfxFree(p);
278  return 0;
279  }
280  return &p->fl;
281  }
282 
283  static const char *fatfsFlRead(gfileList *pfl) {
284  #define ffl ((fatfsList *)pfl)
285 
286  while(1) {
287  #if _USE_LFN
288  ffl->fno.lfname = ffl->lfn;
289  ffl->fno.lfsize = sizeof(ffl->lfn);
290  #endif
291 
292  // Read the next entry
293  if (f_readdir(&ffl->dir, &ffl->fno) != FR_OK || !ffl->fno.fname[0])
294  return 0;
295 
296  /* Ignore dot entries */
297  if (ffl->fno.fname[0] == '.') continue;
298 
299  /* Is it a directory */
300  if (ffl->fl.dirs) {
301  if ((ffl->fno.fattrib & AM_DIR))
302  break;
303  } else {
304  if (!(ffl->fno.fattrib & AM_DIR))
305  break;
306  }
307  }
308 
309  #if _USE_LFN
310  return ffl->fno.lfname[0] ? ffl->fno.lfname : ffl->fno.fname;
311  #else
312  return ffl->fno.fname;
313  #endif
314  #undef ffl
315  }
316 
317  static void fatfsFlClose(gfileList *pfl) {
318  f_closedir(&((fatfsList *)pfl)->dir);
319  gfxFree(pfl);
320  }
321 
322 #endif
323 
324 #endif //GFX_USE_GFILE && GFILE_NEED_FATFS
325 
GFILE FATFS wrapper.
GFILE file system header.
struct GFILE GFILE
A file pointer.
Definition: gfile.h:34
void * gfxAlloc(gMemSize sz)
Allocate memory.
void gfxFree(void *ptr)
Free memory.