Branch data Line data Source code
1 : : /* SPDX-FileCopyrightText: Copyright 2026 Cozens Software Solutions Limited
2 : : * SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial
3 : : */
4 : :
5 : : #include "SolidSyslogRecordStorePrivate.h"
6 : :
7 : : #include "SolidSyslogBlockDevice.h"
8 : : #include "SolidSyslogSecurityPolicyDefinition.h"
9 : : #include "SolidSyslogTunables.h"
10 : :
11 : : #include <stdbool.h>
12 : : #include <stdint.h>
13 : : #include <string.h>
14 : :
15 : : struct SolidSyslogBlockDevice;
16 : :
17 : : enum
18 : : {
19 : : MAGIC_SIZE = 2,
20 : : MAGIC_BYTE_0 = 0xA5,
21 : : MAGIC_BYTE_1 = 0x5A,
22 : : RECORD_LENGTH_SIZE = 2,
23 : : /* The policy authenticates magic|length as the cleartext header (an AEAD
24 : : * policy never encrypts it) and message as the body. */
25 : : CONTENT_HEADER_SIZE = MAGIC_SIZE + RECORD_LENGTH_SIZE,
26 : : SENT_FLAG_SIZE = 1,
27 : : SENT_FLAG_UNSENT = 0xFF,
28 : : SENT_FLAG_SENT = 0x00,
29 : : /* Written by releases before 0.4.0 for a record the policy rejected, and
30 : : * still read as finished with. Nothing writes it now. */
31 : : SENT_FLAG_DISCARDED = 0x0F
32 : : };
33 : :
34 : : /* Each record in the buffer is laid out as
35 : : * [ magic | length | message | trailer | sentFlag ]
36 : : * The security policy authenticates the content span (magic|length|message),
37 : : * treating magic|length as the header and message as the body, and owns the
38 : : * trailer (TrailerSize bytes). Field-address helpers chain outward from the
39 : : * record's base so the field offsets are stated in one place each. The same
40 : : * chaining shapes the block-offset helpers below. */
41 : :
42 : : /* cppcheck-suppress constParameterPointer -- hands back the storage for the caller to write through. */
43 : 4542247 : static inline uint8_t* RecordStore_MagicAddress(struct SolidSyslogRecordStore* recordStore)
44 : : {
45 : 4542247 : return recordStore->Buffer;
46 : : }
47 : :
48 : 2546564 : static inline uint8_t* RecordStore_LengthAddress(struct SolidSyslogRecordStore* recordStore)
49 : : {
50 : 2546564 : uint8_t* magic = RecordStore_MagicAddress(recordStore);
51 : 2546564 : return &magic[MAGIC_SIZE];
52 : : }
53 : :
54 : 1959870 : static inline uint8_t* RecordStore_MessageAddress(struct SolidSyslogRecordStore* recordStore)
55 : : {
56 : 1959870 : uint8_t* length = RecordStore_LengthAddress(recordStore);
57 : 1959870 : return &length[RECORD_LENGTH_SIZE];
58 : : }
59 : :
60 : 1229058 : static inline uint8_t* RecordStore_TrailerAddress(struct SolidSyslogRecordStore* recordStore, size_t dataSize)
61 : : {
62 : 1229058 : uint8_t* message = RecordStore_MessageAddress(recordStore);
63 : 1229058 : return &message[dataSize];
64 : : }
65 : :
66 : 497324 : static inline uint8_t* RecordStore_SentFlagAddress(struct SolidSyslogRecordStore* recordStore, size_t dataSize)
67 : : {
68 : 497324 : uint8_t* trailer = RecordStore_TrailerAddress(recordStore, dataSize);
69 : 497324 : return &trailer[recordStore->SecurityPolicy->TrailerSize];
70 : : }
71 : :
72 : 821864 : static inline uint8_t* RecordStore_ContentAddress(struct SolidSyslogRecordStore* recordStore)
73 : : {
74 : 821864 : return RecordStore_MagicAddress(recordStore);
75 : : }
76 : :
77 : 495559 : static inline uint16_t RecordStore_ContentSize(size_t dataSize)
78 : : {
79 : 495559 : return (uint16_t) (MAGIC_SIZE + RECORD_LENGTH_SIZE + dataSize);
80 : : }
81 : :
82 : 506294 : static inline size_t RecordStore_TrailerOffset(size_t recordStart, uint16_t dataLength)
83 : : {
84 : 506294 : return recordStart + MAGIC_SIZE + RECORD_LENGTH_SIZE + dataLength;
85 : : }
86 : :
87 : 270119 : static inline size_t RecordStore_SentFlagOffset(
88 : : const struct SolidSyslogRecordStore* recordStore,
89 : : size_t recordStart,
90 : : uint16_t dataLength
91 : : )
92 : : {
93 : 270119 : return RecordStore_TrailerOffset(recordStart, dataLength) + recordStore->SecurityPolicy->TrailerSize;
94 : : }
95 : :
96 : 19191 : void SolidSyslogRecordStore_Initialise(
97 : : struct SolidSyslogRecordStore* recordStore,
98 : : struct SolidSyslogSecurityPolicy* securityPolicy
99 : : )
100 : : {
101 : 19191 : recordStore->SecurityPolicy = securityPolicy;
102 : 19191 : recordStore->HasReadRecord = false;
103 : 19191 : recordStore->LastReadBlockIndex = 0;
104 : 19191 : recordStore->LastSentFlagOffset = 0;
105 : 19191 : }
106 : :
107 : 19191 : void SolidSyslogRecordStore_Cleanup(struct SolidSyslogRecordStore* recordStore)
108 : : {
109 : : /* No owned resources to release. The next SolidSyslogRecordStore_Initialise overwrites every
110 : : * field, so leave the slot's bytes alone - clearing them would be
111 : : * write-then-overwrite churn. */
112 : : (void) recordStore;
113 : 19191 : }
114 : :
115 : 963067 : size_t SolidSyslogRecordStore_RecordSize(const struct SolidSyslogRecordStore* recordStore, uint16_t dataLength)
116 : : {
117 : 963067 : return (size_t) MAGIC_SIZE + RECORD_LENGTH_SIZE + dataLength + recordStore->SecurityPolicy->TrailerSize +
118 : : SENT_FLAG_SIZE;
119 : : }
120 : :
121 : : static inline bool RecordStore_AssembleRecord(
122 : : struct SolidSyslogRecordStore* recordStore,
123 : : const void* data,
124 : : size_t size
125 : : );
126 : :
127 : 261242 : enum SolidSyslogRecordStoreAppendResult SolidSyslogRecordStore_Append(
128 : : struct SolidSyslogRecordStore* recordStore,
129 : : struct SolidSyslogBlockDevice* blockDevice,
130 : : size_t blockIndex,
131 : : const void* data,
132 : : size_t dataSize
133 : : )
134 : : {
135 : 261242 : enum SolidSyslogRecordStoreAppendResult result = SOLIDSYSLOG_RECORD_STORE_APPEND_SEAL_FAILED;
136 [ + + ]: 261242 : if (RecordStore_AssembleRecord(recordStore, data, dataSize))
137 : : {
138 : 520920 : bool appended = SolidSyslogBlockDevice_Append(
139 : : blockDevice,
140 : : blockIndex,
141 : 260460 : recordStore->Buffer,
142 : 260460 : SolidSyslogRecordStore_RecordSize(recordStore, (uint16_t) dataSize)
143 : : );
144 [ + + ]: 260460 : result = appended ? SOLIDSYSLOG_RECORD_STORE_APPEND_SUCCEEDED : SOLIDSYSLOG_RECORD_STORE_APPEND_DEVICE_FAILED;
145 : : }
146 : 261242 : return result;
147 : : }
148 : :
149 : 261242 : static inline bool RecordStore_AssembleRecord(struct SolidSyslogRecordStore* recordStore, const void* data, size_t size)
150 : : {
151 : 261242 : RecordStore_MagicAddress(recordStore)[0] = MAGIC_BYTE_0;
152 : 261242 : RecordStore_MagicAddress(recordStore)[1] = MAGIC_BYTE_1;
153 : :
154 : : /* Length is packed little-endian into the byte buffer - the on-disk
155 : : * format is LE regardless of host (every supported target is LE; an
156 : : * explicit pack keeps that invariant readable and side-steps MISRA
157 : : * 21.15 which forbids memcpy between incompatible essential types). */
158 : 261242 : uint16_t length = (uint16_t) size;
159 : 261242 : uint8_t* lengthBytes = RecordStore_LengthAddress(recordStore);
160 : 261242 : lengthBytes[0] = (uint8_t) (length & 0xFFU);
161 : 261242 : lengthBytes[1] = (uint8_t) ((length >> 8) & 0xFFU);
162 : 261242 : (void) memcpy(RecordStore_MessageAddress(recordStore), data, size);
163 : :
164 : 783726 : struct SolidSyslogSecurityRecord record = {
165 : 261242 : RecordStore_ContentAddress(recordStore),
166 : 261242 : RecordStore_ContentSize(size),
167 : : CONTENT_HEADER_SIZE,
168 : 261242 : RecordStore_TrailerAddress(recordStore, size)
169 : : };
170 : 261242 : bool sealed = recordStore->SecurityPolicy->SealRecord(recordStore->SecurityPolicy, &record);
171 : :
172 : 261242 : *RecordStore_SentFlagAddress(recordStore, size) = SENT_FLAG_UNSENT;
173 : 261242 : return sealed;
174 : : }
175 : :
176 : : static enum SolidSyslogRecordStoreReadResult RecordStore_ReadAndValidateRecord(
177 : : struct SolidSyslogRecordStore* recordStore,
178 : : struct SolidSyslogBlockDevice* blockDevice,
179 : : size_t blockIndex,
180 : : size_t offset,
181 : : size_t dataSize,
182 : : uint16_t* length
183 : : );
184 : : static inline bool RecordStore_RecordExtentIsKnown(enum SolidSyslogRecordStoreReadResult result);
185 : : static inline void RecordStore_CopyRecordData(
186 : : struct SolidSyslogRecordStore* recordStore,
187 : : uint16_t length,
188 : : void* dst,
189 : : size_t maxSize,
190 : : size_t* bytesRead
191 : : );
192 : : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- blockIndex / offset are positional fields of the just-read record; distinct semantics
193 : : static inline void RecordStore_RememberCurrentRecord(
194 : : struct SolidSyslogRecordStore* recordStore,
195 : : size_t blockIndex,
196 : : size_t offset,
197 : : uint16_t length
198 : : );
199 : :
200 : : // NOLINTEND(bugprone-easily-swappable-parameters)
201 : :
202 : 240082 : enum SolidSyslogRecordStoreReadResult SolidSyslogRecordStore_Read(
203 : : struct SolidSyslogRecordStore* recordStore,
204 : : struct SolidSyslogBlockDevice* blockDevice,
205 : : size_t blockIndex,
206 : : size_t offset,
207 : : size_t dataSize,
208 : : void* dst,
209 : : size_t maxSize,
210 : : size_t* bytesRead
211 : : )
212 : : {
213 : 240082 : uint16_t length = 0U;
214 : :
215 : 240082 : *bytesRead = 0;
216 : :
217 : : enum SolidSyslogRecordStoreReadResult result =
218 : 240082 : RecordStore_ReadAndValidateRecord(recordStore, blockDevice, blockIndex, offset, dataSize, &length);
219 : :
220 [ + + ]: 240082 : if (RecordStore_RecordExtentIsKnown(result))
221 : : {
222 : 235769 : RecordStore_RememberCurrentRecord(recordStore, blockIndex, offset, length);
223 : : }
224 : :
225 [ + + ]: 240082 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
226 : : {
227 : 231984 : RecordStore_CopyRecordData(recordStore, length, dst, maxSize, bytesRead);
228 : : }
229 : :
230 : 240082 : return result;
231 : : }
232 : :
233 : : /* A record whose header read and validated has a length, so it can be stepped
234 : : * over whether or not the policy accepted it. */
235 : 240082 : static inline bool RecordStore_RecordExtentIsKnown(enum SolidSyslogRecordStoreReadResult result)
236 : : {
237 [ + + + + : 240082 : return (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED) || (result == SOLIDSYSLOG_RECORD_STORE_READ_REJECTED) ||
+ + ]
238 : : (result == SOLIDSYSLOG_RECORD_STORE_READ_FINISHED_WITH);
239 : : }
240 : :
241 : : static inline enum SolidSyslogRecordStoreReadResult RecordStore_ReadSpan(
242 : : struct SolidSyslogBlockDevice* blockDevice,
243 : : size_t blockIndex,
244 : : size_t offset,
245 : : void* buf,
246 : : size_t count,
247 : : size_t dataSize
248 : : );
249 : : static enum SolidSyslogRecordStoreReadResult RecordStore_ReadRecordExtent(
250 : : struct SolidSyslogRecordStore* recordStore,
251 : : struct SolidSyslogBlockDevice* blockDevice,
252 : : size_t blockIndex,
253 : : size_t offset,
254 : : size_t dataSize,
255 : : uint16_t* length
256 : : );
257 : : static enum SolidSyslogRecordStoreReadResult RecordStore_ReadHeader(
258 : : struct SolidSyslogRecordStore* recordStore,
259 : : struct SolidSyslogBlockDevice* blockDevice,
260 : : size_t blockIndex,
261 : : size_t offset,
262 : : size_t dataSize,
263 : : uint16_t* length
264 : : );
265 : : static inline bool RecordStore_ValidateHeader(struct SolidSyslogRecordStore* recordStore, uint16_t* length);
266 : : static inline bool RecordStore_SpanIsWithinData(size_t offset, size_t count, size_t dataSize);
267 : : static inline bool RecordStore_RecordIsWithinData(
268 : : const struct SolidSyslogRecordStore* recordStore,
269 : : size_t offset,
270 : : uint16_t length,
271 : : size_t dataSize
272 : : );
273 : : static inline bool RecordStore_FlagReadsFinishedWith(struct SolidSyslogRecordStore* recordStore, uint16_t length);
274 : : static inline bool RecordStore_FlagMarksSentOrDiscarded(uint8_t flag);
275 : : static inline enum SolidSyslogRecordStoreReadResult RecordStore_OpenRecord(
276 : : struct SolidSyslogRecordStore* recordStore,
277 : : uint16_t length
278 : : );
279 : :
280 : : /* A record is read only once it is known to lie whole within the block's data,
281 : : * so one cut short - what a power cut mid-append leaves - is corrupt rather
282 : : * than a device failure. The flag is read with the trailer: a record already
283 : : * marked is finished with, and the policy is not asked about it. */
284 : 240082 : static enum SolidSyslogRecordStoreReadResult RecordStore_ReadAndValidateRecord(
285 : : struct SolidSyslogRecordStore* recordStore,
286 : : struct SolidSyslogBlockDevice* blockDevice,
287 : : size_t blockIndex,
288 : : size_t offset,
289 : : size_t dataSize,
290 : : uint16_t* length
291 : : )
292 : : {
293 : : enum SolidSyslogRecordStoreReadResult result =
294 : 240082 : RecordStore_ReadRecordExtent(recordStore, blockDevice, blockIndex, offset, dataSize, length);
295 : :
296 [ + + ]: 240082 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
297 : : {
298 : 237586 : result = RecordStore_ReadSpan(
299 : : blockDevice,
300 : : blockIndex,
301 : : offset + CONTENT_HEADER_SIZE,
302 : 237586 : RecordStore_MessageAddress(recordStore),
303 : 237586 : *length,
304 : : dataSize
305 : : );
306 : : }
307 : :
308 [ + + ]: 240082 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
309 : : {
310 : 236175 : result = RecordStore_ReadSpan(
311 : : blockDevice,
312 : : blockIndex,
313 : 236175 : RecordStore_TrailerOffset(offset, *length),
314 : 236175 : RecordStore_TrailerAddress(recordStore, *length),
315 : 236175 : recordStore->SecurityPolicy->TrailerSize + SENT_FLAG_SIZE,
316 : : dataSize
317 : : );
318 : : }
319 : :
320 [ + + + + ]: 240082 : if ((result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED) && RecordStore_FlagReadsFinishedWith(recordStore, *length))
321 : : {
322 : 1765 : result = SOLIDSYSLOG_RECORD_STORE_READ_FINISHED_WITH;
323 : : }
324 : :
325 [ + + ]: 240082 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
326 : : {
327 : 234317 : result = RecordStore_OpenRecord(recordStore, *length);
328 : : }
329 : :
330 : 240082 : return result;
331 : : }
332 : :
333 : 236082 : static inline bool RecordStore_FlagReadsFinishedWith(struct SolidSyslogRecordStore* recordStore, uint16_t length)
334 : : {
335 : 236082 : return RecordStore_FlagMarksSentOrDiscarded(*RecordStore_SentFlagAddress(recordStore, length));
336 : : }
337 : :
338 : : /* Exact values only: a flag a power cut left half-written reads as unsent, so
339 : : * the record is sent again rather than lost. */
340 : 270432 : static inline bool RecordStore_FlagMarksSentOrDiscarded(uint8_t flag)
341 : : {
342 [ + + + + ]: 270432 : return (flag == SENT_FLAG_SENT) || (flag == SENT_FLAG_DISCARDED);
343 : : }
344 : :
345 : : /* The header, and that the record it describes lies whole within the data. */
346 : 327085 : static enum SolidSyslogRecordStoreReadResult RecordStore_ReadRecordExtent(
347 : : struct SolidSyslogRecordStore* recordStore,
348 : : struct SolidSyslogBlockDevice* blockDevice,
349 : : size_t blockIndex,
350 : : size_t offset,
351 : : size_t dataSize,
352 : : uint16_t* length
353 : : )
354 : : {
355 : : enum SolidSyslogRecordStoreReadResult result =
356 : 327085 : RecordStore_ReadHeader(recordStore, blockDevice, blockIndex, offset, dataSize, length);
357 : :
358 [ + + ]: 327085 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
359 : : {
360 : 650720 : result = RecordStore_RecordIsWithinData(recordStore, offset, *length, dataSize)
361 : : ? SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED
362 [ + + ]: 325360 : : SOLIDSYSLOG_RECORD_STORE_READ_CORRUPT;
363 : : }
364 : :
365 : 327085 : return result;
366 : : }
367 : :
368 : : /* The header alone: enough to know where the record ends. */
369 : 327085 : static enum SolidSyslogRecordStoreReadResult RecordStore_ReadHeader(
370 : : struct SolidSyslogRecordStore* recordStore,
371 : : struct SolidSyslogBlockDevice* blockDevice,
372 : : size_t blockIndex,
373 : : size_t offset,
374 : : size_t dataSize,
375 : : uint16_t* length
376 : : )
377 : : {
378 : 327085 : enum SolidSyslogRecordStoreReadResult result = SOLIDSYSLOG_RECORD_STORE_READ_END_OF_DATA;
379 : :
380 [ + + ]: 327085 : if (offset < dataSize)
381 : : {
382 : 326305 : result = RecordStore_ReadSpan(
383 : : blockDevice,
384 : : blockIndex,
385 : : offset,
386 : 326305 : RecordStore_ContentAddress(recordStore),
387 : : CONTENT_HEADER_SIZE,
388 : : dataSize
389 : : );
390 : : }
391 : :
392 [ + + ]: 327085 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
393 : : {
394 : 651538 : result = RecordStore_ValidateHeader(recordStore, length) ? SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED
395 [ + + ]: 325769 : : SOLIDSYSLOG_RECORD_STORE_READ_CORRUPT;
396 : : }
397 : :
398 : 327085 : return result;
399 : : }
400 : :
401 : : /* Whole through its sent flag. A record that runs past the data is one a power
402 : : * cut cut short, and its flag byte is where the next record now starts. */
403 : : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- offset and dataSize are a position and a bound; distinct semantics
404 : 325360 : static inline bool RecordStore_RecordIsWithinData(
405 : : const struct SolidSyslogRecordStore* recordStore,
406 : : size_t offset,
407 : : uint16_t length,
408 : : size_t dataSize
409 : : )
410 : : {
411 : 325360 : return RecordStore_SpanIsWithinData(offset, SolidSyslogRecordStore_RecordSize(recordStore, length), dataSize);
412 : : }
413 : :
414 : : // NOLINTEND(bugprone-easily-swappable-parameters)
415 : :
416 : : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- offset, count and dataSize are a position, a length and a bound; distinct semantics
417 : 834416 : static inline enum SolidSyslogRecordStoreReadResult RecordStore_ReadSpan(
418 : : struct SolidSyslogBlockDevice* blockDevice,
419 : : size_t blockIndex,
420 : : size_t offset,
421 : : void* buf,
422 : : size_t count,
423 : : size_t dataSize
424 : : )
425 : : {
426 : 834416 : enum SolidSyslogRecordStoreReadResult result = SOLIDSYSLOG_RECORD_STORE_READ_CORRUPT;
427 : :
428 [ + + ]: 834416 : if (RecordStore_SpanIsWithinData(offset, count, dataSize))
429 : : {
430 : 1668302 : result = SolidSyslogBlockDevice_Read(blockDevice, blockIndex, offset, buf, count)
431 : : ? SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED
432 [ + + ]: 834151 : : SOLIDSYSLOG_RECORD_STORE_READ_DEVICE_FAILED;
433 : : }
434 : :
435 : 834416 : return result;
436 : : }
437 : :
438 : 1159776 : static inline bool RecordStore_SpanIsWithinData(size_t offset, size_t count, size_t dataSize)
439 : : {
440 : 1159776 : return (offset + count) <= dataSize;
441 : : }
442 : :
443 : : // NOLINTEND(bugprone-easily-swappable-parameters)
444 : :
445 : 325769 : static inline bool RecordStore_IsMagicValid(struct SolidSyslogRecordStore* recordStore)
446 : : {
447 [ + + ]: 651335 : return (RecordStore_MagicAddress(recordStore)[0] == MAGIC_BYTE_0) &&
448 [ + + ]: 325566 : (RecordStore_MagicAddress(recordStore)[1] == MAGIC_BYTE_1);
449 : : }
450 : :
451 : 325452 : static inline uint16_t RecordStore_RecordLength(struct SolidSyslogRecordStore* recordStore)
452 : : {
453 : : /* Little-endian unpack - see AssembleRecord for the format invariant. */
454 : 325452 : const uint8_t* lengthBytes = RecordStore_LengthAddress(recordStore);
455 : 325452 : return (uint16_t) (((uint16_t) lengthBytes[0]) | (((uint16_t) lengthBytes[1]) << 8));
456 : : }
457 : :
458 : : /* The store never writes a record of no bytes, so one on the media is damaged. */
459 : 325452 : static inline bool RecordStore_IsValidLength(uint16_t length)
460 : : {
461 [ + + + + ]: 325452 : return (length > 0U) && (length <= SOLIDSYSLOG_MAX_MESSAGE_SIZE);
462 : : }
463 : :
464 : 325769 : static inline bool RecordStore_ValidateHeader(struct SolidSyslogRecordStore* recordStore, uint16_t* length)
465 : : {
466 : 325769 : bool valid = RecordStore_IsMagicValid(recordStore);
467 : :
468 [ + + ]: 325769 : if (valid)
469 : : {
470 : 325452 : *length = RecordStore_RecordLength(recordStore);
471 : 325452 : valid = RecordStore_IsValidLength(*length);
472 : : }
473 : :
474 : 325769 : return valid;
475 : : }
476 : :
477 : 234317 : static inline enum SolidSyslogRecordStoreReadResult RecordStore_OpenRecord(
478 : : struct SolidSyslogRecordStore* recordStore,
479 : : uint16_t length
480 : : )
481 : : {
482 : 702951 : struct SolidSyslogSecurityRecord record = {
483 : 234317 : RecordStore_ContentAddress(recordStore),
484 : 234317 : RecordStore_ContentSize(length),
485 : : CONTENT_HEADER_SIZE,
486 : 234317 : RecordStore_TrailerAddress(recordStore, length)
487 : : };
488 : : enum SolidSyslogSecurityPolicyOpenResult opened =
489 : 234317 : recordStore->SecurityPolicy->OpenRecord(recordStore->SecurityPolicy, &record);
490 : 234317 : enum SolidSyslogRecordStoreReadResult result = SOLIDSYSLOG_RECORD_STORE_READ_COULD_NOT_OPEN;
491 : :
492 [ + + ]: 234317 : if (opened == SOLIDSYSLOG_SECURITY_POLICY_OPEN_OPENED)
493 : : {
494 : 231984 : result = SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED;
495 : : }
496 [ + + ]: 2333 : else if (opened == SOLIDSYSLOG_SECURITY_POLICY_OPEN_REJECTED)
497 : : {
498 : 2020 : result = SOLIDSYSLOG_RECORD_STORE_READ_REJECTED;
499 : : }
500 : : else
501 : : {
502 : : /* No verdict: the record is kept. */
503 : : }
504 : :
505 : 234317 : return result;
506 : : }
507 : :
508 : 231984 : static inline size_t RecordStore_BoundedSize(uint16_t length, size_t maxSize)
509 : : {
510 : 231984 : return (length < maxSize) ? length : maxSize;
511 : : }
512 : :
513 : 231984 : static inline void RecordStore_CopyRecordData(
514 : : struct SolidSyslogRecordStore* recordStore,
515 : : uint16_t length,
516 : : void* dst,
517 : : size_t maxSize,
518 : : size_t* bytesRead
519 : : )
520 : : {
521 : 231984 : size_t copySize = RecordStore_BoundedSize(length, maxSize);
522 : 231984 : (void) memcpy(dst, RecordStore_MessageAddress(recordStore), copySize);
523 : 231984 : *bytesRead = copySize;
524 : 231984 : }
525 : :
526 : : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- blockIndex / offset are positional fields of the just-read record; distinct semantics
527 : 235769 : static inline void RecordStore_RememberCurrentRecord(
528 : : struct SolidSyslogRecordStore* recordStore,
529 : : size_t blockIndex,
530 : : size_t offset,
531 : : uint16_t length
532 : : )
533 : : {
534 : 235769 : recordStore->LastReadBlockIndex = blockIndex;
535 : 235769 : recordStore->LastSentFlagOffset = RecordStore_SentFlagOffset(recordStore, offset, length);
536 : 235769 : recordStore->HasReadRecord = true;
537 : 235769 : }
538 : :
539 : : // NOLINTEND(bugprone-easily-swappable-parameters)
540 : :
541 : : static inline bool RecordStore_WriteSentFlag(
542 : : const struct SolidSyslogRecordStore* recordStore,
543 : : struct SolidSyslogBlockDevice* blockDevice
544 : : );
545 : :
546 : 231068 : enum SolidSyslogRecordStoreMarkResult SolidSyslogRecordStore_MarkLastReadAsSent(
547 : : struct SolidSyslogRecordStore* recordStore,
548 : : struct SolidSyslogBlockDevice* blockDevice,
549 : : size_t* nextCursor
550 : : )
551 : : {
552 : 231068 : enum SolidSyslogRecordStoreMarkResult result = SOLIDSYSLOG_RECORD_STORE_MARK_NOTHING_READ;
553 : :
554 [ + + ]: 231068 : if (recordStore->HasReadRecord)
555 : : {
556 : 231067 : result = SOLIDSYSLOG_RECORD_STORE_MARK_DEVICE_FAILED;
557 : :
558 [ + + ]: 231067 : if (RecordStore_WriteSentFlag(recordStore, blockDevice))
559 : : {
560 : 231035 : *nextCursor = recordStore->LastSentFlagOffset + SENT_FLAG_SIZE;
561 : 231035 : recordStore->HasReadRecord = false;
562 : 231035 : result = SOLIDSYSLOG_RECORD_STORE_MARK_SUCCEEDED;
563 : : }
564 : : }
565 : :
566 : 231068 : return result;
567 : : }
568 : :
569 : 231067 : static inline bool RecordStore_WriteSentFlag(
570 : : const struct SolidSyslogRecordStore* recordStore,
571 : : struct SolidSyslogBlockDevice* blockDevice
572 : : )
573 : : {
574 : 231067 : uint8_t flag = SENT_FLAG_SENT;
575 : 462134 : return SolidSyslogBlockDevice_WriteAt(
576 : : blockDevice,
577 : 231067 : recordStore->LastReadBlockIndex,
578 : 231067 : recordStore->LastSentFlagOffset,
579 : : &flag,
580 : : SENT_FLAG_SIZE
581 : : );
582 : : }
583 : :
584 : 3785 : size_t SolidSyslogRecordStore_StepPastLastRead(struct SolidSyslogRecordStore* recordStore)
585 : : {
586 : 3785 : recordStore->HasReadRecord = false;
587 : 3785 : return recordStore->LastSentFlagOffset + SENT_FLAG_SIZE;
588 : : }
589 : :
590 : 13925 : void SolidSyslogRecordStore_ForgetLastRead(struct SolidSyslogRecordStore* recordStore)
591 : : {
592 : 13925 : recordStore->HasReadRecord = false;
593 : 13925 : }
594 : :
595 : : static bool RecordStore_AdvancePastSentRecord(
596 : : struct SolidSyslogRecordStore* recordStore,
597 : : struct SolidSyslogBlockDevice* blockDevice,
598 : : size_t blockIndex,
599 : : size_t* cursor,
600 : : size_t blockSize,
601 : : enum SolidSyslogRecordStoreScanResult* scanned
602 : : );
603 : : static inline enum SolidSyslogRecordStoreReadResult RecordStore_IsRecordSentOrDiscarded(
604 : : const struct SolidSyslogRecordStore* recordStore,
605 : : struct SolidSyslogBlockDevice* blockDevice,
606 : : size_t blockIndex,
607 : : size_t recordStart,
608 : : uint16_t length,
609 : : size_t blockSize,
610 : : bool* finishedWith
611 : : );
612 : : static inline void RecordStore_SkipRecord(
613 : : const struct SolidSyslogRecordStore* recordStore,
614 : : size_t* cursor,
615 : : uint16_t length
616 : : );
617 : :
618 : 18911 : size_t SolidSyslogRecordStore_FindFirstUnsent(
619 : : struct SolidSyslogRecordStore* recordStore,
620 : : struct SolidSyslogBlockDevice* blockDevice,
621 : : size_t blockIndex,
622 : : size_t blockSize,
623 : : enum SolidSyslogRecordStoreScanResult* scanned
624 : : )
625 : : {
626 : 18911 : size_t cursor = 0U;
627 : 18911 : bool scanning = true;
628 : 18911 : *scanned = SOLIDSYSLOG_RECORD_STORE_SCAN_CLEAN;
629 : :
630 [ + + + + ]: 54214 : while (scanning && (cursor < blockSize))
631 : : {
632 : 35303 : scanning = RecordStore_AdvancePastSentRecord(recordStore, blockDevice, blockIndex, &cursor, blockSize, scanned);
633 : : }
634 : :
635 : 18911 : return cursor;
636 : : }
637 : :
638 : 35303 : static bool RecordStore_AdvancePastSentRecord(
639 : : struct SolidSyslogRecordStore* recordStore,
640 : : struct SolidSyslogBlockDevice* blockDevice,
641 : : size_t blockIndex,
642 : : size_t* cursor,
643 : : size_t blockSize,
644 : : enum SolidSyslogRecordStoreScanResult* scanned
645 : : )
646 : : {
647 : 35303 : uint16_t length = 0U;
648 : 35303 : bool finishedWith = false;
649 : 35303 : bool advanced = false;
650 : : /* The flag says whether the record is still wanted; only a read of a wanted
651 : : * record verifies it, so the policy is not run over records already sent. */
652 : : enum SolidSyslogRecordStoreReadResult result =
653 : 35303 : RecordStore_ReadRecordExtent(recordStore, blockDevice, blockIndex, *cursor, blockSize, &length);
654 : :
655 [ + + ]: 35303 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
656 : : {
657 : 34350 : result = RecordStore_IsRecordSentOrDiscarded(
658 : : recordStore,
659 : : blockDevice,
660 : : blockIndex,
661 : : *cursor,
662 : : length,
663 : : blockSize,
664 : : &finishedWith
665 : : );
666 : : }
667 : :
668 [ + + ]: 35303 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_DEVICE_FAILED)
669 : : {
670 : 128 : *cursor = blockSize;
671 : 128 : *scanned = SOLIDSYSLOG_RECORD_STORE_SCAN_DEVICE_FAILED;
672 : : }
673 [ + + ]: 35175 : else if (finishedWith)
674 : : {
675 : 27017 : RecordStore_SkipRecord(recordStore, cursor, length);
676 : 27017 : advanced = true;
677 : : }
678 [ + + ]: 8158 : else if (result == SOLIDSYSLOG_RECORD_STORE_READ_CORRUPT)
679 : : {
680 : 865 : *cursor = blockSize;
681 : 865 : *scanned = SOLIDSYSLOG_RECORD_STORE_SCAN_CORRUPT;
682 : : }
683 : : else
684 : : {
685 : : /* The first unsent record: the scan stops on it. */
686 : : }
687 : :
688 : 35303 : return advanced;
689 : : }
690 : :
691 : : /* A sent flag past the end of the data is the last byte of a record a power cut
692 : : * interrupted: the record is damaged, not sent, and no record is read as
693 : : * finished with until its flag has been. */
694 : 34350 : static inline enum SolidSyslogRecordStoreReadResult RecordStore_IsRecordSentOrDiscarded(
695 : : const struct SolidSyslogRecordStore* recordStore,
696 : : struct SolidSyslogBlockDevice* blockDevice,
697 : : size_t blockIndex,
698 : : size_t recordStart,
699 : : uint16_t length,
700 : : size_t blockSize,
701 : : bool* finishedWith
702 : : )
703 : : {
704 : 34350 : uint8_t flag = SENT_FLAG_UNSENT;
705 : 34350 : enum SolidSyslogRecordStoreReadResult result = RecordStore_ReadSpan(
706 : : blockDevice,
707 : : blockIndex,
708 : : RecordStore_SentFlagOffset(recordStore, recordStart, length),
709 : : &flag,
710 : : SENT_FLAG_SIZE,
711 : : blockSize
712 : : );
713 : 34350 : *finishedWith = RecordStore_FlagMarksSentOrDiscarded(flag);
714 : 34350 : return result;
715 : : }
716 : :
717 : 77375 : static inline void RecordStore_SkipRecord(
718 : : const struct SolidSyslogRecordStore* recordStore,
719 : : size_t* cursor,
720 : : uint16_t length
721 : : )
722 : : {
723 : 77375 : *cursor += SolidSyslogRecordStore_RecordSize(recordStore, length);
724 : 77375 : }
725 : :
726 : : static inline enum SolidSyslogRecordStoreScanResult RecordStore_ScanResultOf(
727 : : enum SolidSyslogRecordStoreReadResult result
728 : : );
729 : :
730 : : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- blockIndex, cursor and blockSize are a block, a position in it and a bound; distinct semantics
731 : 18669 : enum SolidSyslogRecordStoreScanResult SolidSyslogRecordStore_ScanToEnd(
732 : : struct SolidSyslogRecordStore* recordStore,
733 : : struct SolidSyslogBlockDevice* blockDevice,
734 : : size_t blockIndex,
735 : : size_t cursor,
736 : : size_t blockSize
737 : : )
738 : : {
739 : 18669 : size_t position = cursor;
740 : 18669 : enum SolidSyslogRecordStoreScanResult scanned = SOLIDSYSLOG_RECORD_STORE_SCAN_CLEAN;
741 : :
742 [ + + + + ]: 70369 : while ((scanned == SOLIDSYSLOG_RECORD_STORE_SCAN_CLEAN) && (position < blockSize))
743 : : {
744 : 51700 : uint16_t length = 0U;
745 : : enum SolidSyslogRecordStoreReadResult result =
746 : 51700 : RecordStore_ReadRecordExtent(recordStore, blockDevice, blockIndex, position, blockSize, &length);
747 : :
748 [ + + ]: 51700 : if (result == SOLIDSYSLOG_RECORD_STORE_READ_SUCCEEDED)
749 : : {
750 : 50358 : RecordStore_SkipRecord(recordStore, &position, length);
751 : : }
752 : : else
753 : : {
754 : 1342 : scanned = RecordStore_ScanResultOf(result);
755 : : }
756 : : }
757 : :
758 : 18669 : return scanned;
759 : : }
760 : :
761 : : // NOLINTEND(bugprone-easily-swappable-parameters)
762 : :
763 : : /* What a record that would not read means for the block: a device that failed,
764 : : * or data that is corrupt. */
765 : 1342 : static inline enum SolidSyslogRecordStoreScanResult RecordStore_ScanResultOf(
766 : : enum SolidSyslogRecordStoreReadResult result
767 : : )
768 : : {
769 : : return (result == SOLIDSYSLOG_RECORD_STORE_READ_DEVICE_FAILED) ? SOLIDSYSLOG_RECORD_STORE_SCAN_DEVICE_FAILED
770 [ + + ]: 1342 : : SOLIDSYSLOG_RECORD_STORE_SCAN_CORRUPT;
771 : : }
|