fs_port_fatfs.c
Go to the documentation of this file.
1 /**
2  * @file fs_port_fatfs.c
3  * @brief File system abstraction layer (FatFs)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 2.4.4
27  **/
28 
29 //Dependencies
30 #include <string.h>
31 #include "fs_port.h"
32 #include "fs_port_fatfs.h"
33 #include "error.h"
34 #include "debug.h"
35 
36 //FatFs revision
37 #define FATFS_R(major, minor, patch) ((major << 16) | (minor << 8) | (0x ## patch))
38 
39 //Check revision ID
40 #if (_FATFS == 124)
41  #define FATFS_REVISON FATFS_R(0, 7, c)
42 #elif (_FATFS == 126)
43  #define FATFS_REVISON FATFS_R(0, 7, e)
44 #elif (_FATFS == 8085)
45  #define FATFS_REVISON FATFS_R(0, 8, 0)
46 #elif (_FATFS == 8255)
47  #define FATFS_REVISON FATFS_R(0, 8, a)
48 #elif (_FATFS == 8237)
49  #define FATFS_REVISON FATFS_R(0, 8, b)
50 #elif (_FATFS == 6502)
51  #define FATFS_REVISON FATFS_R(0, 9, 0)
52 #elif (_FATFS == 4004)
53  #define FATFS_REVISON FATFS_R(0, 9, a)
54 #elif (_FATFS == 82786)
55  #define FATFS_REVISON FATFS_R(0, 9, b)
56 #elif (_FATFS == 80960)
57  #define FATFS_REVISON FATFS_R(0, 10, 0)
58 #elif (_FATFS == 29000)
59  #define FATFS_REVISON FATFS_R(0, 10, a)
60 #elif (_FATFS == 8051)
61  #define FATFS_REVISON FATFS_R(0, 10, b)
62 #elif (_FATFS == 80376)
63  #define FATFS_REVISON FATFS_R(0, 10, c)
64 #elif (_FATFS == 32020)
65  #define FATFS_REVISON FATFS_R(0, 11, 0)
66 #elif (_FATFS == 64180)
67  #define FATFS_REVISON FATFS_R(0, 11, a)
68 #elif (_FATFS == 88100)
69  #define FATFS_REVISON FATFS_R(0, 12, 0)
70 #elif (_FATFS == 80186)
71  #define FATFS_REVISON FATFS_R(0, 12, a)
72 #elif (_FATFS == 68020)
73  #define FATFS_REVISON FATFS_R(0, 12, b)
74 #elif (_FATFS == 68300)
75  #define FATFS_REVISON FATFS_R(0, 12, c)
76 #elif (FF_DEFINED == 87030)
77  #define FATFS_REVISON FATFS_R(0, 13, 0)
78 #elif (FF_DEFINED == 89352)
79  #define FATFS_REVISON FATFS_R(0, 13, a)
80 #elif (FF_DEFINED == 63463)
81  #define FATFS_REVISON FATFS_R(0, 13, b)
82 #elif (FF_DEFINED == 86604)
83  #define FATFS_REVISON FATFS_R(0, 13, c)
84 #elif (FF_DEFINED == 86606)
85  #define FATFS_REVISON FATFS_R(0, 14, 0)
86 #elif (FF_DEFINED == 80196)
87  #define FATFS_REVISON FATFS_R(0, 14, a)
88 #elif (FF_DEFINED == 86631)
89  #define FATFS_REVISON FATFS_R(0, 14, b)
90 #elif (FF_DEFINED == 80286)
91  #define FATFS_REVISON FATFS_R(0, 15, 0)
92 #else
93  #define FATFS_REVISON FATFS_R(0, 0, 0)
94 #endif
95 
96 //File system objects
97 static FATFS fs;
98 static FIL fileTable[FS_MAX_FILES];
99 static DIR dirTable[FS_MAX_DIRS];
100 
101 //Mutex that protects critical sections
102 static OsMutex fsMutex;
103 
104 
105 /**
106  * @brief File system initialization
107  * @return Error code
108  **/
109 
111 {
112  FRESULT res;
113 
114  //Clear file system objects
115  osMemset(fileTable, 0, sizeof(fileTable));
116  osMemset(dirTable, 0, sizeof(dirTable));
117 
118  //Create a mutex to protect critical sections
119  if(!osCreateMutex(&fsMutex))
120  {
121  //Failed to create mutex
122  return ERROR_OUT_OF_RESOURCES;
123  }
124 
125  //Mount file system
126 #if (FATFS_REVISON <= FATFS_R(0, 9, b))
127  res = f_mount(0, &fs);
128 #else
129  res = f_mount(&fs, "", 1);
130 #endif
131 
132  //Failed to mount file system?
133  if(res != FR_OK)
134  {
135  //Clean up side effects
136  osDeleteMutex(&fsMutex);
137  //Report an error
138  return ERROR_FAILURE;
139  }
140 
141  //Successful processing
142  return NO_ERROR;
143 }
144 
145 
146 /**
147  * @brief Check whether a file exists
148  * @param[in] path NULL-terminated string specifying the filename
149  * @return The function returns TRUE if the file exists. Otherwise FALSE is returned
150  **/
151 
153 {
154  FRESULT res;
155  FILINFO fno;
156 
157 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
158  fno.lfname = NULL;
159  fno.lfsize = 0;
160 #endif
161 
162  //Make sure the pathname is valid
163  if(path == NULL)
164  return FALSE;
165 
166 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
167  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
168  //Enter critical section
169  osAcquireMutex(&fsMutex);
170 #endif
171 
172  //Check whether the file exists
173  res = f_stat(path, &fno);
174 
175 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
176  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
177  //Leave critical section
178  osReleaseMutex(&fsMutex);
179 #endif
180 
181  //Any error to report?
182  if(res != FR_OK)
183  return FALSE;
184 
185  //Valid file?
186  if(fno.fattrib & AM_DIR)
187  {
188  return FALSE;
189  }
190  else
191  {
192  return TRUE;
193  }
194 }
195 
196 
197 /**
198  * @brief Retrieve the size of the specified file
199  * @param[in] path NULL-terminated string specifying the filename
200  * @param[out] size Size of the file in bytes
201  * @return Error code
202  **/
203 
204 error_t fsGetFileSize(const char_t *path, uint32_t *size)
205 {
206  FRESULT res;
207  FILINFO fno;
208 
209 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
210  fno.lfname = NULL;
211  fno.lfsize = 0;
212 #endif
213 
214  //Check parameters
215  if(path == NULL || size == NULL)
217 
218 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
219  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
220  //Enter critical section
221  osAcquireMutex(&fsMutex);
222 #endif
223 
224  //Retrieve information about the specified file
225  res = f_stat(path, &fno);
226 
227 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
228  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
229  //Leave critical section
230  osReleaseMutex(&fsMutex);
231 #endif
232 
233  //Any error to report?
234  if(res != FR_OK)
235  return ERROR_FAILURE;
236 
237  //Valid file?
238  if(fno.fattrib & AM_DIR)
239  return ERROR_FAILURE;
240 
241  //Return the size of the file
242  *size = fno.fsize;
243 
244  //Successful processing
245  return NO_ERROR;
246 }
247 
248 
249 /**
250  * @brief Retrieve the attributes of the specified file
251  * @param[in] path NULL-terminated string specifying the filename
252  * @param[out] fileStat File attributes
253  * @return Error code
254  **/
255 
256 error_t fsGetFileStat(const char_t *path, FsFileStat *fileStat)
257 {
258  FRESULT res;
259  FILINFO fno;
260 
261 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
262  fno.lfname = NULL;
263  fno.lfsize = 0;
264 #endif
265 
266  //Check parameters
267  if(path == NULL || fileStat == NULL)
269 
270 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
271  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
272  //Enter critical section
273  osAcquireMutex(&fsMutex);
274 #endif
275 
276  //Retrieve information about the specified file
277  res = f_stat(path, &fno);
278 
279 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
280  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
281  //Leave critical section
282  osReleaseMutex(&fsMutex);
283 #endif
284 
285  //Any error to report?
286  if(res != FR_OK)
287  return ERROR_FAILURE;
288 
289  //Clear file attributes
290  osMemset(fileStat, 0, sizeof(FsFileStat));
291 
292  //File attributes
293  fileStat->attributes = fno.fattrib;
294  //File size
295  fileStat->size = fno.fsize;
296 
297  //Time of last modification
298  fileStat->modified.year = 1980 + ((fno.fdate >> 9) & 0x7F);
299  fileStat->modified.month = (fno.fdate >> 5) & 0x0F;
300  fileStat->modified.day = fno.fdate & 0x1F;
301  fileStat->modified.dayOfWeek = 0;
302  fileStat->modified.hours = (fno.ftime >> 11) & 0x1F;
303  fileStat->modified.minutes = (fno.ftime >> 5) & 0x3F;
304  fileStat->modified.seconds = (fno.ftime & 0x1F) * 2;
305  fileStat->modified.milliseconds = 0;
306 
307  //Make sure the date is valid
308  fileStat->modified.month = MAX(fileStat->modified.month, 1);
309  fileStat->modified.month = MIN(fileStat->modified.month, 12);
310  fileStat->modified.day = MAX(fileStat->modified.day, 1);
311  fileStat->modified.day = MIN(fileStat->modified.day, 31);
312 
313  //Successful processing
314  return NO_ERROR;
315 }
316 
317 
318 /**
319  * @brief Rename the specified file
320  * @param[in] oldPath NULL-terminated string specifying the pathname of the file to be renamed
321  * @param[in] newPath NULL-terminated string specifying the new filename
322  * @return Error code
323  **/
324 
325 error_t fsRenameFile(const char_t *oldPath, const char_t *newPath)
326 {
327 #if (_FS_READONLY == 1 || FF_FS_READONLY == 1)
328  //Read-only configuration
329  return ERROR_READ_ONLY_ACCESS;
330 #else
331  FRESULT res;
332 
333  //Check parameters
334  if(oldPath == NULL || newPath == NULL)
336 
337 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
338  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
339  //Enter critical section
340  osAcquireMutex(&fsMutex);
341 #endif
342 
343  //Rename the specified file
344  res = f_rename(oldPath, newPath);
345 
346 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
347  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
348  //Leave critical section
349  osReleaseMutex(&fsMutex);
350 #endif
351 
352  //Any error to report?
353  if(res != FR_OK)
354  return ERROR_FAILURE;
355 
356  //Successful processing
357  return NO_ERROR;
358 #endif
359 }
360 
361 
362 /**
363  * @brief Delete a file
364  * @param[in] path NULL-terminated string specifying the filename
365  * @return Error code
366  **/
367 
369 {
370 #if (_FS_READONLY == 1 || FF_FS_READONLY == 1)
371  //Read-only configuration
372  return ERROR_READ_ONLY_ACCESS;
373 #else
374  FRESULT res;
375 
376  //Make sure the pathname is valid
377  if(path == NULL)
379 
380 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
381  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
382  //Enter critical section
383  osAcquireMutex(&fsMutex);
384 #endif
385 
386  //Delete the specified file
387  res = f_unlink(path);
388 
389 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
390  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
391  //Leave critical section
392  osReleaseMutex(&fsMutex);
393 #endif
394 
395  //Any error to report?
396  if(res != FR_OK)
397  return ERROR_FAILURE;
398 
399  //Successful processing
400  return NO_ERROR;
401 #endif
402 }
403 
404 
405 /**
406  * @brief Open the specified file for reading or writing
407  * @param[in] path NULL-terminated string specifying the filename
408  * @param[in] mode Type of access permitted (FS_FILE_MODE_READ,
409  * FS_FILE_MODE_WRITE or FS_FILE_MODE_CREATE)
410  * @return File handle
411  **/
412 
413 FsFile *fsOpenFile(const char_t *path, uint_t mode)
414 {
415  uint_t i;
416  uint_t flags;
417  FRESULT res;
418 
419  //File pointer
420  FsFile *file = NULL;
421 
422  //Make sure the pathname is valid
423  if(path == NULL)
424  return NULL;
425 
426  //Enter critical section
427  osAcquireMutex(&fsMutex);
428 
429  //Loop through the file objects
430  for(i = 0; i < FS_MAX_FILES; i++)
431  {
432  //Unused file object found?
433 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
434  if(fileTable[i].fs == NULL)
435 #else
436  if(fileTable[i].obj.fs == NULL)
437 #endif
438  {
439  //Default access mode
440  flags = 0;
441 
442  //Check access mode
443  if(mode & FS_FILE_MODE_READ)
444  flags |= FA_READ;
445 
446  if(mode & FS_FILE_MODE_WRITE)
447  flags |= FA_WRITE;
448 
449  if(mode & FS_FILE_MODE_CREATE)
450  flags |= FA_OPEN_ALWAYS;
451 
452  if(mode & FS_FILE_MODE_TRUNC)
453  flags |= FA_CREATE_ALWAYS;
454 
455  //Open the specified file
456  res = f_open(&fileTable[i], path, flags);
457 
458  //Check status code
459  if(res == FR_OK)
460  file = &fileTable[i];
461 
462  //Stop immediately
463  break;
464  }
465  }
466 
467  //Leave critical section
468  osReleaseMutex(&fsMutex);
469  //Return a handle to the file
470  return file;
471 }
472 
473 
474 /**
475  * @brief Move to specified position in file
476  * @param[in] file Handle that identifies the file
477  * @param[in] offset Number of bytes to move from origin
478  * @param[in] origin Position used as reference for the offset (FS_SEEK_SET,
479  * FS_SEEK_CUR or FS_SEEK_END)
480  * @return Error code
481  **/
482 
484 {
485  FRESULT res;
486 
487  //Make sure the file pointer is valid
488  if(file == NULL)
490 
491 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
492  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
493  //Enter critical section
494  osAcquireMutex(&fsMutex);
495 #endif
496 
497  //The origin is used as reference for the offset
498  if(origin == FS_SEEK_CUR)
499  {
500  //The offset is relative to the current file pointer
501  offset += f_tell((FIL *) file);
502  }
503  else if(origin == FS_SEEK_END)
504  {
505  //The offset is relative to the end of the file
506  offset += f_size((FIL *) file);
507  }
508  else
509  {
510  //The offset is absolute
511  }
512 
513  //Move read/write pointer
514  res = f_lseek((FIL *) file, offset);
515 
516 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
517  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
518  //Leave critical section
519  osReleaseMutex(&fsMutex);
520 #endif
521 
522  //Any error to report?
523  if(res != FR_OK)
524  return ERROR_FAILURE;
525 
526  //Successful processing
527  return NO_ERROR;
528 }
529 
530 
531 /**
532  * @brief Write data to the specified file
533  * @param[in] file Handle that identifies the file to be written
534  * @param[in] data Pointer to a buffer containing the data to be written
535  * @param[in] length Number of data bytes to write
536  * @return Error code
537  **/
538 
540 {
541 #if (_FS_READONLY == 1 || FF_FS_READONLY == 1)
542  //Read-only configuration
543  return ERROR_READ_ONLY_ACCESS;
544 #else
545  UINT n;
546  FRESULT res;
547 
548  //Make sure the file pointer is valid
549  if(file == NULL)
551 
552 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
553  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
554  //Enter critical section
555  osAcquireMutex(&fsMutex);
556 #endif
557 
558  //Write data
559  res = f_write((FIL *) file, data, length, &n);
560 
561 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
562  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
563  //Leave critical section
564  osReleaseMutex(&fsMutex);
565 #endif
566 
567  //Any error to report?
568  if(res != FR_OK)
569  return ERROR_FAILURE;
570 
571  //Sanity check
572  if(n != length)
573  return ERROR_FAILURE;
574 
575  //Successful processing
576  return NO_ERROR;
577 #endif
578 }
579 
580 
581 /**
582  * @brief Read data from the specified file
583  * @param[in] file Handle that identifies the file to be read
584  * @param[in] data Pointer to the buffer where to copy the data
585  * @param[in] size Size of the buffer, in bytes
586  * @param[out] length Number of data bytes that have been read
587  * @return Error code
588  **/
589 
590 error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
591 {
592  UINT n;
593  FRESULT res;
594 
595  //Check parameters
596  if(file == NULL || length == NULL)
598 
599  //No data has been read yet
600  *length = 0;
601 
602 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
603  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
604  //Enter critical section
605  osAcquireMutex(&fsMutex);
606 #endif
607 
608  //Read data
609  res = f_read((FIL *) file, data, size, &n);
610 
611 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
612  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
613  //Leave critical section
614  osReleaseMutex(&fsMutex);
615 #endif
616 
617  //Any error to report?
618  if(res != FR_OK)
619  return ERROR_FAILURE;
620 
621  //End of file?
622  if(!n)
623  return ERROR_END_OF_FILE;
624 
625  //Total number of data that have been read
626  *length = n;
627  //Successful processing
628  return NO_ERROR;
629 }
630 
631 
632 /**
633  * @brief Close a file
634  * @param[in] file Handle that identifies the file to be closed
635  **/
636 
638 {
639  //Make sure the file pointer is valid
640  if(file != NULL)
641  {
642  //Enter critical section
643  osAcquireMutex(&fsMutex);
644 
645  //Close the specified file
646  f_close((FIL *) file);
647 
648  //Mark the corresponding entry as free
649 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
650  ((FIL *) file)->fs = NULL;
651 #else
652  ((FIL *) file)->obj.fs = NULL;
653 #endif
654 
655  //Leave critical section
656  osReleaseMutex(&fsMutex);
657  }
658 }
659 
660 
661 /**
662  * @brief Check whether a directory exists
663  * @param[in] path NULL-terminated string specifying the directory path
664  * @return The function returns TRUE if the directory exists. Otherwise FALSE is returned
665  **/
666 
668 {
669  FRESULT res;
670  FILINFO fno;
671 
672 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
673  fno.lfname = NULL;
674  fno.lfsize = 0;
675 #endif
676 
677  //Make sure the pathname is valid
678  if(path == NULL)
679  return FALSE;
680 
681  //Root directory?
682  if(osStrcmp(path, "/") == 0)
683  return TRUE;
684 
685 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
686  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
687  //Enter critical section
688  osAcquireMutex(&fsMutex);
689 #endif
690 
691  //Check whether the file exists
692  res = f_stat(path, &fno);
693 
694 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
695  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
696  //Leave critical section
697  osReleaseMutex(&fsMutex);
698 #endif
699 
700  //Any error to report?
701  if(res != FR_OK)
702  return FALSE;
703 
704  //Valid directory?
705  if(fno.fattrib & AM_DIR)
706  {
707  return TRUE;
708  }
709  else
710  {
711  return FALSE;
712  }
713 }
714 
715 
716 /**
717  * @brief Create a directory
718  * @param[in] path NULL-terminated string specifying the directory path
719  * @return Error code
720  **/
721 
723 {
724 #if (_FS_READONLY == 1 || FF_FS_READONLY == 1)
725  //Read-only configuration
726  return ERROR_READ_ONLY_ACCESS;
727 #else
728  FRESULT res;
729 
730  //Make sure the pathname is valid
731  if(path == NULL)
733 
734 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
735  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
736  //Enter critical section
737  osAcquireMutex(&fsMutex);
738 #endif
739 
740  //Create a new directory
741  res = f_mkdir(path);
742 
743 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
744  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
745  //Leave critical section
746  osReleaseMutex(&fsMutex);
747 #endif
748 
749  //Any error to report?
750  if(res != FR_OK)
751  return ERROR_FAILURE;
752 
753  //Successful processing
754  return NO_ERROR;
755 #endif
756 }
757 
758 
759 /**
760  * @brief Remove a directory
761  * @param[in] path NULL-terminated string specifying the directory path
762  * @return Error code
763  **/
764 
766 {
767 #if (_FS_READONLY == 1 || FF_FS_READONLY == 1)
768  //Read-only configuration
769  return ERROR_READ_ONLY_ACCESS;
770 #else
771  FRESULT res;
772 
773  //Make sure the pathname is valid
774  if(path == NULL)
776 
777 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
778  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
779  //Enter critical section
780  osAcquireMutex(&fsMutex);
781 #endif
782 
783  //Remove the specified directory
784  res = f_unlink(path);
785 
786 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
787  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
788  //Leave critical section
789  osReleaseMutex(&fsMutex);
790 #endif
791 
792  //Any error to report?
793  if(res != FR_OK)
794  return ERROR_FAILURE;
795 
796  //Successful processing
797  return NO_ERROR;
798 #endif
799 }
800 
801 
802 /**
803  * @brief Open a directory stream
804  * @param[in] path NULL-terminated string specifying the directory path
805  * @return Directory handle
806  **/
807 
808 FsDir *fsOpenDir(const char_t *path)
809 {
810  uint_t i;
811  FRESULT res;
812 
813  //Directory pointer
814  FsDir *dir = NULL;
815 
816  //Make sure the pathname is valid
817  if(path == NULL)
818  return NULL;
819 
820  //Enter critical section
821  osAcquireMutex(&fsMutex);
822 
823  //Loop through the directory objects
824  for(i = 0; i < FS_MAX_DIRS; i++)
825  {
826  //Unused directory object found?
827 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
828  if(dirTable[i].fs == NULL)
829 #else
830  if(dirTable[i].obj.fs == NULL)
831 #endif
832  {
833  //Open the specified directory
834  res = f_opendir(&dirTable[i], path);
835 
836  //Check status code
837  if(res == FR_OK)
838  dir = &dirTable[i];
839 
840  //Stop immediately
841  break;
842  }
843  }
844 
845  //Leave critical section
846  osReleaseMutex(&fsMutex);
847  //Return a handle to the directory
848  return dir;
849 }
850 
851 
852 /**
853  * @brief Read an entry from the specified directory stream
854  * @param[in] dir Handle that identifies the directory
855  * @param[out] dirEntry Pointer to a directory entry
856  * @return Error code
857  **/
858 
860 {
861  FRESULT res;
862  FILINFO fno;
863  char_t *fn;
864  size_t n;
865 
866 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
867  char_t lfn[_MAX_LFN + 1];
868  fno.lfname = lfn;
869  fno.lfsize = sizeof(lfn);
870 #endif
871 
872  //Make sure the directory pointer is valid
873  if(dir == NULL)
875 
876 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
877  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
878  //Enter critical section
879  osAcquireMutex(&fsMutex);
880 #endif
881 
882  //Read the specified directory
883  res = f_readdir((DIR *) dir, &fno);
884 
885 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
886  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
887  //Leave critical section
888  osReleaseMutex(&fsMutex);
889 #endif
890 
891  //Any error to report?
892  if(res != FR_OK)
893  return ERROR_FAILURE;
894 
895  //End of the directory stream?
896  if(fno.fname[0] == '\0')
897  return ERROR_END_OF_STREAM;
898 
899  //Point to the long filename
900 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
901  fn = (*fno.lfname != '\0') ? fno.lfname : fno.fname;
902 #else
903  fn = fno.fname;
904 #endif
905 
906  //File attributes
907  dirEntry->attributes = fno.fattrib;
908  //File size
909  dirEntry->size = fno.fsize;
910 
911  //Time of last modification
912  dirEntry->modified.year = 1980 + ((fno.fdate >> 9) & 0x7F);
913  dirEntry->modified.month = (fno.fdate >> 5) & 0x0F;
914  dirEntry->modified.day = fno.fdate & 0x1F;
915  dirEntry->modified.dayOfWeek = 0;
916  dirEntry->modified.hours = (fno.ftime >> 11) & 0x1F;
917  dirEntry->modified.minutes = (fno.ftime >> 5) & 0x3F;
918  dirEntry->modified.seconds = (fno.ftime & 0x1F) * 2;
919  dirEntry->modified.milliseconds = 0;
920 
921  //Make sure the date is valid
922  dirEntry->modified.month = MAX(dirEntry->modified.month, 1);
923  dirEntry->modified.month = MIN(dirEntry->modified.month, 12);
924  dirEntry->modified.day = MAX(dirEntry->modified.day, 1);
925  dirEntry->modified.day = MIN(dirEntry->modified.day, 31);
926 
927  //Retrieve the length of the file name
928  n = osStrlen(fn);
929  //Limit the number of characters to be copied
930  n = MIN(n, FS_MAX_NAME_LEN);
931 
932  //Copy file name
933  osStrncpy(dirEntry->name, fn, n);
934  //Properly terminate the string with a NULL character
935  dirEntry->name[n] = '\0';
936 
937  //Successful processing
938  return NO_ERROR;
939 }
940 
941 
942 /**
943  * @brief Close a directory stream
944  * @param[in] dir Handle that identifies the directory to be closed
945  **/
946 
947 void fsCloseDir(FsDir *dir)
948 {
949  //Make sure the directory pointer is valid
950  if(dir != NULL)
951  {
952  //Enter critical section
953  osAcquireMutex(&fsMutex);
954 
955 #if (FATFS_REVISON >= FATFS_R(0, 10, 0))
956  //Close the specified directory
957  f_closedir((DIR *) dir);
958 #endif
959 
960  //Mark the corresponding entry as free
961 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
962  ((DIR *) dir)->fs = NULL;
963 #else
964  ((DIR *) dir)->obj.fs = NULL;
965 #endif
966 
967  //Leave critical section
968  osReleaseMutex(&fsMutex);
969  }
970 }
error_t fsSeekFile(FsFile *file, int_t offset, uint_t origin)
Move to specified position in file.
int bool_t
Definition: compiler_port.h:53
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
signed int int_t
Definition: compiler_port.h:49
error_t fsGetFileSize(const char_t *path, uint32_t *size)
Retrieve the size of the specified file.
uint16_t year
Definition: date_time.h:48
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
#define osStrcmp(s1, s2)
Definition: os_port.h:171
#define osStrlen(s)
Definition: os_port.h:165
error_t fsRemoveDir(const char_t *path)
Remove a directory.
@ ERROR_END_OF_STREAM
Definition: error.h:210
const uint8_t res[]
Directory descriptor.
Definition: fs_port_posix.h:60
error_t fsCreateDir(const char_t *path)
Create a directory.
@ FS_FILE_MODE_WRITE
Definition: fs_port.h:73
uint8_t day
Definition: date_time.h:50
error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
Read data from the specified file.
FsDir * fsOpenDir(const char_t *path)
Open a directory stream.
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
@ FS_SEEK_END
Definition: fs_port.h:87
uint8_t minutes
Definition: date_time.h:53
error_t
Error codes.
Definition: error.h:43
#define FS_MAX_FILES
Definition: fs_port_fatfs.h:38
void fsCloseFile(FsFile *file)
Close a file.
error_t fsRenameFile(const char_t *oldPath, const char_t *newPath)
Rename the specified file.
bool_t fsFileExists(const char_t *path)
Check whether a file exists.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ FS_SEEK_CUR
Definition: fs_port.h:86
error_t fsReadDir(FsDir *dir, FsDirEntry *dirEntry)
Read an entry from the specified directory stream.
FsFile * fsOpenFile(const char_t *path, uint_t mode)
Open the specified file for reading or writing.
@ ERROR_END_OF_FILE
Definition: error.h:159
uint32_t attributes
Definition: fs_port.h:97
File status.
Definition: fs_port.h:96
uint32_t size
Definition: fs_port.h:98
#define FS_MAX_NAME_LEN
Definition: fs_port.h:40
uint8_t hours
Definition: date_time.h:52
Error codes description.
uint8_t length
Definition: tcp.h:368
#define MIN(a, b)
Definition: os_port.h:63
uint8_t seconds
Definition: date_time.h:54
File system abstraction layer.
Mutex object.
char_t name[FS_MAX_NAME_LEN+1]
Definition: fs_port.h:112
uint8_t flags
Definition: tcp.h:351
#define MAX(a, b)
Definition: os_port.h:67
uint8_t month
Definition: date_time.h:49
char char_t
Definition: compiler_port.h:48
error_t fsInit(void)
File system initialization.
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
DateTime modified
Definition: fs_port.h:111
uint8_t n
DateTime modified
Definition: fs_port.h:99
Directory entry.
Definition: fs_port.h:108
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
bool_t fsDirExists(const char_t *path)
Check whether a directory exists.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
uint32_t attributes
Definition: fs_port.h:109
uint32_t size
Definition: fs_port.h:110
uint8_t file[128]
Definition: dhcp_common.h:223
@ FS_FILE_MODE_TRUNC
Definition: fs_port.h:75
error_t fsWriteFile(FsFile *file, void *data, size_t length)
Write data to the specified file.
#define osStrncpy(s1, s2, length)
Definition: os_port.h:213
error_t fsGetFileStat(const char_t *path, FsFileStat *fileStat)
Retrieve the attributes of the specified file.
uint16_t milliseconds
Definition: date_time.h:55
#define FS_MAX_DIRS
Definition: fs_port_fatfs.h:45
@ FS_FILE_MODE_READ
Definition: fs_port.h:72
void fsCloseDir(FsDir *dir)
Close a directory stream.
uint8_t dayOfWeek
Definition: date_time.h:51
File system abstraction layer (FatFs)
unsigned int uint_t
Definition: compiler_port.h:50
#define osMemset(p, value, length)
Definition: os_port.h:135
@ ERROR_READ_ONLY_ACCESS
Definition: error.h:225
error_t fsDeleteFile(const char_t *path)
Delete a file.
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
@ FS_FILE_MODE_CREATE
Definition: fs_port.h:74
void FsFile
File descriptor.
Definition: fs_port_fatfs.h:60