Coverage Report

Created: 2025-06-20 06:55

/src/connectedhomeip/src/platform/Linux/CHIPLinuxStorage.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *
3
 *    Copyright (c) 2020-2022 Project CHIP Authors
4
 *    All rights reserved.
5
 *
6
 *    Licensed under the Apache License, Version 2.0 (the "License");
7
 *    you may not use this file except in compliance with the License.
8
 *    You may obtain a copy of the License at
9
 *
10
 *        http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 *    Unless required by applicable law or agreed to in writing, software
13
 *    distributed under the License is distributed on an "AS IS" BASIS,
14
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 *    See the License for the specific language governing permissions and
16
 *    limitations under the License.
17
 */
18
19
/**
20
 *    @file
21
 *         This file implements a class for managing client application
22
 *         user-editable settings on Linux platform.
23
 *
24
 */
25
26
#include <errno.h>
27
#include <fstream>
28
#include <inttypes.h>
29
#include <libgen.h>
30
#include <string>
31
#include <unistd.h>
32
33
#include <lib/support/Base64.h>
34
#include <lib/support/CHIPMem.h>
35
#include <lib/support/CodeUtils.h>
36
#include <lib/support/ScopedBuffer.h>
37
#include <lib/support/logging/CHIPLogging.h>
38
#include <platform/Linux/CHIPLinuxStorage.h>
39
#include <platform/internal/CHIPDeviceLayerInternal.h>
40
41
namespace chip {
42
namespace DeviceLayer {
43
namespace Internal {
44
45
ChipLinuxStorage::ChipLinuxStorage()
46
8
{
47
8
    mDirty = false;
48
8
}
49
50
0
ChipLinuxStorage::~ChipLinuxStorage() {}
51
52
CHIP_ERROR ChipLinuxStorage::Init(const char * configFile)
53
4
{
54
4
    CHIP_ERROR retval = CHIP_NO_ERROR;
55
56
4
    if (mInitialized)
57
0
    {
58
0
        ChipLogError(DeviceLayer, "ChipLinuxStorage::Init: Attempt to re-initialize with KVS config file: %s",
59
0
                     StringOrNullMarker(configFile));
60
0
        return CHIP_NO_ERROR;
61
0
    }
62
63
4
    ChipLogDetail(DeviceLayer, "ChipLinuxStorage::Init: Using KVS config file: %s", StringOrNullMarker(configFile));
64
65
4
    mConfigPath.assign(configFile);
66
4
    retval = ChipLinuxStorageIni::Init();
67
68
4
    if (retval == CHIP_NO_ERROR)
69
4
    {
70
4
        std::ifstream ifs;
71
72
4
        ifs.open(configFile, std::ifstream::in);
73
74
        // Create default setting file if not exist.
75
4
        if (!ifs.good())
76
4
        {
77
4
            mDirty = true;
78
4
            retval = Commit();
79
4
            mDirty = false;
80
4
        }
81
4
    }
82
83
4
    if (retval == CHIP_NO_ERROR)
84
4
    {
85
4
        retval = ChipLinuxStorageIni::AddConfig(mConfigPath);
86
4
    }
87
88
4
    mInitialized = true;
89
90
4
    return retval;
91
4
}
92
93
CHIP_ERROR ChipLinuxStorage::ReadValue(const char * key, bool & val)
94
0
{
95
0
    CHIP_ERROR retval = CHIP_NO_ERROR;
96
0
    uint32_t result;
97
98
0
    mLock.lock();
99
100
0
    retval = ChipLinuxStorageIni::GetUIntValue(key, result);
101
0
    val    = (result != 0);
102
103
0
    mLock.unlock();
104
105
0
    return retval;
106
0
}
107
108
CHIP_ERROR ChipLinuxStorage::ReadValue(const char * key, uint16_t & val)
109
22
{
110
22
    CHIP_ERROR retval = CHIP_NO_ERROR;
111
112
22
    mLock.lock();
113
114
22
    retval = ChipLinuxStorageIni::GetUInt16Value(key, val);
115
116
22
    mLock.unlock();
117
118
22
    return retval;
119
22
}
120
121
CHIP_ERROR ChipLinuxStorage::ReadValue(const char * key, uint32_t & val)
122
3
{
123
3
    CHIP_ERROR retval = CHIP_NO_ERROR;
124
125
3
    mLock.lock();
126
127
3
    retval = ChipLinuxStorageIni::GetUIntValue(key, val);
128
129
3
    mLock.unlock();
130
131
3
    return retval;
132
3
}
133
134
CHIP_ERROR ChipLinuxStorage::ReadValue(const char * key, uint64_t & val)
135
0
{
136
0
    CHIP_ERROR retval = CHIP_NO_ERROR;
137
138
0
    mLock.lock();
139
140
0
    retval = ChipLinuxStorageIni::GetUInt64Value(key, val);
141
142
0
    mLock.unlock();
143
144
0
    return retval;
145
0
}
146
147
CHIP_ERROR ChipLinuxStorage::ReadValueStr(const char * key, char * buf, size_t bufSize, size_t & outLen)
148
1
{
149
1
    CHIP_ERROR retval = CHIP_NO_ERROR;
150
151
1
    mLock.lock();
152
153
1
    retval = ChipLinuxStorageIni::GetStringValue(key, buf, bufSize, outLen);
154
155
1
    mLock.unlock();
156
157
1
    return retval;
158
1
}
159
160
CHIP_ERROR ChipLinuxStorage::ReadValueBin(const char * key, uint8_t * buf, size_t bufSize, size_t & outLen)
161
249
{
162
249
    CHIP_ERROR retval = CHIP_NO_ERROR;
163
164
249
    mLock.lock();
165
166
249
    retval = ChipLinuxStorageIni::GetBinaryBlobValue(key, buf, bufSize, outLen);
167
168
249
    mLock.unlock();
169
170
249
    return retval;
171
249
}
172
173
CHIP_ERROR ChipLinuxStorage::WriteValue(const char * key, bool val)
174
0
{
175
0
    CHIP_ERROR retval = CHIP_NO_ERROR;
176
177
0
    if (val)
178
0
    {
179
0
        retval = WriteValue(key, static_cast<uint32_t>(1));
180
0
    }
181
0
    else
182
0
    {
183
0
        retval = WriteValue(key, static_cast<uint32_t>(0));
184
0
    }
185
186
0
    return retval;
187
0
}
188
189
CHIP_ERROR ChipLinuxStorage::WriteValue(const char * key, uint16_t val)
190
2
{
191
2
    char buf[16];
192
193
2
    snprintf(buf, sizeof(buf), "%u", val);
194
195
2
    return WriteValueStr(key, buf);
196
2
}
197
198
CHIP_ERROR ChipLinuxStorage::WriteValue(const char * key, uint32_t val)
199
7
{
200
7
    char buf[32];
201
202
7
    snprintf(buf, sizeof(buf), "%d", val);
203
204
7
    return WriteValueStr(key, buf);
205
7
}
206
207
CHIP_ERROR ChipLinuxStorage::WriteValue(const char * key, uint64_t val)
208
0
{
209
0
    char buf[64];
210
211
0
    snprintf(buf, sizeof(buf), "%" PRIu64, val);
212
213
0
    return WriteValueStr(key, buf);
214
0
}
215
216
CHIP_ERROR ChipLinuxStorage::WriteValueStr(const char * key, const char * val)
217
22
{
218
22
    CHIP_ERROR retval = CHIP_NO_ERROR;
219
220
22
    mLock.lock();
221
222
22
    retval = ChipLinuxStorageIni::AddEntry(key, val);
223
224
22
    mDirty = true;
225
226
22
    mLock.unlock();
227
228
22
    return retval;
229
22
}
230
231
CHIP_ERROR ChipLinuxStorage::WriteValueBin(const char * key, const uint8_t * data, size_t dataLen)
232
12
{
233
12
    static const size_t kMaxBlobSize = 5 * 1024;
234
235
12
    CHIP_ERROR retval = CHIP_NO_ERROR;
236
12
    chip::Platform::ScopedMemoryBuffer<char> encodedData;
237
12
    size_t encodedDataLen     = 0;
238
12
    size_t expectedEncodedLen = ((dataLen + 3) * 4) / 3;
239
240
    // We only support encoding blobs up to 5kb
241
12
    if (dataLen > kMaxBlobSize)
242
0
    {
243
0
        retval = CHIP_ERROR_INVALID_ARGUMENT;
244
0
    }
245
246
    // Compute our expectedEncodedLen
247
    // Allocate just enough space for the encoded data, and the NULL terminator
248
12
    if (retval == CHIP_NO_ERROR)
249
12
    {
250
12
        if (!encodedData.Alloc(expectedEncodedLen + 1))
251
0
        {
252
0
            retval = CHIP_ERROR_NO_MEMORY;
253
0
        }
254
12
    }
255
256
    // Encode it
257
12
    if (retval == CHIP_NO_ERROR)
258
12
    {
259
        // We tested above that dataLen is no more than kMaxBlobSize.
260
12
        static_assert(kMaxBlobSize < UINT16_MAX, "dataLen won't fit");
261
12
        encodedDataLen              = Base64Encode(data, static_cast<uint16_t>(dataLen), encodedData.Get());
262
12
        encodedData[encodedDataLen] = 0;
263
12
    }
264
265
    // Store it
266
12
    if (retval == CHIP_NO_ERROR)
267
12
    {
268
12
        WriteValueStr(key, encodedData.Get());
269
12
    }
270
271
12
    return retval;
272
12
}
273
274
CHIP_ERROR ChipLinuxStorage::ClearValue(const char * key)
275
1
{
276
1
    CHIP_ERROR retval = CHIP_NO_ERROR;
277
278
1
    mLock.lock();
279
280
1
    retval = ChipLinuxStorageIni::RemoveEntry(key);
281
282
1
    if (retval == CHIP_NO_ERROR)
283
0
    {
284
0
        mDirty = true;
285
0
    }
286
1
    else
287
1
    {
288
1
        retval = CHIP_ERROR_KEY_NOT_FOUND;
289
1
    }
290
291
1
    mLock.unlock();
292
293
1
    return retval;
294
1
}
295
296
CHIP_ERROR ChipLinuxStorage::ClearAll()
297
0
{
298
0
    CHIP_ERROR retval = CHIP_NO_ERROR;
299
300
0
    mLock.lock();
301
302
0
    retval = ChipLinuxStorageIni::RemoveAll();
303
304
0
    mLock.unlock();
305
306
0
    if (retval == CHIP_NO_ERROR)
307
0
    {
308
0
        mDirty = true;
309
0
        retval = Commit();
310
0
    }
311
0
    else
312
0
    {
313
0
        retval = CHIP_ERROR_WRITE_FAILED;
314
0
    }
315
316
0
    return retval;
317
0
}
318
319
bool ChipLinuxStorage::HasValue(const char * key)
320
8
{
321
8
    bool retval;
322
323
8
    mLock.lock();
324
325
8
    retval = ChipLinuxStorageIni::HasValue(key);
326
327
8
    mLock.unlock();
328
329
8
    return retval;
330
8
}
331
332
CHIP_ERROR ChipLinuxStorage::Commit()
333
26
{
334
26
    CHIP_ERROR retval = CHIP_NO_ERROR;
335
336
26
    if (mDirty && !mConfigPath.empty())
337
26
    {
338
26
        mLock.lock();
339
340
26
        retval = ChipLinuxStorageIni::CommitConfig(mConfigPath);
341
342
26
        mLock.unlock();
343
26
    }
344
0
    else
345
0
    {
346
0
        retval = CHIP_ERROR_WRITE_FAILED;
347
0
    }
348
349
26
    return retval;
350
26
}
351
352
} // namespace Internal
353
} // namespace DeviceLayer
354
} // namespace chip