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 
40 
41 // ----------------------------------------------------------------------
42 // Command handler implementations
43 // ----------------------------------------------------------------------
44 
45 void FileManager ::CreateDirectory_cmdHandler(const FwOpcodeType opCode,
46  const U32 cmdSeq,
47  const Fw::CmdStringArg& dirName) {
48  Fw::LogStringArg logStringDirName(dirName.toChar());
49  this->log_ACTIVITY_HI_CreateDirectoryStarted(logStringDirName);
50  bool errorIfDirExists = true;
51  const Os::FileSystem::Status status = Os::FileSystem::createDirectory(dirName.toChar(), errorIfDirExists);
52  if (status != Os::FileSystem::OP_OK) {
53  this->log_WARNING_HI_DirectoryCreateError(logStringDirName, status);
54  } else {
55  this->log_ACTIVITY_HI_CreateDirectorySucceeded(logStringDirName);
56  }
57  this->emitTelemetry(status);
58  this->sendCommandResponse(opCode, cmdSeq, status);
59 }
60 
61 void FileManager ::RemoveFile_cmdHandler(const FwOpcodeType opCode,
62  const U32 cmdSeq,
63  const Fw::CmdStringArg& fileName,
64  const bool ignoreErrors) {
65  Fw::LogStringArg logStringFileName(fileName.toChar());
66  this->log_ACTIVITY_HI_RemoveFileStarted(logStringFileName);
67  const Os::FileSystem::Status status = Os::FileSystem::removeFile(fileName.toChar());
68  if (status != Os::FileSystem::OP_OK) {
69  this->log_WARNING_HI_FileRemoveError(logStringFileName, status);
70  if (ignoreErrors == true) {
71  ++this->errorCount;
72  this->tlmWrite_Errors(this->errorCount);
73  this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK);
74  return;
75  }
76  } else {
77  this->log_ACTIVITY_HI_RemoveFileSucceeded(logStringFileName);
78  }
79  this->emitTelemetry(status);
80  this->sendCommandResponse(opCode, cmdSeq, status);
81 }
82 
83 void FileManager ::MoveFile_cmdHandler(const FwOpcodeType opCode,
84  const U32 cmdSeq,
85  const Fw::CmdStringArg& sourceFileName,
86  const Fw::CmdStringArg& destFileName) {
87  Fw::LogStringArg logStringSource(sourceFileName.toChar());
88  Fw::LogStringArg logStringDest(destFileName.toChar());
89  this->log_ACTIVITY_HI_MoveFileStarted(logStringSource, logStringDest);
90  const Os::FileSystem::Status status = Os::FileSystem::moveFile(sourceFileName.toChar(), destFileName.toChar());
91  if (status != Os::FileSystem::OP_OK) {
92  this->log_WARNING_HI_FileMoveError(logStringSource, logStringDest, status);
93  } else {
94  this->log_ACTIVITY_HI_MoveFileSucceeded(logStringSource, logStringDest);
95  }
96  this->emitTelemetry(status);
97  this->sendCommandResponse(opCode, cmdSeq, status);
98 }
99 
100 void FileManager ::RemoveDirectory_cmdHandler(const FwOpcodeType opCode,
101  const U32 cmdSeq,
102  const Fw::CmdStringArg& dirName) {
103  Fw::LogStringArg logStringDirName(dirName.toChar());
104  this->log_ACTIVITY_HI_RemoveDirectoryStarted(logStringDirName);
106  if (status != Os::FileSystem::OP_OK) {
107  this->log_WARNING_HI_DirectoryRemoveError(logStringDirName, status);
108  } else {
109  this->log_ACTIVITY_HI_RemoveDirectorySucceeded(logStringDirName);
110  }
111  this->emitTelemetry(status);
112  this->sendCommandResponse(opCode, cmdSeq, status);
113 }
114 
115 void FileManager ::ShellCommand_cmdHandler(const FwOpcodeType opCode,
116  const U32 cmdSeq,
117  const Fw::CmdStringArg& command,
118  const Fw::CmdStringArg& logFileName) {
119  Fw::LogStringArg logStringCommand(command.toChar());
120  this->log_ACTIVITY_HI_ShellCommandStarted(logStringCommand);
121  int status = this->systemCall(command, logFileName);
122  if (status == 0) {
123  this->log_ACTIVITY_HI_ShellCommandSucceeded(logStringCommand);
124  } else {
125  this->log_WARNING_HI_ShellCommandFailed(logStringCommand, static_cast<U32>(status));
126  }
127  this->emitTelemetry(status == 0 ? Os::FileSystem::OP_OK : Os::FileSystem::OTHER_ERROR);
128  this->sendCommandResponse(opCode, cmdSeq, status == 0 ? Os::FileSystem::OP_OK : Os::FileSystem::OTHER_ERROR);
129 }
130 
131 void FileManager ::AppendFile_cmdHandler(const FwOpcodeType opCode,
132  const U32 cmdSeq,
133  const Fw::CmdStringArg& source,
134  const Fw::CmdStringArg& target) {
135  Fw::LogStringArg logStringSource(source.toChar());
136  Fw::LogStringArg logStringTarget(target.toChar());
137  this->log_ACTIVITY_HI_AppendFileStarted(logStringSource, logStringTarget);
138 
139  Os::FileSystem::Status status;
140  status = Os::FileSystem::appendFile(source.toChar(), target.toChar(), true);
141  if (status != Os::FileSystem::OP_OK) {
142  this->log_WARNING_HI_AppendFileFailed(logStringSource, logStringTarget, status);
143  } else {
144  this->log_ACTIVITY_HI_AppendFileSucceeded(logStringSource, logStringTarget);
145  }
146 
147  this->emitTelemetry(status);
148  this->sendCommandResponse(opCode, cmdSeq, status);
149 }
150 
151 void FileManager ::FileSize_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, const Fw::CmdStringArg& fileName) {
152  Fw::LogStringArg logStringFileName(fileName.toChar());
153  this->log_ACTIVITY_HI_FileSizeStarted(logStringFileName);
154 
155  FwSizeType size_arg;
156  const Os::FileSystem::Status status = Os::FileSystem::getFileSize(fileName.toChar(), size_arg);
157  if (status != Os::FileSystem::OP_OK) {
158  this->log_WARNING_HI_FileSizeError(logStringFileName, status);
159  } else {
160  this->log_ACTIVITY_HI_FileSizeSucceeded(logStringFileName, size_arg);
161  }
162  this->emitTelemetry(status);
163  this->sendCommandResponse(opCode, cmdSeq, status);
164 }
165 
166 void FileManager ::ListDirectory_cmdHandler(const FwOpcodeType opCode,
167  const U32 cmdSeq,
168  const Fw::CmdStringArg& dirName) {
169  // Check if we're already listing a directory
170  if (m_listState == LISTING_IN_PROGRESS) {
171  this->log_WARNING_HI_ListDirectoryError(dirName, static_cast<U32>(Os::Directory::OTHER_ERROR));
172  this->sendCommandResponse(opCode, cmdSeq, Os::FileSystem::OTHER_ERROR);
173  return;
174  }
175 
177 
178  // Open the directory for reading
179  Os::Directory::Status status = m_currentDir.open(dirName.toChar(), Os::Directory::OpenMode::READ);
180 
181  if (status != Os::Directory::OP_OK) {
182  this->log_WARNING_HI_ListDirectoryError(dirName, static_cast<U32>(status));
183  this->emitTelemetry(Os::FileSystem::OTHER_ERROR);
184  this->sendCommandResponse(opCode, cmdSeq, Os::FileSystem::OTHER_ERROR);
185  return;
186  }
187 
188  // Initialize state machine for asynchronous processing
189  m_listState = LISTING_IN_PROGRESS;
190  m_currentDirName = dirName;
191  m_currentOpCode = opCode;
192  m_currentCmdSeq = cmdSeq;
193  m_totalEntries = 0;
194 
195  // Directory listing will be processed asynchronously by the rate group.
196  // The schedIn_handler will process FILES_PER_RATE_TICK directory entries per rate tick to
197  // prevent event flooding while maintaining configurable performance.
198  // Command response will be sent when listing completes.
199 }
200 
201 void FileManager ::pingIn_handler(const FwIndexType portNum, U32 key) {
202  // return key
203  this->pingOut_out(0, key);
204 }
205 
206 void FileManager ::schedIn_handler(const FwIndexType portNum, U32 context) {
207  // Only process if we're in the middle of a directory listing
208  if (m_listState == LISTING_IN_PROGRESS) {
209  // Process multiple files per rate tick based on configuration
210  for (U32 fileCount = 0; fileCount < Svc::FileManagerConfig::FILES_PER_RATE_TICK; fileCount++) {
211  Fw::String filename;
212  Os::Directory::Status status = m_currentDir.read(filename);
213 
214  if (status == Os::Directory::NO_MORE_FILES) {
215  // We're done listing - close directory and send response
216  m_currentDir.close();
217  m_listState = IDLE;
218 
219  this->log_ACTIVITY_HI_ListDirectorySucceeded(m_currentDirName, m_totalEntries);
220  this->emitTelemetry(Os::FileSystem::OP_OK);
221  this->sendCommandResponse(m_currentOpCode, m_currentCmdSeq, Os::FileSystem::OP_OK);
222  break; // Exit the loop since we're done
223 
224  } else if (status == Os::Directory::OP_OK) {
225  // Construct full path for type checking
226  Fw::String fullPath;
227  fullPath.format("%s/%s", m_currentDirName.toChar(), filename.toChar());
228 
229  // Determine entry type
231 
232  if (pathType == Os::FileSystem::FILE) {
233  // Regular file: get size and emit file event
234  FwSizeType fileSize;
235  Os::FileSystem::Status sizeStatus = Os::FileSystem::getFileSize(fullPath.toChar(), fileSize);
237  m_currentDirName, filename,
238  (sizeStatus == Os::FileSystem::OP_OK) ? fileSize : static_cast<FwSizeType>(0));
239  } else if (pathType == Os::FileSystem::DIRECTORY) {
240  // Subdirectory: emit subdirectory event
241  this->log_ACTIVITY_HI_DirectoryListingSubdir(m_currentDirName, filename);
242  } else {
243  // Special file or inaccessible: treat as file with 0 size
244  this->log_ACTIVITY_HI_DirectoryListing(m_currentDirName, filename, static_cast<FwSizeType>(0));
245  }
246 
247  m_totalEntries++;
248 
249  } else {
250  // Error reading directory - close and send error response
251  m_currentDir.close();
252  m_listState = IDLE;
253 
254  this->log_WARNING_HI_ListDirectoryError(m_currentDirName, static_cast<U32>(status));
255  this->emitTelemetry(Os::FileSystem::OTHER_ERROR);
256  this->sendCommandResponse(m_currentOpCode, m_currentCmdSeq, Os::FileSystem::OTHER_ERROR);
257  break; // Exit the loop since we had an error
258  }
259  }
260  }
261 }
262 
263 // ----------------------------------------------------------------------
264 // Helper methods
265 // ----------------------------------------------------------------------
266 
267 int FileManager ::systemCall(const Fw::CmdStringArg& command, const Fw::CmdStringArg& logFileName) const {
268  // Create a buffer of at least enough size for storing the eval string less the 2 %s tokens, two command strings,
269  // and a null terminator at the end
270  const char evalStr[] = "eval '%s' 1>>%s 2>&1\n";
271  constexpr U32 bufferSize = (sizeof(evalStr) - 4) + (2 * FW_CMD_STRING_MAX_SIZE) + 1;
272  char buffer[bufferSize];
273 
274  // Wrap that buffer in an external string for formatting purposes
275  Fw::ExternalString stringBuffer(buffer, bufferSize);
276  Fw::FormatStatus formatStatus = stringBuffer.format(evalStr, command.toChar(), logFileName.toChar());
277  // Since the buffer is exactly sized, the only error can occur is a software error not caused by ground
278  FW_ASSERT(formatStatus == Fw::FormatStatus::SUCCESS);
279 
280  // Call the system
281  const int status = system(stringBuffer.toChar());
282  return status;
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.
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:207
void log_WARNING_HI_FileSizeError(const Fw::StringBase &fileName, U32 status) const
FileManager(const char *const compName)
Definition: FileManager.cpp:29
const char * toChar() const
Definition: String.hpp:50
static Status removeDirectory(const char *path)
Remove a directory at the specified path.
Definition: FileSystem.cpp:82
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:176
void log_ACTIVITY_HI_ListDirectorySucceeded(const Fw::StringBase &dirName, U32 fileCount) const
Auto-generated base for FileManager component.
void log_ACTIVITY_HI_ListDirectoryStarted(const Fw::StringBase &dirName) const
void pingOut_out(FwIndexType portNum, U32 key)
Invoke output port pingOut.
void log_ACTIVITY_HI_MoveFileStarted(const Fw::StringBase &sourceFileName, const Fw::StringBase &destFileName) const
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 log_ACTIVITY_HI_ShellCommandSucceeded(const Fw::StringBase &command) 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
A string backed by an external buffer.
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:55
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:225
static Status createDirectory(const char *path, bool errorIfAlreadyExists=false)
Create a new directory at the specified path.
Definition: FileSystem.cpp:110
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:137
other OS-specific error
Definition: FileSystem.hpp:40
const char * toChar() const
Definition: CmdString.hpp:50
void log_ACTIVITY_HI_AppendFileStarted(const Fw::StringBase &source, const Fw::StringBase &target) const
void tlmWrite_Errors(U32 arg, Fw::Time _tlmTime=Fw::Time()) const
void log_ACTIVITY_HI_RemoveFileStarted(const Fw::StringBase &fileName) const
void log_ACTIVITY_HI_ShellCommandStarted(const Fw::StringBase &command) const
PlatformIndexType FwIndexType
Operation was successful.
Definition: Directory.hpp:20
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.
Operation was successful.
Definition: FileSystem.hpp:24
static constexpr U32 FILES_PER_RATE_TICK
#define FW_CMD_STRING_MAX_SIZE
Max character size of command string arguments.
Definition: FpConfig.h:185
void log_WARNING_HI_ShellCommandFailed(const Fw::StringBase &command, U32 status) const
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:86
void log_WARNING_HI_FileRemoveError(const Fw::StringBase &fileName, U32 status) const
FormatStatus
status of string format calls
Definition: format.hpp:18