SolidSyslog coverage report
Current view: top level - Platform/LittleFs/Source - SolidSyslogLittleFsFile.c (source / functions) Coverage Total Hit
Test: SolidSyslog Lines: 100.0 % 108 108
Test Date: 2026-11-12 23:14:35 Functions: 100.0 % 18 18
Branches: 100.0 % 40 40

             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 "SolidSyslogLittleFsFile.h"
       6                 :             : 
       7                 :             : #include <stdbool.h>
       8                 :             : #include <stddef.h>
       9                 :             : #include <stdint.h>
      10                 :             : 
      11                 :             : #include "SolidSyslogError.h"
      12                 :             : #include "SolidSyslogErrorCategory.h"
      13                 :             : #include "SolidSyslogFileCategories.h"
      14                 :             : #include "SolidSyslogFileDefinition.h"
      15                 :             : #include "SolidSyslogLittleFsFilePrivate.h"
      16                 :             : #include "SolidSyslogNullFile.h"
      17                 :             : #include "lfs.h"
      18                 :             : 
      19                 :             : const struct SolidSyslogErrorSource SolidSyslogLittleFsFileErrorSource = {"LittleFsFile", SolidSyslogFileErrors_Name};
      20                 :             : 
      21                 :             : /* The File contract says Open creates the file when absent and never truncates
      22                 :             :  * an existing one. */
      23                 :             : #define LITTLEFSFILE_READ_WRITE_OR_CREATE (LFS_O_RDWR | LFS_O_CREAT)
      24                 :             : 
      25                 :             : static bool LittleFsFile_Open(struct SolidSyslogFile* base, const char* path);
      26                 :             : static void LittleFsFile_Close(struct SolidSyslogFile* base);
      27                 :             : static bool LittleFsFile_IsOpen(struct SolidSyslogFile* base);
      28                 :             : static bool LittleFsFile_Read(struct SolidSyslogFile* base, void* buf, size_t count);
      29                 :             : static bool LittleFsFile_Write(struct SolidSyslogFile* base, const void* buf, size_t count);
      30                 :             : static void LittleFsFile_SeekTo(struct SolidSyslogFile* base, size_t offset);
      31                 :             : static bool LittleFsFile_Size(struct SolidSyslogFile* base, size_t* size);
      32                 :             : static void LittleFsFile_Truncate(struct SolidSyslogFile* base);
      33                 :             : static bool LittleFsFile_Exists(struct SolidSyslogFile* base, const char* path);
      34                 :             : static bool LittleFsFile_Delete(struct SolidSyslogFile* base, const char* path);
      35                 :             : 
      36                 :             : static inline struct SolidSyslogLittleFsFile* LittleFsFile_SelfFromBase(struct SolidSyslogFile* base);
      37                 :             : static inline bool LittleFsFile_IsValidSetup(const lfs_t* filesystem, const void* fileBuffer, uint32_t fileBufferBytes);
      38                 :             : static inline void LittleFsFile_ReportFailure(enum SolidSyslogFileErrors code, int nativeCode);
      39                 :             : static inline bool LittleFsFile_IsWholeTransfer(lfs_ssize_t transferred, size_t count);
      40                 :             : static inline bool LittleFsFile_Sync(struct SolidSyslogLittleFsFile* self);
      41                 :             : static inline int LittleFsFile_SeekToStart(struct SolidSyslogLittleFsFile* self);
      42                 :             : 
      43                 :          55 : bool SolidSyslogLittleFsFile_Initialise(
      44                 :             :     struct SolidSyslogFile* base,
      45                 :             :     lfs_t* filesystem,
      46                 :             :     void* fileBuffer,
      47                 :             :     uint32_t fileBufferBytes
      48                 :             : )
      49                 :             : {
      50                 :          55 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
      51                 :          55 :     bool valid = LittleFsFile_IsValidSetup(filesystem, fileBuffer, fileBufferBytes);
      52                 :             :     /* Start from the Null vtable so any slot this adapter has not filled is a
      53                 :             :      * safe no-op rather than a NULL dispatch. */
      54                 :          55 :     self->Base = *SolidSyslogNullFile_Get();
      55         [ +  + ]:          55 :     if (valid == true)
      56                 :             :     {
      57                 :          51 :         self->Filesystem = filesystem;
      58                 :          51 :         self->OpenConfig.buffer = fileBuffer;
      59                 :          51 :         self->Base.Open = LittleFsFile_Open;
      60                 :          51 :         self->Base.Close = LittleFsFile_Close;
      61                 :          51 :         self->Base.IsOpen = LittleFsFile_IsOpen;
      62                 :          51 :         self->Base.Read = LittleFsFile_Read;
      63                 :          51 :         self->Base.Write = LittleFsFile_Write;
      64                 :          51 :         self->Base.SeekTo = LittleFsFile_SeekTo;
      65                 :          51 :         self->Base.Size = LittleFsFile_Size;
      66                 :          51 :         self->Base.Truncate = LittleFsFile_Truncate;
      67                 :          51 :         self->Base.Exists = LittleFsFile_Exists;
      68                 :          51 :         self->Base.Delete = LittleFsFile_Delete;
      69                 :          51 :         self->IsOpen = false;
      70                 :             :     }
      71                 :          55 :     return valid;
      72                 :             : }
      73                 :             : 
      74                 :        1258 : static inline struct SolidSyslogLittleFsFile* LittleFsFile_SelfFromBase(struct SolidSyslogFile* base)
      75                 :             : {
      76                 :        1258 :     return (struct SolidSyslogLittleFsFile*) base;
      77                 :             : }
      78                 :             : 
      79                 :             : /* Checked here rather than at Open so a wiring fault is one report at Create
      80                 :             :  * instead of a surprise on the first record the store writes. The size cannot
      81                 :             :  * change later: cache_size is fixed when the integrator mounts. */
      82                 :          55 : static inline bool LittleFsFile_IsValidSetup(const lfs_t* filesystem, const void* fileBuffer, uint32_t fileBufferBytes)
      83                 :             : {
      84                 :          55 :     bool valid = false;
      85         [ +  + ]:          55 :     if (filesystem == NULL)
      86                 :             :     {
      87                 :           2 :         LittleFsFile_Report(
      88                 :             :             SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
      89                 :             :             SOLIDSYSLOG_CAT_BAD_CONFIG,
      90                 :             :             SOLIDSYSLOG_FILE_ERROR_NULL_FILESYSTEM
      91                 :             :         );
      92                 :             :     }
      93   [ +  +  +  + ]:          53 :     else if ((fileBuffer == NULL) || (fileBufferBytes < filesystem->cfg->cache_size))
      94                 :             :     {
      95                 :           2 :         LittleFsFile_Report(
      96                 :             :             SOLIDSYSLOG_BAD_CONFIG_FATAL_SEVERITY,
      97                 :             :             SOLIDSYSLOG_CAT_BAD_CONFIG,
      98                 :             :             SOLIDSYSLOG_FILE_ERROR_BUFFER_TOO_SMALL
      99                 :             :         );
     100                 :             :     }
     101                 :             :     else
     102                 :             :     {
     103                 :          51 :         valid = true;
     104                 :             :     }
     105                 :          55 :     return valid;
     106                 :             : }
     107                 :             : 
     108                 :          55 : void SolidSyslogLittleFsFile_Cleanup(struct SolidSyslogFile* base)
     109                 :             : {
     110                 :             :     /* Close first: the slot is about to be reusable, and LittleFS would
     111                 :             :      * otherwise keep a file open against a buffer the caller may reclaim. */
     112                 :          55 :     LittleFsFile_Close(base);
     113                 :             :     /* Overwrite the abstract base with the shared NullFile vtable so
     114                 :             :      * use-after-destroy is a safe no-op rather than a NULL-fn-pointer crash. */
     115                 :          55 :     *base = *SolidSyslogNullFile_Get();
     116                 :          55 : }
     117                 :             : 
     118                 :          36 : static bool LittleFsFile_Open(struct SolidSyslogFile* base, const char* path)
     119                 :             : {
     120                 :          36 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     121                 :             :     int result =
     122                 :          36 :         lfs_file_opencfg(self->Filesystem, &self->Handle, path, LITTLEFSFILE_READ_WRITE_OR_CREATE, &self->OpenConfig);
     123                 :          36 :     self->IsOpen = (result == LFS_ERR_OK);
     124         [ +  + ]:          36 :     if (!self->IsOpen)
     125                 :             :     {
     126                 :           1 :         LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_OPEN_FAILED, result);
     127                 :             :     }
     128                 :          36 :     return self->IsOpen;
     129                 :             : }
     130                 :             : 
     131                 :             : /* The fault, with the negative lfs code behind it when the call answered one.
     132                 :             :  * A short transfer answers a count, not a code. */
     133                 :             : // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -- every caller passes a named code and the result it read
     134                 :          18 : static inline void LittleFsFile_ReportFailure(enum SolidSyslogFileErrors code, int nativeCode)
     135                 :             : {
     136         [ +  + ]:          18 :     if (nativeCode != LFS_ERR_OK)
     137                 :             :     {
     138                 :          16 :         SolidSyslog_ErrorWithNativeCode(
     139                 :             :             SOLIDSYSLOG_FILE_IO_FAILED_SEVERITY,
     140                 :             :             &SolidSyslogLittleFsFileErrorSource,
     141                 :             :             SOLIDSYSLOG_CAT_FILE_IO_FAILED,
     142                 :             :             (int32_t) code,
     143                 :             :             (int32_t) nativeCode
     144                 :             :         );
     145                 :             :     }
     146                 :             :     else
     147                 :             :     {
     148                 :           2 :         LittleFsFile_Report(SOLIDSYSLOG_FILE_IO_FAILED_SEVERITY, SOLIDSYSLOG_CAT_FILE_IO_FAILED, code);
     149                 :             :     }
     150                 :          18 : }
     151                 :             : 
     152                 :          68 : static void LittleFsFile_Close(struct SolidSyslogFile* base)
     153                 :             : {
     154                 :          68 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     155         [ +  + ]:          68 :     if (self->IsOpen)
     156                 :             :     {
     157                 :          35 :         int result = lfs_file_close(self->Filesystem, &self->Handle);
     158                 :             :         /* The file is released whether or not the close could flush. */
     159                 :          35 :         self->IsOpen = false;
     160         [ +  + ]:          35 :         if (result != LFS_ERR_OK)
     161                 :             :         {
     162                 :           2 :             LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_CLOSE_FAILED, result);
     163                 :             :         }
     164                 :             :     }
     165                 :          68 : }
     166                 :             : 
     167                 :          66 : static bool LittleFsFile_IsOpen(struct SolidSyslogFile* base)
     168                 :             : {
     169                 :          66 :     return LittleFsFile_SelfFromBase(base)->IsOpen;
     170                 :             : }
     171                 :             : 
     172                 :          33 : static bool LittleFsFile_Read(struct SolidSyslogFile* base, void* buf, size_t count)
     173                 :             : {
     174                 :          33 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     175                 :          33 :     lfs_ssize_t read = lfs_file_read(self->Filesystem, &self->Handle, buf, (lfs_size_t) count);
     176                 :             :     /* A short read answers a count, which the store judges; a failure answers
     177                 :             :      * a negative code. The contract fails them the same way. */
     178         [ +  + ]:          33 :     if (read < 0)
     179                 :             :     {
     180                 :           1 :         LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_READ_FAILED, (int) read);
     181                 :             :     }
     182                 :          33 :     return LittleFsFile_IsWholeTransfer(read, count);
     183                 :             : }
     184                 :             : 
     185                 :             : /* lfs_file_read and lfs_file_write answer a negative code, or how many bytes
     186                 :             :  * moved. */
     187                 :          55 : static inline bool LittleFsFile_IsWholeTransfer(lfs_ssize_t transferred, size_t count)
     188                 :             : {
     189   [ +  +  +  + ]:          55 :     return (transferred >= 0) && ((size_t) transferred == count);
     190                 :             : }
     191                 :             : 
     192                 :          22 : static bool LittleFsFile_Write(struct SolidSyslogFile* base, const void* buf, size_t count)
     193                 :             : {
     194                 :          22 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     195                 :          22 :     lfs_ssize_t written = lfs_file_write(self->Filesystem, &self->Handle, buf, (lfs_size_t) count);
     196                 :          22 :     bool wroteAllData = LittleFsFile_IsWholeTransfer(written, count);
     197         [ +  + ]:          22 :     if (wroteAllData)
     198                 :             :     {
     199                 :             :         /* The File contract makes a true return mean the bytes are on the media:
     200                 :             :          * the BlockStore treats it as durable across power loss, so the sync is
     201                 :             :          * part of the write rather than something a caller arranges. */
     202                 :          19 :         wroteAllData = LittleFsFile_Sync(self);
     203                 :             :     }
     204                 :             :     else
     205                 :             :     {
     206                 :             :         /* A short write has no code behind it. */
     207                 :           3 :         LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_WRITE_FAILED, (written < 0) ? (int) written : LFS_ERR_OK);
     208                 :             :     }
     209                 :          22 :     return wroteAllData;
     210                 :             : }
     211                 :             : 
     212                 :          19 : static inline bool LittleFsFile_Sync(struct SolidSyslogLittleFsFile* self)
     213                 :             : {
     214                 :          19 :     int result = lfs_file_sync(self->Filesystem, &self->Handle);
     215         [ +  + ]:          19 :     if (result != LFS_ERR_OK)
     216                 :             :     {
     217                 :           6 :         LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_SYNC_FAILED, result);
     218                 :             :     }
     219                 :          19 :     return result == LFS_ERR_OK;
     220                 :             : }
     221                 :             : 
     222                 :          46 : static void LittleFsFile_SeekTo(struct SolidSyslogFile* base, size_t offset)
     223                 :             : {
     224                 :          46 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     225                 :          46 :     lfs_soff_t position = lfs_file_seek(self->Filesystem, &self->Handle, (lfs_soff_t) offset, LFS_SEEK_SET);
     226                 :             :     /* lfs answers the new position, or a negative code. */
     227         [ +  + ]:          46 :     if (position < 0)
     228                 :             :     {
     229                 :           1 :         LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_SEEK_FAILED, (int) position);
     230                 :             :     }
     231                 :          46 : }
     232                 :             : 
     233                 :          18 : static bool LittleFsFile_Size(struct SolidSyslogFile* base, size_t* size)
     234                 :             : {
     235                 :          18 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     236                 :          18 :     lfs_soff_t length = lfs_file_size(self->Filesystem, &self->Handle);
     237                 :             :     /* lfs reports an error as a negative value. */
     238                 :          18 :     bool known = length >= 0;
     239         [ +  + ]:          18 :     if (!known)
     240                 :             :     {
     241                 :           2 :         LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_SIZE_FAILED, (int) length);
     242                 :             :     }
     243         [ +  + ]:          18 :     *size = known ? (size_t) length : 0U;
     244                 :          18 :     return known;
     245                 :             : }
     246                 :             : 
     247                 :             : /* Seek as well as truncate: the contract leaves the file open at length zero,
     248                 :             :  * and the shared position would otherwise sit past the new end. The seek is
     249                 :             :  * part of the truncate, so either step failing is the truncate failing. */
     250                 :           9 : static void LittleFsFile_Truncate(struct SolidSyslogFile* base)
     251                 :             : {
     252                 :           9 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     253                 :           9 :     int result = lfs_file_truncate(self->Filesystem, &self->Handle, 0);
     254         [ +  + ]:           9 :     if (result == LFS_ERR_OK)
     255                 :             :     {
     256                 :           8 :         result = LittleFsFile_SeekToStart(self);
     257                 :             :     }
     258         [ +  + ]:           9 :     if (result != LFS_ERR_OK)
     259                 :             :     {
     260                 :           2 :         LittleFsFile_ReportFailure(SOLIDSYSLOG_FILE_ERROR_TRUNCATE_FAILED, result);
     261                 :             :     }
     262                 :           9 : }
     263                 :             : 
     264                 :             : /* LFS_ERR_OK, or the negative code the seek answered. */
     265                 :           8 : static inline int LittleFsFile_SeekToStart(struct SolidSyslogLittleFsFile* self)
     266                 :             : {
     267                 :           8 :     lfs_soff_t position = lfs_file_seek(self->Filesystem, &self->Handle, 0, LFS_SEEK_SET);
     268                 :           8 :     return (position < 0) ? (int) position : LFS_ERR_OK;
     269                 :             : }
     270                 :             : 
     271                 :             : /* A path that is not there is the answer, not a fault, so nothing is reported. */
     272                 :         902 : static bool LittleFsFile_Exists(struct SolidSyslogFile* base, const char* path)
     273                 :             : {
     274                 :         902 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     275                 :             :     struct lfs_info info;
     276                 :         902 :     return lfs_stat(self->Filesystem, path, &info) == LFS_ERR_OK;
     277                 :             : }
     278                 :             : 
     279                 :           3 : static bool LittleFsFile_Delete(struct SolidSyslogFile* base, const char* path)
     280                 :             : {
     281                 :           3 :     struct SolidSyslogLittleFsFile* self = LittleFsFile_SelfFromBase(base);
     282                 :           3 :     int result = lfs_remove(self->Filesystem, path);
     283                 :             :     /* The contract counts an absent path as removed. */
     284   [ +  +  +  + ]:           3 :     return (result == LFS_ERR_OK) || (result == LFS_ERR_NOENT);
     285                 :             : }
        

Generated by: LCOV version 2.0-1