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