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 
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 
15  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
16  m_delegate.~FileSystemInterface();
17 }
18 
20  FW_ASSERT(&this->m_delegate == reinterpret_cast<FileSystemInterface*>(&this->m_handle_storage[0]));
21  return this->m_delegate.getHandle();
22 }
23 
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 
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 
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 
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
65 }
66 
68  static FileSystem s_singleton;
69  return s_singleton;
70 }
71 
72 // ------------------------------------------------------------
73 // Static functions calling implementation-specific operations
74 // ------------------------------------------------------------
75 
78 }
79 
82 }
83 
84 FileSystem::Status FileSystem::rename(const char* sourcePath, const char* destPath) {
85  return FileSystem::getSingleton()._rename(sourcePath, destPath);
86 }
87 
89  return FileSystem::getSingleton()._getWorkingDirectory(path, bufferSize);
90 }
91 
94 }
95 
96 FileSystem::Status FileSystem::getFreeSpace(const char* path, FwSizeType& totalBytes, FwSizeType& freeBytes) {
97  return FileSystem::getSingleton()._getFreeSpace(path, totalBytes, freeBytes);
98 }
99 
100 // ------------------------------------------------------------
101 // Additional functions built on top of OS-specific operations
102 // ------------------------------------------------------------
103 
104 FileSystem::Status FileSystem::createDirectory(const char* path, bool errorIfAlreadyExists) {
105  FW_ASSERT(path != nullptr);
106  Status status = Status::OP_OK;
107  Os::Directory dir;
108  // If errorIfAlreadyExists is true, use CREATE_EXCLUSIVE mode, otherwise use CREATE_IF_MISSING
109  Directory::OpenMode mode =
110  errorIfAlreadyExists ? Directory::OpenMode::CREATE_EXCLUSIVE : Directory::OpenMode::CREATE_IF_MISSING;
111  Directory::Status dirStatus = dir.open(path, mode);
112  dir.close();
113  if (dirStatus != Directory::OP_OK) {
114  return FileSystem::handleDirectoryError(dirStatus);
115  }
116  return status;
117 }
118 
120  FW_ASSERT(path != nullptr);
121  Status status = Status::OP_OK;
122  Os::File file;
123  File::Status file_status = file.open(path, Os::File::OPEN_WRITE);
124  file.close();
125  if (file_status != File::OP_OK) {
126  status = FileSystem::handleFileError(file_status);
127  }
128  return status;
129 }
130 
132  FW_ASSERT(path != nullptr);
133  Os::File file;
134  File::Status file_status = file.open(path, Os::File::OPEN_READ);
135  file.close();
136  if (file_status == File::OP_OK) {
137  return PathType::FILE;
138  }
139  Os::Directory dir;
140  Directory::Status dir_status = dir.open(path, Os::Directory::OpenMode::READ);
141  dir.close();
142  if (dir_status == Directory::Status::OP_OK) {
143  return PathType::DIRECTORY;
144  }
145  return PathType::NOT_EXIST;
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  chunkSize = FW_MIN(FILE_SYSTEM_FILE_CHUNK_SIZE, size - copiedSize);
302  file_status = source.read(fileBuffer, chunkSize, Os::File::WaitType::WAIT);
303  if (file_status != File::OP_OK) {
304  return FileSystem::handleFileError(file_status);
305  }
306  file_status = destination.write(fileBuffer, chunkSize, Os::File::WaitType::WAIT);
307  if (file_status != File::OP_OK) {
308  return FileSystem::handleFileError(file_status);
309  }
310  }
311 
312  return FileSystem::OP_OK;
313 } // end copyFileData
314 
315 } // namespace Os
FileSystemHandle * getHandle() override
return the underlying FileSystem handle (implementation specific)
Definition: FileSystem.cpp:19
static Status rename(const char *sourcePath, const char *destPath)
Rename a file from source to destination.
Definition: FileSystem.cpp:84
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:96
Status _getWorkingDirectory(char *path, FwSizeType bufferSize) override
Get the current working directory.
Definition: FileSystem.cpp:43
static Status removeDirectory(const char *path)
Remove a directory at the specified path.
Definition: FileSystem.cpp:76
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:85
No permission to read/write file.
Definition: File.hpp:33
Open file for writing.
Definition: File.hpp:23
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:62
Status _rename(const char *sourcePath, const char *destPath) override
Rename a file from source to destination.
Definition: FileSystem.cpp:36
No permission to read directory.
Definition: Directory.hpp:22
Open file for appending.
Definition: File.hpp:25
No space left.
Definition: File.hpp:32
static FileSystem & getSingleton()
get a reference to singleton
Definition: FileSystem.cpp:67
#define FW_MIN(a, b)
MIN macro.
Definition: BasicTypes.h:95
void close() override
Close directory.
Definition: Directory.cpp:72
File doesn&#39;t exist (for read)
Definition: File.hpp:31
Status _removeFile(const char *path) override
Remove a file at the specified path.
Definition: FileSystem.cpp:30
void close() override
close the file, if not opened then do nothing
Definition: File.cpp:70
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:56
Status _removeDirectory(const char *path) override
Remove a directory at the specified path.
Definition: FileSystem.cpp:24
static Status getWorkingDirectory(char *path, FwSizeType bufferSize)
Get the current working directory.
Definition: FileSystem.cpp:88
uint8_t U8
8-bit unsigned integer
Definition: BasicTypes.h:56
Directory class.
Definition: Directory.hpp:117
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:104
static PathType getPathType(const char *path)
Return the type of the path (file, directory, or doesn&#39;t exist)
Definition: FileSystem.cpp:131
other OS-specific error
Definition: FileSystem.hpp:41
Operation was successful.
Definition: File.hpp:30
Operation was successful.
Definition: Directory.hpp:20
Operation is not supported by the current implementation.
Definition: FileSystem.hpp:40
FileSystem class.
Definition: FileSystem.hpp:117
Open file for reading.
Definition: File.hpp:21
Status open(const char *path, OpenMode mode) override
Open or create a directory.
Definition: Directory.cpp:30
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:25
Directory already exists.
Definition: Directory.hpp:28
~FileSystem() final
Destructor.
Definition: FileSystem.cpp:14
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:92
Status _changeWorkingDirectory(const char *path) override
Change the current working directory to the specified path.
Definition: FileSystem.cpp:50
#define FW_ASSERT(...)
Definition: Assert.hpp:14
static Status removeFile(const char *path)
Remove a file at the specified path.
Definition: FileSystem.cpp:80
Path doesn&#39;t exist.
Definition: FileSystem.hpp:33
static Status touch(const char *path)
Touch a file at the specified path, creating it if it doesn&#39;t exist.
Definition: FileSystem.cpp:119