F´ Flight Software - C/C++ Documentation  NASA-v2.0.1
A framework for building embedded system applications to NASA flight quality standards.
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