GCC Code Coverage Report


Directory: ./
File: BufferLoggerFile.cpp
Date: 2026-09-03 22:13:17
Exec Total Coverage
Lines: 0 116 0.0%
Functions: 0 13 0.0%
Branches: 0 69 0.0%

Line Branch Exec Source
1 // ======================================================================
2 // \title BufferLoggerFile.cpp
3 // \author bocchino, dinkel, mereweth
4 // \brief Implementation for Svc::BufferLogger::BufferLoggerFile
5 //
6 // \copyright
7 // Copyright (C) 2015-2017 California Institute of Technology.
8 // ALL RIGHTS RESERVED. United States Government Sponsorship
9 // acknowledged.
10 //
11 // ======================================================================
12
13 #include "Os/ValidatedFile.hpp"
14 #include "Svc/BufferLogger/BufferLogger.hpp"
15 #include "Utils/Hash/Hash.hpp"
16
17 namespace Svc {
18
19 // ----------------------------------------------------------------------
20 // Constructors and destructors
21 // ----------------------------------------------------------------------
22
23 BufferLogger::File ::File(BufferLogger& bufferLogger)
24 : m_bufferLogger(bufferLogger),
25 m_prefix(""),
26 m_suffix(""),
27 m_baseName(""),
28 m_fileCounter(0),
29 m_maxSize(0),
30 m_sizeOfSize(0),
31 m_mode(Mode::CLOSED),
32 m_bytesWritten(0) {}
33
34 BufferLogger::File ::~File() {
35 this->close();
36 }
37
38 // ----------------------------------------------------------------------
39 // Public functions
40 // ----------------------------------------------------------------------
41
42 void BufferLogger::File ::init(const char* const logFilePrefix,
43 const char* const logFileSuffix,
44 const FwSizeType maxFileSize,
45 const U8 sizeOfSize) {
46 // NOTE(mereweth) - only call this before opening the file
47 FW_ASSERT(this->m_mode == File::Mode::CLOSED);
48
49 this->m_prefix = logFilePrefix;
50 this->m_suffix = logFileSuffix;
51 this->m_maxSize = maxFileSize;
52 this->m_sizeOfSize = sizeOfSize;
53
54 FW_ASSERT(sizeOfSize <= sizeof(FwSizeType), static_cast<FwAssertArgType>(sizeOfSize));
55 FW_ASSERT(m_maxSize > sizeOfSize, static_cast<FwAssertArgType>(m_maxSize));
56 }
57
58 void BufferLogger::File ::setBaseName(const Fw::ConstStringBase& baseName) {
59 if (this->m_mode == File::Mode::OPEN) {
60 this->closeAndEmitEvent();
61 }
62 this->m_baseName = baseName;
63 this->m_fileCounter = 0;
64 this->open();
65 }
66
67 void BufferLogger::File ::logBuffer(const U8* const data, const FwSizeType size) {
68 FW_ASSERT(data != nullptr);
69 // Close the file if it will be too big
70 if (this->m_mode == File::Mode::OPEN) {
71 const FwSizeType projectedByteCount = this->m_bytesWritten + this->m_sizeOfSize + size;
72 if (projectedByteCount > this->m_maxSize) {
73 this->closeAndEmitEvent();
74 }
75 }
76 // Open a file if necessary
77 if (this->m_mode == File::Mode::CLOSED) {
78 this->open();
79 }
80 // Write to the file if it is open
81 if (this->m_mode == File::Mode::OPEN) {
82 (void)this->writeBuffer(data, size);
83 }
84 }
85
86 void BufferLogger::File ::closeAndEmitEvent() {
87 if (this->m_mode == File::Mode::OPEN) {
88 this->close();
89 Fw::LogStringArg logStringArg(this->m_name.toChar());
90 this->m_bufferLogger.log_DIAGNOSTIC_BL_LogFileClosed(logStringArg);
91 }
92 }
93
94 // ----------------------------------------------------------------------
95 // Private functions
96 // ----------------------------------------------------------------------
97
98 void BufferLogger::File ::open() {
99 FW_ASSERT(this->m_mode == File::Mode::CLOSED);
100
101 // NOTE(mereweth) - check that file path has been set and that initLog has been called
102 if ((this->m_baseName.toChar()[0] == '\0') || (this->m_sizeOfSize > sizeof(FwSizeType)) ||
103 (this->m_maxSize <= this->m_sizeOfSize)) {
104 this->m_bufferLogger.log_WARNING_HI_BL_NoLogFileOpenInitError();
105 return;
106 }
107
108 Fw::FormatStatus formatStatus;
109 if (this->m_fileCounter == 0) {
110 formatStatus =
111 this->m_name.format("%s%s%s", this->m_prefix.toChar(), this->m_baseName.toChar(), this->m_suffix.toChar());
112 } else {
113 formatStatus = this->m_name.format("%s%s%" PRI_FwSizeType "%s", this->m_prefix.toChar(),
114 this->m_baseName.toChar(), this->m_fileCounter, this->m_suffix.toChar());
115 }
116 if (formatStatus != Fw::FormatStatus::SUCCESS) {
117 this->m_bufferLogger.log_WARNING_HI_BL_LogFileNameError(static_cast<Fw::StringFormatStatus::T>(formatStatus));
118 return;
119 }
120
121 const Os::File::Status status = this->m_osFile.open(this->m_name.toChar(), Os::File::OPEN_WRITE);
122 if (status == Os::File::OP_OK) {
123 this->m_fileCounter++;
124 // Reset bytes written
125 this->m_bytesWritten = 0;
126 // Initialize incremental hash
127 this->m_hash.init();
128 // Set mode
129 this->m_mode = File::Mode::OPEN;
130 } else {
131 Fw::LogStringArg string(this->m_name.toChar());
132 this->m_bufferLogger.log_WARNING_HI_BL_LogFileOpenError(status, string);
133 }
134 }
135
136 bool BufferLogger::File ::writeBuffer(const U8* const data, const FwSizeType size) {
137 bool status = this->writeSize(size);
138 if (status) {
139 status = this->writeBytes(data, size);
140 }
141 return status;
142 }
143
144 bool BufferLogger::File ::writeSize(const FwSizeType size) {
145 FW_ASSERT(this->m_sizeOfSize <= sizeof(FwSizeType));
146 // Reject sizes that do not fit in sizeOfSize bytes; writing the low bytes would corrupt the log
147 if ((this->m_sizeOfSize < sizeof(FwSizeType)) && ((size >> (8 * this->m_sizeOfSize)) != 0)) {
148 Fw::LogStringArg string(this->m_name.toChar());
149 this->m_bufferLogger.log_WARNING_HI_BL_LogFileWriteError(Os::File::INVALID_ARGUMENT, 0, static_cast<U32>(size),
150 string);
151 return false;
152 }
153 U8 sizeBuffer[sizeof(FwSizeType)];
154 FwSizeType sizeRegister = size;
155 for (U8 i = 0; i < this->m_sizeOfSize; ++i) {
156 sizeBuffer[this->m_sizeOfSize - i - 1] = sizeRegister & 0xFF;
157 sizeRegister >>= 8;
158 }
159 const bool status = this->writeBytes(sizeBuffer, this->m_sizeOfSize);
160 return status;
161 }
162
163 bool BufferLogger::File ::writeBytes(const void* const data, const FwSizeType length) {
164 FwSizeType size = length;
165 const Os::File::Status fileStatus = this->m_osFile.write(reinterpret_cast<const U8*>(data), size);
166 bool status;
167 if (fileStatus == Os::File::OP_OK && static_cast<FwSizeType>(size) == length) {
168 this->m_bytesWritten += length;
169 this->m_hash.update(data, length);
170 status = true;
171 } else {
172 Fw::LogStringArg string(this->m_name.toChar());
173
174 this->m_bufferLogger.log_WARNING_HI_BL_LogFileWriteError(fileStatus, static_cast<U32>(size),
175 static_cast<U32>(length), string);
176 status = false;
177 }
178 return status;
179 }
180
181 void BufferLogger::File ::writeHashFile() {
182 // Finalize the incrementally computed hash
183 Utils::HashBuffer hashBuffer;
184 this->m_hash.finalize(hashBuffer);
185
186 // Write hash file via ValidatedFile
187 Os::ValidatedFile validatedFile(this->m_name.toChar());
188 const Os::ValidateFile::Status status = validatedFile.createHashFile(hashBuffer);
189 if (status != Os::ValidateFile::VALIDATION_OK) {
190 Fw::LogStringArg logStringArg(validatedFile.getHashFileName().toChar());
191 this->m_bufferLogger.log_WARNING_HI_BL_LogFileValidationError(logStringArg, status);
192 }
193 }
194
195 bool BufferLogger::File ::flush() {
196 // Unbuffered file I/O requires no flush; flush the Os::File here if using buffered I/O
197 return true;
198 }
199
200 void BufferLogger::File ::close() {
201 if (this->m_mode == File::Mode::OPEN) {
202 // Close file
203 this->m_osFile.close();
204 // Write out the hash file to disk
205 this->writeHashFile();
206 // Update mode
207 this->m_mode = File::Mode::CLOSED;
208 }
209 }
210
211 } // namespace Svc
212