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.0
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  return FALSE;
188  else
189  return TRUE;
190 }
191 
192 
193 /**
194  * @brief Retrieve the size of the specified file
195  * @param[in] path NULL-terminated string specifying the filename
196  * @param[out] size Size of the file in bytes
197  * @return Error code
198  **/
199 
200 error_t fsGetFileSize(const char_t *path, uint32_t *size)
201 {
202  FRESULT res;
203  FILINFO fno;
204 
205 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
206  fno.lfname = NULL;
207  fno.lfsize = 0;
208 #endif
209 
210  //Check parameters
211  if(path == NULL || size == NULL)
213 
214 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
215  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
216  //Enter critical section
217  osAcquireMutex(&fsMutex);
218 #endif
219 
220  //Retrieve information about the specified file
221  res = f_stat(path, &fno);
222 
223 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
224  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
225  //Leave critical section
226  osReleaseMutex(&fsMutex);
227 #endif
228 
229  //Any error to report?
230  if(res != FR_OK)
231  return ERROR_FAILURE;
232 
233  //Valid file?
234  if(fno.fattrib & AM_DIR)
235  return ERROR_FAILURE;
236 
237  //Return the size of the file
238  *size = fno.fsize;
239 
240  //Successful processing
241  return NO_ERROR;
242 }
243 
244 
245 /**
246  * @brief Retrieve the attributes of the specified file
247  * @param[in] path NULL-terminated string specifying the filename
248  * @param[out] fileStat File attributes
249  * @return Error code
250  **/
251 
252 error_t fsGetFileStat(const char_t *path, FsFileStat *fileStat)
253 {
254  FRESULT res;
255  FILINFO fno;
256 
257 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
258  fno.lfname = NULL;
259  fno.lfsize = 0;
260 #endif
261 
262  //Check parameters
263  if(path == NULL || fileStat == NULL)
265 
266 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
267  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
268  //Enter critical section
269  osAcquireMutex(&fsMutex);
270 #endif
271 
272  //Retrieve information about the specified file
273  res = f_stat(path, &fno);
274 
275 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
276  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
277  //Leave critical section
278  osReleaseMutex(&fsMutex);
279 #endif
280 
281  //Any error to report?
282  if(res != FR_OK)
283  return ERROR_FAILURE;
284 
285  //Clear file attributes
286  osMemset(fileStat, 0, sizeof(FsFileStat));
287 
288  //File attributes
289  fileStat->attributes = fno.fattrib;
290  //File size
291  fileStat->size = fno.fsize;
292 
293  //Time of last modification
294  fileStat->modified.year = 1980 + ((fno.fdate >> 9) & 0x7F);
295  fileStat->modified.month = (fno.fdate >> 5) & 0x0F;
296  fileStat->modified.day = fno.fdate & 0x1F;
297  fileStat->modified.dayOfWeek = 0;
298  fileStat->modified.hours = (fno.ftime >> 11) & 0x1F;
299  fileStat->modified.minutes = (fno.ftime >> 5) & 0x3F;
300  fileStat->modified.seconds = (fno.ftime & 0x1F) * 2;
301  fileStat->modified.milliseconds = 0;
302 
303  //Make sure the date is valid
304  fileStat->modified.month = MAX(fileStat->modified.month, 1);
305  fileStat->modified.month = MIN(fileStat->modified.month, 12);
306  fileStat->modified.day = MAX(fileStat->modified.day, 1);
307  fileStat->modified.day = MIN(fileStat->modified.day, 31);
308 
309  //Successful processing
310  return NO_ERROR;
311 }
312 
313 
314 /**
315  * @brief Rename the specified file
316  * @param[in] oldPath NULL-terminated string specifying the pathname of the file to be renamed
317  * @param[in] newPath NULL-terminated string specifying the new filename
318  * @return Error code
319  **/
320 
321 error_t fsRenameFile(const char_t *oldPath, const char_t *newPath)
322 {
323 #if (_FS_READONLY == 1 || FF_FS_READONLY ==1)
324  //Read-only configuration
325  return ERROR_READ_ONLY_ACCESS;
326 #else
327  FRESULT res;
328 
329  //Check parameters
330  if(oldPath == NULL || newPath == NULL)
332 
333 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
334  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
335  //Enter critical section
336  osAcquireMutex(&fsMutex);
337 #endif
338 
339  //Rename the specified file
340  res = f_rename(oldPath, newPath);
341 
342 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
343  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
344  //Leave critical section
345  osReleaseMutex(&fsMutex);
346 #endif
347 
348  //Any error to report?
349  if(res != FR_OK)
350  return ERROR_FAILURE;
351 
352  //Successful processing
353  return NO_ERROR;
354 #endif
355 }
356 
357 
358 /**
359  * @brief Delete a file
360  * @param[in] path NULL-terminated string specifying the filename
361  * @return Error code
362  **/
363 
365 {
366 #if (_FS_READONLY == 1 || FF_FS_READONLY ==1)
367  //Read-only configuration
368  return ERROR_READ_ONLY_ACCESS;
369 #else
370  FRESULT res;
371 
372  //Make sure the pathname is valid
373  if(path == NULL)
375 
376 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
377  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
378  //Enter critical section
379  osAcquireMutex(&fsMutex);
380 #endif
381 
382  //Delete the specified file
383  res = f_unlink(path);
384 
385 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
386  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
387  //Leave critical section
388  osReleaseMutex(&fsMutex);
389 #endif
390 
391  //Any error to report?
392  if(res != FR_OK)
393  return ERROR_FAILURE;
394 
395  //Successful processing
396  return NO_ERROR;
397 #endif
398 }
399 
400 
401 /**
402  * @brief Open the specified file for reading or writing
403  * @param[in] path NULL-terminated string specifying the filename
404  * @param[in] mode Type of access permitted (FS_FILE_MODE_READ,
405  * FS_FILE_MODE_WRITE or FS_FILE_MODE_CREATE)
406  * @return File handle
407  **/
408 
409 FsFile *fsOpenFile(const char_t *path, uint_t mode)
410 {
411  uint_t i;
412  uint_t flags;
413  FRESULT res;
414 
415  //File pointer
416  FsFile *file = NULL;
417 
418  //Make sure the pathname is valid
419  if(path == NULL)
420  return NULL;
421 
422  //Enter critical section
423  osAcquireMutex(&fsMutex);
424 
425  //Loop through the file objects
426  for(i = 0; i < FS_MAX_FILES; i++)
427  {
428  //Unused file object found?
429 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
430  if(fileTable[i].fs == NULL)
431 #else
432  if(fileTable[i].obj.fs == NULL)
433 #endif
434  {
435  //Default access mode
436  flags = 0;
437 
438  //Check access mode
439  if(mode & FS_FILE_MODE_READ)
440  flags |= FA_READ;
441 
442  if(mode & FS_FILE_MODE_WRITE)
443  flags |= FA_WRITE;
444 
445  if(mode & FS_FILE_MODE_CREATE)
446  flags |= FA_OPEN_ALWAYS;
447 
448  if(mode & FS_FILE_MODE_TRUNC)
449  flags |= FA_CREATE_ALWAYS;
450 
451  //Open the specified file
452  res = f_open(&fileTable[i], path, flags);
453 
454  //Check status code
455  if(res == FR_OK)
456  file = &fileTable[i];
457 
458  //Stop immediately
459  break;
460  }
461  }
462 
463  //Leave critical section
464  osReleaseMutex(&fsMutex);
465  //Return a handle to the file
466  return file;
467 }
468 
469 
470 /**
471  * @brief Move to specified position in file
472  * @param[in] file Handle that identifies the file
473  * @param[in] offset Number of bytes to move from origin
474  * @param[in] origin Position used as reference for the offset (FS_SEEK_SET,
475  * FS_SEEK_CUR or FS_SEEK_END)
476  * @return Error code
477  **/
478 
480 {
481  FRESULT res;
482 
483  //Make sure the file pointer is valid
484  if(file == NULL)
486 
487 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
488  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
489  //Enter critical section
490  osAcquireMutex(&fsMutex);
491 #endif
492 
493  //The origin is used as reference for the offset
494  if(origin == FS_SEEK_CUR)
495  {
496  //The offset is relative to the current file pointer
497  offset += f_tell((FIL *) file);
498  }
499  else if(origin == FS_SEEK_END)
500  {
501  //The offset is relative to the end of the file
502  offset += f_size((FIL *) file);
503  }
504  else
505  {
506  //The offset is absolute
507  }
508 
509  //Move read/write pointer
510  res = f_lseek((FIL *) file, offset);
511 
512 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
513  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
514  //Leave critical section
515  osReleaseMutex(&fsMutex);
516 #endif
517 
518  //Any error to report?
519  if(res != FR_OK)
520  return ERROR_FAILURE;
521 
522  //Successful processing
523  return NO_ERROR;
524 }
525 
526 
527 /**
528  * @brief Write data to the specified file
529  * @param[in] file Handle that identifies the file to be written
530  * @param[in] data Pointer to a buffer containing the data to be written
531  * @param[in] length Number of data bytes to write
532  * @return Error code
533  **/
534 
536 {
537 #if (_FS_READONLY == 1 || FF_FS_READONLY ==1)
538  //Read-only configuration
539  return ERROR_READ_ONLY_ACCESS;
540 #else
541  UINT n;
542  FRESULT res;
543 
544  //Make sure the file pointer is valid
545  if(file == NULL)
547 
548 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
549  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
550  //Enter critical section
551  osAcquireMutex(&fsMutex);
552 #endif
553 
554  //Write data
555  res = f_write((FIL *) file, data, length, &n);
556 
557 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
558  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
559  //Leave critical section
560  osReleaseMutex(&fsMutex);
561 #endif
562 
563  //Any error to report?
564  if(res != FR_OK)
565  return ERROR_FAILURE;
566 
567  //Sanity check
568  if(n != length)
569  return ERROR_FAILURE;
570 
571  //Successful processing
572  return NO_ERROR;
573 #endif
574 }
575 
576 
577 /**
578  * @brief Read data from the specified file
579  * @param[in] file Handle that identifies the file to be read
580  * @param[in] data Pointer to the buffer where to copy the data
581  * @param[in] size Size of the buffer, in bytes
582  * @param[out] length Number of data bytes that have been read
583  * @return Error code
584  **/
585 
586 error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
587 {
588  UINT n;
589  FRESULT res;
590 
591  //Check parameters
592  if(file == NULL || length == NULL)
594 
595  //No data has been read yet
596  *length = 0;
597 
598 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
599  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
600  //Enter critical section
601  osAcquireMutex(&fsMutex);
602 #endif
603 
604  //Read data
605  res = f_read((FIL *) file, data, size, &n);
606 
607 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
608  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
609  //Leave critical section
610  osReleaseMutex(&fsMutex);
611 #endif
612 
613  //Any error to report?
614  if(res != FR_OK)
615  return ERROR_FAILURE;
616 
617  //End of file?
618  if(!n)
619  return ERROR_END_OF_FILE;
620 
621  //Total number of data that have been read
622  *length = n;
623  //Successful processing
624  return NO_ERROR;
625 }
626 
627 
628 /**
629  * @brief Close a file
630  * @param[in] file Handle that identifies the file to be closed
631  **/
632 
634 {
635  //Make sure the file pointer is valid
636  if(file != NULL)
637  {
638  //Enter critical section
639  osAcquireMutex(&fsMutex);
640 
641  //Close the specified file
642  f_close((FIL *) file);
643 
644  //Mark the corresponding entry as free
645 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
646  ((FIL *) file)->fs = NULL;
647 #else
648  ((FIL *) file)->obj.fs = NULL;
649 #endif
650 
651  //Leave critical section
652  osReleaseMutex(&fsMutex);
653  }
654 }
655 
656 
657 /**
658  * @brief Check whether a directory exists
659  * @param[in] path NULL-terminated string specifying the directory path
660  * @return The function returns TRUE if the directory exists. Otherwise FALSE is returned
661  **/
662 
664 {
665  FRESULT res;
666  FILINFO fno;
667 
668 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
669  fno.lfname = NULL;
670  fno.lfsize = 0;
671 #endif
672 
673  //Make sure the pathname is valid
674  if(path == NULL)
675  return FALSE;
676 
677  //Root directory?
678  if(!osStrcmp(path, "/"))
679  return TRUE;
680 
681 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
682  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
683  //Enter critical section
684  osAcquireMutex(&fsMutex);
685 #endif
686 
687  //Check whether the file exists
688  res = f_stat(path, &fno);
689 
690 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
691  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
692  //Leave critical section
693  osReleaseMutex(&fsMutex);
694 #endif
695 
696  //Any error to report?
697  if(res != FR_OK)
698  return FALSE;
699 
700  //Valid directory?
701  if(fno.fattrib & AM_DIR)
702  return TRUE;
703  else
704  return FALSE;
705 }
706 
707 
708 /**
709  * @brief Create a directory
710  * @param[in] path NULL-terminated string specifying the directory path
711  * @return Error code
712  **/
713 
715 {
716 #if (_FS_READONLY == 1 || FF_FS_READONLY ==1)
717  //Read-only configuration
718  return ERROR_READ_ONLY_ACCESS;
719 #else
720  FRESULT res;
721 
722  //Make sure the pathname is valid
723  if(path == NULL)
725 
726 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
727  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
728  //Enter critical section
729  osAcquireMutex(&fsMutex);
730 #endif
731 
732  //Create a new directory
733  res = f_mkdir(path);
734 
735 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
736  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
737  //Leave critical section
738  osReleaseMutex(&fsMutex);
739 #endif
740 
741  //Any error to report?
742  if(res != FR_OK)
743  return ERROR_FAILURE;
744 
745  //Successful processing
746  return NO_ERROR;
747 #endif
748 }
749 
750 
751 /**
752  * @brief Remove a directory
753  * @param[in] path NULL-terminated string specifying the directory path
754  * @return Error code
755  **/
756 
758 {
759 #if (_FS_READONLY == 1 || FF_FS_READONLY ==1)
760  //Read-only configuration
761  return ERROR_READ_ONLY_ACCESS;
762 #else
763  FRESULT res;
764 
765  //Make sure the pathname is valid
766  if(path == NULL)
768 
769 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
770  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
771  //Enter critical section
772  osAcquireMutex(&fsMutex);
773 #endif
774 
775  //Remove the specified directory
776  res = f_unlink(path);
777 
778 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
779  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
780  //Leave critical section
781  osReleaseMutex(&fsMutex);
782 #endif
783 
784  //Any error to report?
785  if(res != FR_OK)
786  return ERROR_FAILURE;
787 
788  //Successful processing
789  return NO_ERROR;
790 #endif
791 }
792 
793 
794 /**
795  * @brief Open a directory stream
796  * @param[in] path NULL-terminated string specifying the directory path
797  * @return Directory handle
798  **/
799 
800 FsDir *fsOpenDir(const char_t *path)
801 {
802  uint_t i;
803  FRESULT res;
804 
805  //Directory pointer
806  FsDir *dir = NULL;
807 
808  //Make sure the pathname is valid
809  if(path == NULL)
810  return NULL;
811 
812  //Enter critical section
813  osAcquireMutex(&fsMutex);
814 
815  //Loop through the directory objects
816  for(i = 0; i < FS_MAX_DIRS; i++)
817  {
818  //Unused directory object found?
819 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
820  if(dirTable[i].fs == NULL)
821 #else
822  if(dirTable[i].obj.fs == NULL)
823 #endif
824  {
825  //Open the specified directory
826  res = f_opendir(&dirTable[i], path);
827 
828  //Check status code
829  if(res == FR_OK)
830  dir = &dirTable[i];
831 
832  //Stop immediately
833  break;
834  }
835  }
836 
837  //Leave critical section
838  osReleaseMutex(&fsMutex);
839  //Return a handle to the directory
840  return dir;
841 }
842 
843 
844 /**
845  * @brief Read an entry from the specified directory stream
846  * @param[in] dir Handle that identifies the directory
847  * @param[out] dirEntry Pointer to a directory entry
848  * @return Error code
849  **/
850 
852 {
853  FRESULT res;
854  FILINFO fno;
855  char_t *fn;
856  size_t n;
857 
858 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
859  char_t lfn[_MAX_LFN + 1];
860  fno.lfname = lfn;
861  fno.lfsize = sizeof(lfn);
862 #endif
863 
864  //Make sure the directory pointer is valid
865  if(dir == NULL)
867 
868 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
869  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
870  //Enter critical section
871  osAcquireMutex(&fsMutex);
872 #endif
873 
874  //Read the specified directory
875  res = f_readdir((DIR *) dir, &fno);
876 
877 #if ((FATFS_REVISON <= FATFS_R(0, 12, c) && _FS_REENTRANT == 0) || \
878  (FATFS_REVISON >= FATFS_R(0, 13, 0) && FF_FS_REENTRANT == 0))
879  //Leave critical section
880  osReleaseMutex(&fsMutex);
881 #endif
882 
883  //Any error to report?
884  if(res != FR_OK)
885  return ERROR_FAILURE;
886 
887  //End of the directory stream?
888  if(fno.fname[0] == '\0')
889  return ERROR_END_OF_STREAM;
890 
891  //Point to the long filename
892 #if (FATFS_REVISON <= FATFS_R(0, 11, a) && _USE_LFN != 0)
893  fn = (*fno.lfname != '\0') ? fno.lfname : fno.fname;
894 #else
895  fn = fno.fname;
896 #endif
897 
898  //File attributes
899  dirEntry->attributes = fno.fattrib;
900  //File size
901  dirEntry->size = fno.fsize;
902 
903  //Time of last modification
904  dirEntry->modified.year = 1980 + ((fno.fdate >> 9) & 0x7F);
905  dirEntry->modified.month = (fno.fdate >> 5) & 0x0F;
906  dirEntry->modified.day = fno.fdate & 0x1F;
907  dirEntry->modified.dayOfWeek = 0;
908  dirEntry->modified.hours = (fno.ftime >> 11) & 0x1F;
909  dirEntry->modified.minutes = (fno.ftime >> 5) & 0x3F;
910  dirEntry->modified.seconds = (fno.ftime & 0x1F) * 2;
911  dirEntry->modified.milliseconds = 0;
912 
913  //Make sure the date is valid
914  dirEntry->modified.month = MAX(dirEntry->modified.month, 1);
915  dirEntry->modified.month = MIN(dirEntry->modified.month, 12);
916  dirEntry->modified.day = MAX(dirEntry->modified.day, 1);
917  dirEntry->modified.day = MIN(dirEntry->modified.day, 31);
918 
919  //Retrieve the length of the file name
920  n = osStrlen(fn);
921  //Limit the number of characters to be copied
922  n = MIN(n, FS_MAX_NAME_LEN);
923 
924  //Copy file name
925  osStrncpy(dirEntry->name, fn, n);
926  //Properly terminate the string with a NULL character
927  dirEntry->name[n] = '\0';
928 
929  //Successful processing
930  return NO_ERROR;
931 }
932 
933 
934 /**
935  * @brief Close a directory stream
936  * @param[in] dir Handle that identifies the directory to be closed
937  **/
938 
939 void fsCloseDir(FsDir *dir)
940 {
941  //Make sure the directory pointer is valid
942  if(dir != NULL)
943  {
944  //Enter critical section
945  osAcquireMutex(&fsMutex);
946 
947 #if (FATFS_REVISON >= FATFS_R(0, 10, 0))
948  //Close the specified directory
949  f_closedir((DIR *) dir);
950 #endif
951 
952  //Mark the corresponding entry as free
953 #if (FATFS_REVISON <= FATFS_R(0, 11, a))
954  ((DIR *) dir)->fs = NULL;
955 #else
956  ((DIR *) dir)->obj.fs = NULL;
957 #endif
958 
959  //Leave critical section
960  osReleaseMutex(&fsMutex);
961  }
962 }
signed int int_t
Definition: compiler_port.h:49
unsigned int uint_t
Definition: compiler_port.h:50
char char_t
Definition: compiler_port.h:48
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
uint8_t file[128]
Definition: dhcp_common.h:223
uint8_t n
Error codes description.
error_t
Error codes.
Definition: error.h:43
@ ERROR_READ_ONLY_ACCESS
Definition: error.h:224
@ ERROR_END_OF_FILE
Definition: error.h:159
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ ERROR_END_OF_STREAM
Definition: error.h:210
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
uint8_t data[]
Definition: ethernet.h:222
File system abstraction layer.
@ FS_FILE_MODE_CREATE
Definition: fs_port.h:74
@ FS_FILE_MODE_READ
Definition: fs_port.h:72
@ FS_FILE_MODE_TRUNC
Definition: fs_port.h:75
@ FS_FILE_MODE_WRITE
Definition: fs_port.h:73
#define FS_MAX_NAME_LEN
Definition: fs_port.h:40
@ FS_SEEK_END
Definition: fs_port.h:87
@ FS_SEEK_CUR
Definition: fs_port.h:86
error_t fsSeekFile(FsFile *file, int_t offset, uint_t origin)
Move to specified position in file.
bool_t fsFileExists(const char_t *path)
Check whether a file exists.
error_t fsInit(void)
File system initialization.
error_t fsRemoveDir(const char_t *path)
Remove a directory.
error_t fsDeleteFile(const char_t *path)
Delete a file.
bool_t fsDirExists(const char_t *path)
Check whether a directory exists.
error_t fsGetFileSize(const char_t *path, uint32_t *size)
Retrieve the size of the specified file.
void fsCloseFile(FsFile *file)
Close a file.
error_t fsRenameFile(const char_t *oldPath, const char_t *newPath)
Rename the specified file.
FsDir * fsOpenDir(const char_t *path)
Open a directory stream.
error_t fsCreateDir(const char_t *path)
Create a directory.
void fsCloseDir(FsDir *dir)
Close a directory stream.
error_t fsGetFileStat(const char_t *path, FsFileStat *fileStat)
Retrieve the attributes of the specified file.
error_t fsWriteFile(FsFile *file, void *data, size_t length)
Write data to the specified file.
FsFile * fsOpenFile(const char_t *path, uint_t mode)
Open the specified file for reading or writing.
error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
Read data from the specified file.
error_t fsReadDir(FsDir *dir, FsDirEntry *dirEntry)
Read an entry from the specified directory stream.
File system abstraction layer (FatFs)
#define FS_MAX_DIRS
Definition: fs_port_fatfs.h:45
void FsFile
File descriptor.
Definition: fs_port_fatfs.h:60
#define FS_MAX_FILES
Definition: fs_port_fatfs.h:38
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osStrcmp(s1, s2)
Definition: os_port.h:171
#define MIN(a, b)
Definition: os_port.h:63
#define osStrlen(s)
Definition: os_port.h:165
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define osStrncpy(s1, s2, length)
Definition: os_port.h:213
#define MAX(a, b)
Definition: os_port.h:67
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
const uint8_t res[]
uint8_t hours
Definition: date_time.h:52
uint8_t dayOfWeek
Definition: date_time.h:51
uint8_t month
Definition: date_time.h:49
uint8_t seconds
Definition: date_time.h:54
uint16_t year
Definition: date_time.h:48
uint8_t day
Definition: date_time.h:50
uint8_t minutes
Definition: date_time.h:53
uint16_t milliseconds
Definition: date_time.h:55
Directory entry.
Definition: fs_port.h:108
char_t name[FS_MAX_NAME_LEN+1]
Definition: fs_port.h:112
uint32_t attributes
Definition: fs_port.h:109
uint32_t size
Definition: fs_port.h:110
DateTime modified
Definition: fs_port.h:111
Directory descriptor.
Definition: fs_port_posix.h:60
File status.
Definition: fs_port.h:96
uint32_t attributes
Definition: fs_port.h:97
uint32_t size
Definition: fs_port.h:98
DateTime modified
Definition: fs_port.h:99
Mutex object.
uint8_t length
Definition: tcp.h:368
uint8_t flags
Definition: tcp.h:351