F´ Flight Software - C/C++ Documentation
A framework for building embedded system applications to NASA flight quality standards.
FileManager.cpp
Go to the documentation of this file.
1 // ======================================================================
2 // \title FileManager.hpp
3 // \author bocchino
4 // \brief hpp file for FileManager component implementation class
5 //
6 // \copyright
7 // Copyright 2009-2015, by the California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12 
13 #include <cstdio>
14 #include <cstdlib>
15 
16 #include <Fw/FPrimeBasicTypes.hpp>
17 #include "Fw/Types/Assert.hpp"
19 #include "Os/Directory.hpp"
21 #include "config/FileManagerConfig.hpp"
22 
23 namespace Svc {
24 
25 // ----------------------------------------------------------------------
26 // Construction, initialization, and destruction
27 // ----------------------------------------------------------------------
28 
29 FileManager ::FileManager(const char* const compName
30  )
31  : FileManagerComponentBase(compName),
32  commandCount(0),
33  errorCount(0),
34  m_listState(IDLE),
35  m_totalEntries(0),
36  m_currentOpCode(0),
37  m_currentCmdSeq(0),
38  m_runQueued(false) {}
39 
41 
42 // ----------------------------------------------------------------------
43 // Command handler implementations
44 // ----------------------------------------------------------------------
45 
46 void FileManager ::CreateDirectory_cmdHandler(const FwOpcodeType opCode,
47  const U32 cmdSeq,
48  const Fw::CmdStringArg& dirName) {
49  Fw::LogStringArg logStringDirName(dirName.toChar());
50  this->log_ACTIVITY_HI_CreateDirectoryStarted(logStringDirName);
51  bool errorIfDirExists = true;
52  const Os::FileSystem::Status status = Os::FileSystem::createDirectory(dirName.toChar(), errorIfDirExists);
53  if (status != Os::FileSystem::OP_OK) {
54  this->log_WARNING_HI_DirectoryCreateError(logStringDirName, status);
55  } else {
56  this->log_ACTIVITY_HI_CreateDirectorySucceeded(logStringDirName);
57  }
58  this->emitTelemetry(status);
59  this->sendCommandResponse(opCode, cmdSeq, status);
60 }
61 
62 void FileManager ::RemoveFile_cmdHandler(const FwOpcodeType opCode,
63  const U32 cmdSeq,
64  const Fw::CmdStringArg& fileName,
65  const bool ignoreErrors) {
66  Fw::LogStringArg logStringFileName(fileName.toChar());
67  this->log_ACTIVITY_HI_RemoveFileStarted(logStringFileName);
68  const Os::FileSystem::Status status = Os::FileSystem::removeFile(fileName.toChar());
69  if (status != Os::FileSystem::OP_OK) {
70  this->log_WARNING_HI_FileRemoveError(logStringFileName, status);
71  if (ignoreErrors == true) {
72  ++this->errorCount;
73  this->tlmWrite_Errors(this->errorCount);
74  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
75  return;
76  }
77  } else {
78  this->log_ACTIVITY_HI_RemoveFileSucceeded(logStringFileName);
79  }
80  this->emitTelemetry(status);
81  this->sendCommandResponse(opCode, cmdSeq, status);
82 }
83 
84 void FileManager ::MoveFile_cmdHandler(const FwOpcodeType opCode,
85  const U32 cmdSeq,
86  const Fw::CmdStringArg& sourceFileName,
87  const Fw::CmdStringArg& destFileName) {
88  Fw::LogStringArg logStringSource(sourceFileName.toChar());
89  Fw::LogStringArg logStringDest(destFileName.toChar());
90  this->log_ACTIVITY_HI_MoveFileStarted(logStringSource, logStringDest);
91  const Os::FileSystem::Status status = Os::FileSystem::moveFile(sourceFileName.toChar(), destFileName.toChar());
92  if (status != Os::FileSystem::OP_OK) {
93  this->log_WARNING_HI_FileMoveError(logStringSource, logStringDest, status);
94  } else {
95  this->log_ACTIVITY_HI_MoveFileSucceeded(logStringSource, logStringDest);
96  }
97  this->emitTelemetry(status);
98  this->sendCommandResponse(opCode, cmdSeq, status);
99 }
100 
101 void FileManager ::RemoveDirectory_cmdHandler(const FwOpcodeType opCode,
102  const U32 cmdSeq,
103  const Fw::CmdStringArg& dirName) {
104  Fw::LogStringArg logStringDirName(dirName.toChar());
105  this->log_ACTIVITY_HI_RemoveDirectoryStarted(logStringDirName);
107  if (status != Os::FileSystem::OP_OK) {
108  this->log_WARNING_HI_DirectoryRemoveError(logStringDirName, status);
109  } else {
110  this->log_ACTIVITY_HI_RemoveDirectorySucceeded(logStringDirName);
111  }
112  this->emitTelemetry(status);
113  this->sendCommandResponse(opCode, cmdSeq, status);
114 }
115 
116 void FileManager ::AppendFile_cmdHandler(const FwOpcodeType opCode,
117  const U32 cmdSeq,
118  const Fw::CmdStringArg& source,
119  const Fw::CmdStringArg& target) {
120  Fw::LogStringArg logStringSource(source.toChar());
121  Fw::LogStringArg logStringTarget(target.toChar());
122  this->log_ACTIVITY_HI_AppendFileStarted(logStringSource, logStringTarget);
123 
124  Os::FileSystem::Status status;
125  status = Os::FileSystem::appendFile(source.toChar(), target.toChar(), true);
126  if (status != Os::FileSystem::OP_OK) {
127  this->log_WARNING_HI_AppendFileFailed(logStringSource, logStringTarget, status);
128  } else {
129  this->log_ACTIVITY_HI_AppendFileSucceeded(logStringSource, logStringTarget);
130  }
131 
132  this->emitTelemetry(status);
133  this->sendCommandResponse(opCode, cmdSeq, status);
134 }
135 
136 void FileManager ::FileSize_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, const Fw::CmdStringArg& fileName) {
137  Fw::LogStringArg logStringFileName(fileName.toChar());
138  this->log_ACTIVITY_HI_FileSizeStarted(logStringFileName);
139 
140  FwSizeType size_arg;
141  const Os::FileSystem::Status status = Os::FileSystem::getFileSize(fileName.toChar(), size_arg);
142  if (status != Os::FileSystem::OP_OK) {
143  this->log_WARNING_HI_FileSizeError(logStringFileName, status);
144  } else {
145  this->log_ACTIVITY_HI_FileSizeSucceeded(logStringFileName, size_arg);
146  }
147  this->emitTelemetry(status);
148  this->sendCommandResponse(opCode, cmdSeq, status);
149 }
150 
151 void FileManager ::ListDirectory_cmdHandler(const FwOpcodeType opCode,
152  const U32 cmdSeq,
153  const Fw::CmdStringArg& dirName) {
154  // Check if we're already listing a directory
155  if (m_listState == LISTING_IN_PROGRESS) {
156  this->log_WARNING_HI_ListDirectoryError(dirName, static_cast<U32>(Os::Directory::OTHER_ERROR));
157  this->sendCommandResponse(opCode, cmdSeq, Os::FileSystem::OTHER_ERROR);
158  return;
159  }
160 
162 
163  // Open the directory for reading
164  Os::Directory::Status status = m_currentDir.open(dirName.toChar(), Os::Directory::OpenMode::READ);
165 
166  if (status != Os::Directory::OP_OK) {
167  this->log_WARNING_HI_ListDirectoryError(dirName, static_cast<U32>(status));
168  this->emitTelemetry(Os::FileSystem::OTHER_ERROR);
169  this->sendCommandResponse(opCode, cmdSeq, Os::FileSystem::OTHER_ERROR);
170  return;
171  }
172 
173  // Initialize state machine for asynchronous processing
174  m_listState = LISTING_IN_PROGRESS;
175  m_currentDirName = dirName;
176  m_currentOpCode = opCode;
177  m_currentCmdSeq = cmdSeq;
178  m_totalEntries = 0;
179 
180  // Directory listing will be processed asynchronously by the rate group.
181  // The schedIn_handler will process FILES_PER_RATE_TICK directory entries per rate tick to
182  // prevent event flooding while maintaining configurable performance.
183  // Command response will be sent when listing completes.
184 }
185 
186 void FileManager ::CalculateCrc_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& filename) {
187  Os::File file;
188  U32 crcValue = 0;
189  this->log_ACTIVITY_HI_CalculateCrcStarted(filename);
190 
191  Os::File::Status status = file.open(filename.toChar(), Os::File::OPEN_READ);
192  if (status == Os::File::OP_OK) {
193  status = file.calculateCrc(crcValue);
194  }
195 
196  if (status == Os::File::OP_OK) {
197  this->log_ACTIVITY_HI_CalculateCrcSucceeded(filename, crcValue);
198  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
199  } else {
200  this->log_WARNING_HI_CalculateCrcFailed(filename, status);
201  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR);
202  }
203  file.close();
204 }
205 
206 void FileManager ::pingIn_handler(const FwIndexType portNum, U32 key) {
207  // return key
208  this->pingOut_out(0, key);
209 }
210 
211 void FileManager ::schedIn_handler(const FwIndexType portNum, U32 context) {
212  bool isQueued = false;
213  // m_runQueued will be compared to isQueued (false). When equal (i.e. m_runQueued is false) the atomic will be
214  // set to true and the function will return true indicating that a run was successfully marked as queued and thus
215  // the internal handler should be invoked.
216  bool expects_enqueue = this->m_runQueued.compare_exchange_strong(isQueued, true);
217  if (expects_enqueue) {
219  }
220 }
221 
222 void FileManager ::run_internalInterfaceHandler() {
223  FW_ASSERT(this->m_runQueued);
224  this->m_runQueued = false; // Run is not queued anymore (we are running)
225  // Only process if we're in the middle of a directory listing
226  if (m_listState == LISTING_IN_PROGRESS) {
227  // Process multiple files per rate tick based on configuration
228  for (U32 fileCount = 0; fileCount < Svc::FileManagerConfig::FILES_PER_RATE_TICK; fileCount++) {
229  Fw::String filename;
230  Os::Directory::Status status = m_currentDir.read(filename);
231 
232  if (status == Os::Directory::NO_MORE_FILES) {
233  // We're done listing - close directory and send response
234  m_currentDir.close();
235  m_listState = IDLE;
236 
237  this->log_ACTIVITY_HI_ListDirectorySucceeded(m_currentDirName, m_totalEntries);
238  this->emitTelemetry(Os::FileSystem::OP_OK);
239  this->sendCommandResponse(m_currentOpCode, m_currentCmdSeq, Os::FileSystem::OP_OK);
240  break; // Exit the loop since we're done
241 
242  } else if (status == Os::Directory::OP_OK) {
243  // Construct full path for type checking
244  Fw::String fullPath;
245  fullPath.format("%s/%s", m_currentDirName.toChar(), filename.toChar());
246 
247  // Determine entry type
249 
250  if (pathType == Os::FileSystem::FILE) {
251  // Regular file: get size and emit file event
252  FwSizeType fileSize;
253  Os::FileSystem::Status sizeStatus = Os::FileSystem::getFileSize(fullPath.toChar(), fileSize);
255  m_currentDirName, filename,
256  (sizeStatus == Os::FileSystem::OP_OK) ? fileSize : static_cast<FwSizeType>(0));
257  } else if (pathType == Os::FileSystem::DIRECTORY) {
258  // Subdirectory: emit subdirectory event
259  this->log_ACTIVITY_HI_DirectoryListingSubdir(m_currentDirName, filename);
260  } else {
261  // Special file or inaccessible: treat as file with 0 size
262  this->log_ACTIVITY_HI_DirectoryListing(m_currentDirName, filename, static_cast<FwSizeType>(0));
263  }
264 
265  m_totalEntries++;
266 
267  } else {
268  // Error reading directory - close and send error response
269  m_currentDir.close();
270  m_listState = IDLE;
271 
272  this->log_WARNING_HI_ListDirectoryError(m_currentDirName, static_cast<U32>(status));
273  this->emitTelemetry(Os::FileSystem::OTHER_ERROR);
274  this->sendCommandResponse(m_currentOpCode, m_currentCmdSeq, Os::FileSystem::OTHER_ERROR);
275  break; // Exit the loop since we had an error
276  }
277  }
278  }
279 }
280 
281 // ----------------------------------------------------------------------
282 // Helper methods
283 // ----------------------------------------------------------------------
284 
285 void FileManager ::emitTelemetry(const Os::FileSystem::Status status) {
286  if (status == Os::FileSystem::OP_OK) {
287  ++this->commandCount;
288  this->tlmWrite_CommandsExecuted(this->commandCount);
289  } else {
290  ++this->errorCount;
291  this->tlmWrite_Errors(this->errorCount);
292  }
293 }
294 
295 void FileManager ::sendCommandResponse(const FwOpcodeType opCode,
296  const U32 cmdSeq,
297  const Os::FileSystem::Status status) {
298  this->cmdResponse_out(opCode, cmdSeq,
300 }
301 
302 } // namespace Svc
void log_WARNING_HI_ListDirectoryError(const Fw::StringBase &dirName, U32 status) const
void log_ACTIVITY_HI_DirectoryListingSubdir(const Fw::StringBase &dirName, const Fw::StringBase &subdirName) const
void log_ACTIVITY_HI_CreateDirectoryStarted(const Fw::StringBase &dirName) const
FwIdType FwOpcodeType
The type of a command opcode.
Status calculateCrc(U32 &crc)
calculate the CRC32 of the entire file
Definition: File.cpp:212
void log_ACTIVITY_HI_RemoveDirectorySucceeded(const Fw::StringBase &dirName) const
void log_ACTIVITY_HI_DirectoryListing(const Fw::StringBase &dirName, const Fw::StringBase &fileName, FwSizeType fileSize) const
PlatformSizeType FwSizeType
static Status moveFile(const char *sourcePath, const char *destPath)
Move a file from sourcePath to destPath.
Definition: FileSystem.cpp:208
void log_ACTIVITY_HI_CalculateCrcStarted(const Fw::StringBase &fileName) const
void log_WARNING_HI_FileSizeError(const Fw::StringBase &fileName, U32 status) const
void run_internalInterfaceInvoke()
Internal interface base-class function for run.
FileManager(const char *const compName)
Definition: FileManager.cpp:29
const char * toChar() const
Convert to a C-style char*.
Definition: String.hpp:50
static Status removeDirectory(const char *path)
Remove a directory at the specified path.
Definition: FileSystem.cpp:83
void log_ACTIVITY_HI_FileSizeSucceeded(const Fw::StringBase &fileName, FwSizeType size) const
static Status appendFile(const char *sourcePath, const char *destPath, bool createMissingDest=false)
Append the source file to the destination file.
Definition: FileSystem.cpp:177
void log_ACTIVITY_HI_ListDirectorySucceeded(const Fw::StringBase &dirName, U32 fileCount) const
Auto-generated base for FileManager component.
void log_ACTIVITY_HI_CalculateCrcSucceeded(const Fw::StringBase &fileName, U32 crc) const
void log_ACTIVITY_HI_ListDirectoryStarted(const Fw::StringBase &dirName) const
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
void log_ACTIVITY_HI_MoveFileStarted(const Fw::StringBase &sourceFileName, const Fw::StringBase &destFileName) const
void pingOut_out(FwIndexType portNum, U32 key) const
Invoke output port pingOut.
void log_ACTIVITY_HI_AppendFileSucceeded(const Fw::StringBase &source, const Fw::StringBase &target) const
void log_ACTIVITY_HI_CreateDirectorySucceeded(const Fw::StringBase &dirName) const
A catch-all for other errors. Have to look in implementation-specific code.
Definition: Directory.hpp:30
void log_ACTIVITY_HI_RemoveDirectoryStarted(const Fw::StringBase &dirName) const
void close() override
Close directory.
Definition: Directory.cpp:73
Status read(char *fileNameBuffer, FwSizeType buffSize) override
Get next filename from directory stream.
Definition: Directory.cpp:54
void close() override
close the file, if not opened then do nothing
Definition: File.cpp:71
void cmdResponse_out(FwOpcodeType opCode, U32 cmdSeq, Fw::CmdResponse response)
Emit command response.
Directory stream has no more files.
Definition: Directory.hpp:25
void log_ACTIVITY_HI_FileSizeStarted(const Fw::StringBase &fileName) const
FormatStatus format(const CHAR *formatString,...)
write formatted string to buffer
Definition: StringBase.cpp:39
Command successfully executed.
void log_ACTIVITY_HI_MoveFileSucceeded(const Fw::StringBase &sourceFileName, const Fw::StringBase &destFileName) const
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
void log_WARNING_HI_DirectoryRemoveError(const Fw::StringBase &dirName, U32 status) const
Command had execution error.
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
const char * toChar() const
Convert to a C-style char*.
Definition: CmdString.hpp:50
void log_ACTIVITY_HI_AppendFileStarted(const Fw::StringBase &source, const Fw::StringBase &target) const
Operation was successful.
Definition: File.hpp:40
void tlmWrite_Errors(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void log_ACTIVITY_HI_RemoveFileStarted(const Fw::StringBase &fileName) const
PlatformIndexType FwIndexType
Operation was successful.
Definition: Directory.hpp:20
Open file for reading.
Definition: File.hpp:31
void log_WARNING_HI_AppendFileFailed(const Fw::StringBase &source, const Fw::StringBase &target, U32 status) const
Status open(const char *path, OpenMode mode) override
Open or create a directory.
Definition: Directory.cpp:31
RateGroupDivider component implementation.
void log_WARNING_HI_CalculateCrcFailed(const Fw::StringBase &fileName, U32 status) const
Operation was successful.
Definition: FileSystem.hpp:24
static constexpr U32 FILES_PER_RATE_TICK
void log_WARNING_HI_DirectoryCreateError(const Fw::StringBase &dirName, U32 status) const
void log_ACTIVITY_HI_RemoveFileSucceeded(const Fw::StringBase &fileName) const
void log_WARNING_HI_FileMoveError(const Fw::StringBase &sourceFileName, const Fw::StringBase &destFileName, U32 status) const
void tlmWrite_CommandsExecuted(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
#define FW_ASSERT(...)
Definition: Assert.hpp:14
static Status removeFile(const char *path)
Remove a file at the specified path.
Definition: FileSystem.cpp:87
void log_WARNING_HI_FileRemoveError(const Fw::StringBase &fileName, U32 status) const