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

             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 "SolidSyslogFileBlockDevice.h"
       6                 :             : 
       7                 :             : #include <stdbool.h>
       8                 :             : #include <stddef.h>
       9                 :             : #include <stdint.h>
      10                 :             : 
      11                 :             : #include "SolidSyslogBlockDeviceDefinition.h"
      12                 :             : #include "SolidSyslogError.h"
      13                 :             : #include "SolidSyslogFile.h"
      14                 :             : #include "SolidSyslogFileBlockDeviceErrors.h"
      15                 :             : #include "SolidSyslogFileBlockDevicePrivate.h"
      16                 :             : #include "SolidSyslogFormatter.h"
      17                 :             : #include "SolidSyslogNullBlockDevice.h"
      18                 :             : #include "SolidSyslogTunables.h"
      19                 :             : 
      20                 :             : const struct SolidSyslogErrorSource SolidSyslogFileBlockDeviceErrorSource = {
      21                 :             :     "FileBlockDevice",
      22                 :             :     SolidSyslogFileBlockDeviceErrors_Name
      23                 :             : };
      24                 :             : 
      25                 :             : struct SolidSyslogFile;
      26                 :             : 
      27                 :             : static const char FILE_EXTENSION[] = ".log";
      28                 :             : 
      29                 :             : enum
      30                 :             : {
      31                 :             :     SEQUENCE_DIGITS = 2U,
      32                 :             :     FILENAME_SUFFIX = SEQUENCE_DIGITS + sizeof(FILE_EXTENSION) - 1U,
      33                 :             :     MAX_PREFIX_LENGTH = (size_t) SOLIDSYSLOG_MAX_PATH_SIZE - (size_t) FILENAME_SUFFIX - 1U,
      34                 :             :     /* Two-digit on-disk sequence - indices > 99 cannot be represented
      35                 :             :      * uniquely. Without this guard, a wide blockIndex would be narrowed
      36                 :             :      * to uint8_t and alias an existing block (256 -> 00). */
      37                 :             :     MAX_BLOCK_INDEX = 99U
      38                 :             : };
      39                 :             : 
      40                 :       31735 : static inline bool FileBlockDevice_IsValidBlockIndex(size_t blockIndex)
      41                 :             : {
      42                 :       31735 :     return blockIndex <= MAX_BLOCK_INDEX;
      43                 :             : }
      44                 :             : 
      45                 :             : /* vtable - forward-declared because SolidSyslogFileBlockDevice_Initialise wires them before their definitions */
      46                 :             : static bool FileBlockDevice_Acquire(struct SolidSyslogBlockDevice* base, size_t blockIndex);
      47                 :             : static bool FileBlockDevice_Dispose(struct SolidSyslogBlockDevice* base, size_t blockIndex);
      48                 :             : static bool FileBlockDevice_Exists(struct SolidSyslogBlockDevice* base, size_t blockIndex);
      49                 :             : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- vtable signature: blockIndex / offset are positional, distinct semantics
      50                 :             : static bool FileBlockDevice_Read(
      51                 :             :     struct SolidSyslogBlockDevice* base,
      52                 :             :     size_t blockIndex,
      53                 :             :     size_t offset,
      54                 :             :     void* buf,
      55                 :             :     size_t count
      56                 :             : );
      57                 :             : // NOLINTEND(bugprone-easily-swappable-parameters)
      58                 :             : static bool FileBlockDevice_Append(
      59                 :             :     struct SolidSyslogBlockDevice* base,
      60                 :             :     size_t blockIndex,
      61                 :             :     const void* buf,
      62                 :             :     size_t count
      63                 :             : );
      64                 :             : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- vtable signature: blockIndex / offset are positional, distinct semantics
      65                 :             : static bool FileBlockDevice_WriteAt(
      66                 :             :     struct SolidSyslogBlockDevice* base,
      67                 :             :     size_t blockIndex,
      68                 :             :     size_t offset,
      69                 :             :     const void* buf,
      70                 :             :     size_t count
      71                 :             : );
      72                 :             : // NOLINTEND(bugprone-easily-swappable-parameters)
      73                 :             : static bool FileBlockDevice_Size(struct SolidSyslogBlockDevice* base, size_t blockIndex, size_t* size);
      74                 :             : static size_t FileBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice* base);
      75                 :             : 
      76                 :             : static inline struct SolidSyslogFileBlockDevice* FileBlockDevice_SelfFromBase(struct SolidSyslogBlockDevice* base);
      77                 :             : static inline void FileBlockDevice_CloseIfOpen(struct OpenHandle* handle);
      78                 :             : 
      79                 :         352 : void SolidSyslogFileBlockDevice_Initialise(
      80                 :             :     struct SolidSyslogBlockDevice* base,
      81                 :             :     struct SolidSyslogFile* file,
      82                 :             :     const char* pathPrefix,
      83                 :             :     size_t blockSize
      84                 :             : )
      85                 :             : {
      86                 :         352 :     struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
      87                 :         352 :     self->Base.Acquire = FileBlockDevice_Acquire;
      88                 :         352 :     self->Base.Dispose = FileBlockDevice_Dispose;
      89                 :         352 :     self->Base.Exists = FileBlockDevice_Exists;
      90                 :         352 :     self->Base.Read = FileBlockDevice_Read;
      91                 :         352 :     self->Base.Append = FileBlockDevice_Append;
      92                 :         352 :     self->Base.WriteAt = FileBlockDevice_WriteAt;
      93                 :         352 :     self->Base.Size = FileBlockDevice_Size;
      94                 :         352 :     self->Base.GetBlockSize = FileBlockDevice_GetBlockSize;
      95                 :         352 :     self->Handle = (struct OpenHandle) {.File = file, .BlockIndex = 0, .IsOpen = false};
      96                 :         352 :     self->PathPrefix = pathPrefix;
      97                 :         352 :     self->BlockSize = blockSize;
      98                 :         352 : }
      99                 :             : 
     100                 :         352 : void SolidSyslogFileBlockDevice_Cleanup(struct SolidSyslogBlockDevice* base)
     101                 :             : {
     102                 :             :     /* Close the cached file handle while we can still see it; then overwrite the
     103                 :             :      * abstract base with the shared NullBlockDevice vtable so use-after-destroy is
     104                 :             :      * a safe no-op rather than a NULL-fn-pointer crash. Derived fields are private
     105                 :             :      * to this TU; the next SolidSyslogFileBlockDevice_Initialise overwrites them. */
     106                 :         352 :     struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     107                 :         352 :     FileBlockDevice_CloseIfOpen(&self->Handle);
     108                 :         352 :     *base = *SolidSyslogNullBlockDevice_Get();
     109                 :         352 : }
     110                 :             : 
     111                 :       33050 : static inline struct SolidSyslogFileBlockDevice* FileBlockDevice_SelfFromBase(struct SolidSyslogBlockDevice* base)
     112                 :             : {
     113                 :       33050 :     return (struct SolidSyslogFileBlockDevice*) base;
     114                 :             : }
     115                 :             : 
     116                 :         352 : static inline void FileBlockDevice_CloseIfOpen(struct OpenHandle* handle)
     117                 :             : {
     118         [ +  + ]:         352 :     if (handle->IsOpen)
     119                 :             :     {
     120                 :         229 :         SolidSyslogFile_Close(handle->File);
     121                 :         229 :         handle->IsOpen = false;
     122                 :             :     }
     123                 :         352 : }
     124                 :             : 
     125                 :             : static bool FileBlockDevice_EnsureHandleOpenOnBlock(
     126                 :             :     struct OpenHandle* handle,
     127                 :             :     const struct SolidSyslogFileBlockDevice* self,
     128                 :             :     size_t blockIndex
     129                 :             : );
     130                 :             : static bool FileBlockDevice_OpenHandleOnBlock(
     131                 :             :     struct OpenHandle* handle,
     132                 :             :     const struct SolidSyslogFileBlockDevice* self,
     133                 :             :     size_t blockIndex
     134                 :             : );
     135                 :             : static inline const char* FileBlockDevice_FormatBlockFilename(
     136                 :             :     const struct SolidSyslogFileBlockDevice* self,
     137                 :             :     SolidSyslogFormatterStorage* storage,
     138                 :             :     size_t blockIndex
     139                 :             : );
     140                 :             : 
     141                 :         476 : static bool FileBlockDevice_Acquire(struct SolidSyslogBlockDevice* base, size_t blockIndex)
     142                 :             : {
     143                 :         476 :     bool ready = false;
     144                 :             : 
     145         [ +  + ]:         476 :     if (FileBlockDevice_IsValidBlockIndex(blockIndex))
     146                 :             :     {
     147                 :         473 :         struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     148                 :         473 :         ready = FileBlockDevice_EnsureHandleOpenOnBlock(&self->Handle, self, blockIndex);
     149                 :             : 
     150         [ +  + ]:         473 :         if (ready)
     151                 :             :         {
     152                 :         466 :             SolidSyslogFile_Truncate(self->Handle.File);
     153                 :             :         }
     154                 :             :     }
     155                 :             : 
     156                 :         476 :     return ready;
     157                 :             : }
     158                 :             : 
     159                 :        5368 : static inline bool FileBlockDevice_IsHandleAlreadyOpenOnBlock(
     160                 :             :     const struct OpenHandle* handle,
     161                 :             :     bool underlyingFileIsOpen,
     162                 :             :     size_t blockIndex
     163                 :             : )
     164                 :             : {
     165   [ +  +  +  +  :        5368 :     return handle->IsOpen && underlyingFileIsOpen && (handle->BlockIndex == blockIndex);
                   +  + ]
     166                 :             : }
     167                 :             : 
     168                 :        5368 : static bool FileBlockDevice_EnsureHandleOpenOnBlock(
     169                 :             :     struct OpenHandle* handle,
     170                 :             :     const struct SolidSyslogFileBlockDevice* self,
     171                 :             :     size_t blockIndex
     172                 :             : )
     173                 :             : {
     174                 :        5368 :     bool underlyingFileIsOpen = SolidSyslogFile_IsOpen(handle->File);
     175                 :        5368 :     bool ready = FileBlockDevice_IsHandleAlreadyOpenOnBlock(handle, underlyingFileIsOpen, blockIndex);
     176                 :             : 
     177         [ +  + ]:        5368 :     if (!ready)
     178                 :             :     {
     179                 :        1081 :         ready = FileBlockDevice_OpenHandleOnBlock(handle, self, blockIndex);
     180                 :             :     }
     181                 :             : 
     182                 :        5368 :     return ready;
     183                 :             : }
     184                 :             : 
     185                 :        1081 : static bool FileBlockDevice_OpenHandleOnBlock(
     186                 :             :     struct OpenHandle* handle,
     187                 :             :     const struct SolidSyslogFileBlockDevice* self,
     188                 :             :     size_t blockIndex
     189                 :             : )
     190                 :             : {
     191         [ +  + ]:        1081 :     if (SolidSyslogFile_IsOpen(handle->File))
     192                 :             :     {
     193                 :         748 :         SolidSyslogFile_Close(handle->File);
     194                 :             :     }
     195                 :        1081 :     handle->IsOpen = false;
     196                 :             : 
     197                 :             :     SolidSyslogFormatterStorage nameStorage[SOLIDSYSLOG_FORMATTER_STORAGE_SIZE(SOLIDSYSLOG_MAX_PATH_SIZE)];
     198                 :        1081 :     const char* name = FileBlockDevice_FormatBlockFilename(self, nameStorage, blockIndex);
     199                 :             : 
     200                 :        1081 :     bool opened = SolidSyslogFile_Open(handle->File, name);
     201                 :             : 
     202         [ +  + ]:        1081 :     if (opened)
     203                 :             :     {
     204                 :        1067 :         handle->BlockIndex = blockIndex;
     205                 :        1067 :         handle->IsOpen = true;
     206                 :             :     }
     207                 :             : 
     208                 :        1081 :     return opened;
     209                 :             : }
     210                 :             : 
     211                 :       27439 : static inline const char* FileBlockDevice_FormatBlockFilename(
     212                 :             :     const struct SolidSyslogFileBlockDevice* self,
     213                 :             :     SolidSyslogFormatterStorage* storage,
     214                 :             :     size_t blockIndex
     215                 :             : )
     216                 :             : {
     217                 :       27439 :     struct SolidSyslogFormatter* formatter = SolidSyslogFormatter_Create(storage, SOLIDSYSLOG_MAX_PATH_SIZE);
     218                 :             : 
     219                 :       27439 :     SolidSyslogFormatter_BoundedString(formatter, self->PathPrefix, MAX_PREFIX_LENGTH);
     220                 :       27439 :     SolidSyslogFormatter_TwoDigit(formatter, (uint8_t) blockIndex);
     221                 :       27439 :     SolidSyslogFormatter_BoundedString(formatter, FILE_EXTENSION, sizeof(FILE_EXTENSION) - 1U);
     222                 :             : 
     223                 :       27439 :     return SolidSyslogFormatter_AsFormattedBuffer(formatter);
     224                 :             : }
     225                 :             : 
     226                 :             : static inline void FileBlockDevice_CloseIfHoldingBlock(struct OpenHandle* handle, size_t blockIndex);
     227                 :             : 
     228                 :         110 : static bool FileBlockDevice_Dispose(struct SolidSyslogBlockDevice* base, size_t blockIndex)
     229                 :             : {
     230                 :         110 :     bool disposed = false;
     231                 :             : 
     232         [ +  + ]:         110 :     if (FileBlockDevice_IsValidBlockIndex(blockIndex))
     233                 :             :     {
     234                 :         109 :         struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     235                 :             : 
     236                 :         109 :         FileBlockDevice_CloseIfHoldingBlock(&self->Handle, blockIndex);
     237                 :             : 
     238                 :             :         SolidSyslogFormatterStorage nameStorage[SOLIDSYSLOG_FORMATTER_STORAGE_SIZE(SOLIDSYSLOG_MAX_PATH_SIZE)];
     239                 :         109 :         const char* name = FileBlockDevice_FormatBlockFilename(self, nameStorage, blockIndex);
     240                 :         109 :         disposed = SolidSyslogFile_Delete(self->Handle.File, name);
     241                 :             :     }
     242                 :             : 
     243                 :         110 :     return disposed;
     244                 :             : }
     245                 :             : 
     246                 :         109 : static inline void FileBlockDevice_CloseIfHoldingBlock(struct OpenHandle* handle, size_t blockIndex)
     247                 :             : {
     248   [ +  +  +  + ]:         109 :     if (handle->IsOpen && (handle->BlockIndex == blockIndex))
     249                 :             :     {
     250                 :          76 :         SolidSyslogFile_Close(handle->File);
     251                 :          76 :         handle->IsOpen = false;
     252                 :             :     }
     253                 :         109 : }
     254                 :             : 
     255                 :       26250 : static bool FileBlockDevice_Exists(struct SolidSyslogBlockDevice* base, size_t blockIndex)
     256                 :             : {
     257                 :       26250 :     bool exists = false;
     258                 :             : 
     259         [ +  + ]:       26250 :     if (FileBlockDevice_IsValidBlockIndex(blockIndex))
     260                 :             :     {
     261                 :       26249 :         struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     262                 :             :         SolidSyslogFormatterStorage nameStorage[SOLIDSYSLOG_FORMATTER_STORAGE_SIZE(SOLIDSYSLOG_MAX_PATH_SIZE)];
     263                 :       26249 :         const char* name = FileBlockDevice_FormatBlockFilename(self, nameStorage, blockIndex);
     264                 :       26249 :         exists = SolidSyslogFile_Exists(self->Handle.File, name);
     265                 :             :     }
     266                 :             : 
     267                 :       26250 :     return exists;
     268                 :             : }
     269                 :             : 
     270                 :             : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- vtable signature: blockIndex / offset are positional, distinct semantics
     271                 :        3125 : static bool FileBlockDevice_Read(
     272                 :             :     struct SolidSyslogBlockDevice* base,
     273                 :             :     size_t blockIndex,
     274                 :             :     size_t offset,
     275                 :             :     void* buf,
     276                 :             :     size_t count
     277                 :             : )
     278                 :             : {
     279                 :        3125 :     bool read = false;
     280                 :             : 
     281         [ +  + ]:        3125 :     if (FileBlockDevice_IsValidBlockIndex(blockIndex))
     282                 :             :     {
     283                 :        3124 :         struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     284         [ +  + ]:        3124 :         if (FileBlockDevice_EnsureHandleOpenOnBlock(&self->Handle, self, blockIndex))
     285                 :             :         {
     286                 :        3123 :             SolidSyslogFile_SeekTo(self->Handle.File, offset);
     287                 :        3123 :             read = SolidSyslogFile_Read(self->Handle.File, buf, count);
     288                 :             :         }
     289                 :             :     }
     290                 :             : 
     291                 :        3125 :     return read;
     292                 :             : }
     293                 :             : 
     294                 :             : // NOLINTEND(bugprone-easily-swappable-parameters)
     295                 :             : 
     296                 :        1102 : static bool FileBlockDevice_Append(
     297                 :             :     struct SolidSyslogBlockDevice* base,
     298                 :             :     size_t blockIndex,
     299                 :             :     const void* buf,
     300                 :             :     size_t count
     301                 :             : )
     302                 :             : {
     303                 :        1102 :     bool written = false;
     304                 :             : 
     305         [ +  + ]:        1102 :     if (FileBlockDevice_IsValidBlockIndex(blockIndex))
     306                 :             :     {
     307                 :        1101 :         struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     308         [ +  + ]:        1101 :         if (FileBlockDevice_EnsureHandleOpenOnBlock(&self->Handle, self, blockIndex))
     309                 :             :         {
     310                 :        1100 :             size_t end = 0U;
     311         [ +  + ]:        1100 :             if (SolidSyslogFile_Size(self->Handle.File, &end))
     312                 :             :             {
     313                 :        1096 :                 SolidSyslogFile_SeekTo(self->Handle.File, end);
     314                 :        1096 :                 written = SolidSyslogFile_Write(self->Handle.File, buf, count);
     315                 :             :             }
     316                 :             :         }
     317                 :             :     }
     318                 :             : 
     319                 :        1102 :     return written;
     320                 :             : }
     321                 :             : 
     322                 :             : // NOLINTBEGIN(bugprone-easily-swappable-parameters) -- vtable signature: blockIndex / offset are positional, distinct semantics
     323                 :         458 : static bool FileBlockDevice_WriteAt(
     324                 :             :     struct SolidSyslogBlockDevice* base,
     325                 :             :     size_t blockIndex,
     326                 :             :     size_t offset,
     327                 :             :     const void* buf,
     328                 :             :     size_t count
     329                 :             : )
     330                 :             : {
     331                 :         458 :     bool written = false;
     332                 :             : 
     333         [ +  + ]:         458 :     if (FileBlockDevice_IsValidBlockIndex(blockIndex))
     334                 :             :     {
     335                 :         457 :         struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     336         [ +  + ]:         457 :         if (FileBlockDevice_EnsureHandleOpenOnBlock(&self->Handle, self, blockIndex))
     337                 :             :         {
     338                 :         456 :             SolidSyslogFile_SeekTo(self->Handle.File, offset);
     339                 :         456 :             written = SolidSyslogFile_Write(self->Handle.File, buf, count);
     340                 :             :         }
     341                 :             :     }
     342                 :             : 
     343                 :         458 :     return written;
     344                 :             : }
     345                 :             : 
     346                 :             : // NOLINTEND(bugprone-easily-swappable-parameters)
     347                 :             : 
     348                 :         214 : static bool FileBlockDevice_Size(struct SolidSyslogBlockDevice* base, size_t blockIndex, size_t* size)
     349                 :             : {
     350                 :         214 :     bool known = false;
     351                 :         214 :     *size = 0U;
     352                 :             : 
     353         [ +  + ]:         214 :     if (FileBlockDevice_IsValidBlockIndex(blockIndex))
     354                 :             :     {
     355                 :         213 :         struct SolidSyslogFileBlockDevice* self = FileBlockDevice_SelfFromBase(base);
     356                 :         213 :         known = FileBlockDevice_EnsureHandleOpenOnBlock(&self->Handle, self, blockIndex);
     357                 :             : 
     358         [ +  + ]:         213 :         if (known)
     359                 :             :         {
     360                 :         209 :             known = SolidSyslogFile_Size(self->Handle.File, size);
     361                 :             :         }
     362                 :             :     }
     363                 :             : 
     364                 :         214 :     return known;
     365                 :             : }
     366                 :             : 
     367                 :         620 : static size_t FileBlockDevice_GetBlockSize(struct SolidSyslogBlockDevice* base)
     368                 :             : {
     369                 :         620 :     return FileBlockDevice_SelfFromBase(base)->BlockSize;
     370                 :             : }
        

Generated by: LCOV version 2.0-1