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