SolidSyslog coverage report
Current view: top level - Core/Source - SolidSyslogRecordStore.c (source / functions) Coverage Total Hit
Test: SolidSyslog Lines: 100.0 % 213 213
Test Date: 2026-11-12 23:14:35 Functions: 100.0 % 42 42
Branches: 100.0 % 80 80

             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                 :             : }
        

Generated by: LCOV version 2.0-1