F´ Flight Software - C/C++ Documentation  NASA-v2.0.1
A framework for building embedded system applications to NASA flight quality standards.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
FileSystem.cpp
Go to the documentation of this file.
1 #include <FpConfig.hpp>
3 #include <Os/FileSystem.hpp>
4 #include <Os/File.hpp>
5 #include <Fw/Types/Assert.hpp>
6 
7 #include <cerrno>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <dirent.h>
11 #include <stdio.h> // Needed for rename
12 #include <string.h>
13 #include <limits>
14 #include <sys/statvfs.h>
15 
16 namespace Os {
17 
18  namespace FileSystem {
19 
20  Status createDirectory(const char* path) {
21 
22  Status stat = OP_OK;
23 
24 #ifdef __VXWORKS__
25  int mkStat = ::mkdir(path);
26 #else
27  int mkStat = ::mkdir(path,S_IRWXU);
28 #endif
29 
30  if (-1 == mkStat) {
31  switch (errno) {
32  case EACCES:
33  case EPERM:
34  case EROFS:
35  case EFAULT:
36  stat = NO_PERMISSION;
37  break;
38  case EEXIST:
39  stat = ALREADY_EXISTS;
40  break;
41  case ELOOP:
42  case ENOENT:
43  case ENAMETOOLONG:
44  stat = INVALID_PATH;
45  break;
46  case ENOTDIR:
47  stat = NOT_DIR;
48  break;
49  case ENOSPC:
50  case EDQUOT:
51  stat = NO_SPACE;
52  break;
53  case EMLINK:
54  stat = FILE_LIMIT;
55  break;
56  default:
57  stat = OTHER_ERROR;
58  break;
59  }
60  }
61 
62  return stat;
63  } // end createDirectory
64 
65  Status removeDirectory(const char* path) {
66 
67  Status stat = OP_OK;
68 
69  if (::rmdir(path) == -1) {
70  switch (errno) {
71  case EACCES:
72  case EPERM:
73  case EROFS:
74  case EFAULT:
75  stat = NO_PERMISSION;
76  break;
77  case ENOTEMPTY:
78  case EEXIST:
79  stat = NOT_EMPTY;
80  break;
81  case EINVAL:
82  case ELOOP:
83  case ENOENT:
84  case ENAMETOOLONG:
85  stat = INVALID_PATH;
86  break;
87  case ENOTDIR:
88  stat = NOT_DIR;
89  break;
90  case EBUSY:
91  stat = BUSY;
92  break;
93  default:
94  stat = OTHER_ERROR;
95  break;
96  }
97  }
98 
99  return stat;
100  } // end removeDirectory
101 
102  Status readDirectory(const char* path, const U32 maxNum,
103  Fw::EightyCharString fileArray[],
104  U32& numFiles)
105  {
106  Status dirStat = OP_OK;
107  DIR * dirPtr = NULL;
108  struct dirent *direntData = NULL;
109 
110  FW_ASSERT(fileArray != NULL);
111  FW_ASSERT(path != NULL);
112 
113  // Open directory failed:
114  if((dirPtr = ::opendir(path)) == NULL) {
115 
116  switch (errno) {
117  case EACCES:
118  dirStat = NO_PERMISSION;
119  break;
120  case ENOENT:
121  dirStat = INVALID_PATH;
122  break;
123  case ENOTDIR:
124  dirStat = NOT_DIR;
125  break;
126  default:
127  dirStat = OTHER_ERROR;
128  break;
129  }
130  return dirStat;
131  }
132 
133  // Set errno to 0 so we know why we exited readdir
134  errno = 0;
135  U32 arrayIdx = 0;
136  U32 limitCount = 0;
137  const U32 loopLimit = std::numeric_limits<U32>::max();
138 
139  // Read the directory contents and store in passed in array:
140  while(arrayIdx < maxNum && limitCount < loopLimit) {
141 
142  ++limitCount;
143 
144  if((direntData = ::readdir(dirPtr)) != NULL) {
145  // We are only care about regular files
146  if(direntData->d_type == DT_REG) {
147 
148  FW_ASSERT(arrayIdx < maxNum,
149  static_cast<NATIVE_INT_TYPE>(arrayIdx),
150  static_cast<NATIVE_INT_TYPE>(maxNum));
151 
152  Fw::EightyCharString str(direntData->d_name);
153  fileArray[arrayIdx++] = str;
154  }
155  }
156  else {
157  // readdir failed, did it error or did we run out of files?
158  if(errno != 0) {
159  // Only error from readdir is EBADF
160  dirStat = OTHER_ERROR;
161  }
162  break;
163  }
164  }
165 
166  if(limitCount == loopLimit) {
167  dirStat = FILE_LIMIT;
168  }
169 
170  if(::closedir(dirPtr) == -1) {
171  // Only error from closedir is EBADF
172  dirStat = OTHER_ERROR;
173  }
174 
175  numFiles = arrayIdx;
176 
177  return dirStat;
178  }
179 
180  Status removeFile(const char* path) {
181 
182  Status stat = OP_OK;
183 
184  if(::unlink(path) == -1) {
185  switch (errno) {
186  case EACCES:
187  case EPERM:
188  case EROFS:
189  stat = NO_PERMISSION;
190  break;
191  case EISDIR:
192  stat = IS_DIR;
193  break;
194  case ELOOP:
195  case ENOENT:
196  case ENAMETOOLONG:
197  stat = INVALID_PATH;
198  break;
199  case ENOTDIR:
200  stat = NOT_DIR;
201  break;
202  case EBUSY:
203  stat = BUSY;
204  break;
205  default:
206  stat = OTHER_ERROR;
207  break;
208  }
209  }
210 
211  return stat;
212  } // end removeFile
213 
214  Status moveFile(const char* originPath, const char* destPath) {
215 
216  Status stat = OP_OK;
217 
218  if(::rename(originPath, destPath) == -1) {
219  switch (errno) {
220  case EACCES:
221  case EPERM:
222  case EROFS:
223  case EFAULT:
224  stat = NO_PERMISSION;
225  break;
226  case EDQUOT:
227  case ENOSPC:
228  stat = NO_SPACE;
229  break;
230  case ELOOP:
231  case ENAMETOOLONG:
232  case ENOENT:
233  case EINVAL:
234  stat = INVALID_PATH;
235  break;
236  case ENOTDIR:
237  case EISDIR: // Old path is not a dir
238  stat = NOT_DIR;
239  break;
240  case ENOTEMPTY:
241  case EEXIST:
242  stat = NOT_EMPTY;
243  break;
244  case EMLINK:
245  stat = FILE_LIMIT;
246  break;
247  case EBUSY:
248  stat = BUSY;
249  break;
250  default:
251  stat = OTHER_ERROR;
252  break;
253  }
254  }
255  return stat;
256 
257  } // end moveFile
258 
259  Status handleFileError(File::Status fileStatus) {
260  Status fileSystemStatus = OTHER_ERROR;
261 
262  switch(fileStatus) {
263  case File::NO_SPACE:
264  fileSystemStatus = NO_SPACE;
265  break;
266  case File::NO_PERMISSION:
267  fileSystemStatus = NO_PERMISSION;
268  break;
269  case File::DOESNT_EXIST:
270  fileSystemStatus = INVALID_PATH;
271  break;
272  default:
273  fileSystemStatus = OTHER_ERROR;
274  }
275  return fileSystemStatus;
276  } // end handleFileError
277 
285  Status initAndCheckFileStats(const char* filePath,
286  struct stat* fileInfo=NULL) {
287  FileSystem::Status fs_status;
288  struct stat local_info;
289  if(!fileInfo) {
290  // No external struct given, so use the local one
291  fileInfo = &local_info;
292  }
293 
294  if(::stat(filePath, fileInfo) == -1) {
295  switch (errno) {
296  case EACCES:
297  fs_status = NO_PERMISSION;
298  break;
299  case ELOOP:
300  case ENOENT:
301  case ENAMETOOLONG:
302  fs_status = INVALID_PATH;
303  break;
304  case ENOTDIR:
305  fs_status = NOT_DIR;
306  break;
307  default:
308  fs_status = OTHER_ERROR;
309  break;
310  }
311  return fs_status;
312  }
313 
314  // Make sure the origin is a regular file
315  if(!S_ISREG(fileInfo->st_mode)) {
316  return INVALID_PATH;
317  }
318 
319  return OP_OK;
320  }
321 
334  Status copyFileData(File source, File destination, U64 size) {
335  U8 fileBuffer[FILE_SYSTEM_CHUNK_SIZE];
336  File::Status file_status;
337 
338  // Set loop limit
339  const U64 copyLoopLimit = (((U64)size/FILE_SYSTEM_CHUNK_SIZE)) + 2;
340 
341  U64 loopCounter = 0;
342  NATIVE_INT_TYPE chunkSize;
343  while(loopCounter < copyLoopLimit) {
344  chunkSize = FILE_SYSTEM_CHUNK_SIZE;
345  file_status = source.read(&fileBuffer, chunkSize, false);
346  if(file_status != File::OP_OK) {
347  return handleFileError(file_status);
348  }
349 
350  if(chunkSize == 0) {
351  //file has been successfully copied
352  break;
353  }
354 
355  file_status = destination.write(fileBuffer, chunkSize, true);
356  if(file_status != File::OP_OK) {
357  return handleFileError(file_status);
358  }
359  loopCounter++;
360  }
361  FW_ASSERT(loopCounter < copyLoopLimit);
362 
363  return FileSystem::OP_OK;
364  } // end copyFileData
365 
366  Status copyFile(const char* originPath, const char* destPath) {
367  FileSystem::Status fs_status;
368  File::Status file_status;
369 
370  U64 fileSize = 0;
371 
372  File source;
373  File destination;
374 
375  fs_status = initAndCheckFileStats(originPath);
376  if(FileSystem::OP_OK != fs_status) {
377  return fs_status;
378  }
379 
380  // Get the file size:
381  fs_status = FileSystem::getFileSize(originPath, fileSize);
382  if(FileSystem::OP_OK != fs_status) {
383  return fs_status;
384  }
385 
386  file_status = source.open(originPath, File::OPEN_READ);
387  if(file_status != File::OP_OK) {
388  return handleFileError(file_status);
389  }
390 
391  file_status = destination.open(destPath, File::OPEN_WRITE);
392  if(file_status != File::OP_OK) {
393  return handleFileError(file_status);
394  }
395 
396  fs_status = copyFileData(source, destination, fileSize);
397 
398  (void) source.close();
399  (void) destination.close();
400 
401  return fs_status;
402  } // end copyFile
403 
404  Status appendFile(const char* originPath, const char* destPath, bool createMissingDest) {
405  FileSystem::Status fs_status;
406  File::Status file_status;
407  U64 fileSize = 0;
408 
409  File source;
410  File destination;
411 
412  fs_status = initAndCheckFileStats(originPath);
413  if(FileSystem::OP_OK != fs_status) {
414  return fs_status;
415  }
416 
417  // Get the file size:
418  fs_status = FileSystem::getFileSize(originPath, fileSize);
419  if(FileSystem::OP_OK != fs_status) {
420  return fs_status;
421  }
422 
423  file_status = source.open(originPath, File::OPEN_READ);
424  if(file_status != File::OP_OK) {
425  return handleFileError(file_status);
426  }
427 
428  // If needed, check if destination file exists (and exit if not)
429  if(!createMissingDest) {
430  fs_status = initAndCheckFileStats(destPath);
431  if(FileSystem::OP_OK != fs_status) {
432  return fs_status;
433  }
434  }
435 
436  file_status = destination.open(destPath, File::OPEN_APPEND);
437  if(file_status != File::OP_OK) {
438  return handleFileError(file_status);
439  }
440 
441  fs_status = copyFileData(source, destination, fileSize);
442 
443  (void) source.close();
444  (void) destination.close();
445 
446  return fs_status;
447  } // end appendFile
448 
449  Status getFileSize(const char* path, U64& size) {
450 
451  Status fileStat = OP_OK;
452  struct stat fileStatStruct;
453 
454  fileStat = initAndCheckFileStats(path, &fileStatStruct);
455  if(FileSystem::OP_OK == fileStat) {
456  // Only check size if struct was initialized successfully
457  size = fileStatStruct.st_size;
458  }
459 
460  return fileStat;
461  } // end getFileSize
462 
463  Status changeWorkingDirectory(const char* path) {
464 
465  Status stat = OP_OK;
466 
467  if (::chdir(path) == -1) {
468  switch (errno) {
469  case EACCES:
470  case EFAULT:
471  stat = NO_PERMISSION;
472  break;
473  case ENOTEMPTY:
474  stat = NOT_EMPTY;
475  break;
476  case ENOENT:
477  case ELOOP:
478  case ENAMETOOLONG:
479  stat = INVALID_PATH;
480  break;
481  case ENOTDIR:
482  stat = NOT_DIR;
483  break;
484  default:
485  stat = OTHER_ERROR;
486  break;
487  }
488  }
489 
490  return stat;
491  } // end changeWorkingDirectory
492 
493  Status getFreeSpace(const char* path, U64& totalBytes, U64& freeBytes) {
494  Status stat = OP_OK;
495 
496  struct statvfs fsStat;
497  int ret = statvfs(path, &fsStat);
498  if (ret) {
499  switch (errno) {
500  case EACCES:
501  stat = NO_PERMISSION;
502  break;
503  case ELOOP:
504  case ENOENT:
505  case ENAMETOOLONG:
506  stat = INVALID_PATH;
507  break;
508  case ENOTDIR:
509  stat = NOT_DIR;
510  break;
511  default:
512  stat = OTHER_ERROR;
513  break;
514  }
515  return stat;
516  }
517 
518  totalBytes = (U64) fsStat.f_blocks * (U64) fsStat.f_frsize;
519  freeBytes = (U64) fsStat.f_bfree * (U64) fsStat.f_frsize;
520  return stat;
521  }
522 
523  // Public function to get the file count for a given directory.
524  Status getFileCount (const char* directory, U32& fileCount) {
525  Status dirStat = OP_OK;
526  DIR * dirPtr = NULL;
527  struct dirent *direntData = NULL;
528  U32 limitCount;
529  const U64 loopLimit = ((((U64) 1) << 32)-1); // Max value of U32
530 
531  fileCount = 0;
532  if((dirPtr = ::opendir(directory)) == NULL) {
533  switch (errno) {
534  case EACCES:
535  dirStat = NO_PERMISSION;
536  break;
537  case ENOENT:
538  dirStat = INVALID_PATH;
539  break;
540  case ENOTDIR:
541  dirStat = NOT_DIR;
542  break;
543  default:
544  dirStat = OTHER_ERROR;
545  break;
546  }
547  return dirStat;
548  }
549 
550  // Set errno to 0 so we know why we exited readdir
551  errno = 0;
552  for(limitCount = 0; limitCount < loopLimit; limitCount++) {
553  if((direntData = ::readdir(dirPtr)) != NULL) {
554  // We are only counting regular files
555  if(direntData->d_type == DT_REG) {
556  fileCount++;
557  }
558  }
559  else {
560  // readdir failed, did it error or did we run out of files?
561  if(errno != 0) {
562  // Only error from readdir is EBADF
563  dirStat = OTHER_ERROR;
564  }
565  break;
566  }
567  }
568  if(limitCount == loopLimit) {
569  dirStat = FILE_LIMIT;
570  }
571 
572  if(::closedir(dirPtr) == -1) {
573  // Only error from closedir is EBADF
574  dirStat = OTHER_ERROR;
575  }
576 
577  return dirStat;
578  } //end getFileCount
579 
580  } // end FileSystem namespace
581 
582 } // end Os namespace
Os
Definition: File.cpp:7
Os::File::NO_SPACE
@ NO_SPACE
No space left.
Definition: File.hpp:27
Os::FileSystem::getFileCount
Status getFileCount(const char *directory, U32 &fileCount)
counts the number of files in the given directory
Definition: FileSystem.cpp:48
Os::File::NO_PERMISSION
@ NO_PERMISSION
No permission to read/write file.
Definition: File.hpp:28
Os::FileSystem::Status
Status
Definition: FileSystem.hpp:15
Os::FileSystem::initAndCheckFileStats
Status initAndCheckFileStats(const char *filePath, struct stat *fileInfo=NULL)
Definition: FileSystem.cpp:285
Os::File::close
void close(void)
close file
Definition: File.cpp:37
Os::FileSystem::copyFile
Status copyFile(const char *originPath, const char *destPath)
moves a file from origin to destination
Definition: FileSystem.cpp:36
Os::FileSystem::NO_SPACE
@ NO_SPACE
No space left.
Definition: FileSystem.hpp:18
Os::File::read
Status read(void *buffer, NATIVE_INT_TYPE &size, bool waitForFull=true)
waitForFull = true to wait for all bytes to be read
Definition: File.cpp:29
U8
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.hpp:76
Os::FileSystem::readDirectory
Status readDirectory(const char *path, const U32 maxNum, Fw::EightyCharString fileArray[])
Definition: FileSystem.cpp:17
Fw::EightyCharString
Definition: EightyCharString.hpp:10
Os::FileSystem::removeDirectory
Status removeDirectory(const char *path)
remove a directory at location path
Definition: FileSystem.cpp:13
Os::FileSystem::copyFileData
Status copyFileData(File source, File destination, U64 size)
Definition: FileSystem.cpp:334
Os::FileSystem::changeWorkingDirectory
Status changeWorkingDirectory(const char *path)
move current directory to path
Definition: FileSystem.cpp:44
FileSystem.hpp
Os::FileSystem::NOT_DIR
@ NOT_DIR
Path is not a directory.
Definition: FileSystem.hpp:20
Assert.hpp
Os::FileSystem::OTHER_ERROR
@ OTHER_ERROR
other OS-specific error
Definition: FileSystem.hpp:26
Os::FileSystem::moveFile
Status moveFile(const char *originPath, const char *destPath)
Definition: FileSystem.cpp:27
Os::FileSystem::NOT_EMPTY
@ NOT_EMPTY
directory is not empty
Definition: FileSystem.hpp:22
U64
#define U64(C)
Definition: sha.h:176
Os::File::write
Status write(const void *buffer, NATIVE_INT_TYPE &size, bool waitForDone=true)
write size; will return amount written or errno
Definition: File.cpp:33
Os::File::DOESNT_EXIST
@ DOESNT_EXIST
File doesn't exist (for read)
Definition: File.hpp:26
Os::FileSystem::OP_OK
@ OP_OK
Operation was successful.
Definition: FileSystem.hpp:16
Os::FileSystem::INVALID_PATH
@ INVALID_PATH
Path is too long, too many sym links, doesn't exist, ect.
Definition: FileSystem.hpp:23
Os::FileSystem::IS_DIR
@ IS_DIR
Path is a directory.
Definition: FileSystem.hpp:21
Os::File::OPEN_WRITE
@ OPEN_WRITE
Open file for writing.
Definition: File.hpp:17
FW_ASSERT
#define FW_ASSERT(...)
Definition: Assert.hpp:9
Os::File::OPEN_APPEND
@ OPEN_APPEND
Open file for appending.
Definition: File.hpp:21
Os::File::open
Status open(const char *fileName, Mode mode)
open file. Writing creates file if it doesn't exist
Definition: File.cpp:13
File.hpp
Os::FileSystem::appendFile
Status appendFile(const char *originPath, const char *destPath, bool createMissingDest=false)
copies a file from origin to destination
Definition: FileSystem.cpp:404
Os::FileSystem::ALREADY_EXISTS
@ ALREADY_EXISTS
File already exists.
Definition: FileSystem.hpp:17
FpConfig.hpp
ISF configuration file.
Os::FileSystem::getFreeSpace
Status getFreeSpace(const char *path, U64 &totalBytes, U64 &freeBytes)
get FS free and total space in bytes on filesystem containing path
Definition: FileSystem.cpp:493
Os::File::Status
Status
Definition: File.hpp:24
Os::FileSystem::FILE_LIMIT
@ FILE_LIMIT
Too many files or links.
Definition: FileSystem.hpp:24
Os::FileSystem::handleFileError
Status handleFileError(File::Status fileStatus)
Definition: FileSystem.cpp:32
Os::FileSystem::createDirectory
Status createDirectory(const char *path)
create a new directory at location path
Definition: FileSystem.cpp:9
Os::FileSystem::NO_PERMISSION
@ NO_PERMISSION
No permission to write.
Definition: FileSystem.hpp:19
BasicTypes.hpp
Declares ISF basic types.
Os::File::OP_OK
@ OP_OK
Operation was successful.
Definition: File.hpp:25
Os::FileSystem::getFileSize
Status getFileSize(const char *path, U64 &size)
append file origin to destination file. If boolean true, creates a brand new file if the destination ...
Definition: FileSystem.cpp:40
NATIVE_INT_TYPE
int NATIVE_INT_TYPE
native integer type declaration
Definition: BasicTypes.hpp:29
Os::File::OPEN_READ
@ OPEN_READ
Open file for reading.
Definition: File.hpp:16
NULL
#define NULL
NULL.
Definition: BasicTypes.hpp:100
Os::FileSystem::BUSY
@ BUSY
Operand is in use by the system or by a process.
Definition: FileSystem.hpp:25
Os::FileSystem::removeFile
Status removeFile(const char *path)
removes a file at location path
Definition: FileSystem.cpp:22
Os::File
Definition: File.hpp:11
FILE_SYSTEM_CHUNK_SIZE
#define FILE_SYSTEM_CHUNK_SIZE
Definition: FileSystem.hpp:8