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