F´ Flight Software - C/C++ Documentation  devel
A framework for building embedded system applications to NASA flight quality standards.
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 
8 namespace Os {
9 
10 FileSystem::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 
14 FileSystem::~FileSystem() {
15  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
16  m_delegate.~FileSystemInterface();
17 }
18 
19 FileSystemHandle* FileSystem::getHandle() {
20  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
21  return this->m_delegate.getHandle();
22 }
23 
24 FileSystem::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 
30 FileSystem::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 
36 FileSystem::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 
43 FileSystem::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 
50 FileSystem::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 
56 FileSystem::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 
63  // Force trigger on the fly singleton setup
64  (void) FileSystem::getSingleton();
65 }
66 
67 FileSystem& FileSystem::getSingleton() {
68  static FileSystem s_singleton;
69  return s_singleton;
70 }
71 
72 
73 // ------------------------------------------------------------
74 // Static functions calling implementation-specific operations
75 // ------------------------------------------------------------
76 
77 FileSystem::Status FileSystem::removeDirectory(const char* path) {
78  return FileSystem::getSingleton()._removeDirectory(path);
79 }
80 
81 FileSystem::Status FileSystem::removeFile(const char* path) {
82  return FileSystem::getSingleton()._removeFile(path);
83 }
84 
85 FileSystem::Status FileSystem::rename(const char* sourcePath, const char* destPath) {
86  return FileSystem::getSingleton()._rename(sourcePath, destPath);
87 }
88 
89 FileSystem::Status FileSystem::getWorkingDirectory(char* path, FwSizeType bufferSize) {
90  return FileSystem::getSingleton()._getWorkingDirectory(path, bufferSize);
91 }
92 
93 FileSystem::Status FileSystem::changeWorkingDirectory(const char* path) {
94  return FileSystem::getSingleton()._changeWorkingDirectory(path);
95 }
96 
97 FileSystem::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 
106 FileSystem::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 
120 FileSystem::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 
132 FileSystem::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;
141  Directory::Status dir_status = dir.open(path, Os::Directory::OpenMode::READ);
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 
149 bool FileSystem::exists(const char* path) {
150  return FileSystem::getPathType(path) != PathType::NOT_EXIST;
151 } // end exists
152 
153 FileSystem::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 
178 FileSystem::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 
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 
209 FileSystem::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 
227 FileSystem::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 
245 FileSystem::Status FileSystem::handleFileError(File::Status fileStatus) {
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 
264 FileSystem::Status FileSystem::handleDirectoryError(Directory::Status dirStatus) {
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 
286 FileSystem::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.
Definition: Directory.hpp:117
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
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
@ 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.
Definition: FileSystem.hpp:117
Status _removeDirectory(const char *path) override
Remove a directory at the specified path.
Definition: FileSystem.cpp:24
Status
Generic OK/ERROR status.
Definition: Os.hpp:25
@ OP_OK
Operation succeeded.
Definition: Os.hpp:26
@ OTHER_ERROR
A catch-all for other errors. Have to look in implementation-specific code.
@ NO_SPACE
No space left on the device for writing.
void init()
Initialize the OS Abstraction Layer (OSAL)
Definition: Os.cpp:15