F´ Flight Software - C/C++ Documentation
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// ======================================================================
2// \title Os/FileSystem.cpp
3// \brief common function implementation for Os::FileSystem
4// ======================================================================
5#include <Fw/Types/Assert.hpp>
6#include <Os/FileSystem.hpp>
7
8namespace Os {
9
10FileSystem::FileSystem() : m_handle_storage(), m_delegate(*FileSystemInterface::getDelegate(m_handle_storage)) {
11 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
12}
13
14FileSystem::~FileSystem() {
15 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
16 m_delegate.~FileSystemInterface();
17}
18
19FileSystemHandle* FileSystem::getHandle() {
20 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
21 return this->m_delegate.getHandle();
22}
23
24FileSystem::Status FileSystem::_removeDirectory(const char* path) {
25 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
26 FW_ASSERT(path != nullptr);
27 return this->m_delegate._removeDirectory(path);
28}
29
30FileSystem::Status FileSystem::_removeFile(const char* path) {
31 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
32 FW_ASSERT(path != nullptr);
33 return this->m_delegate._removeFile(path);
34}
35
36FileSystem::Status FileSystem::_rename(const char* sourcePath, const char* destPath) {
37 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
38 FW_ASSERT(sourcePath != nullptr);
39 FW_ASSERT(destPath != nullptr);
40 return this->m_delegate._rename(sourcePath, destPath);
41}
42
43FileSystem::Status FileSystem::_getWorkingDirectory(char* path, FwSizeType bufferSize) {
44 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
45 FW_ASSERT(path != nullptr);
46 FW_ASSERT(bufferSize > 0); // because bufferSize=0 would trigger a malloc in some implementations (e.g. Posix)
47 return this->m_delegate._getWorkingDirectory(path, bufferSize);
48}
49
50FileSystem::Status FileSystem::_changeWorkingDirectory(const char* path) {
51 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
52 FW_ASSERT(path != nullptr);
53 return this->m_delegate._changeWorkingDirectory(path);
54}
55
56FileSystem::Status FileSystem::_getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes) {
57 FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
58 FW_ASSERT(path != nullptr);
59 return this->m_delegate._getFreeSpace(path, totalBytes, freeBytes);
60}
61
62void FileSystem::init() {
63 // Force trigger on the fly singleton setup
64 (void) FileSystem::getSingleton();
65}
66
67FileSystem& FileSystem::getSingleton() {
68 static FileSystem s_singleton;
69 return s_singleton;
70}
71
72
73// ------------------------------------------------------------
74// Static functions calling implementation-specific operations
75// ------------------------------------------------------------
76
77FileSystem::Status FileSystem::removeDirectory(const char* path) {
78 return FileSystem::getSingleton()._removeDirectory(path);
79}
80
81FileSystem::Status FileSystem::removeFile(const char* path) {
82 return FileSystem::getSingleton()._removeFile(path);
83}
84
85FileSystem::Status FileSystem::rename(const char* sourcePath, const char* destPath) {
86 return FileSystem::getSingleton()._rename(sourcePath, destPath);
87}
88
89FileSystem::Status FileSystem::getWorkingDirectory(char* path, FwSizeType bufferSize) {
90 return FileSystem::getSingleton()._getWorkingDirectory(path, bufferSize);
91}
92
93FileSystem::Status FileSystem::changeWorkingDirectory(const char* path) {
94 return FileSystem::getSingleton()._changeWorkingDirectory(path);
95}
96
97FileSystem::Status FileSystem::getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes) {
98 return FileSystem::getSingleton()._getFreeSpace(path, totalBytes, freeBytes);
99}
100
101
102// ------------------------------------------------------------
103// Additional functions built on top of OS-specific operations
104// ------------------------------------------------------------
105
106FileSystem::Status FileSystem::createDirectory(const char* path, bool errorIfAlreadyExists) {
107 FW_ASSERT(path != nullptr);
108 Status status = Status::OP_OK;
109 Os::Directory dir;
110 // If errorIfAlreadyExists is true, use CREATE_EXCLUSIVE mode, otherwise use CREATE_IF_MISSING
111 Directory::OpenMode mode = errorIfAlreadyExists ? Directory::OpenMode::CREATE_EXCLUSIVE : Directory::OpenMode::CREATE_IF_MISSING;
112 Directory::Status dirStatus = dir.open(path, mode);
113 dir.close();
114 if (dirStatus != Directory::OP_OK) {
115 return FileSystem::handleDirectoryError(dirStatus);
116 }
117 return status;
118}
119
120FileSystem::Status FileSystem::touch(const char* path) {
121 FW_ASSERT(path != nullptr);
122 Status status = Status::OP_OK;
123 Os::File file;
124 File::Status file_status = file.open(path, Os::File::OPEN_WRITE);
125 file.close();
126 if (file_status != File::OP_OK) {
127 status = FileSystem::handleFileError(file_status);
128 }
129 return status;
130}
131
132FileSystem::PathType FileSystem::getPathType(const char* path) {
133 FW_ASSERT(path != nullptr);
134 Os::File file;
135 File::Status file_status = file.open(path, Os::File::OPEN_READ);
136 file.close();
137 if (file_status == File::OP_OK) {
138 return PathType::FILE;
139 }
140 Os::Directory dir;
142 dir.close();
143 if (dir_status == Directory::Status::OP_OK) {
144 return PathType::DIRECTORY;
145 }
146 return PathType::NOT_EXIST;
147} // end getPathType
148
149bool FileSystem::exists(const char* path) {
150 return FileSystem::getPathType(path) != PathType::NOT_EXIST;
151} // end exists
152
153FileSystem::Status FileSystem::copyFile(const char* sourcePath, const char* destPath) {
154 FW_ASSERT(sourcePath != nullptr);
155 FW_ASSERT(destPath != nullptr);
156 Os::File source;
157 Os::File destination;
158 Os::File::Status fileStatus = source.open(sourcePath, Os::File::OPEN_READ);
159 if (fileStatus != Os::File::OP_OK) {
160 return FileSystem::handleFileError(fileStatus);
161 }
162 fileStatus = destination.open(destPath, Os::File::OPEN_WRITE);
163 if (fileStatus != Os::File::OP_OK) {
164 return FileSystem::handleFileError(fileStatus);
165 }
166
167 FwSignedSizeType sourceFileSize = 0;
168 FileSystem::Status fs_status = FileSystem::getFileSize(sourcePath, sourceFileSize);
169 if (fs_status != FileSystem::Status::OP_OK) {
170 return fs_status;
171 }
172
173 fs_status = FileSystem::copyFileData(source, destination, sourceFileSize);
174
175 return fs_status;
176} // end copyFile
177
178FileSystem::Status FileSystem::appendFile(const char* sourcePath, const char* destPath, bool createMissingDest) {
179 Os::File source;
180 Os::File destination;
181
182 // If requested, check if destination file exists and exit if does not exist
183 if (not createMissingDest and not FileSystem::exists(destPath)) {
184 return Status::DOESNT_EXIST;
185 }
186
187 Os::File::Status fileStatus = source.open(sourcePath, Os::File::OPEN_READ);
188 if (fileStatus != Os::File::OP_OK) {
189 return FileSystem::handleFileError(fileStatus);
190 }
191 fileStatus = destination.open(destPath, Os::File::OPEN_APPEND);
192 if (fileStatus != Os::File::OP_OK) {
193 return FileSystem::handleFileError(fileStatus);
194 }
195
196 FileSystem::Status fs_status = FileSystem::OP_OK;
197
198 FwSignedSizeType sourceFileSize = 0;
199 fs_status = FileSystem::getFileSize(sourcePath, sourceFileSize);
200 if (fs_status != FileSystem::Status::OP_OK) {
201 return fs_status;
202 }
203
204 fs_status = FileSystem::copyFileData(source, destination, sourceFileSize);
205
206 return fs_status;
207} // end appendFile
208
209FileSystem::Status FileSystem::moveFile(const char* source, const char* destination) {
210 Status status = Status::OP_OK;
211
212 // Try to rename the file
213 status = FileSystem::rename(source, destination);
214
215 // If rename fails because of cross-device rename, attempt to copy and remove instead
216 if (status == Status::EXDEV_ERROR) {
217 status = FileSystem::copyFile(source, destination);
218 if (status != Status::OP_OK) {
219 return status;
220 }
221 status = FileSystem::removeFile(source);
222 }
223
224 return status;
225}
226
227FileSystem::Status FileSystem::getFileSize(const char* path, FwSignedSizeType& size) {
228 Os::File file;
229 Os::File::Status status = file.open(path, Os::File::OPEN_READ);
230 if (status != File::Status::OP_OK) {
231 return FileSystem::handleFileError(status);
232 }
233 status = file.size(size);
234 if (status != File::Status::OP_OK) {
235 return FileSystem::handleFileError(status);
236 }
237 return FileSystem::OP_OK;
238}
239
240
241// ------------------------------------------------------------
242// Internal helper functions
243// ------------------------------------------------------------
244
245FileSystem::Status FileSystem::handleFileError(File::Status fileStatus) {
246 FileSystem::Status status = FileSystem::OTHER_ERROR;
247
248 switch (fileStatus) {
249 case File::NO_SPACE:
250 status = FileSystem::NO_SPACE;
251 break;
252 case File::NO_PERMISSION:
253 status = FileSystem::NO_PERMISSION;
254 break;
255 case File::DOESNT_EXIST:
256 status = FileSystem::DOESNT_EXIST;
257 break;
258 default:
259 status = FileSystem::OTHER_ERROR;
260 }
261 return status;
262} // end handleFileError
263
264FileSystem::Status FileSystem::handleDirectoryError(Directory::Status dirStatus) {
265 FileSystem::Status status = FileSystem::OTHER_ERROR;
266
267 switch (dirStatus) {
268 case Directory::DOESNT_EXIST:
269 status = FileSystem::DOESNT_EXIST;
270 break;
271 case Directory::NO_PERMISSION:
272 status = FileSystem::NO_PERMISSION;
273 break;
274 case Directory::ALREADY_EXISTS:
275 status = FileSystem::ALREADY_EXISTS;
276 break;
277 case Directory::NOT_SUPPORTED:
278 status = FileSystem::NOT_SUPPORTED;
279 break;
280 default:
281 status = FileSystem::OTHER_ERROR;
282 }
283 return status;
284} // end handleFileError
285
286FileSystem::Status FileSystem::copyFileData(File& source, File& destination, FwSignedSizeType size) {
287 static_assert(FILE_SYSTEM_FILE_CHUNK_SIZE != 0, "FILE_SYSTEM_FILE_CHUNK_SIZE must be >0");
288 U8 fileBuffer[FILE_SYSTEM_FILE_CHUNK_SIZE];
289 File::Status file_status;
290
291 FwSignedSizeType copiedSize = 0;
292 FwSignedSizeType chunkSize = FILE_SYSTEM_FILE_CHUNK_SIZE;
293
294 // Copy the file in chunks - loop until all data is copied
295 for (copiedSize = 0; copiedSize < size; copiedSize += chunkSize) {
296 // chunkSize is FILE_SYSTEM_FILE_CHUNK_SIZE unless size-copiedSize is less than that
297 // in which case chunkSize is size-copiedSize, ensuring the last chunk reads the remaining data
298 chunkSize = FW_MIN(FILE_SYSTEM_FILE_CHUNK_SIZE, size - copiedSize);
299 file_status = source.read(fileBuffer, chunkSize, Os::File::WaitType::WAIT);
300 if (file_status != File::OP_OK) {
301 return FileSystem::handleFileError(file_status);
302 }
303 file_status = destination.write(fileBuffer, chunkSize, Os::File::WaitType::WAIT);
304 if (file_status != File::OP_OK) {
305 return FileSystem::handleFileError(file_status);
306 }
307 }
308
309 return FileSystem::OP_OK;
310} // end copyFileData
311
312} // namespace Os
#define FW_ASSERT(...)
Definition Assert.hpp:14
#define FW_MIN(a, b)
MIN macro.
Definition BasicTypes.h:72
uint8_t U8
8-bit unsigned integer
Definition BasicTypes.h:30
PlatformSignedSizeType FwSignedSizeType
Definition FpConfig.h:30
PlatformSizeType FwSizeType
Definition FpConfig.h:35
Directory class.
Status open(const char *path, OpenMode mode) override
Open or create a directory.
Definition Directory.cpp:30
void close() override
Close directory.
Definition Directory.cpp:72
@ READ
Error if directory doesn't exist.
Definition Directory.hpp:34
Status size(FwSignedSizeType &size_result) override
get size of currently open file
Definition File.cpp:85
void close() override
close the file, if not opened then do nothing
Definition File.cpp:70
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
Definition File.cpp:45
@ WAIT
Do wait for read/write operation to finish.
Definition File.hpp:58
@ OP_OK
Operation was successful.
Definition File.hpp:30
@ OPEN_WRITE
Open file for writing.
Definition File.hpp:23
@ OPEN_READ
Open file for reading.
Definition File.hpp:21
@ OPEN_APPEND
Open file for appending.
Definition File.hpp:25
FileSystem class.
Status _removeDirectory(const char *path) override
Remove a directory at the specified path.