| Line | Branch | Exec | Source |
|---|---|---|---|
| 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" | ||
| 18 | #include "Fw/Types/ExternalString.hpp" | ||
| 19 | #include "Fw/Types/StringUtils.hpp" | ||
| 20 | #include "Os/Directory.hpp" | ||
| 21 | #include "Os/FilePathUtils.hpp" | ||
| 22 | #include "Svc/FileManager/FileManager.hpp" | ||
| 23 | #include "config/FileManagerConfig.hpp" | ||
| 24 | |||
| 25 | namespace Svc { | ||
| 26 | |||
| 27 | // ---------------------------------------------------------------------- | ||
| 28 | // Construction, initialization, and destruction | ||
| 29 | // ---------------------------------------------------------------------- | ||
| 30 | |||
| 31 | 32 | FileManager ::FileManager(const char* const compName //!< The component name | |
| 32 | 32 | ) | |
| 33 | : FileManagerComponentBase(compName), | ||
| 34 | 32 | commandCount(0), | |
| 35 | 32 | errorCount(0), | |
| 36 |
1/1✓ Branch 4 taken 32 times.
|
32 | m_sandboxDir(""), |
| 37 | 32 | m_sandboxConfigured(false), | |
| 38 | 32 | m_listState(IDLE), | |
| 39 | 32 | m_totalEntries(0), | |
| 40 | 32 | m_currentOpCode(0), | |
| 41 | 32 | m_currentCmdSeq(0), | |
| 42 | 32 | m_runQueued(false), | |
| 43 | 32 | m_dpState(DP_IDLE), | |
| 44 | 32 | m_dpFileSize(0), | |
| 45 | 32 | m_dpOffset(0), | |
| 46 | 32 | m_dpChunkSize(0), | |
| 47 | 32 | m_dpEndOffset(0), | |
| 48 | 32 | m_dpPriority(0), | |
| 49 | 32 | m_dpChunkCount(0), | |
| 50 | 32 | m_dpOpCode(0), | |
| 51 | 32 | m_dpCmdSeq(0), | |
| 52 |
4/4✓ Branch 10 taken 32 times.
✓ Branch 16 taken 32 times.
✓ Branch 22 taken 32 times.
✓ Branch 28 taken 32 times.
|
128 | m_dpBuffer{} {} |
| 53 | |||
| 54 | 64 | FileManager ::~FileManager() {} | |
| 55 | |||
| 56 | 37 | void FileManager ::configure(const char* sandboxDir) { | |
| 57 | 37 | FW_ASSERT(sandboxDir != nullptr); | |
| 58 | |||
| 59 | // Resolve the sandbox directory (relative paths resolve against CWD) | ||
| 60 | 37 | char resolved[Os::FilePathUtils::MAX_PATH_LENGTH]; | |
| 61 | const Os::FilePathUtils::Status resolveStatus = | ||
| 62 |
1/1✓ Branch 1 taken 37 times.
|
37 | Os::FilePathUtils::resolveFromCwd(sandboxDir, resolved, sizeof(resolved)); |
| 63 | 37 | FW_ASSERT(resolveStatus == Os::FilePathUtils::VALID, static_cast<FwAssertArgType>(resolveStatus)); | |
| 64 | |||
| 65 | // Ensure trailing '/' | ||
| 66 |
1/1✓ Branch 1 taken 37 times.
|
37 | const FwSizeType resolvedLen = Fw::StringUtils::string_length(resolved, Os::FilePathUtils::MAX_PATH_LENGTH); |
| 67 | 37 | FW_ASSERT(resolvedLen > 0); | |
| 68 | 37 | FW_ASSERT(resolvedLen < Os::FilePathUtils::MAX_PATH_LENGTH); | |
| 69 |
2/2✓ Branch 3 taken 2 times.
✓ Branch 4 taken 35 times.
|
37 | if (resolved[resolvedLen - 1] != '/') { |
| 70 | 2 | FW_ASSERT(resolvedLen + 2 <= Os::FilePathUtils::MAX_PATH_LENGTH); | |
| 71 | 2 | resolved[resolvedLen] = '/'; | |
| 72 | 2 | resolved[resolvedLen + 1] = '\0'; | |
| 73 | } | ||
| 74 | |||
| 75 |
1/1✓ Branch 6 taken 37 times.
|
37 | this->m_sandboxDir = resolved; |
| 76 | 37 | this->m_sandboxConfigured = true; | |
| 77 | 37 | } | |
| 78 | |||
| 79 | 51 | bool FileManager ::resolveInSandbox(const Fw::CmdStringArg& path, | |
| 80 | Fw::FileNameString& resolved, | ||
| 81 | const FwOpcodeType opCode, | ||
| 82 | const U32 cmdSeq) { | ||
| 83 | 51 | bool accepted = false; | |
| 84 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 51 times.
✓ Branch 5 taken 50 times.
✓ Branch 6 taken 1 times.
|
51 | if (this->m_sandboxConfigured) { |
| 85 | 50 | char resolvedBuffer[Os::FilePathUtils::MAX_PATH_LENGTH]; | |
| 86 | const Os::FilePathUtils::Status resolveStatus = | ||
| 87 |
1/1✓ Branch 5 taken 50 times.
|
50 | Os::FilePathUtils::resolveFromCwd(path.toChar(), resolvedBuffer, sizeof(resolvedBuffer)); |
| 88 |
3/4✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 9 times.
|
100 | if ((resolveStatus == Os::FilePathUtils::VALID) && |
| 89 |
3/3✓ Branch 7 taken 50 times.
✓ Branch 9 taken 41 times.
✓ Branch 10 taken 9 times.
|
50 | (Os::FilePathUtils::checkContainment(resolvedBuffer, this->m_sandboxDir.toChar()) == |
| 90 | Os::FilePathUtils::VALID)) { | ||
| 91 |
1/1✓ Branch 4 taken 41 times.
|
41 | resolved = resolvedBuffer; |
| 92 | 41 | accepted = true; | |
| 93 | } | ||
| 94 | } | ||
| 95 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 41 times.
|
51 | if (!accepted) { |
| 96 |
2/2✓ Branch 12 taken 10 times.
✓ Branch 16 taken 10 times.
|
20 | this->log_WARNING_HI_PathOutsideSandbox(Fw::LogStringArg(path.toChar()), |
| 97 |
1/1✓ Branch 7 taken 10 times.
|
20 | Fw::LogStringArg(this->m_sandboxDir.toChar())); |
| 98 | 10 | ++this->errorCount; | |
| 99 |
2/2✓ Branch 6 taken 10 times.
✓ Branch 13 taken 10 times.
|
10 | this->tlmWrite_Errors(this->errorCount); |
| 100 |
2/2✓ Branch 6 taken 10 times.
✓ Branch 9 taken 10 times.
|
10 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::VALIDATION_ERROR); |
| 101 | } | ||
| 102 | 51 | return accepted; | |
| 103 | } | ||
| 104 | |||
| 105 | // ---------------------------------------------------------------------- | ||
| 106 | // Command handler implementations | ||
| 107 | // ---------------------------------------------------------------------- | ||
| 108 | |||
| 109 | 5 | void FileManager ::CreateDirectory_cmdHandler(const FwOpcodeType opCode, | |
| 110 | const U32 cmdSeq, | ||
| 111 | const Fw::CmdStringArg& dirName) { | ||
| 112 |
1/1✓ Branch 2 taken 5 times.
|
5 | Fw::FileNameString resolvedDirName; |
| 113 |
3/3✓ Branch 4 taken 5 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 4 times.
|
5 | if (!this->resolveInSandbox(dirName, resolvedDirName, opCode, cmdSeq)) { |
| 114 | 1 | return; | |
| 115 | } | ||
| 116 |
1/1✓ Branch 6 taken 4 times.
|
4 | Fw::LogStringArg logStringDirName(dirName.toChar()); |
| 117 |
1/1✓ Branch 5 taken 4 times.
|
4 | this->log_ACTIVITY_HI_CreateDirectoryStarted(logStringDirName); |
| 118 | 4 | bool errorIfDirExists = true; | |
| 119 |
1/1✓ Branch 3 taken 4 times.
|
4 | const Os::FileSystem::Status status = Os::FileSystem::createDirectory(resolvedDirName.toChar(), errorIfDirExists); |
| 120 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (status != Os::FileSystem::OP_OK) { |
| 121 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_DirectoryCreateError(logStringDirName, status); |
| 122 | } else { | ||
| 123 |
1/1✓ Branch 5 taken 3 times.
|
3 | this->log_ACTIVITY_HI_CreateDirectorySucceeded(logStringDirName); |
| 124 | } | ||
| 125 |
1/1✓ Branch 4 taken 4 times.
|
4 | this->emitTelemetry(status); |
| 126 |
1/1✓ Branch 4 taken 4 times.
|
4 | this->sendCommandResponse(opCode, cmdSeq, status); |
| 127 | 5 | } | |
| 128 | |||
| 129 | 5 | void FileManager ::RemoveFile_cmdHandler(const FwOpcodeType opCode, | |
| 130 | const U32 cmdSeq, | ||
| 131 | const Fw::CmdStringArg& fileName, | ||
| 132 | const bool ignoreErrors) { | ||
| 133 |
1/1✓ Branch 2 taken 5 times.
|
5 | Fw::FileNameString resolvedFileName; |
| 134 |
3/3✓ Branch 4 taken 5 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 3 times.
|
5 | if (!this->resolveInSandbox(fileName, resolvedFileName, opCode, cmdSeq)) { |
| 135 | 2 | return; | |
| 136 | } | ||
| 137 |
1/1✓ Branch 6 taken 3 times.
|
3 | Fw::LogStringArg logStringFileName(fileName.toChar()); |
| 138 |
1/1✓ Branch 5 taken 3 times.
|
3 | this->log_ACTIVITY_HI_RemoveFileStarted(logStringFileName); |
| 139 |
1/1✓ Branch 3 taken 3 times.
|
3 | const Os::FileSystem::Status status = Os::FileSystem::removeFile(resolvedFileName.toChar()); |
| 140 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (status != Os::FileSystem::OP_OK) { |
| 141 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_FileRemoveError(logStringFileName, status); |
| 142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ignoreErrors == true) { |
| 143 | ✗ | ++this->errorCount; | |
| 144 | ✗ | this->tlmWrite_Errors(this->errorCount); | |
| 145 | ✗ | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); | |
| 146 | ✗ | return; | |
| 147 | } | ||
| 148 | } else { | ||
| 149 |
1/1✓ Branch 5 taken 2 times.
|
2 | this->log_ACTIVITY_HI_RemoveFileSucceeded(logStringFileName); |
| 150 | } | ||
| 151 |
1/1✓ Branch 4 taken 3 times.
|
3 | this->emitTelemetry(status); |
| 152 |
1/1✓ Branch 4 taken 3 times.
|
3 | this->sendCommandResponse(opCode, cmdSeq, status); |
| 153 | 5 | } | |
| 154 | |||
| 155 | 4 | void FileManager ::MoveFile_cmdHandler(const FwOpcodeType opCode, | |
| 156 | const U32 cmdSeq, | ||
| 157 | const Fw::CmdStringArg& sourceFileName, | ||
| 158 | const Fw::CmdStringArg& destFileName) { | ||
| 159 |
1/1✓ Branch 2 taken 4 times.
|
4 | Fw::FileNameString resolvedSource; |
| 160 |
1/1✓ Branch 2 taken 4 times.
|
4 | Fw::FileNameString resolvedDest; |
| 161 |
4/5✓ Branch 4 taken 4 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 3 times.
|
8 | if (!this->resolveInSandbox(sourceFileName, resolvedSource, opCode, cmdSeq) || |
| 162 |
3/3✓ Branch 4 taken 4 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 3 times.
|
4 | !this->resolveInSandbox(destFileName, resolvedDest, opCode, cmdSeq)) { |
| 163 | 1 | return; | |
| 164 | } | ||
| 165 |
1/1✓ Branch 6 taken 3 times.
|
3 | Fw::LogStringArg logStringSource(sourceFileName.toChar()); |
| 166 |
1/1✓ Branch 6 taken 3 times.
|
3 | Fw::LogStringArg logStringDest(destFileName.toChar()); |
| 167 |
1/1✓ Branch 5 taken 3 times.
|
3 | this->log_ACTIVITY_HI_MoveFileStarted(logStringSource, logStringDest); |
| 168 |
1/1✓ Branch 5 taken 3 times.
|
3 | const Os::FileSystem::Status status = Os::FileSystem::moveFile(resolvedSource.toChar(), resolvedDest.toChar()); |
| 169 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (status != Os::FileSystem::OP_OK) { |
| 170 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_FileMoveError(logStringSource, logStringDest, status); |
| 171 | } else { | ||
| 172 |
1/1✓ Branch 5 taken 2 times.
|
2 | this->log_ACTIVITY_HI_MoveFileSucceeded(logStringSource, logStringDest); |
| 173 | } | ||
| 174 |
1/1✓ Branch 4 taken 3 times.
|
3 | this->emitTelemetry(status); |
| 175 |
1/1✓ Branch 4 taken 3 times.
|
3 | this->sendCommandResponse(opCode, cmdSeq, status); |
| 176 | 5 | } | |
| 177 | |||
| 178 | 3 | void FileManager ::RemoveDirectory_cmdHandler(const FwOpcodeType opCode, | |
| 179 | const U32 cmdSeq, | ||
| 180 | const Fw::CmdStringArg& dirName) { | ||
| 181 |
1/1✓ Branch 2 taken 3 times.
|
3 | Fw::FileNameString resolvedDirName; |
| 182 |
3/3✓ Branch 4 taken 3 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 2 times.
|
3 | if (!this->resolveInSandbox(dirName, resolvedDirName, opCode, cmdSeq)) { |
| 183 | 1 | return; | |
| 184 | } | ||
| 185 |
1/1✓ Branch 6 taken 2 times.
|
2 | Fw::LogStringArg logStringDirName(dirName.toChar()); |
| 186 |
1/1✓ Branch 5 taken 2 times.
|
2 | this->log_ACTIVITY_HI_RemoveDirectoryStarted(logStringDirName); |
| 187 |
1/1✓ Branch 3 taken 2 times.
|
2 | const Os::FileSystem::Status status = Os::FileSystem::removeDirectory(resolvedDirName.toChar()); |
| 188 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (status != Os::FileSystem::OP_OK) { |
| 189 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_DirectoryRemoveError(logStringDirName, status); |
| 190 | } else { | ||
| 191 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_ACTIVITY_HI_RemoveDirectorySucceeded(logStringDirName); |
| 192 | } | ||
| 193 |
1/1✓ Branch 4 taken 2 times.
|
2 | this->emitTelemetry(status); |
| 194 |
1/1✓ Branch 4 taken 2 times.
|
2 | this->sendCommandResponse(opCode, cmdSeq, status); |
| 195 | 3 | } | |
| 196 | |||
| 197 | 4 | void FileManager ::AppendFile_cmdHandler(const FwOpcodeType opCode, | |
| 198 | const U32 cmdSeq, | ||
| 199 | const Fw::CmdStringArg& source, | ||
| 200 | const Fw::CmdStringArg& target) { | ||
| 201 |
1/1✓ Branch 2 taken 4 times.
|
4 | Fw::FileNameString resolvedSource; |
| 202 |
1/1✓ Branch 2 taken 4 times.
|
4 | Fw::FileNameString resolvedTarget; |
| 203 |
5/5✓ Branch 4 taken 4 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 3 times.
|
7 | if (!this->resolveInSandbox(source, resolvedSource, opCode, cmdSeq) || |
| 204 |
2/3✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
|
3 | !this->resolveInSandbox(target, resolvedTarget, opCode, cmdSeq)) { |
| 205 | 1 | return; | |
| 206 | } | ||
| 207 |
1/1✓ Branch 6 taken 3 times.
|
3 | Fw::LogStringArg logStringSource(source.toChar()); |
| 208 |
1/1✓ Branch 6 taken 3 times.
|
3 | Fw::LogStringArg logStringTarget(target.toChar()); |
| 209 |
1/1✓ Branch 5 taken 3 times.
|
3 | this->log_ACTIVITY_HI_AppendFileStarted(logStringSource, logStringTarget); |
| 210 | |||
| 211 | Os::FileSystem::Status status; | ||
| 212 |
1/1✓ Branch 5 taken 3 times.
|
3 | status = Os::FileSystem::appendFile(resolvedSource.toChar(), resolvedTarget.toChar(), true); |
| 213 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (status != Os::FileSystem::OP_OK) { |
| 214 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_AppendFileFailed(logStringSource, logStringTarget, status); |
| 215 | } else { | ||
| 216 |
1/1✓ Branch 5 taken 2 times.
|
2 | this->log_ACTIVITY_HI_AppendFileSucceeded(logStringSource, logStringTarget); |
| 217 | } | ||
| 218 | |||
| 219 |
1/1✓ Branch 4 taken 3 times.
|
3 | this->emitTelemetry(status); |
| 220 |
1/1✓ Branch 4 taken 3 times.
|
3 | this->sendCommandResponse(opCode, cmdSeq, status); |
| 221 | 5 | } | |
| 222 | |||
| 223 | 5 | void FileManager ::FileSize_cmdHandler(const FwOpcodeType opCode, const U32 cmdSeq, const Fw::CmdStringArg& fileName) { | |
| 224 |
1/1✓ Branch 2 taken 5 times.
|
5 | Fw::FileNameString resolvedFileName; |
| 225 |
3/3✓ Branch 4 taken 5 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 4 times.
|
5 | if (!this->resolveInSandbox(fileName, resolvedFileName, opCode, cmdSeq)) { |
| 226 | 1 | return; | |
| 227 | } | ||
| 228 |
1/1✓ Branch 6 taken 4 times.
|
4 | Fw::LogStringArg logStringFileName(fileName.toChar()); |
| 229 |
1/1✓ Branch 5 taken 4 times.
|
4 | this->log_ACTIVITY_HI_FileSizeStarted(logStringFileName); |
| 230 | |||
| 231 | 4 | FwSizeType size_arg; | |
| 232 |
1/1✓ Branch 3 taken 4 times.
|
4 | const Os::FileSystem::Status status = Os::FileSystem::getFileSize(resolvedFileName.toChar(), size_arg); |
| 233 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (status != Os::FileSystem::OP_OK) { |
| 234 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_FileSizeError(logStringFileName, status); |
| 235 | } else { | ||
| 236 |
1/1✓ Branch 5 taken 3 times.
|
3 | this->log_ACTIVITY_HI_FileSizeSucceeded(logStringFileName, size_arg); |
| 237 | } | ||
| 238 |
1/1✓ Branch 4 taken 4 times.
|
4 | this->emitTelemetry(status); |
| 239 |
1/1✓ Branch 4 taken 4 times.
|
4 | this->sendCommandResponse(opCode, cmdSeq, status); |
| 240 | 5 | } | |
| 241 | |||
| 242 | 4 | void FileManager ::ListDirectory_cmdHandler(const FwOpcodeType opCode, | |
| 243 | const U32 cmdSeq, | ||
| 244 | const Fw::CmdStringArg& dirName) { | ||
| 245 | // Check if we're already listing a directory | ||
| 246 |
2/4✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
|
4 | if (m_listState == LISTING_IN_PROGRESS) { |
| 247 | ✗ | this->log_WARNING_HI_ListDirectoryError(dirName, static_cast<U32>(Os::Directory::OTHER_ERROR)); | |
| 248 | ✗ | this->emitTelemetry(Os::FileSystem::OTHER_ERROR); | |
| 249 | ✗ | this->sendCommandResponse(opCode, cmdSeq, Os::FileSystem::OTHER_ERROR); | |
| 250 | ✗ | return; | |
| 251 | } | ||
| 252 | |||
| 253 |
1/1✓ Branch 2 taken 4 times.
|
4 | Fw::FileNameString resolvedDirName; |
| 254 |
3/3✓ Branch 4 taken 4 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 3 times.
|
4 | if (!this->resolveInSandbox(dirName, resolvedDirName, opCode, cmdSeq)) { |
| 255 | 1 | return; | |
| 256 | } | ||
| 257 | |||
| 258 |
1/1✓ Branch 8 taken 3 times.
|
3 | this->log_ACTIVITY_HI_ListDirectoryStarted(dirName); |
| 259 | |||
| 260 | // Open the directory for reading | ||
| 261 |
1/1✓ Branch 8 taken 3 times.
|
3 | Os::Directory::Status status = m_currentDir.open(resolvedDirName.toChar(), Os::Directory::OpenMode::READ); |
| 262 | |||
| 263 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (status != Os::Directory::OP_OK) { |
| 264 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_WARNING_HI_ListDirectoryError(dirName, static_cast<U32>(status)); |
| 265 |
1/1✓ Branch 4 taken 1 times.
|
1 | this->emitTelemetry(Os::FileSystem::OTHER_ERROR); |
| 266 |
1/1✓ Branch 4 taken 1 times.
|
1 | this->sendCommandResponse(opCode, cmdSeq, Os::FileSystem::OTHER_ERROR); |
| 267 | 1 | return; | |
| 268 | } | ||
| 269 | |||
| 270 | // Initialize state machine for asynchronous processing | ||
| 271 | 2 | m_listState = LISTING_IN_PROGRESS; | |
| 272 |
1/1✓ Branch 9 taken 2 times.
|
2 | m_currentDirName = dirName; |
| 273 | 2 | m_currentOpCode = opCode; | |
| 274 | 2 | m_currentCmdSeq = cmdSeq; | |
| 275 | 2 | m_totalEntries = 0; | |
| 276 | |||
| 277 | // Directory listing will be processed asynchronously by the rate group. | ||
| 278 | // The schedIn_handler will process FILES_PER_RATE_TICK directory entries per rate tick to | ||
| 279 | // prevent event flooding while maintaining configurable performance. | ||
| 280 | // Command response will be sent when listing completes. | ||
| 281 | 4 | } | |
| 282 | |||
| 283 | 2 | void FileManager ::CalculateCrc_cmdHandler(FwOpcodeType opCode, U32 cmdSeq, const Fw::CmdStringArg& filename) { | |
| 284 |
1/1✓ Branch 2 taken 2 times.
|
2 | Os::File file; |
| 285 | 2 | U32 crcValue = 0; | |
| 286 |
1/1✓ Branch 2 taken 2 times.
|
2 | Fw::FileNameString resolvedFilename; |
| 287 |
3/3✓ Branch 4 taken 2 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 1 times.
|
2 | if (!this->resolveInSandbox(filename, resolvedFilename, opCode, cmdSeq)) { |
| 288 | 1 | return; | |
| 289 | } | ||
| 290 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_ACTIVITY_HI_CalculateCrcStarted(filename); |
| 291 | |||
| 292 |
1/1✓ Branch 4 taken 1 times.
|
1 | Os::File::Status status = file.open(resolvedFilename.toChar(), Os::File::OPEN_READ); |
| 293 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (status == Os::File::OP_OK) { |
| 294 |
1/1✓ Branch 2 taken 1 times.
|
1 | status = file.calculateCrc(crcValue); |
| 295 | } | ||
| 296 | |||
| 297 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (status == Os::File::OP_OK) { |
| 298 |
1/1✓ Branch 8 taken 1 times.
|
1 | this->log_ACTIVITY_HI_CalculateCrcSucceeded(filename, crcValue); |
| 299 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 300 | } else { | ||
| 301 | ✗ | this->log_WARNING_HI_CalculateCrcFailed(filename, status); | |
| 302 | ✗ | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::EXECUTION_ERROR); | |
| 303 | } | ||
| 304 |
1/1✓ Branch 2 taken 1 times.
|
1 | file.close(); |
| 305 | 3 | } | |
| 306 | |||
| 307 | 13 | void FileManager ::GenerateDp_cmdHandler(FwOpcodeType opCode, | |
| 308 | U32 cmdSeq, | ||
| 309 | const Fw::CmdStringArg& fileName, | ||
| 310 | U32 chunkSize, | ||
| 311 | U64 beginOffset, | ||
| 312 | U64 endOffset, | ||
| 313 | U32 priority, | ||
| 314 | const FileManager_GenerateDpMode& mode) { | ||
| 315 |
1/1✓ Branch 6 taken 13 times.
|
13 | Fw::LogStringArg logFileName(fileName.toChar()); |
| 316 | |||
| 317 | // Reject a second request while one is already running | ||
| 318 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 12 times.
|
13 | if (this->m_dpState != DP_IDLE) { |
| 319 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
|
1 | this->log_WARNING_HI_GenerateDpFailed(logFileName, FileManager_GenerateDpStage::BUSY, 0); |
| 320 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 321 | 1 | return; | |
| 322 | } | ||
| 323 | |||
| 324 | // Data products must be available | ||
| 325 |
5/8✓ Branch 5 taken 12 times.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 14 taken 12 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 12 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 12 times.
|
12 | if (!this->isConnected_productGetOut_OutputPort(0) || !this->isConnected_productSendOut_OutputPort(0)) { |
| 326 | ✗ | this->log_WARNING_HI_GenerateDpBufferFailed(logFileName); | |
| 327 | ✗ | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); | |
| 328 | ✗ | return; | |
| 329 | } | ||
| 330 | |||
| 331 | // Clamp the requested chunk size to the configured read buffer | ||
| 332 | 12 | U32 effectiveChunkSize = chunkSize; | |
| 333 |
4/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10 times.
|
12 | if ((effectiveChunkSize == 0) || (effectiveChunkSize > FileManagerConfig::GENERATE_DP_MAX_CHUNK_SIZE)) { |
| 334 | 2 | effectiveChunkSize = FileManagerConfig::GENERATE_DP_MAX_CHUNK_SIZE; | |
| 335 | } | ||
| 336 | |||
| 337 |
1/1✓ Branch 2 taken 12 times.
|
12 | Fw::FileNameString resolvedFileName; |
| 338 |
3/3✓ Branch 4 taken 12 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 11 times.
|
12 | if (!this->resolveInSandbox(fileName, resolvedFileName, opCode, cmdSeq)) { |
| 339 | 1 | return; | |
| 340 | } | ||
| 341 | |||
| 342 |
1/1✓ Branch 8 taken 11 times.
|
11 | Os::File::Status status = this->m_dpFile.open(resolvedFileName.toChar(), Os::File::OPEN_READ); |
| 343 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 10 times.
|
11 | if (status != Os::File::OP_OK) { |
| 344 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
|
1 | this->log_WARNING_HI_GenerateDpFailed(logFileName, FileManager_GenerateDpStage::OPEN, static_cast<U32>(status)); |
| 345 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 346 | 1 | return; | |
| 347 | } | ||
| 348 | |||
| 349 | 10 | FwSizeType fileSize = 0; | |
| 350 |
1/1✓ Branch 6 taken 10 times.
|
10 | status = this->m_dpFile.size(fileSize); |
| 351 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (status != Os::File::OP_OK) { |
| 352 | ✗ | this->m_dpFile.close(); | |
| 353 | ✗ | this->log_WARNING_HI_GenerateDpFailed(logFileName, FileManager_GenerateDpStage::SIZE, static_cast<U32>(status)); | |
| 354 | ✗ | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); | |
| 355 | ✗ | return; | |
| 356 | } | ||
| 357 | |||
| 358 | // An end offset of zero, or one past the end of the file, means the end of | ||
| 359 | // the file. Ranges let an operator retransmit part of a file or spread the | ||
| 360 | // downlink over several commands. | ||
| 361 | 10 | U64 effectiveEnd = endOffset; | |
| 362 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
10 | if ((effectiveEnd == 0) || (effectiveEnd > static_cast<U64>(fileSize))) { |
| 363 | 8 | effectiveEnd = static_cast<U64>(fileSize); | |
| 364 | } | ||
| 365 | |||
| 366 | 10 | const bool emptyFile = (fileSize == 0); | |
| 367 |
5/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 8 times.
|
10 | const bool badRange = (beginOffset > static_cast<U64>(fileSize)) || (!emptyFile && (beginOffset >= effectiveEnd)); |
| 368 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (badRange) { |
| 369 |
1/1✓ Branch 6 taken 1 times.
|
1 | this->m_dpFile.close(); |
| 370 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_GenerateDpInvalidRange(logFileName, beginOffset, endOffset, static_cast<U64>(fileSize)); |
| 371 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 9 taken 1 times.
|
1 | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); |
| 372 | 1 | return; | |
| 373 | } | ||
| 374 | |||
| 375 | // Position the file at the start of the requested range | ||
| 376 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
|
9 | if (beginOffset > 0) { |
| 377 |
1/1✓ Branch 6 taken 1 times.
|
1 | status = this->m_dpFile.seek(static_cast<FwSignedSizeType>(beginOffset), Os::File::SeekType::ABSOLUTE); |
| 378 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (status != Os::File::OP_OK) { |
| 379 | ✗ | this->m_dpFile.close(); | |
| 380 | ✗ | this->log_WARNING_HI_GenerateDpFailed(logFileName, FileManager_GenerateDpStage::SEEK, | |
| 381 | static_cast<U32>(status)); | ||
| 382 | ✗ | this->cmdResponse_out(opCode, cmdSeq, Fw::CmdResponse::OK); | |
| 383 | ✗ | return; | |
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 |
2/2✓ Branch 6 taken 9 times.
✓ Branch 15 taken 9 times.
|
9 | this->m_dpFileName = Fw::String(fileName.toChar()); |
| 388 | 9 | this->m_dpFileSize = fileSize; | |
| 389 | 9 | this->m_dpOffset = beginOffset; | |
| 390 | 9 | this->m_dpEndOffset = effectiveEnd; | |
| 391 | 9 | this->m_dpChunkSize = effectiveChunkSize; | |
| 392 | 9 | this->m_dpChunkCount = 0; | |
| 393 | 9 | this->m_dpOpCode = opCode; | |
| 394 | 9 | this->m_dpCmdSeq = cmdSeq; | |
| 395 | // A priority of zero reverts to the configured default | ||
| 396 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
|
9 | this->m_dpPriority = (priority == 0) ? static_cast<FwDpPriorityType>(FileManagerCfg::DEFAULT_DP_PRIORITY) |
| 397 | : static_cast<FwDpPriorityType>(priority); | ||
| 398 | 9 | this->m_dpState = DP_IN_PROGRESS; | |
| 399 | |||
| 400 | // Report the number of bytes that will be written, which is the requested | ||
| 401 | // range rather than the size of the whole file | ||
| 402 |
1/1✓ Branch 13 taken 9 times.
|
9 | this->log_ACTIVITY_HI_GenerateDpStarted(logFileName, this->m_dpEndOffset - this->m_dpOffset); |
| 403 | |||
| 404 | // An empty range produces no chunks, so complete immediately | ||
| 405 |
2/2✓ Branch 8 taken 1 times.
✓ Branch 9 taken 8 times.
|
9 | if (this->m_dpOffset >= this->m_dpEndOffset) { |
| 406 |
1/1✓ Branch 9 taken 1 times.
|
1 | this->log_ACTIVITY_HI_GenerateDpComplete(logFileName, this->m_dpChunkCount); |
| 407 |
1/1✓ Branch 4 taken 1 times.
|
1 | this->finishDpGeneration(); |
| 408 | 1 | return; | |
| 409 | } | ||
| 410 | |||
| 411 | // In immediate mode the whole range is emitted here, so that a project that | ||
| 412 | // wants the file out quickly is not limited by the rate group. In paced | ||
| 413 | // mode the rate group meters the work out and the response is deferred. | ||
| 414 |
2/2✓ Branch 4 taken 2 times.
✓ Branch 5 taken 6 times.
|
8 | if (mode == FileManager_GenerateDpMode::IMMEDIATE) { |
| 415 |
1/1✓ Branch 4 taken 2 times.
|
2 | this->processDpChunks(0); |
| 416 | } | ||
| 417 | 17 | } | |
| 418 | |||
| 419 | 19 | void FileManager ::processDpChunks(U32 chunkLimit) { | |
| 420 |
1/1✓ Branch 8 taken 19 times.
|
19 | Fw::LogStringArg logFileName(this->m_dpFileName.toChar()); |
| 421 | |||
| 422 | // A limit of zero means emit the whole remaining range in this call | ||
| 423 | 19 | const bool paced = (chunkLimit > 0); | |
| 424 | |||
| 425 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 11 times.
|
33 | for (U32 chunk = 0; !paced || (chunk < chunkLimit); chunk++) { |
| 426 | // Number of bytes remaining in the requested range. The loop returns as | ||
| 427 | // soon as the range is exhausted, so this is always non-zero here. | ||
| 428 | 22 | const FwSizeType remaining = static_cast<FwSizeType>(this->m_dpEndOffset - this->m_dpOffset); | |
| 429 | |||
| 430 | 22 | const FwSizeType requestedSize = (remaining < static_cast<FwSizeType>(this->m_dpChunkSize)) | |
| 431 | ? remaining | ||
| 432 | : static_cast<FwSizeType>(this->m_dpChunkSize); | ||
| 433 | |||
| 434 | // The file size is known, so a short read means the file changed underneath us | ||
| 435 | 22 | FwSizeType readSize = requestedSize; | |
| 436 |
1/1✓ Branch 8 taken 22 times.
|
22 | const Os::File::Status status = this->m_dpFile.read(this->m_dpBuffer, readSize); |
| 437 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
22 | if ((status != Os::File::OP_OK) || (readSize != requestedSize)) { |
| 438 | ✗ | this->log_WARNING_HI_GenerateDpFailed(logFileName, FileManager_GenerateDpStage::READ, | |
| 439 | static_cast<U32>(status)); | ||
| 440 | ✗ | this->finishDpGeneration(); | |
| 441 | ✗ | return; | |
| 442 | } | ||
| 443 | |||
| 444 | // Request a container large enough for this chunk's header and data | ||
| 445 | 22 | const FwSizeType dpSize = SIZE_OF_FileChunkHeaderRecord_RECORD + SIZE_OF_FileChunkDataRecord_RECORD(readSize); | |
| 446 |
1/1✓ Branch 2 taken 22 times.
|
22 | DpContainer container; |
| 447 |
1/1✓ Branch 5 taken 22 times.
|
22 | const Fw::Success::T dpStatus = this->dpGet_FileDpContainer(dpSize, container); |
| 448 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 21 times.
|
22 | if (dpStatus != Fw::Success::SUCCESS) { |
| 449 |
1/1✓ Branch 5 taken 1 times.
|
1 | this->log_WARNING_HI_GenerateDpBufferFailed(logFileName); |
| 450 |
1/1✓ Branch 4 taken 1 times.
|
1 | this->finishDpGeneration(); |
| 451 | 1 | return; | |
| 452 | } | ||
| 453 | 21 | container.setPriority(this->m_dpPriority); | |
| 454 | |||
| 455 | // Each chunk is a metadata record followed by a data record, so that | ||
| 456 | // ground tools can reassemble the file from any number of containers | ||
| 457 |
1/1✓ Branch 9 taken 21 times.
|
21 | const FileManager_FileChunkHeader header(this->m_dpFileName, this->m_dpOffset, static_cast<U32>(readSize)); |
| 458 |
1/1✓ Branch 2 taken 21 times.
|
21 | Fw::SerializeStatus serializeStatus = container.serializeRecord_FileChunkHeaderRecord(header); |
| 459 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1 times.
|
21 | if (serializeStatus == Fw::FW_SERIALIZE_OK) { |
| 460 |
1/1✓ Branch 4 taken 20 times.
|
20 | serializeStatus = container.serializeRecord_FileChunkDataRecord(this->m_dpBuffer, readSize); |
| 461 | } | ||
| 462 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 20 times.
|
21 | if (serializeStatus != Fw::FW_SERIALIZE_OK) { |
| 463 |
2/2✓ Branch 6 taken 1 times.
✓ Branch 10 taken 1 times.
|
1 | this->log_WARNING_HI_GenerateDpFailed(logFileName, FileManager_GenerateDpStage::SERIALIZE, |
| 464 | static_cast<U32>(serializeStatus)); | ||
| 465 |
1/1✓ Branch 4 taken 1 times.
|
1 | this->finishDpGeneration(); |
| 466 | 1 | return; | |
| 467 | } | ||
| 468 | |||
| 469 |
2/2✓ Branch 7 taken 20 times.
✓ Branch 10 taken 20 times.
|
20 | this->dpSend(container); |
| 470 | |||
| 471 | 20 | this->m_dpOffset += static_cast<U64>(readSize); | |
| 472 | 20 | this->m_dpChunkCount++; | |
| 473 | |||
| 474 | // Last chunk of the requested range | ||
| 475 |
2/2✓ Branch 8 taken 6 times.
✓ Branch 9 taken 14 times.
|
20 | if (this->m_dpOffset >= this->m_dpEndOffset) { |
| 476 |
1/1✓ Branch 9 taken 6 times.
|
6 | this->log_ACTIVITY_HI_GenerateDpComplete(logFileName, this->m_dpChunkCount); |
| 477 |
1/1✓ Branch 4 taken 6 times.
|
6 | this->finishDpGeneration(); |
| 478 | 6 | return; | |
| 479 | } | ||
| 480 | 29 | } | |
| 481 | 19 | } | |
| 482 | |||
| 483 | 9 | void FileManager ::finishDpGeneration() { | |
| 484 | 9 | this->m_dpFile.close(); | |
| 485 | 9 | this->m_dpState = DP_IDLE; | |
| 486 | 9 | this->m_dpOffset = 0; | |
| 487 | 9 | this->m_dpEndOffset = 0; | |
| 488 | 9 | this->m_dpFileSize = 0; | |
| 489 | // Failures emit a warning event but still respond with OK, so that a bad | ||
| 490 | // file name or a transient resource problem does not stop a whole sequence | ||
| 491 |
2/2✓ Branch 6 taken 9 times.
✓ Branch 17 taken 9 times.
|
9 | this->cmdResponse_out(this->m_dpOpCode, this->m_dpCmdSeq, Fw::CmdResponse::OK); |
| 492 | 9 | } | |
| 493 | |||
| 494 | ✗ | void FileManager ::pingIn_handler(const FwIndexType portNum, U32 key) { | |
| 495 | // return key | ||
| 496 | ✗ | this->pingOut_out(0, key); | |
| 497 | ✗ | } | |
| 498 | |||
| 499 | 29 | void FileManager ::schedIn_handler(const FwIndexType portNum, U32 context) { | |
| 500 | 29 | bool isQueued = false; | |
| 501 | // m_runQueued will be compared to isQueued (false). When equal (i.e. m_runQueued is false) the atomic will be | ||
| 502 | // set to true and the function will return true indicating that a run was successfully marked as queued and thus | ||
| 503 | // the internal handler should be invoked. | ||
| 504 | 29 | bool expects_enqueue = this->m_runQueued.compare_exchange_strong(isQueued, true); | |
| 505 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | if (expects_enqueue) { |
| 506 |
1/1✓ Branch 5 taken 29 times.
|
29 | this->run_internalInterfaceInvoke(); |
| 507 | } | ||
| 508 | 29 | } | |
| 509 | |||
| 510 | 29 | void FileManager ::run_internalInterfaceHandler() { | |
| 511 | 29 | FW_ASSERT(this->m_runQueued); | |
| 512 | 29 | this->m_runQueued = false; // Run is not queued anymore (we are running) | |
| 513 | // Data product generation is paced the same way as directory listing | ||
| 514 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 17 times.
✓ Branch 6 taken 12 times.
|
29 | if (this->m_dpState == DP_IN_PROGRESS) { |
| 515 | 17 | this->processDpChunks(FileManagerConfig::CHUNKS_PER_RATE_TICK); | |
| 516 | } | ||
| 517 | |||
| 518 | // Only process if we're in the middle of a directory listing | ||
| 519 |
3/4✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 17 times.
|
29 | if (m_listState == LISTING_IN_PROGRESS) { |
| 520 | // Process multiple files per rate tick based on configuration | ||
| 521 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 10 times.
|
22 | for (U32 fileCount = 0; fileCount < Svc::FileManagerConfig::FILES_PER_RATE_TICK; fileCount++) { |
| 522 |
1/1✓ Branch 2 taken 12 times.
|
12 | Fw::String filename; |
| 523 |
1/1✓ Branch 6 taken 12 times.
|
12 | Os::Directory::Status status = m_currentDir.read(filename); |
| 524 | |||
| 525 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
|
12 | if (status == Os::Directory::NO_MORE_FILES) { |
| 526 | // We're done listing - close directory and send response | ||
| 527 |
1/1✓ Branch 6 taken 2 times.
|
2 | m_currentDir.close(); |
| 528 | 2 | m_listState = IDLE; | |
| 529 | |||
| 530 |
1/1✓ Branch 12 taken 2 times.
|
2 | this->log_ACTIVITY_HI_ListDirectorySucceeded(m_currentDirName, m_totalEntries); |
| 531 |
1/1✓ Branch 4 taken 2 times.
|
2 | this->emitTelemetry(Os::FileSystem::OP_OK); |
| 532 |
1/1✓ Branch 12 taken 2 times.
|
2 | this->sendCommandResponse(m_currentOpCode, m_currentCmdSeq, Os::FileSystem::OP_OK); |
| 533 | 2 | break; // Exit the loop since we're done | |
| 534 | |||
| 535 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | } else if (status == Os::Directory::OP_OK) { |
| 536 | // Construct full path for type checking | ||
| 537 |
1/1✓ Branch 2 taken 10 times.
|
10 | Fw::String fullPath; |
| 538 |
1/1✓ Branch 10 taken 10 times.
|
10 | Fw::FormatStatus formatStatus = fullPath.format("%s/%s", m_currentDirName.toChar(), filename.toChar()); |
| 539 | |||
| 540 | // Determine entry type | ||
| 541 | Os::FileSystem::PathType pathType = (formatStatus == Fw::FormatStatus::SUCCESS) | ||
| 542 |
2/3✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 5 taken 10 times.
|
10 | ? Os::FileSystem::getPathType(fullPath.toChar()) |
| 543 | 10 | : Os::FileSystem::NOT_EXIST; | |
| 544 | |||
| 545 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (formatStatus != Fw::FormatStatus::SUCCESS) { |
| 546 | // Cannot determine the type of an entry whose path did not format | ||
| 547 | ✗ | this->log_WARNING_HI_FileNameFormatError(filename, | |
| 548 | static_cast<Fw::StringFormatStatus::T>(formatStatus)); | ||
| 549 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
|
10 | } else if (pathType == Os::FileSystem::FILE) { |
| 550 | // Regular file: get size and emit file event | ||
| 551 | 6 | FwSizeType fileSize; | |
| 552 |
1/1✓ Branch 3 taken 6 times.
|
6 | Os::FileSystem::Status sizeStatus = Os::FileSystem::getFileSize(fullPath.toChar(), fileSize); |
| 553 |
2/3✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 10 taken 6 times.
|
6 | this->log_ACTIVITY_HI_DirectoryListing( |
| 554 | m_currentDirName, filename, | ||
| 555 | (sizeStatus == Os::FileSystem::OP_OK) ? fileSize : static_cast<FwSizeType>(0)); | ||
| 556 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | } else if (pathType == Os::FileSystem::DIRECTORY) { |
| 557 | // Subdirectory: emit subdirectory event | ||
| 558 |
1/1✓ Branch 8 taken 4 times.
|
4 | this->log_ACTIVITY_HI_DirectoryListingSubdir(m_currentDirName, filename); |
| 559 | } else { | ||
| 560 | // Special file or inaccessible: treat as file with 0 size | ||
| 561 | ✗ | this->log_ACTIVITY_HI_DirectoryListing(m_currentDirName, filename, static_cast<FwSizeType>(0)); | |
| 562 | } | ||
| 563 | |||
| 564 | 10 | m_totalEntries++; | |
| 565 | |||
| 566 | 10 | } else { | |
| 567 | // Error reading directory - close and send error response | ||
| 568 | ✗ | m_currentDir.close(); | |
| 569 | ✗ | m_listState = IDLE; | |
| 570 | |||
| 571 | ✗ | this->log_WARNING_HI_ListDirectoryError(m_currentDirName, static_cast<U32>(status)); | |
| 572 | ✗ | this->emitTelemetry(Os::FileSystem::OTHER_ERROR); | |
| 573 | ✗ | this->sendCommandResponse(m_currentOpCode, m_currentCmdSeq, Os::FileSystem::OTHER_ERROR); | |
| 574 | ✗ | break; // Exit the loop since we had an error | |
| 575 | } | ||
| 576 | 12 | } | |
| 577 | } | ||
| 578 | 29 | } | |
| 579 | |||
| 580 | // ---------------------------------------------------------------------- | ||
| 581 | // Helper methods | ||
| 582 | // ---------------------------------------------------------------------- | ||
| 583 | |||
| 584 | 22 | void FileManager ::emitTelemetry(const Os::FileSystem::Status status) { | |
| 585 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 7 times.
|
22 | if (status == Os::FileSystem::OP_OK) { |
| 586 | 15 | ++this->commandCount; | |
| 587 |
2/2✓ Branch 6 taken 15 times.
✓ Branch 13 taken 15 times.
|
15 | this->tlmWrite_CommandsExecuted(this->commandCount); |
| 588 | } else { | ||
| 589 | 7 | ++this->errorCount; | |
| 590 |
2/2✓ Branch 6 taken 7 times.
✓ Branch 13 taken 7 times.
|
7 | this->tlmWrite_Errors(this->errorCount); |
| 591 | } | ||
| 592 | 22 | } | |
| 593 | |||
| 594 | 22 | void FileManager ::sendCommandResponse(const FwOpcodeType opCode, | |
| 595 | const U32 cmdSeq, | ||
| 596 | const Os::FileSystem::Status status) { | ||
| 597 |
4/4✓ Branch 5 taken 15 times.
✓ Branch 6 taken 7 times.
✓ Branch 8 taken 22 times.
✓ Branch 11 taken 22 times.
|
22 | this->cmdResponse_out(opCode, cmdSeq, |
| 598 | (status == Os::FileSystem::OP_OK) ? Fw::CmdResponse::OK : Fw::CmdResponse::EXECUTION_ERROR); | ||
| 599 | 22 | } | |
| 600 | |||
| 601 | } // namespace Svc | ||
| 602 |