fs_port_rl_fs.c
Go to the documentation of this file.
1 /**
2  * @file fs_port_rl_fs.c
3  * @brief File system abstraction layer (RL-FlashFS)
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_rl_fs.h"
33 #include "str.h"
34 #include "path.h"
35 #include "error.h"
36 #include "debug.h"
37 
38 
39 /**
40  * @brief File system initialization
41  * @return Error code
42  **/
43 
44 __weak_func error_t fsInit(void)
45 {
46  error_t error;
47  fsStatus status;
48 
49  //Initialize file system
50  status = finit("M0:");
51 
52  //Check status code
53  if(status == fsOK)
54  {
55  //Mount drive
56  status = fmount("M0:");
57  }
58 
59  //On success, fsOK is returned
60  if(status == fsOK)
61  {
62  error = NO_ERROR;
63  }
64  else
65  {
66  error = ERROR_FAILURE;
67  }
68 
69  //Return status code
70  return error;
71 }
72 
73 
74 /**
75  * @brief Check whether a file exists
76  * @param[in] path NULL-terminated string specifying the filename
77  * @return The function returns TRUE if the file exists. Otherwise FALSE is returned
78  **/
79 
81 {
82  fsStatus status;
83  fsFileInfo fileInfo;
84  bool_t found;
85 
86  //Initialize flag
87  found = FALSE;
88 
89  //Make sure the pathname is valid
90  if(path != NULL)
91  {
92  //The fileID field must be initialized to zero
93  fileInfo.fileID = 0;
94  //Find the specified path name
95  status = ffind(path, &fileInfo);
96 
97  //Check status code
98  if(status == fsOK)
99  {
100  //Valid file?
101  if((fileInfo.attrib & FS_FAT_ATTR_DIRECTORY) == 0)
102  {
103  found = TRUE;
104  }
105  }
106  }
107 
108  //The function returns TRUE if the file exists
109  return found;
110 }
111 
112 
113 /**
114  * @brief Retrieve the size of the specified file
115  * @param[in] path NULL-terminated string specifying the filename
116  * @param[out] size Size of the file in bytes
117  * @return Error code
118  **/
119 
120 error_t fsGetFileSize(const char_t *path, uint32_t *size)
121 {
122  fsStatus status;
123  fsFileInfo fileInfo;
124 
125  //Check parameters
126  if(path == NULL || size == NULL)
128 
129  //The fileID field must be initialized to zero
130  fileInfo.fileID = 0;
131  //Find the specified path name
132  status = ffind(path, &fileInfo);
133 
134  //Any error to report?
135  if(status != fsOK)
136  return ERROR_FAILURE;
137 
138  //Valid file?
139  if((fileInfo.attrib & FS_FAT_ATTR_DIRECTORY) != 0)
140  return ERROR_FAILURE;
141 
142  //Return the size of the file
143  *size = fileInfo.size;
144 
145  //Successful processing
146  return NO_ERROR;
147 }
148 
149 
150 /**
151  * @brief Retrieve the attributes of the specified file
152  * @param[in] path NULL-terminated string specifying the filename
153  * @param[out] fileStat File attributes
154  * @return Error code
155  **/
156 
157 error_t fsGetFileStat(const char_t *path, FsFileStat *fileStat)
158 {
159  fsStatus status;
160  fsFileInfo fileInfo;
161 
162  //Check parameters
163  if(path == NULL || fileStat == NULL)
165 
166  //The fileID field must be initialized to zero
167  fileInfo.fileID = 0;
168  //Find the specified path name
169  status = ffind(path, &fileInfo);
170 
171  //Any error to report?
172  if(status != fsOK)
173  return ERROR_FAILURE;
174 
175  //Clear file attributes
176  osMemset(fileStat, 0, sizeof(FsFileStat));
177 
178  //File attributes
179  fileStat->attributes = fileInfo.attrib;
180  //File size
181  fileStat->size = fileInfo.size;
182 
183  //Time of last modification
184  fileStat->modified.year = fileInfo.time.year;
185  fileStat->modified.month = fileInfo.time.mon;
186  fileStat->modified.day = fileInfo.time.day;
187  fileStat->modified.hours = fileInfo.time.hr;
188  fileStat->modified.minutes = fileInfo.time.min;
189  fileStat->modified.seconds = fileInfo.time.sec;
190  fileStat->modified.milliseconds = 0;
191 
192  //Make sure the date is valid
193  fileStat->modified.month = MAX(fileStat->modified.month, 1);
194  fileStat->modified.month = MIN(fileStat->modified.month, 12);
195  fileStat->modified.day = MAX(fileStat->modified.day, 1);
196  fileStat->modified.day = MIN(fileStat->modified.day, 31);
197 
198  //Successful processing
199  return NO_ERROR;
200 }
201 
202 
203 /**
204  * @brief Rename the specified file
205  * @param[in] oldPath NULL-terminated string specifying the pathname of the file to be renamed
206  * @param[in] newPath NULL-terminated string specifying the new filename
207  * @return Error code
208  **/
209 
210 error_t fsRenameFile(const char_t *oldPath, const char_t *newPath)
211 {
212  error_t error;
213  fsStatus status;
214  const char_t *newName;
215 
216  //Check parameters
217  if(oldPath == NULL || newPath == NULL)
219 
220  //Get new file name
221  newName = pathGetFilename(newPath);
222 
223  //Rename the specified file
224  status = frename(oldPath, newName);
225 
226  //On success, fsOK is returned
227  if(status == fsOK)
228  {
229  error = NO_ERROR;
230  }
231  else
232  {
233  error = ERROR_FAILURE;
234  }
235 
236  //Return status code
237  return error;
238 }
239 
240 
241 /**
242  * @brief Delete a file
243  * @param[in] path NULL-terminated string specifying the filename
244  * @return Error code
245  **/
246 
248 {
249  error_t error;
250  fsStatus status;
251 
252  //Make sure the pathname is valid
253  if(path == NULL)
255 
256  //Delete the specified file
257  status = fdelete(path, "");
258 
259  //On success, fsOK is returned
260  if(status == fsOK)
261  {
262  error = NO_ERROR;
263  }
264  else
265  {
266  error = ERROR_FAILURE;
267  }
268 
269  //Return status code
270  return error;
271 }
272 
273 
274 /**
275  * @brief Open the specified file for reading or writing
276  * @param[in] path NULL-terminated string specifying the filename
277  * @param[in] mode Type of access permitted (FS_FILE_MODE_READ,
278  * FS_FILE_MODE_WRITE or FS_FILE_MODE_CREATE)
279  * @return File handle
280  **/
281 
282 FsFile *fsOpenFile(const char_t *path, uint_t mode)
283 {
284  char_t s[4];
285 
286  //File pointer
287  FILE *fp = NULL;
288 
289  //Make sure the pathname is valid
290  if(path == NULL)
291  return NULL;
292 
293  //Check file access mode
294  if(mode & FS_FILE_MODE_WRITE)
295  {
296  osStrcpy(s, "wb");
297  }
298  else
299  {
300  osStrcpy(s, "rb");
301  }
302 
303  //Open the specified file
304  fp = fopen(path, s);
305 
306  //Return a handle to the file
307  return fp;
308 }
309 
310 
311 /**
312  * @brief Move to specified position in file
313  * @param[in] file Handle that identifies the file
314  * @param[in] offset Number of bytes to move from origin
315  * @param[in] origin Position used as reference for the offset (FS_SEEK_SET,
316  * FS_SEEK_CUR or FS_SEEK_END)
317  * @return Error code
318  **/
319 
321 {
322  error_t error;
323  int_t ret;
324 
325  //Make sure the file pointer is valid
326  if(file == NULL)
328 
329  //The origin is used as reference for the offset
330  if(origin == FS_SEEK_CUR)
331  {
332  //The offset is relative to the current file pointer
333  origin = SEEK_CUR;
334  }
335  else if(origin == FS_SEEK_END)
336  {
337  //The offset is relative to the end of the file
338  origin = SEEK_END;
339  }
340  else
341  {
342  //The offset is absolute
343  origin = SEEK_SET;
344  }
345 
346  //Move read/write pointer
347  ret = fseek(file, offset, origin);
348 
349  //On success, zero is returned
350  if(ret == 0)
351  {
352  error = NO_ERROR;
353  }
354  else
355  {
356  error = ERROR_FAILURE;
357  }
358 
359  //Return status code
360  return error;
361 }
362 
363 
364 /**
365  * @brief Write data to the specified file
366  * @param[in] file Handle that identifies the file to be written
367  * @param[in] data Pointer to a buffer containing the data to be written
368  * @param[in] length Number of data bytes to write
369  * @return Error code
370  **/
371 
373 {
374  error_t error;
375  int_t n;
376 
377  //Make sure the file pointer is valid
378  if(file == NULL)
380 
381  //Write data
382  n = fwrite(data, sizeof(uint8_t), length, file);
383 
384  //The total number of elements successfully written is returned. If this
385  //number differs from the count parameter, a writing error prevented the
386  //function from completing
387  if(n == length)
388  {
389  error = NO_ERROR;
390  }
391  else
392  {
393  error = ERROR_FAILURE;
394  }
395 
396  //Return status code
397  return error;
398 }
399 
400 
401 /**
402  * @brief Read data from the specified file
403  * @param[in] file Handle that identifies the file to be read
404  * @param[in] data Pointer to the buffer where to copy the data
405  * @param[in] size Size of the buffer, in bytes
406  * @param[out] length Number of data bytes that have been read
407  * @return Error code
408  **/
409 
410 error_t fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
411 {
412  error_t error;
413  int_t n;
414 
415  //Check parameters
416  if(file == NULL || length == NULL)
418 
419  //No data has been read yet
420  *length = 0;
421 
422  //Read data
423  n = fread(data, sizeof(uint8_t), size, file);
424 
425  //The total number of elements successfully read is returned. If this
426  //number differs from the count parameter, either a reading error occurred
427  //or the end-of-file was reached while reading
428  if(n != 0)
429  {
430  //Total number of data that have been read
431  *length = n;
432 
433  //Successful processing
434  error = NO_ERROR;
435  }
436  else
437  {
438  //Report an error
439  error = ERROR_END_OF_FILE;
440  }
441 
442  //Return status code
443  return error;
444 }
445 
446 
447 /**
448  * @brief Close a file
449  * @param[in] file Handle that identifies the file to be closed
450  **/
451 
453 {
454  //Make sure the file pointer is valid
455  if(file != NULL)
456  {
457  //Close the specified file
458  fclose(file);
459  }
460 }
461 
462 
463 /**
464  * @brief Check whether a directory exists
465  * @param[in] path NULL-terminated string specifying the directory path
466  * @return The function returns TRUE if the directory exists. Otherwise FALSE is returned
467  **/
468 
470 {
471  fsStatus status;
472  fsFileInfo fileInfo;
473  bool_t found;
474 
475  //Initialize flag
476  found = FALSE;
477 
478  //Make sure the pathname is valid
479  if(path != NULL)
480  {
481  //Root directory?
482  if(osStrcmp(path, "/") == 0 || osStrcmp(path, "\\") == 0)
483  {
484  //The root directory always exists
485  found = TRUE;
486  }
487  else
488  {
489  //The fileID field must be initialized to zero
490  fileInfo.fileID = 0;
491  //Find the specified path name
492  status = ffind(path, &fileInfo);
493 
494  //Check status code
495  if(status == fsOK)
496  {
497  //Valid directory?
498  if((fileInfo.attrib & FS_FAT_ATTR_DIRECTORY) != 0)
499  {
500  found = TRUE;
501  }
502  }
503  }
504  }
505 
506  //The function returns TRUE if the directory exists
507  return found;
508 }
509 
510 
511 /**
512  * @brief Create a directory
513  * @param[in] path NULL-terminated string specifying the directory path
514  * @return Error code
515  **/
516 
518 {
519  error_t error;
520  fsStatus status;
521 
522  //Make sure the pathname is valid
523  if(path == NULL)
525 
526  //Create a new directory
527  status = fmkdir(path);
528 
529  //On success, fsOK is returned
530  if(status == fsOK)
531  {
532  error = NO_ERROR;
533  }
534  else
535  {
536  error = ERROR_FAILURE;
537  }
538 
539  //Return status code
540  return error;
541 }
542 
543 
544 /**
545  * @brief Remove a directory
546  * @param[in] path NULL-terminated string specifying the directory path
547  * @return Error code
548  **/
549 
551 {
552  error_t error;
553  fsStatus status;
554 
555  //Make sure the pathname is valid
556  if(path == NULL)
558 
559  //Remove the specified directory
560  status = frmdir(path, "");
561 
562  //On success, fsOK is returned
563  if(status == fsOK)
564  {
565  error = NO_ERROR;
566  }
567  else
568  {
569  error = ERROR_FAILURE;
570  }
571 
572  //Return status code
573  return error;
574 }
575 
576 
577 /**
578  * @brief Open a directory stream
579  * @param[in] path NULL-terminated string specifying the directory path
580  * @return Directory handle
581  **/
582 
583 FsDir *fsOpenDir(const char_t *path)
584 {
585  FsDir *dir;
586 
587  //Valid directory path?
588  if(path != NULL)
589  {
590  //Check whether the directory exists
591  if(fsDirExists(path))
592  {
593  //Allocate a memory buffer to hold the directory descriptor
594  dir = osAllocMem(sizeof(FsDir));
595 
596  //Successful memory allocation?
597  if(dir != NULL)
598  {
599  //Initialize the directory descriptor
600  osMemset(dir, 0, sizeof(FsDir));
601 
602  //Specify the search pattern
603  strSafeCopy(dir->pattern, path, FS_MAX_PATH_LEN);
605  pathCombine(dir->pattern, "*", FS_MAX_PATH_LEN);
606 
607  //Start a new search
608  dir->fileInfo.fileID = 0;
609  }
610  }
611  else
612  {
613  //The specified directory does not exist
614  dir = NULL;
615  }
616  }
617  else
618  {
619  //Invalid parameter
620  dir = NULL;
621  }
622 
623  //Return a handle to the directory
624  return dir;
625 }
626 
627 
628 /**
629  * @brief Read an entry from the specified directory stream
630  * @param[in] dir Handle that identifies the directory
631  * @param[out] dirEntry Pointer to a directory entry
632  * @return Error code
633  **/
634 
636 {
637  error_t error;
638  fsStatus status;
639 
640  //Check parameters
641  if(dir == NULL || dirEntry == NULL)
643 
644  //Clear directory entry
645  osMemset(dirEntry, 0, sizeof(FsDirEntry));
646 
647  //Read the specified directory
648  status = ffind(dir->pattern, &dir->fileInfo);
649 
650  //Valid directory entry?
651  if(status == fsOK)
652  {
653  //Copy the file name component
654  strSafeCopy(dirEntry->name, dir->fileInfo.name, FS_MAX_NAME_LEN);
655 
656  //File attributes
657  dirEntry->attributes = dir->fileInfo.attrib;
658  //File size
659  dirEntry->size = dir->fileInfo.size;
660 
661  //Time of last modification
662  dirEntry->modified.year = dir->fileInfo.time.year;
663  dirEntry->modified.month = dir->fileInfo.time.mon;
664  dirEntry->modified.day = dir->fileInfo.time.day;
665  dirEntry->modified.hours = dir->fileInfo.time.hr;
666  dirEntry->modified.minutes = dir->fileInfo.time.min;
667  dirEntry->modified.seconds = dir->fileInfo.time.sec;
668  dirEntry->modified.milliseconds = 0;
669 
670  //Make sure the date is valid
671  dirEntry->modified.month = MAX(dirEntry->modified.month, 1);
672  dirEntry->modified.month = MIN(dirEntry->modified.month, 12);
673  dirEntry->modified.day = MAX(dirEntry->modified.day, 1);
674  dirEntry->modified.day = MIN(dirEntry->modified.day, 31);
675 
676  //Successful processing
677  error = NO_ERROR;
678  }
679  else
680  {
681  //End of the directory stream
682  error = ERROR_END_OF_STREAM;
683  }
684 
685  //Return status code
686  return error;
687 }
688 
689 
690 /**
691  * @brief Close a directory stream
692  * @param[in] dir Handle that identifies the directory to be closed
693  **/
694 
695 void fsCloseDir(FsDir *dir)
696 {
697  //Make sure the directory pointer is valid
698  if(dir != NULL)
699  {
700  //Release directory descriptor
701  osFreeMem(dir);
702  }
703 }
Path manipulation helper functions.
fsFileInfo fileInfo
Definition: fs_port_rl_fs.h:63
String manipulation helper functions.
int bool_t
Definition: compiler_port.h:53
signed int int_t
Definition: compiler_port.h:49
File system abstraction layer (RL-FlashFS)
uint16_t year
Definition: date_time.h:48
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
error_t fsRemoveDir(const char_t *path)
Remove a directory.
bool_t fsFileExists(const char_t *path)
Check whether a file exists.
Definition: fs_port_rl_fs.c:80
__weak_func error_t fsInit(void)
File system initialization.
Definition: fs_port_rl_fs.c:44
#define osStrcmp(s1, s2)
Definition: os_port.h:171
@ ERROR_END_OF_STREAM
Definition: error.h:210
Directory descriptor.
Definition: fs_port_posix.h:60
@ FS_FILE_MODE_WRITE
Definition: fs_port.h:73
const char_t * pathGetFilename(const char_t *path)
Extract the file name from the supplied path.
Definition: path.c:81
uint8_t day
Definition: date_time.h:50
__weak_func void * osAllocMem(size_t size)
Allocate a memory block.
void pathCanonicalize(char_t *path)
Simplify a path.
Definition: path.c:158
error_t fsSeekFile(FsFile *file, int_t offset, uint_t origin)
Move to specified position in file.
#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
FsFile * fsOpenFile(const char_t *path, uint_t mode)
Open the specified file for reading or writing.
error_t fsGetFileSize(const char_t *path, uint32_t *size)
Retrieve the size of the specified file.
FsDir * fsOpenDir(const char_t *path)
Open a directory stream.
__weak_func void osFreeMem(void *p)
Release a previously allocated memory block.
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ FS_SEEK_CUR
Definition: fs_port.h:86
@ 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.
error_t fsReadDir(FsDir *dir, FsDirEntry *dirEntry)
Read an entry from the specified directory stream.
error_t fsGetFileStat(const char_t *path, FsFileStat *fileStat)
Retrieve the attributes of the specified file.
char_t name[FS_MAX_NAME_LEN+1]
Definition: fs_port.h:112
#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 fsReadFile(FsFile *file, void *data, size_t size, size_t *length)
Read data from the specified file.
error_t strSafeCopy(char_t *dest, const char_t *src, size_t destSize)
Copy string.
Definition: str.c:172
error_t fsCreateDir(const char_t *path)
Create a directory.
DateTime modified
Definition: fs_port.h:111
uint8_t n
DateTime modified
Definition: fs_port.h:99
#define FS_MAX_PATH_LEN
Definition: fs_port_posix.h:37
Directory entry.
Definition: fs_port.h:108
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
error_t fsWriteFile(FsFile *file, void *data, size_t length)
Write data to the specified file.
uint16_t milliseconds
Definition: date_time.h:55
uint8_t s
Definition: igmp_common.h:234
error_t fsDeleteFile(const char_t *path)
Delete a file.
void fsCloseFile(FsFile *file)
Close a file.
char_t pattern[FS_MAX_PATH_LEN+1]
Definition: fs_port_rl_fs.h:62
error_t fsRenameFile(const char_t *oldPath, const char_t *newPath)
Rename the specified file.
unsigned int uint_t
Definition: compiler_port.h:50
void fsCloseDir(FsDir *dir)
Close a directory stream.
#define osMemset(p, value, length)
Definition: os_port.h:135
#define osStrcpy(s1, s2)
Definition: os_port.h:207
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
void pathCombine(char_t *path, const char_t *more, size_t maxLen)
Concatenate two paths.
Definition: path.c:394
bool_t fsDirExists(const char_t *path)
Check whether a directory exists.
void FsFile
File descriptor.
Definition: fs_port_fatfs.h:60