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