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