Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / Tizen / CHIPLinuxStorageIni.cpp
1 /*
2  *
3  *    Copyright (c) 2020 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  *          Provides an implementation of the Configuration key-value store object
22  *          using IniPP on Linux platform.
23  *
24  */
25
26 #include <fstream>
27 #include <string>
28 #include <unistd.h>
29
30 #include <platform/Linux/CHIPLinuxStorageIni.h>
31 #include <platform/internal/CHIPDeviceLayerInternal.h>
32 #include <support/Base64.h>
33 #include <support/CHIPMem.h>
34 #include <support/CodeUtils.h>
35 #include <support/logging/CHIPLogging.h>
36
37 namespace chip {
38 namespace DeviceLayer {
39 namespace Internal {
40
41 CHIP_ERROR ChipLinuxStorageIni::Init()
42 {
43     return RemoveAll();
44 }
45
46 CHIP_ERROR ChipLinuxStorageIni::GetDefaultSection(std::map<std::string, std::string> & section)
47 {
48     CHIP_ERROR retval = CHIP_NO_ERROR;
49
50     auto it = mConfigStore.sections.find("DEFAULT");
51
52     if (it != mConfigStore.sections.end())
53     {
54         section = mConfigStore.sections["DEFAULT"];
55     }
56     else
57     {
58         retval = CHIP_ERROR_KEY_NOT_FOUND;
59     }
60
61     return retval;
62 }
63
64 CHIP_ERROR ChipLinuxStorageIni::AddConfig(const std::string & configFile)
65 {
66     CHIP_ERROR retval = CHIP_NO_ERROR;
67     std::ifstream ifs;
68
69     ifs.open(configFile, std::ifstream::in);
70
71     if (ifs.is_open())
72     {
73         mConfigStore.parse(ifs);
74         ifs.close();
75     }
76     else
77     {
78         ChipLogError(DeviceLayer, "Failed to open config file: %s", configFile.c_str());
79         retval = CHIP_ERROR_OPEN_FAILED;
80     }
81
82     return retval;
83 }
84
85 // Updating a file atomically and durably on Linux requires:
86 // 1. Writing to a temporary file
87 // 2. Sync'ing the temp file to commit updated data
88 // 3. Using rename() to overwrite the existing file
89 CHIP_ERROR ChipLinuxStorageIni::CommitConfig(const std::string & configFile)
90 {
91     CHIP_ERROR retval = CHIP_NO_ERROR;
92     std::ofstream ofs;
93     std::string tmpPath = configFile;
94
95     tmpPath.append(".tmp");
96
97     ofs.open(tmpPath, std::ofstream::out | std::ofstream::trunc);
98
99     if (ofs.is_open())
100     {
101         ChipLogProgress(DeviceLayer, "writing settings to file (%s)", tmpPath.c_str());
102
103         mConfigStore.generate(ofs);
104         ofs.close();
105
106         if (rename(tmpPath.c_str(), configFile.c_str()) == 0)
107         {
108             ChipLogError(DeviceLayer, "renamed tmp file to file (%s)", configFile.c_str());
109         }
110         else
111         {
112             ChipLogError(DeviceLayer, "failed to rename (%s), %s (%d)", tmpPath.c_str(), strerror(errno), errno);
113             retval = CHIP_ERROR_WRITE_FAILED;
114         }
115     }
116     else
117     {
118         ChipLogError(DeviceLayer, "failed to open file (%s) for writing", tmpPath.c_str());
119         retval = CHIP_ERROR_OPEN_FAILED;
120     }
121
122     return retval;
123 }
124
125 CHIP_ERROR ChipLinuxStorageIni::GetUIntValue(const char * key, uint32_t & val)
126 {
127     CHIP_ERROR retval = CHIP_NO_ERROR;
128     std::map<std::string, std::string> section;
129
130     retval = GetDefaultSection(section);
131
132     if (retval == CHIP_NO_ERROR)
133     {
134         auto it = section.find(key);
135
136         if (it != section.end())
137         {
138             if (!inipp::extract(section[key], val))
139             {
140                 retval = CHIP_ERROR_INVALID_ARGUMENT;
141             }
142         }
143         else
144         {
145             retval = CHIP_ERROR_KEY_NOT_FOUND;
146         }
147     }
148
149     return retval;
150 }
151
152 CHIP_ERROR ChipLinuxStorageIni::GetUInt64Value(const char * key, uint64_t & val)
153 {
154     CHIP_ERROR retval = CHIP_NO_ERROR;
155     std::map<std::string, std::string> section;
156
157     retval = GetDefaultSection(section);
158
159     if (retval == CHIP_NO_ERROR)
160     {
161         auto it = section.find(key);
162
163         if (it != section.end())
164         {
165             if (!inipp::extract(section[key], val))
166             {
167                 retval = CHIP_ERROR_INVALID_ARGUMENT;
168             }
169         }
170         else
171         {
172             retval = CHIP_ERROR_KEY_NOT_FOUND;
173         }
174     }
175
176     return retval;
177 }
178
179 CHIP_ERROR ChipLinuxStorageIni::GetStringValue(const char * key, char * buf, size_t bufSize, size_t & outLen)
180 {
181     CHIP_ERROR retval = CHIP_NO_ERROR;
182     std::map<std::string, std::string> section;
183
184     retval = GetDefaultSection(section);
185
186     if (retval == CHIP_NO_ERROR)
187     {
188         auto it = section.find(key);
189
190         if (it != section.end())
191         {
192             std::string value;
193             if (inipp::extract(section[key], value))
194             {
195                 size_t len = value.size();
196
197                 if (len > bufSize - 1)
198                 {
199                     outLen = len;
200                     retval = CHIP_ERROR_BUFFER_TOO_SMALL;
201                 }
202                 else
203                 {
204                     outLen      = value.copy(buf, len);
205                     buf[outLen] = '\0';
206                 }
207             }
208             else
209             {
210                 retval = CHIP_ERROR_INVALID_ARGUMENT;
211             }
212         }
213         else
214         {
215             retval = CHIP_ERROR_KEY_NOT_FOUND;
216         }
217     }
218
219     return retval;
220 }
221
222 CHIP_ERROR ChipLinuxStorageIni::GetBinaryBlobDataAndLengths(const char * key,
223                                                             chip::Platform::ScopedMemoryBuffer<char> & encodedData,
224                                                             size_t & encodedDataLen, size_t & decodedDataLen)
225 {
226     size_t encodedDataPaddingLen = 0;
227     std::map<std::string, std::string> section;
228     CHIP_ERROR err = GetDefaultSection(section);
229     if (err != CHIP_NO_ERROR)
230     {
231         return err;
232     }
233
234     auto it = section.find(key);
235     if (it == section.end())
236     {
237         return CHIP_ERROR_KEY_NOT_FOUND;
238     }
239
240     std::string value;
241
242     // Compute the expectedDecodedLen
243     if (!inipp::extract(section[key], value))
244     {
245         return CHIP_ERROR_INVALID_ARGUMENT;
246     }
247
248     size_t len = value.size();
249     if (!encodedData.Alloc(len + 1))
250     {
251         return CHIP_ERROR_NO_MEMORY;
252     }
253     encodedDataLen              = value.copy(encodedData.Get(), len);
254     encodedData[encodedDataLen] = '\0';
255
256     // Check if encoded data was padded. Only "=" or "==" padding combinations are allowed.
257     if ((encodedDataLen > 0) && (encodedData[encodedDataLen - 1] == '='))
258     {
259         encodedDataPaddingLen++;
260         if ((encodedDataLen > 1) && (encodedData[encodedDataLen - 2] == '='))
261             encodedDataPaddingLen++;
262     }
263
264     decodedDataLen = ((encodedDataLen - encodedDataPaddingLen) * 3) / 4;
265
266     return CHIP_NO_ERROR;
267 }
268
269 CHIP_ERROR ChipLinuxStorageIni::GetBinaryBlobValue(const char * key, uint8_t * decodedData, size_t bufSize, size_t & decodedDataLen)
270 {
271     CHIP_ERROR retval = CHIP_NO_ERROR;
272     chip::Platform::ScopedMemoryBuffer<char> encodedData;
273     size_t encodedDataLen;
274     size_t expectedDecodedLen = 0;
275
276     retval = GetBinaryBlobDataAndLengths(key, encodedData, encodedDataLen, expectedDecodedLen);
277
278     // Check the size
279     if (retval != CHIP_NO_ERROR)
280     {
281         return retval;
282     }
283
284     if (expectedDecodedLen > bufSize)
285     {
286         decodedDataLen = expectedDecodedLen;
287         return CHIP_ERROR_BUFFER_TOO_SMALL;
288     }
289
290     if (encodedDataLen > UINT16_MAX)
291     {
292         // We can't even pass this length into Base64Decode.
293         return CHIP_ERROR_DECODE_FAILED;
294     }
295
296     // Decode it
297     // Cast is safe because we checked encodedDataLen above.
298     decodedDataLen = Base64Decode(encodedData.Get(), static_cast<uint16_t>(encodedDataLen), decodedData);
299     if (decodedDataLen == UINT16_MAX || decodedDataLen > expectedDecodedLen)
300     {
301         return CHIP_ERROR_DECODE_FAILED;
302     }
303
304     return CHIP_NO_ERROR;
305 }
306
307 bool ChipLinuxStorageIni::HasValue(const char * key)
308 {
309     std::map<std::string, std::string> section;
310
311     if (GetDefaultSection(section) != CHIP_NO_ERROR)
312         return false;
313
314     auto it = section.find(key);
315
316     return it != section.end();
317 }
318
319 CHIP_ERROR ChipLinuxStorageIni::AddEntry(const char * key, const char * value)
320 {
321     CHIP_ERROR retval = CHIP_NO_ERROR;
322
323     if ((key != nullptr) && (value != nullptr))
324     {
325         std::map<std::string, std::string> & section = mConfigStore.sections["DEFAULT"];
326         section[key]                                 = std::string(value);
327     }
328     else
329     {
330         ChipLogError(DeviceLayer, "Invalid input argument, failed to add entry");
331         retval = CHIP_ERROR_INVALID_ARGUMENT;
332     }
333
334     return retval;
335 }
336
337 CHIP_ERROR ChipLinuxStorageIni::RemoveEntry(const char * key)
338 {
339     CHIP_ERROR retval = CHIP_NO_ERROR;
340
341     std::map<std::string, std::string> & section = mConfigStore.sections["DEFAULT"];
342
343     auto it = section.find(key);
344
345     if (it != section.end())
346     {
347         section.erase(it);
348     }
349     else
350     {
351         retval = CHIP_ERROR_KEY_NOT_FOUND;
352     }
353
354     return retval;
355 }
356
357 CHIP_ERROR ChipLinuxStorageIni::RemoveAll()
358 {
359     mConfigStore.clear();
360
361     return CHIP_NO_ERROR;
362 }
363
364 } // namespace Internal
365 } // namespace DeviceLayer
366 } // namespace chip