1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "preferences_xml_utils.h"
17 #include "base64_helper.h"
18 #include <sys/stat.h>
19
20 #include <cerrno>
21 #include <cstring>
22 #include <sstream>
23
24 #include "libxml/parser.h"
25 #include <libxml/xmlwriter.h>
26 #include "log_print.h"
27 #include "preferences_dfx_adapter.h"
28 #include "preferences_file_lock.h"
29 #include "preferences_file_operation.h"
30 #include "preferences_utils.h"
31
32 namespace OHOS {
33 namespace NativePreferences {
34 constexpr int TOO_MANY_OPEN_FILES = 24;
35 constexpr int PRE_ALLOCATE_BUFFER_SIZE = 128;
36 constexpr int NO_SPACE_LEFT_ON_DEVICE = 28;
37 constexpr int DISK_QUOTA_EXCEEDED = 122;
38 constexpr int REQUIRED_KEY_NOT_AVAILABLE = 126;
39 constexpr int REQUIRED_KEY_REVOKED = 128;
40
41 constexpr const char *TAG_PREFERENCES = "preferences";
42 constexpr const char *TAG_VERSION = "version";
43 constexpr const char *VERSION_VALUE = "1.0";
44 constexpr const char *ATTR_KEY = "key";
45 constexpr const char *ATTR_VALUE = "value";
46
47 static bool ParseNodeElement(const xmlNode *node, Element &element);
48 static bool ParsePrimitiveNodeElement(const xmlNode *node, Element &element);
49 static bool ParseStringNodeElement(const xmlNode *node, Element &element);
50 static bool ParseArrayNodeElement(const xmlNode *node, Element &element);
51
52 struct ValueVisitor {
53 std::string_view typeTag;
54 std::string valueStr;
55 std::string_view childrenTag;
56 std::vector<std::string> arrayValues;
57
operator ()OHOS::NativePreferences::ValueVisitor58 void operator()(int val)
59 {
60 typeTag = "int";
61 valueStr = std::to_string(val);
62 }
63
operator ()OHOS::NativePreferences::ValueVisitor64 void operator()(bool val)
65 {
66 typeTag = "bool";
67 valueStr = val ? "true" : "false";
68 }
69
operator ()OHOS::NativePreferences::ValueVisitor70 void operator()(int64_t val)
71 {
72 typeTag = "long";
73 valueStr = std::to_string(val);
74 }
75
operator ()OHOS::NativePreferences::ValueVisitor76 void operator()(uint64_t val)
77 {
78 typeTag = "uint64_t";
79 valueStr = std::to_string(val);
80 }
81
operator ()OHOS::NativePreferences::ValueVisitor82 void operator()(float val)
83 {
84 typeTag = "float";
85 valueStr = std::to_string(val);
86 }
87
operator ()OHOS::NativePreferences::ValueVisitor88 void operator()(double val)
89 {
90 typeTag = "double";
91 valueStr = std::to_string(val);
92 }
93
operator ()OHOS::NativePreferences::ValueVisitor94 void operator()(const std::string& val)
95 {
96 typeTag = "string";
97 valueStr = val;
98 }
99
operator ()OHOS::NativePreferences::ValueVisitor100 void operator()(const std::vector<std::string>& val)
101 {
102 typeTag = "stringArray";
103 childrenTag = "string";
104 arrayValues.reserve(val.size());
105 for (const auto& s : val) {
106 arrayValues.push_back(s);
107 }
108 }
109
operator ()OHOS::NativePreferences::ValueVisitor110 void operator()(const std::vector<double>& val)
111 {
112 typeTag = "doubleArray";
113 childrenTag = "double";
114 arrayValues.reserve(val.size());
115 for (const auto& d : val) {
116 arrayValues.push_back(std::to_string(d));
117 }
118 }
119
operator ()OHOS::NativePreferences::ValueVisitor120 void operator()(const std::vector<bool>& val)
121 {
122 typeTag = "boolArray";
123 childrenTag = "bool";
124 arrayValues.reserve(val.size());
125 for (const auto& b : val) {
126 arrayValues.push_back(b ? "true" : "false");
127 }
128 }
129
operator ()OHOS::NativePreferences::ValueVisitor130 void operator()(const std::vector<uint8_t>& val)
131 {
132 typeTag = "uint8Array";
133 valueStr = Base64Helper::Encode(val);
134 }
135
operator ()OHOS::NativePreferences::ValueVisitor136 void operator()(const Object& val)
137 {
138 typeTag = "object";
139 valueStr = val.valueStr;
140 }
141
operator ()OHOS::NativePreferences::ValueVisitor142 void operator()(const BigInt& val)
143 {
144 typeTag = "BigInt";
145 childrenTag = "uint64_t";
146 arrayValues.reserve(val.words_.size() + 1);
147 for (const auto& word : val.words_) {
148 arrayValues.push_back(std::to_string(word));
149 }
150 arrayValues.push_back(std::to_string(static_cast<uint64_t>(val.sign_)));
151 }
152
operator ()OHOS::NativePreferences::ValueVisitor153 void operator()(const std::monostate&)
154 {
155 typeTag = "unknown";
156 LOG_ERROR("Encountered unknown type in PreferencesValue");
157 }
158 };
159
160 class XmlWriterWrapper {
161 public:
XmlWriterWrapper(xmlTextWriterPtr writer)162 explicit XmlWriterWrapper(xmlTextWriterPtr writer) : writer_(writer) {}
~XmlWriterWrapper()163 ~XmlWriterWrapper()
164 {
165 if (writer_) {
166 xmlFreeTextWriter(writer_);
167 }
168 }
169
get() const170 xmlTextWriterPtr get() const
171 {
172 return writer_;
173 }
174 private:
175 xmlTextWriterPtr writer_;
176 };
177
178 class XmlBufferWrapper {
179 public:
XmlBufferWrapper(xmlBufferPtr buffer)180 explicit XmlBufferWrapper(xmlBufferPtr buffer) : buffer_(buffer) {}
~XmlBufferWrapper()181 ~XmlBufferWrapper()
182 {
183 if (buffer_) {
184 xmlBufferFree(buffer_);
185 }
186 }
187
get() const188 xmlBufferPtr get() const
189 {
190 return buffer_;
191 }
192 private:
193 xmlBufferPtr buffer_;
194 };
195
196 #define XML_CHECK(expr, msg) \
197 do { \
198 if (!(expr)) { \
199 const xmlError *xmlErr = xmlGetLastError(); \
200 LOG_ERROR("%{public}s. Error: %{public}s", msg, xmlErr ? xmlErr->message : "Unknown"); \
201 return false; \
202 } \
203 } while (0)
204
205 template<typename T>
GetTypeName()206 std::string GetTypeName()
207 {
208 return "unknown";
209 }
210
211 template<>
GetTypeName()212 std::string GetTypeName<int>()
213 {
214 return "int";
215 }
216
217 template<>
GetTypeName()218 std::string GetTypeName<bool>()
219 {
220 return "bool";
221 }
222
223 template<>
GetTypeName()224 std::string GetTypeName<int64_t>()
225 {
226 return "long";
227 }
228
229 template<>
GetTypeName()230 std::string GetTypeName<uint64_t>()
231 {
232 return "uint64_t";
233 }
234
235 template<>
GetTypeName()236 std::string GetTypeName<float>()
237 {
238 return "float";
239 }
240
241 template<>
GetTypeName()242 std::string GetTypeName<double>()
243 {
244 return "double";
245 }
246
247 template<>
GetTypeName()248 std::string GetTypeName<std::string>()
249 {
250 return "string";
251 }
252
253 template<>
GetTypeName()254 std::string GetTypeName<std::vector<std::string>>()
255 {
256 return "stringArray";
257 }
258
259 template<>
GetTypeName()260 std::string GetTypeName<std::vector<double>>()
261 {
262 return "doubleArray";
263 }
264
265 template<>
GetTypeName()266 std::string GetTypeName<std::vector<bool>>()
267 {
268 return "boolArray";
269 }
270
271 template<>
GetTypeName()272 std::string GetTypeName<std::vector<uint8_t>>()
273 {
274 return "uint8Array";
275 }
276
277 template<>
GetTypeName()278 std::string GetTypeName<Object>()
279 {
280 return "object";
281 }
282
283 template<>
GetTypeName()284 std::string GetTypeName<BigInt>()
285 {
286 return "BigInt";
287 }
288
289 template<typename T>
Convert2PrefValue(const Element & element,T & value)290 static void Convert2PrefValue(const Element &element, T &value)
291 {
292 if constexpr (std::is_same<T, std::string>::value) {
293 value = element.value_;
294 } else if constexpr (std::is_same<T, bool>::value) {
295 value = (element.value_.compare("true") == 0) ? true : false;
296 } else if constexpr (std::is_same<T, std::monostate>::value) {
297 value = std::monostate();
298 } else {
299 std::stringstream ss;
300 ss << element.value_;
301 ss >> value;
302 }
303 }
304
305 template<typename T>
Convert2PrefValue(const Element & element,std::vector<T> & values)306 static void Convert2PrefValue(const Element &element, std::vector<T> &values)
307 {
308 for (const auto &child : element.children_) {
309 T value;
310 Convert2PrefValue(child, value);
311 values.push_back(value);
312 }
313 }
314
Convert2PrefValue(const Element & element,BigInt & value)315 static void Convert2PrefValue(const Element &element, BigInt &value)
316 {
317 for (const auto &child : element.children_) {
318 uint64_t val;
319 Convert2PrefValue(child, val);
320 value.words_.push_back(val);
321 }
322 value.sign_ = 0;
323 if (!value.words_.empty()) {
324 value.sign_ = static_cast<int>(value.words_[value.words_.size() - 1]);
325 value.words_.pop_back();
326 }
327 }
328
329 template<typename T>
GetPrefValue(const Element & element,T & value)330 bool GetPrefValue(const Element &element, T &value)
331 {
332 LOG_WARN("unknown element type. the key is %{public}s", Anonymous::ToBeAnonymous(element.key_).c_str());
333 return false;
334 }
335
Convert2PrefValue(const Element & element,std::vector<uint8_t> & value)336 static void Convert2PrefValue(const Element &element, std::vector<uint8_t> &value)
337 {
338 if (!Base64Helper::Decode(element.value_, value)) {
339 value.clear();
340 }
341 }
342
Convert2PrefValue(const Element & element,Object & value)343 static void Convert2PrefValue(const Element &element, Object &value)
344 {
345 value.valueStr = element.value_;
346 }
347
348 template<typename T, typename First, typename... Types>
GetPrefValue(const Element & element,T & value)349 bool GetPrefValue(const Element &element, T &value)
350 {
351 if (element.tag_ == GetTypeName<First>()) {
352 First val;
353 Convert2PrefValue(element, val);
354 value = val;
355 return true;
356 }
357 return GetPrefValue<T, Types...>(element, value);
358 }
359
360 template<typename... Types>
Convert2PrefValue(const Element & element,std::variant<Types...> & value)361 bool Convert2PrefValue(const Element &element, std::variant<Types...> &value)
362 {
363 return GetPrefValue<decltype(value), Types...>(element, value);
364 }
365
ReadXmlElement(const Element & element,std::unordered_map<std::string,PreferencesValue> & prefConMap)366 void ReadXmlElement(const Element &element, std::unordered_map<std::string, PreferencesValue> &prefConMap)
367 {
368 PreferencesValue value(static_cast<int64_t>(0));
369 if (Convert2PrefValue(element, value.value_)) {
370 prefConMap.insert({element.key_, value});
371 }
372 }
373
IsFileExist(const std::string & inputPath)374 static bool IsFileExist(const std::string &inputPath)
375 {
376 if (inputPath.length() > PATH_MAX) {
377 return false;
378 }
379 struct stat buffer;
380 return (stat(inputPath.c_str(), &buffer) == 0);
381 }
382
RemoveBackupFile(const std::string & fileName)383 static void RemoveBackupFile(const std::string &fileName)
384 {
385 std::string backupFileName = PreferencesUtils::MakeFilePath(fileName, PreferencesUtils::STR_BACKUP);
386 if (IsFileExist(backupFileName) && std::remove(backupFileName.c_str())) {
387 LOG_WARN("failed to delete backup file %{public}d.", errno);
388 }
389 }
390
ReadFile(const std::string & fileName,int & errCode)391 static xmlDoc *ReadFile(const std::string &fileName, int &errCode)
392 {
393 xmlDoc *doc = xmlReadFile(fileName.c_str(), "UTF-8", XML_PARSE_NOBLANKS | XML_PARSE_HUGE);
394 errCode = errno;
395 return doc;
396 }
397
ReportXmlFileCorrupted(const std::string & fileName,const std::string & bundleName,const std::string & operationMsg,int errCode)398 static void ReportXmlFileCorrupted(const std::string &fileName, const std::string &bundleName,
399 const std::string &operationMsg, int errCode)
400 {
401 ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName),
402 E_ERROR, errCode, operationMsg };
403 PreferencesDfxManager::Report(reportParam, EVENT_NAME_DB_CORRUPTED);
404 ReportParam succreportParam = reportParam;
405 succreportParam.errCode = E_OK;
406 succreportParam.errnoCode = 0;
407 succreportParam.appendix = "restore success";
408 PreferencesDfxManager::Report(succreportParam, EVENT_NAME_DB_CORRUPTED);
409 }
410
ReportNonCorruptError(const std::string & faultType,const std::string & fileName,const std::string & bundleName,int errCode)411 static bool ReportNonCorruptError(
412 const std::string &faultType, const std::string &fileName, const std::string &bundleName, int errCode)
413 {
414 if (errCode == REQUIRED_KEY_NOT_AVAILABLE || errCode == REQUIRED_KEY_REVOKED) {
415 ReportFaultParam reportParam = { faultType, bundleName, NORMAL_DB, ExtractFileName(fileName),
416 E_OPERAT_IS_LOCKED, faultType + " the screen is locked." };
417 PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::USE_WHEN_SCREEN_LOCKED);
418 return true;
419 }
420 if (errCode == NO_SPACE_LEFT_ON_DEVICE || errCode == DISK_QUOTA_EXCEEDED || errCode == TOO_MANY_OPEN_FILES) {
421 ReportFaultParam param = { faultType, bundleName, NORMAL_DB, ExtractFileName(fileName),
422 E_ERROR, faultType + " " + std::strerror(errCode)};
423 PreferencesDfxManager::ReportFault(param);
424 return true;
425 }
426 return false;
427 }
428
RenameFromBackupFile(const std::string & fileName,const std::string & bundleName,bool & isReportCorrupt,bool & isBakFileExist)429 static bool RenameFromBackupFile(
430 const std::string &fileName, const std::string &bundleName, bool &isReportCorrupt, bool &isBakFileExist)
431 {
432 std::string backupFileName = PreferencesUtils::MakeFilePath(fileName, PreferencesUtils::STR_BACKUP);
433 if (!IsFileExist(backupFileName)) {
434 isBakFileExist = false;
435 LOG_DEBUG("the backup file does not exist.");
436 return false;
437 }
438 isBakFileExist = true;
439 xmlResetLastError();
440 int errCode = 0;
441 auto bakDoc = std::shared_ptr<xmlDoc>(ReadFile(backupFileName, errCode),
442 [](xmlDoc *bakDoc) { xmlFreeDoc(bakDoc); });
443 if (bakDoc == nullptr) {
444 const xmlError *xmlErr = xmlGetLastError();
445 std::string errMessage = (xmlErr != nullptr) ? xmlErr->message : "null";
446 LOG_ERROR("%{public}s restore failed, errno:%{public}d, error:%{public}s.",
447 ExtractFileName(fileName).c_str(), errCode, errMessage.c_str());
448 std::remove(backupFileName.c_str());
449 if (ReportNonCorruptError("read bak failed", fileName, bundleName, errCode)) {
450 return false;
451 }
452 isReportCorrupt = true;
453 return false;
454 }
455 if (std::rename(backupFileName.c_str(), fileName.c_str())) {
456 LOG_ERROR("failed to restore backup errno %{public}d.", errno);
457 return false;
458 }
459 isReportCorrupt = false;
460 struct stat fileStats;
461 if (stat(fileName.c_str(), &fileStats) == -1) {
462 LOG_ERROR("failed to stat backup file.");
463 }
464 std::string appindex = "Restored from the backup. The file size is " + std::to_string(fileStats.st_size) + ".";
465 ReportFaultParam reportParam = { "read failed", bundleName, NORMAL_DB, ExtractFileName(fileName),
466 E_XML_RESTORED_FROM_BACKUP_FILE, appindex };
467 PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::RESTORE_FROM_BAK);
468 LOG_INFO("%{public}s restored", ExtractFileName(fileName).c_str());
469 return true;
470 }
471
RenameFile(const std::string & fileName,const std::string & fileType)472 static bool RenameFile(const std::string &fileName, const std::string &fileType)
473 {
474 std::string name = PreferencesUtils::MakeFilePath(fileName, fileType);
475 if (std::rename(fileName.c_str(), name.c_str())) {
476 LOG_ERROR("failed to rename to %{public}s, err:%{public}d.", fileType.c_str(), errno);
477 return false;
478 }
479 return true;
480 }
481
RenameToBackupFile(const std::string & fileName)482 static bool RenameToBackupFile(const std::string &fileName)
483 {
484 return RenameFile(fileName, PreferencesUtils::STR_BACKUP);
485 }
486
RenameToBrokenFile(const std::string & fileName)487 static bool RenameToBrokenFile(const std::string &fileName)
488 {
489 return RenameFile(fileName, PreferencesUtils::STR_BROKEN);
490 }
491
XmlReadFile(const std::string & fileName,const std::string & bundleName)492 static xmlDoc *XmlReadFile(const std::string &fileName, const std::string &bundleName)
493 {
494 xmlDoc *doc = nullptr;
495 bool isReport = false;
496 bool isMultiProcessing = false;
497 PreferencesFileLock fileLock(fileName);
498 fileLock.ReadLock(isMultiProcessing);
499 int errCode = 0;
500 std::string errMessage;
501 if (IsFileExist(fileName)) {
502 LOG_INFO("file:%{public}s, m:%{public}d.", ExtractFileName(fileName).c_str(), isMultiProcessing);
503 doc = ReadFile(fileName, errCode);
504 if (doc != nullptr) {
505 return doc;
506 }
507 const xmlError *xmlErr = xmlGetLastError();
508 errMessage = (xmlErr != nullptr) ? xmlErr->message : "null";
509 LOG_ERROR("failed to read:%{public}s, errno:%{public}d, error:%{public}s.",
510 ExtractFileName(fileName).c_str(), errCode, errMessage.c_str());
511 if (ReportNonCorruptError("read failed", fileName, bundleName, errCode)) {
512 return nullptr;
513 }
514 if (!RenameToBrokenFile(fileName)) {
515 return doc;
516 }
517 isReport = true;
518 }
519
520 bool isExist = true;
521 if (RenameFromBackupFile(fileName, bundleName, isReport, isExist)) {
522 int bakErrCode = 0;
523 doc = ReadFile(fileName, bakErrCode);
524 const xmlError *xmlErr = xmlGetLastError();
525 std::string message = (xmlErr != nullptr) ? xmlErr->message : "null";
526 errMessage.append(" bak: errno is " + std::to_string(bakErrCode) + ", errMessage is " + message);
527 }
528 if (isMultiProcessing) {
529 ReportFaultParam param = { "read failed", bundleName, NORMAL_DB, ExtractFileName(fileName),
530 E_OPERAT_IS_CROSS_PROESS, "Cross-process operations." };
531 PreferencesDfxManager::ReportFault(param);
532 return doc;
533 }
534 if (isReport) {
535 ReportFaultParam param = { "read failed", bundleName, NORMAL_DB, ExtractFileName(fileName),
536 E_ERROR, "read failed, " + errMessage};
537 isExist ? ReportXmlFileCorrupted(fileName, bundleName, errMessage, errCode) :
538 PreferencesDfxManager::ReportFault(param);
539 }
540 return doc;
541 }
542
543 /* static */
ReadSettingXml(const std::string & fileName,const std::string & bundleName,std::unordered_map<std::string,PreferencesValue> & conMap)544 bool PreferencesXmlUtils::ReadSettingXml(const std::string &fileName, const std::string &bundleName,
545 std::unordered_map<std::string, PreferencesValue> &conMap)
546 {
547 if (fileName.size() == 0) {
548 LOG_ERROR("The length of the file name is 0.");
549 return false;
550 }
551 auto doc =
552 std::shared_ptr<xmlDoc>(XmlReadFile(fileName, bundleName), [](xmlDoc *doc) { xmlFreeDoc(doc); });
553 if (doc == nullptr) {
554 return false;
555 }
556
557 xmlNode *root = xmlDocGetRootElement(doc.get());
558 if (!root || xmlStrcmp(root->name, reinterpret_cast<const xmlChar *>("preferences"))) {
559 LOG_ERROR("Failed to obtain the XML root element.");
560 return false;
561 }
562
563 bool success = true;
564 const xmlNode *cur = nullptr;
565 for (cur = root->children; cur != nullptr; cur = cur->next) {
566 Element element;
567
568 if (ParseNodeElement(cur, element)) {
569 ReadXmlElement(element, conMap);
570 } else {
571 success = false;
572 LOG_ERROR("The error occurred during getting xml child elements.");
573 break;
574 }
575 }
576 return success;
577 }
578
579 /* static */
ParseNodeElement(const xmlNode * node,Element & element)580 bool ParseNodeElement(const xmlNode *node, Element &element)
581 {
582 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("string"))
583 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("uint8Array"))
584 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("object"))) {
585 return ParseStringNodeElement(node, element);
586 }
587
588 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("int"))
589 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("long"))
590 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("bool"))
591 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("float"))
592 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("double"))
593 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("uint64_t"))) {
594 return ParsePrimitiveNodeElement(node, element);
595 }
596
597 if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("boolArray"))
598 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("stringArray"))
599 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("doubleArray"))
600 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("BigInt"))
601 || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("set"))) {
602 return ParseArrayNodeElement(node, element);
603 }
604
605 std::string keyName;
606 xmlChar *key = xmlGetProp(node, (const xmlChar *)ATTR_KEY);
607 if (key != nullptr) {
608 keyName = std::string(reinterpret_cast<char *>(key));
609 xmlFree(key);
610 }
611 LOG_ERROR("An unsupported element type was encountered in parsing = %{public}s, keyName = %{public}s.", node->name,
612 Anonymous::ToBeAnonymous(keyName).c_str());
613 return false;
614 }
615
616 /* static */
ParsePrimitiveNodeElement(const xmlNode * node,Element & element)617 bool ParsePrimitiveNodeElement(const xmlNode *node, Element &element)
618 {
619 xmlChar *key = xmlGetProp(node, reinterpret_cast<const xmlChar *>(ATTR_KEY));
620 xmlChar *value = xmlGetProp(node, reinterpret_cast<const xmlChar *>(ATTR_VALUE));
621
622 bool success = false;
623 if (value != nullptr) {
624 element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
625 if (key != nullptr) {
626 element.key_ = std::string(reinterpret_cast<char *>(key));
627 }
628 element.value_ = std::string(reinterpret_cast<char *>(value));
629 success = true;
630 } else {
631 LOG_ERROR("Failed to obtain a valid key or value when parsing %{public}s.", node->name);
632 }
633
634 if (key != nullptr) {
635 xmlFree(key);
636 }
637 if (value != nullptr) {
638 xmlFree(value);
639 }
640 return success;
641 }
642
643 /* static */
ParseStringNodeElement(const xmlNode * node,Element & element)644 bool ParseStringNodeElement(const xmlNode *node, Element &element)
645 {
646 xmlChar *key = xmlGetProp(node, (const xmlChar *)ATTR_KEY);
647 xmlChar *text = xmlNodeGetContent(node);
648
649 bool success = false;
650 if (text != nullptr) {
651 element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
652 if (key != nullptr) {
653 element.key_ = std::string(reinterpret_cast<char *>(key));
654 }
655 element.value_ = std::string(reinterpret_cast<char *>(text));
656 success = true;
657 } else {
658 LOG_ERROR("Failed to obtain a valid key or value when parsing string element.");
659 }
660
661 if (key != nullptr) {
662 xmlFree(key);
663 }
664 if (text != nullptr) {
665 xmlFree(text);
666 }
667 return success;
668 }
669
670 /* static */
ParseArrayNodeElement(const xmlNode * node,Element & element)671 bool ParseArrayNodeElement(const xmlNode *node, Element &element)
672 {
673 xmlChar *key = xmlGetProp(node, (const xmlChar *)ATTR_KEY);
674 const xmlNode *children = node->children;
675
676 bool success = false;
677 if (key != nullptr) {
678 element.tag_ = std::string(reinterpret_cast<const char *>(node->name));
679 element.key_ = std::string(reinterpret_cast<char *>(key));
680
681 const xmlNode *cur = nullptr;
682 bool finishTravelChild = true;
683 for (cur = children; cur != nullptr; cur = cur->next) {
684 Element child;
685 if (ParseNodeElement(cur, child)) {
686 element.children_.push_back(child);
687 } else {
688 finishTravelChild = false;
689 LOG_ERROR("Failed to parse the Array element and could not be completed successfully.");
690 break;
691 }
692 }
693 success = finishTravelChild;
694 } else {
695 LOG_ERROR("Failed to obtain a valid key or value when parsing a Array element.");
696 }
697
698 if (key != nullptr) {
699 xmlFree(key);
700 }
701 return success;
702 }
703
ReportSaveFileFault(const std::string fileName,const std::string & bundleName,bool & isReport,bool isMultiProcessing)704 static void ReportSaveFileFault(const std::string fileName, const std::string &bundleName,
705 bool &isReport, bool isMultiProcessing)
706 {
707 int errCode = errno;
708 bool isExist = false;
709 const xmlError *xmlErr = xmlGetLastError();
710 std::string errMessage = (xmlErr != nullptr) ? xmlErr->message : "null";
711 LOG_ERROR("Save:%{public}s, errno:%{public}d, error:%{public}s.",
712 ExtractFileName(fileName).c_str(), errCode, errMessage.c_str());
713 if (IsFileExist(fileName)) {
714 RenameToBrokenFile(fileName);
715 isReport = true;
716 }
717 RenameFromBackupFile(fileName, bundleName, isReport, isExist);
718 if (ReportNonCorruptError("write failed", fileName, bundleName, errCode)) {
719 return;
720 }
721 if (isMultiProcessing) {
722 ReportFaultParam param = { "write failed", bundleName, NORMAL_DB, ExtractFileName(fileName),
723 E_OPERAT_IS_CROSS_PROESS, "Cross-process operations." };
724 PreferencesDfxManager::ReportFault(param);
725 return;
726 }
727 if (isReport) {
728 ReportFaultParam param = { "write failed", bundleName, NORMAL_DB, ExtractFileName(fileName),
729 E_ERROR, "write failed, " + errMessage};
730 isExist ? ReportXmlFileCorrupted(fileName, bundleName, errMessage, errCode) :
731 PreferencesDfxManager::ReportFault(param);
732 }
733 }
734
SaveXmlFile(const std::string & fileName,const std::string & bundleName,xmlBufferPtr buf)735 static bool SaveXmlFile(const std::string &fileName, const std::string &bundleName, xmlBufferPtr buf)
736 {
737 bool isReport = false;
738 bool isMultiProcessing = false;
739 PreferencesFileLock fileLock(fileName);
740 fileLock.WriteLock(isMultiProcessing);
741 LOG_INFO("file:%{public}s, m:%{public}d.", ExtractFileName(fileName).c_str(), isMultiProcessing);
742 if (IsFileExist(fileName) && !RenameToBackupFile(fileName)) {
743 return false;
744 }
745 int fd = Open(fileName.c_str());
746 if (fd == -1) {
747 LOG_ERROR("failed open:%{public}s", ExtractFileName(fileName).c_str());
748 ReportSaveFileFault(fileName, bundleName, isReport, isMultiProcessing);
749 return false;
750 }
751 if (Write(fd, buf->content, buf->use) < 0) {
752 LOG_ERROR("Failed write:%{public}s", ExtractFileName(fileName).c_str());
753 ReportSaveFileFault(fileName, bundleName, isReport, isMultiProcessing);
754 Close(fd);
755 return false;
756 }
757 if (!Fsync(fd)) {
758 LOG_WARN("Failed to write to the disk.");
759 }
760 Close(fd);
761 RemoveBackupFile(fileName);
762 return true;
763 }
764
WriteXmlElement(xmlTextWriterPtr writer,const std::string & key,const PreferencesValue & value)765 static bool WriteXmlElement(xmlTextWriterPtr writer, const std::string &key, const PreferencesValue &value)
766 {
767 ValueVisitor visitor;
768 std::visit(visitor, value.value_);
769 const char* tag = visitor.typeTag.data();
770 const char* keyPtr = key.c_str();
771 if (visitor.typeTag == "string" || visitor.typeTag == "uint8Array" || visitor.typeTag == "object") {
772 XML_CHECK(xmlTextWriterStartElement(writer, BAD_CAST tag) >= 0, "Start element failed");
773 XML_CHECK(xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_KEY, BAD_CAST keyPtr) >= 0, "Write attr failed");
774 XML_CHECK(xmlTextWriterWriteString(writer, BAD_CAST visitor.valueStr.c_str()) >= 0, "Write value failed");
775 XML_CHECK(xmlTextWriterEndElement(writer) >= 0, "End element failed");
776 } else if (visitor.typeTag == "int" || visitor.typeTag == "long" ||visitor.typeTag == "float" ||
777 visitor.typeTag == "bool" || visitor.typeTag == "double") {
778 XML_CHECK(xmlTextWriterStartElement(writer, BAD_CAST tag) >= 0, "Start element failed");
779 XML_CHECK(xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_KEY, BAD_CAST keyPtr) >= 0, "Write attr failed");
780 XML_CHECK(xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_VALUE, BAD_CAST visitor.valueStr.c_str()) >= 0,
781 "Write attr failed");
782 XML_CHECK(xmlTextWriterEndElement(writer) >= 0, "End element failed");
783 } else if (visitor.typeTag == "doubleArray" || visitor.typeTag == "stringArray" ||
784 visitor.typeTag == "boolArray" || visitor.typeTag == "BigInt") {
785 XML_CHECK(xmlTextWriterStartElement(writer, BAD_CAST tag) >= 0, "Start element failed");
786 XML_CHECK(xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_KEY, BAD_CAST keyPtr) >= 0, "Write attr failed");
787 for (auto &child : visitor.arrayValues) {
788 if (visitor.childrenTag == "string") {
789 XML_CHECK(xmlTextWriterStartElement(writer, BAD_CAST visitor.childrenTag.data()) >= 0,
790 "Start element failed");
791 XML_CHECK(xmlTextWriterWriteString(writer, BAD_CAST child.c_str()) >= 0, "Write value failed");
792 XML_CHECK(xmlTextWriterEndElement(writer) >= 0, "End element failed");
793 } else {
794 XML_CHECK(xmlTextWriterStartElement(writer, BAD_CAST visitor.childrenTag.data()) >= 0,
795 "Start element failed");
796 XML_CHECK(xmlTextWriterWriteAttribute(writer, BAD_CAST ATTR_VALUE, BAD_CAST child.c_str()) >= 0,
797 "Write attr failed");
798 XML_CHECK(xmlTextWriterEndElement(writer) >= 0, "End element failed");
799 }
800 }
801 XML_CHECK(xmlTextWriterEndElement(writer) >= 0, "End element failed");
802 }
803 return true;
804 }
805
806 /* static */
WriteSettingXml(const std::string & fileName,const std::string & bundleName,const std::unordered_map<std::string,PreferencesValue> & writeToDiskMap)807 bool PreferencesXmlUtils::WriteSettingXml(const std::string &fileName, const std::string &bundleName,
808 const std::unordered_map<std::string, PreferencesValue> &writeToDiskMap)
809 {
810 if (fileName.empty()) {
811 LOG_ERROR("The length of the file name is 0.");
812 return false;
813 }
814
815 XmlBufferWrapper bufferWrapper(xmlBufferCreateSize(writeToDiskMap.size() * PRE_ALLOCATE_BUFFER_SIZE));
816 if (!bufferWrapper.get()) {
817 LOG_ERROR("Failed to create XML buffer");
818 return false;
819 }
820 XmlWriterWrapper writerWrapper(xmlNewTextWriterMemory(bufferWrapper.get(), 0));
821 if (!writerWrapper.get()) {
822 LOG_ERROR("Failed to create XML writer");
823 return false;
824 }
825
826 xmlTextWriterPtr writer = writerWrapper.get();
827 xmlTextWriterSetIndent(writer, 0);
828
829 XML_CHECK(xmlTextWriterStartDocument(writer, nullptr, "UTF-8", nullptr) >= 0, "Start document failed");
830 XML_CHECK(xmlTextWriterStartElement(writer, BAD_CAST TAG_PREFERENCES) >= 0, "Start root element failed");
831 XML_CHECK(xmlTextWriterWriteAttribute(writer, BAD_CAST TAG_VERSION, BAD_CAST VERSION_VALUE) >= 0,
832 "Write version failed");
833
834 for (const auto& [key, prefValue] : writeToDiskMap) {
835 if (!WriteXmlElement(writer, key, prefValue)) {
836 return false;
837 }
838 }
839
840 XML_CHECK(xmlTextWriterEndElement(writer) >= 0, "End root failed");
841 XML_CHECK(xmlTextWriterEndDocument(writer) >= 0, "End document failed");
842
843 return SaveXmlFile(fileName, bundleName, bufferWrapper.get());
844 }
845 } // End of namespace NativePreferences
846 } // End of namespace OHOS