1fc223305Sopenharmony_ci/* 2fc223305Sopenharmony_ci * Copyright (C) 2021 Huawei Device Co., Ltd. 3fc223305Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4fc223305Sopenharmony_ci * you may not use this file except in compliance with the License. 5fc223305Sopenharmony_ci * You may obtain a copy of the License at 6fc223305Sopenharmony_ci * 7fc223305Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8fc223305Sopenharmony_ci * 9fc223305Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10fc223305Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11fc223305Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fc223305Sopenharmony_ci * See the License for the specific language governing permissions and 13fc223305Sopenharmony_ci * limitations under the License. 14fc223305Sopenharmony_ci */ 15fc223305Sopenharmony_ci 16fc223305Sopenharmony_ci#include "preferences_xml_utils.h" 17fc223305Sopenharmony_ci 18fc223305Sopenharmony_ci#include <sys/stat.h> 19fc223305Sopenharmony_ci 20fc223305Sopenharmony_ci#include <cerrno> 21fc223305Sopenharmony_ci#include <cstring> 22fc223305Sopenharmony_ci 23fc223305Sopenharmony_ci#include "libxml/parser.h" 24fc223305Sopenharmony_ci#include "log_print.h" 25fc223305Sopenharmony_ci#include "preferences_dfx_adapter.h" 26fc223305Sopenharmony_ci#include "preferences_file_lock.h" 27fc223305Sopenharmony_ci#include "preferences_file_operation.h" 28fc223305Sopenharmony_ci#include "preferences_impl.h" 29fc223305Sopenharmony_ci 30fc223305Sopenharmony_cinamespace OHOS { 31fc223305Sopenharmony_cinamespace NativePreferences { 32fc223305Sopenharmony_ciconstexpr int REQUIRED_KEY_NOT_AVAILABLE = 126; 33fc223305Sopenharmony_ciconstexpr int REQUIRED_KEY_REVOKED = 128; 34fc223305Sopenharmony_cistatic bool ParseNodeElement(const xmlNode *node, Element &element); 35fc223305Sopenharmony_cistatic bool ParsePrimitiveNodeElement(const xmlNode *node, Element &element); 36fc223305Sopenharmony_cistatic bool ParseStringNodeElement(const xmlNode *node, Element &element); 37fc223305Sopenharmony_cistatic bool ParseArrayNodeElement(const xmlNode *node, Element &element); 38fc223305Sopenharmony_cistatic xmlNode *CreateElementNode(Element &element); 39fc223305Sopenharmony_cistatic xmlNode *CreatePrimitiveNode(Element &element); 40fc223305Sopenharmony_cistatic xmlNode *CreateStringNode(Element &element); 41fc223305Sopenharmony_cistatic xmlNode *CreateArrayNode(Element &element); 42fc223305Sopenharmony_ci 43fc223305Sopenharmony_cistatic bool IsFileExist(const std::string &inputPath) 44fc223305Sopenharmony_ci{ 45fc223305Sopenharmony_ci if (inputPath.length() > PATH_MAX) { 46fc223305Sopenharmony_ci return false; 47fc223305Sopenharmony_ci } 48fc223305Sopenharmony_ci struct stat buffer; 49fc223305Sopenharmony_ci return (stat(inputPath.c_str(), &buffer) == 0); 50fc223305Sopenharmony_ci} 51fc223305Sopenharmony_ci 52fc223305Sopenharmony_cistatic void RemoveBackupFile(const std::string &fileName) 53fc223305Sopenharmony_ci{ 54fc223305Sopenharmony_ci std::string backupFileName = MakeFilePath(fileName, STR_BACKUP); 55fc223305Sopenharmony_ci if (IsFileExist(backupFileName) && std::remove(backupFileName.c_str())) { 56fc223305Sopenharmony_ci LOG_WARN("failed to delete backup file %{public}d.", errno); 57fc223305Sopenharmony_ci } 58fc223305Sopenharmony_ci} 59fc223305Sopenharmony_ci 60fc223305Sopenharmony_cistatic xmlDoc *ReadFile(const std::string &fileName, int &errCode) 61fc223305Sopenharmony_ci{ 62fc223305Sopenharmony_ci xmlDoc *doc = xmlReadFile(fileName.c_str(), "UTF-8", XML_PARSE_NOBLANKS | XML_PARSE_HUGE); 63fc223305Sopenharmony_ci errCode = errno; 64fc223305Sopenharmony_ci return doc; 65fc223305Sopenharmony_ci} 66fc223305Sopenharmony_ci 67fc223305Sopenharmony_cistatic void ReportXmlFileIsBroken(const std::string &fileName, const std::string &bundleName, 68fc223305Sopenharmony_ci const std::string &operationMsg, int errCode) 69fc223305Sopenharmony_ci{ 70fc223305Sopenharmony_ci ReportParam reportParam = { bundleName, NORMAL_DB, ExtractFileName(fileName), E_ERROR, errCode, operationMsg }; 71fc223305Sopenharmony_ci PreferencesDfxManager::ReportDbFault(reportParam); 72fc223305Sopenharmony_ci ReportParam succreportParam = reportParam; 73fc223305Sopenharmony_ci succreportParam.errCode = E_OK; 74fc223305Sopenharmony_ci succreportParam.errnoCode = 0; 75fc223305Sopenharmony_ci succreportParam.appendix = "operation: restore success"; 76fc223305Sopenharmony_ci PreferencesDfxManager::ReportDbFault(succreportParam); 77fc223305Sopenharmony_ci} 78fc223305Sopenharmony_ci 79fc223305Sopenharmony_cistatic bool RenameFromBackupFile(const std::string &fileName, const std::string &bundleName, bool &isReportCorrupt) 80fc223305Sopenharmony_ci{ 81fc223305Sopenharmony_ci std::string backupFileName = MakeFilePath(fileName, STR_BACKUP); 82fc223305Sopenharmony_ci if (!IsFileExist(backupFileName)) { 83fc223305Sopenharmony_ci LOG_DEBUG("the backup file does not exist."); 84fc223305Sopenharmony_ci return false; 85fc223305Sopenharmony_ci } 86fc223305Sopenharmony_ci xmlResetLastError(); 87fc223305Sopenharmony_ci int errCode = 0; 88fc223305Sopenharmony_ci auto bakDoc = std::shared_ptr<xmlDoc>(ReadFile(backupFileName, errCode), 89fc223305Sopenharmony_ci [](xmlDoc *bakDoc) { xmlFreeDoc(bakDoc); }); 90fc223305Sopenharmony_ci if (bakDoc == nullptr) { 91fc223305Sopenharmony_ci xmlErrorPtr xmlErr = xmlGetLastError(); 92fc223305Sopenharmony_ci std::string errMessage = (xmlErr != nullptr) ? xmlErr->message : "null"; 93fc223305Sopenharmony_ci LOG_ERROR("restore XML file: %{public}s failed, errno is %{public}d, error is %{public}s.", 94fc223305Sopenharmony_ci ExtractFileName(fileName).c_str(), errCode, errMessage.c_str()); 95fc223305Sopenharmony_ci std::remove(backupFileName.c_str()); 96fc223305Sopenharmony_ci isReportCorrupt = true; 97fc223305Sopenharmony_ci return false; 98fc223305Sopenharmony_ci } 99fc223305Sopenharmony_ci if (std::rename(backupFileName.c_str(), fileName.c_str())) { 100fc223305Sopenharmony_ci LOG_ERROR("failed to restore backup errno %{public}d.", errno); 101fc223305Sopenharmony_ci return false; 102fc223305Sopenharmony_ci } 103fc223305Sopenharmony_ci isReportCorrupt = false; 104fc223305Sopenharmony_ci LOG_INFO("restore XML file %{public}s successfully.", ExtractFileName(fileName).c_str()); 105fc223305Sopenharmony_ci return true; 106fc223305Sopenharmony_ci} 107fc223305Sopenharmony_ci 108fc223305Sopenharmony_cistatic bool RenameFile(const std::string &fileName, const std::string &fileType) 109fc223305Sopenharmony_ci{ 110fc223305Sopenharmony_ci std::string name = MakeFilePath(fileName, fileType); 111fc223305Sopenharmony_ci if (std::rename(fileName.c_str(), name.c_str())) { 112fc223305Sopenharmony_ci LOG_ERROR("failed to rename file to %{public}s file %{public}d.", fileType.c_str(), errno); 113fc223305Sopenharmony_ci return false; 114fc223305Sopenharmony_ci } 115fc223305Sopenharmony_ci return true; 116fc223305Sopenharmony_ci} 117fc223305Sopenharmony_ci 118fc223305Sopenharmony_cistatic bool RenameToBackupFile(const std::string &fileName) 119fc223305Sopenharmony_ci{ 120fc223305Sopenharmony_ci return RenameFile(fileName, STR_BACKUP); 121fc223305Sopenharmony_ci} 122fc223305Sopenharmony_ci 123fc223305Sopenharmony_cistatic bool RenameToBrokenFile(const std::string &fileName) 124fc223305Sopenharmony_ci{ 125fc223305Sopenharmony_ci return RenameFile(fileName, STR_BROKEN); 126fc223305Sopenharmony_ci} 127fc223305Sopenharmony_ci 128fc223305Sopenharmony_cistatic xmlDoc *XmlReadFile(const std::string &fileName, const std::string &bundleName, const std::string &dataGroupId) 129fc223305Sopenharmony_ci{ 130fc223305Sopenharmony_ci xmlDoc *doc = nullptr; 131fc223305Sopenharmony_ci bool isReport = false; 132fc223305Sopenharmony_ci PreferencesFileLock fileLock(MakeFilePath(fileName, STR_LOCK), dataGroupId); 133fc223305Sopenharmony_ci int errCode = 0; 134fc223305Sopenharmony_ci if (IsFileExist(fileName)) { 135fc223305Sopenharmony_ci doc = ReadFile(fileName, errCode); 136fc223305Sopenharmony_ci if (doc != nullptr) { 137fc223305Sopenharmony_ci return doc; 138fc223305Sopenharmony_ci } 139fc223305Sopenharmony_ci xmlErrorPtr xmlErr = xmlGetLastError(); 140fc223305Sopenharmony_ci std::string errMessage = (xmlErr != nullptr) ? xmlErr->message : "null"; 141fc223305Sopenharmony_ci LOG_ERROR("failed to read XML format file: %{public}s, errno is %{public}d, error is %{public}s.", 142fc223305Sopenharmony_ci ExtractFileName(fileName).c_str(), errCode, errMessage.c_str()); 143fc223305Sopenharmony_ci if (errCode == REQUIRED_KEY_NOT_AVAILABLE || errCode == REQUIRED_KEY_REVOKED) { 144fc223305Sopenharmony_ci return nullptr; 145fc223305Sopenharmony_ci } 146fc223305Sopenharmony_ci if (!RenameToBrokenFile(fileName)) { 147fc223305Sopenharmony_ci return doc; 148fc223305Sopenharmony_ci } 149fc223305Sopenharmony_ci isReport = true; 150fc223305Sopenharmony_ci } 151fc223305Sopenharmony_ci 152fc223305Sopenharmony_ci if (RenameFromBackupFile(fileName, bundleName, isReport)) { 153fc223305Sopenharmony_ci doc = ReadFile(fileName, errCode); 154fc223305Sopenharmony_ci } 155fc223305Sopenharmony_ci if (isReport) { 156fc223305Sopenharmony_ci const std::string operationMsg = "operation: failed to read XML format file."; 157fc223305Sopenharmony_ci ReportXmlFileIsBroken(fileName, bundleName, operationMsg, errCode); 158fc223305Sopenharmony_ci } 159fc223305Sopenharmony_ci return doc; 160fc223305Sopenharmony_ci} 161fc223305Sopenharmony_ci 162fc223305Sopenharmony_ci/* static */ 163fc223305Sopenharmony_cibool PreferencesXmlUtils::ReadSettingXml(const std::string &fileName, const std::string &bundleName, 164fc223305Sopenharmony_ci const std::string &dataGroupId, std::vector<Element> &settings) 165fc223305Sopenharmony_ci{ 166fc223305Sopenharmony_ci LOG_RECORD_FILE_NAME("Read setting xml start."); 167fc223305Sopenharmony_ci if (fileName.size() == 0) { 168fc223305Sopenharmony_ci LOG_ERROR("The length of the file name is 0."); 169fc223305Sopenharmony_ci return false; 170fc223305Sopenharmony_ci } 171fc223305Sopenharmony_ci auto doc = 172fc223305Sopenharmony_ci std::shared_ptr<xmlDoc>(XmlReadFile(fileName, bundleName, dataGroupId), [](xmlDoc *doc) { xmlFreeDoc(doc); }); 173fc223305Sopenharmony_ci if (doc == nullptr) { 174fc223305Sopenharmony_ci return false; 175fc223305Sopenharmony_ci } 176fc223305Sopenharmony_ci 177fc223305Sopenharmony_ci xmlNode *root = xmlDocGetRootElement(doc.get()); 178fc223305Sopenharmony_ci if (!root || xmlStrcmp(root->name, reinterpret_cast<const xmlChar *>("preferences"))) { 179fc223305Sopenharmony_ci LOG_ERROR("Failed to obtain the XML root element."); 180fc223305Sopenharmony_ci return false; 181fc223305Sopenharmony_ci } 182fc223305Sopenharmony_ci 183fc223305Sopenharmony_ci bool success = true; 184fc223305Sopenharmony_ci const xmlNode *cur = nullptr; 185fc223305Sopenharmony_ci for (cur = root->children; cur != nullptr; cur = cur->next) { 186fc223305Sopenharmony_ci Element element; 187fc223305Sopenharmony_ci 188fc223305Sopenharmony_ci if (ParseNodeElement(cur, element)) { 189fc223305Sopenharmony_ci settings.push_back(element); 190fc223305Sopenharmony_ci } else { 191fc223305Sopenharmony_ci success = false; 192fc223305Sopenharmony_ci LOG_ERROR("The error occurred during getting xml child elements."); 193fc223305Sopenharmony_ci break; 194fc223305Sopenharmony_ci } 195fc223305Sopenharmony_ci } 196fc223305Sopenharmony_ci 197fc223305Sopenharmony_ci /* free the document */ 198fc223305Sopenharmony_ci LOG_RECORD_FILE_NAME("Read setting xml end."); 199fc223305Sopenharmony_ci return success; 200fc223305Sopenharmony_ci} 201fc223305Sopenharmony_ci 202fc223305Sopenharmony_ci/* static */ 203fc223305Sopenharmony_cibool ParseNodeElement(const xmlNode *node, Element &element) 204fc223305Sopenharmony_ci{ 205fc223305Sopenharmony_ci if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("int")) 206fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("long")) 207fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("bool")) 208fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("float")) 209fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("double")) 210fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("uint64_t"))) { 211fc223305Sopenharmony_ci return ParsePrimitiveNodeElement(node, element); 212fc223305Sopenharmony_ci } 213fc223305Sopenharmony_ci 214fc223305Sopenharmony_ci if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("string")) 215fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("uint8Array")) 216fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("object"))) { 217fc223305Sopenharmony_ci return ParseStringNodeElement(node, element); 218fc223305Sopenharmony_ci } 219fc223305Sopenharmony_ci 220fc223305Sopenharmony_ci if (!xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("boolArray")) 221fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("stringArray")) 222fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("doubleArray")) 223fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("BigInt")) 224fc223305Sopenharmony_ci || !xmlStrcmp(node->name, reinterpret_cast<const xmlChar *>("set"))) { 225fc223305Sopenharmony_ci return ParseArrayNodeElement(node, element); 226fc223305Sopenharmony_ci } 227fc223305Sopenharmony_ci 228fc223305Sopenharmony_ci LOG_ERROR("An unsupported element type was encountered in parsing = %{public}s.", node->name); 229fc223305Sopenharmony_ci return false; 230fc223305Sopenharmony_ci} 231fc223305Sopenharmony_ci 232fc223305Sopenharmony_ci/* static */ 233fc223305Sopenharmony_cibool ParsePrimitiveNodeElement(const xmlNode *node, Element &element) 234fc223305Sopenharmony_ci{ 235fc223305Sopenharmony_ci xmlChar *key = xmlGetProp(node, reinterpret_cast<const xmlChar *>("key")); 236fc223305Sopenharmony_ci xmlChar *value = xmlGetProp(node, reinterpret_cast<const xmlChar *>("value")); 237fc223305Sopenharmony_ci 238fc223305Sopenharmony_ci bool success = false; 239fc223305Sopenharmony_ci if (value != nullptr) { 240fc223305Sopenharmony_ci element.tag_ = std::string(reinterpret_cast<const char *>(node->name)); 241fc223305Sopenharmony_ci if (key != nullptr) { 242fc223305Sopenharmony_ci element.key_ = std::string(reinterpret_cast<char *>(key)); 243fc223305Sopenharmony_ci } 244fc223305Sopenharmony_ci element.value_ = std::string(reinterpret_cast<char *>(value)); 245fc223305Sopenharmony_ci success = true; 246fc223305Sopenharmony_ci } else { 247fc223305Sopenharmony_ci LOG_ERROR("Failed to obtain a valid key or value when parsing %{public}s.", node->name); 248fc223305Sopenharmony_ci } 249fc223305Sopenharmony_ci 250fc223305Sopenharmony_ci if (key != nullptr) { 251fc223305Sopenharmony_ci xmlFree(key); 252fc223305Sopenharmony_ci } 253fc223305Sopenharmony_ci if (value != nullptr) { 254fc223305Sopenharmony_ci xmlFree(value); 255fc223305Sopenharmony_ci } 256fc223305Sopenharmony_ci return success; 257fc223305Sopenharmony_ci} 258fc223305Sopenharmony_ci 259fc223305Sopenharmony_ci/* static */ 260fc223305Sopenharmony_cibool ParseStringNodeElement(const xmlNode *node, Element &element) 261fc223305Sopenharmony_ci{ 262fc223305Sopenharmony_ci xmlChar *key = xmlGetProp(node, (const xmlChar *)"key"); 263fc223305Sopenharmony_ci xmlChar *text = xmlNodeGetContent(node); 264fc223305Sopenharmony_ci 265fc223305Sopenharmony_ci bool success = false; 266fc223305Sopenharmony_ci if (text != nullptr) { 267fc223305Sopenharmony_ci element.tag_ = std::string(reinterpret_cast<const char *>(node->name)); 268fc223305Sopenharmony_ci if (key != nullptr) { 269fc223305Sopenharmony_ci element.key_ = std::string(reinterpret_cast<char *>(key)); 270fc223305Sopenharmony_ci } 271fc223305Sopenharmony_ci element.value_ = std::string(reinterpret_cast<char *>(text)); 272fc223305Sopenharmony_ci success = true; 273fc223305Sopenharmony_ci } else { 274fc223305Sopenharmony_ci LOG_ERROR("Failed to obtain a valid key or value when parsing string element."); 275fc223305Sopenharmony_ci } 276fc223305Sopenharmony_ci 277fc223305Sopenharmony_ci if (key != nullptr) { 278fc223305Sopenharmony_ci xmlFree(key); 279fc223305Sopenharmony_ci } 280fc223305Sopenharmony_ci if (text != nullptr) { 281fc223305Sopenharmony_ci xmlFree(text); 282fc223305Sopenharmony_ci } 283fc223305Sopenharmony_ci return success; 284fc223305Sopenharmony_ci} 285fc223305Sopenharmony_ci 286fc223305Sopenharmony_ci/* static */ 287fc223305Sopenharmony_cibool ParseArrayNodeElement(const xmlNode *node, Element &element) 288fc223305Sopenharmony_ci{ 289fc223305Sopenharmony_ci xmlChar *key = xmlGetProp(node, (const xmlChar *)"key"); 290fc223305Sopenharmony_ci const xmlNode *children = node->children; 291fc223305Sopenharmony_ci 292fc223305Sopenharmony_ci bool success = false; 293fc223305Sopenharmony_ci if (key != nullptr) { 294fc223305Sopenharmony_ci element.tag_ = std::string(reinterpret_cast<const char *>(node->name)); 295fc223305Sopenharmony_ci element.key_ = std::string(reinterpret_cast<char *>(key)); 296fc223305Sopenharmony_ci 297fc223305Sopenharmony_ci const xmlNode *cur = nullptr; 298fc223305Sopenharmony_ci bool finishTravelChild = true; 299fc223305Sopenharmony_ci for (cur = children; cur != nullptr; cur = cur->next) { 300fc223305Sopenharmony_ci Element child; 301fc223305Sopenharmony_ci if (ParseNodeElement(cur, child)) { 302fc223305Sopenharmony_ci element.children_.push_back(child); 303fc223305Sopenharmony_ci } else { 304fc223305Sopenharmony_ci finishTravelChild = false; 305fc223305Sopenharmony_ci LOG_ERROR("Failed to parse the Array element and could not be completed successfully."); 306fc223305Sopenharmony_ci break; 307fc223305Sopenharmony_ci } 308fc223305Sopenharmony_ci } 309fc223305Sopenharmony_ci success = finishTravelChild; 310fc223305Sopenharmony_ci } else { 311fc223305Sopenharmony_ci LOG_ERROR("Failed to obtain a valid key or value when parsing a Array element."); 312fc223305Sopenharmony_ci } 313fc223305Sopenharmony_ci 314fc223305Sopenharmony_ci if (key != nullptr) { 315fc223305Sopenharmony_ci xmlFree(key); 316fc223305Sopenharmony_ci } 317fc223305Sopenharmony_ci return success; 318fc223305Sopenharmony_ci} 319fc223305Sopenharmony_ci 320fc223305Sopenharmony_cistatic std::pair<bool, int> SaveFormatFileEnc(const std::string &fileName, xmlDoc *doc) 321fc223305Sopenharmony_ci{ 322fc223305Sopenharmony_ci return {xmlSaveFormatFileEnc(fileName.c_str(), doc, "UTF-8", 1) > 0, errno}; 323fc223305Sopenharmony_ci} 324fc223305Sopenharmony_ci 325fc223305Sopenharmony_cibool XmlSaveFormatFileEnc( 326fc223305Sopenharmony_ci const std::string &fileName, const std::string &bundleName, const std::string &dataGroupId, xmlDoc *doc) 327fc223305Sopenharmony_ci{ 328fc223305Sopenharmony_ci PreferencesFileLock fileLock(MakeFilePath(fileName, STR_LOCK), dataGroupId); 329fc223305Sopenharmony_ci LOG_INFO("save xml file:%{public}s.", ExtractFileName(fileName).c_str()); 330fc223305Sopenharmony_ci if (IsFileExist(fileName) && !RenameToBackupFile(fileName)) { 331fc223305Sopenharmony_ci return false; 332fc223305Sopenharmony_ci } 333fc223305Sopenharmony_ci 334fc223305Sopenharmony_ci bool isReport = false; 335fc223305Sopenharmony_ci auto [ret, errCode] = SaveFormatFileEnc(fileName, doc); 336fc223305Sopenharmony_ci if (!ret) { 337fc223305Sopenharmony_ci xmlErrorPtr xmlErr = xmlGetLastError(); 338fc223305Sopenharmony_ci std::string errMessage = (xmlErr != nullptr) ? xmlErr->message : "null"; 339fc223305Sopenharmony_ci LOG_ERROR("failed to save XML format file: %{public}s, errno is %{public}d, error is %{public}s.", 340fc223305Sopenharmony_ci ExtractFileName(fileName).c_str(), errCode, errMessage.c_str()); 341fc223305Sopenharmony_ci if (errCode == REQUIRED_KEY_NOT_AVAILABLE || errCode == REQUIRED_KEY_REVOKED) { 342fc223305Sopenharmony_ci return false; 343fc223305Sopenharmony_ci } 344fc223305Sopenharmony_ci if (IsFileExist(fileName)) { 345fc223305Sopenharmony_ci RenameToBrokenFile(fileName); 346fc223305Sopenharmony_ci isReport = true; 347fc223305Sopenharmony_ci } 348fc223305Sopenharmony_ci RenameFromBackupFile(fileName, bundleName, isReport); 349fc223305Sopenharmony_ci if (isReport) { 350fc223305Sopenharmony_ci const std::string operationMsg = "operation: failed to save XML format file."; 351fc223305Sopenharmony_ci ReportXmlFileIsBroken(fileName, bundleName, operationMsg, errCode); 352fc223305Sopenharmony_ci } 353fc223305Sopenharmony_ci return false; 354fc223305Sopenharmony_ci } 355fc223305Sopenharmony_ci 356fc223305Sopenharmony_ci RemoveBackupFile(fileName); 357fc223305Sopenharmony_ci PreferencesXmlUtils::LimitXmlPermission(fileName); 358fc223305Sopenharmony_ci // make sure the file is written to disk. 359fc223305Sopenharmony_ci if (!Fsync(fileName)) { 360fc223305Sopenharmony_ci LOG_WARN("failed to write the file to the disk."); 361fc223305Sopenharmony_ci } 362fc223305Sopenharmony_ci LOG_DEBUG("successfully saved the XML format file"); 363fc223305Sopenharmony_ci return true; 364fc223305Sopenharmony_ci} 365fc223305Sopenharmony_ci 366fc223305Sopenharmony_ci/* static */ 367fc223305Sopenharmony_cibool PreferencesXmlUtils::WriteSettingXml(const std::string &fileName, const std::string &bundleName, 368fc223305Sopenharmony_ci const std::string &dataGroupId, const std::vector<Element> &settings) 369fc223305Sopenharmony_ci{ 370fc223305Sopenharmony_ci LOG_RECORD_FILE_NAME("Write setting xml start."); 371fc223305Sopenharmony_ci if (fileName.size() == 0) { 372fc223305Sopenharmony_ci LOG_ERROR("The length of the file name is 0."); 373fc223305Sopenharmony_ci return false; 374fc223305Sopenharmony_ci } 375fc223305Sopenharmony_ci 376fc223305Sopenharmony_ci // define doc and root Node 377fc223305Sopenharmony_ci auto doc = std::shared_ptr<xmlDoc>(xmlNewDoc(BAD_CAST "1.0"), [](xmlDoc *doc) { xmlFreeDoc(doc); }); 378fc223305Sopenharmony_ci if (doc == nullptr) { 379fc223305Sopenharmony_ci LOG_ERROR("Failed to initialize the xmlDoc."); 380fc223305Sopenharmony_ci return false; 381fc223305Sopenharmony_ci } 382fc223305Sopenharmony_ci xmlNode *rootNode = xmlNewNode(NULL, BAD_CAST "preferences"); 383fc223305Sopenharmony_ci if (rootNode == nullptr) { 384fc223305Sopenharmony_ci LOG_ERROR("The xmlDoc failed to initialize the root node."); 385fc223305Sopenharmony_ci return false; 386fc223305Sopenharmony_ci } 387fc223305Sopenharmony_ci xmlNewProp(rootNode, BAD_CAST "version", BAD_CAST "1.0"); 388fc223305Sopenharmony_ci 389fc223305Sopenharmony_ci // set root node 390fc223305Sopenharmony_ci xmlDocSetRootElement(doc.get(), rootNode); 391fc223305Sopenharmony_ci 392fc223305Sopenharmony_ci // set children node 393fc223305Sopenharmony_ci for (Element element : settings) { 394fc223305Sopenharmony_ci xmlNode *node = CreateElementNode(element); 395fc223305Sopenharmony_ci if (node == nullptr) { 396fc223305Sopenharmony_ci LOG_ERROR("The xmlDoc failed to initialize the element node."); 397fc223305Sopenharmony_ci return false; 398fc223305Sopenharmony_ci } 399fc223305Sopenharmony_ci if (xmlAddChild(rootNode, node) == nullptr) { 400fc223305Sopenharmony_ci /* free node in case of error */ 401fc223305Sopenharmony_ci LOG_ERROR("The xmlDoc failed to add the child node."); 402fc223305Sopenharmony_ci xmlFreeNode(node); 403fc223305Sopenharmony_ci return false; 404fc223305Sopenharmony_ci } 405fc223305Sopenharmony_ci } 406fc223305Sopenharmony_ci 407fc223305Sopenharmony_ci /* 1: formatting spaces are added. */ 408fc223305Sopenharmony_ci bool result = XmlSaveFormatFileEnc(fileName, bundleName, dataGroupId, doc.get()); 409fc223305Sopenharmony_ci LOG_RECORD_FILE_NAME("Write setting xml end."); 410fc223305Sopenharmony_ci return result; 411fc223305Sopenharmony_ci} 412fc223305Sopenharmony_ci 413fc223305Sopenharmony_ci/* static */ 414fc223305Sopenharmony_cixmlNode *CreateElementNode(Element &element) 415fc223305Sopenharmony_ci{ 416fc223305Sopenharmony_ci if ((element.tag_.compare("int") == 0) || (element.tag_.compare("long") == 0) 417fc223305Sopenharmony_ci || (element.tag_.compare("float") == 0) || (element.tag_.compare("bool") == 0) 418fc223305Sopenharmony_ci || (element.tag_.compare("double") == 0)) { 419fc223305Sopenharmony_ci return CreatePrimitiveNode(element); 420fc223305Sopenharmony_ci } 421fc223305Sopenharmony_ci 422fc223305Sopenharmony_ci if (element.tag_.compare("string") == 0 || element.tag_.compare("uint8Array") == 0 423fc223305Sopenharmony_ci || element.tag_.compare("object") == 0) { 424fc223305Sopenharmony_ci return CreateStringNode(element); 425fc223305Sopenharmony_ci } 426fc223305Sopenharmony_ci 427fc223305Sopenharmony_ci if ((element.tag_.compare("doubleArray") == 0) || (element.tag_.compare("stringArray") == 0) 428fc223305Sopenharmony_ci || (element.tag_.compare("boolArray") == 0) || (element.tag_.compare("BigInt") == 0)) { 429fc223305Sopenharmony_ci return CreateArrayNode(element); 430fc223305Sopenharmony_ci } 431fc223305Sopenharmony_ci 432fc223305Sopenharmony_ci LOG_ERROR("An unsupported element type was encountered in parsing = %{public}s.", element.tag_.c_str()); 433fc223305Sopenharmony_ci return nullptr; 434fc223305Sopenharmony_ci} 435fc223305Sopenharmony_ci 436fc223305Sopenharmony_ci/* static */ 437fc223305Sopenharmony_cixmlNode *CreatePrimitiveNode(Element &element) 438fc223305Sopenharmony_ci{ 439fc223305Sopenharmony_ci xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str()); 440fc223305Sopenharmony_ci if (node == nullptr) { 441fc223305Sopenharmony_ci LOG_ERROR("The xmlDoc failed to initialize the primitive element node."); 442fc223305Sopenharmony_ci return nullptr; 443fc223305Sopenharmony_ci } 444fc223305Sopenharmony_ci if (!element.key_.empty()) { 445fc223305Sopenharmony_ci const char *key = element.key_.c_str(); 446fc223305Sopenharmony_ci xmlNewProp(node, BAD_CAST "key", BAD_CAST key); 447fc223305Sopenharmony_ci } 448fc223305Sopenharmony_ci 449fc223305Sopenharmony_ci const char *value = element.value_.c_str(); 450fc223305Sopenharmony_ci xmlNewProp(node, BAD_CAST "value", BAD_CAST value); 451fc223305Sopenharmony_ci return node; 452fc223305Sopenharmony_ci} 453fc223305Sopenharmony_ci 454fc223305Sopenharmony_cixmlNode *CreateStringNode(Element &element) 455fc223305Sopenharmony_ci{ 456fc223305Sopenharmony_ci xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str()); 457fc223305Sopenharmony_ci if (node == nullptr) { 458fc223305Sopenharmony_ci LOG_ERROR("The xmlDoc failed to initialize the string element node."); 459fc223305Sopenharmony_ci return nullptr; 460fc223305Sopenharmony_ci } 461fc223305Sopenharmony_ci 462fc223305Sopenharmony_ci if (!element.key_.empty()) { 463fc223305Sopenharmony_ci const char *key = element.key_.c_str(); 464fc223305Sopenharmony_ci xmlNewProp(node, BAD_CAST "key", BAD_CAST key); 465fc223305Sopenharmony_ci } 466fc223305Sopenharmony_ci 467fc223305Sopenharmony_ci const char *value = element.value_.c_str(); 468fc223305Sopenharmony_ci xmlNodePtr text = xmlNewText(BAD_CAST value); 469fc223305Sopenharmony_ci if (xmlAddChild(node, text) == nullptr) { 470fc223305Sopenharmony_ci xmlFreeNode(text); 471fc223305Sopenharmony_ci } 472fc223305Sopenharmony_ci return node; 473fc223305Sopenharmony_ci} 474fc223305Sopenharmony_ci 475fc223305Sopenharmony_cixmlNode *CreateArrayNode(Element &element) 476fc223305Sopenharmony_ci{ 477fc223305Sopenharmony_ci xmlNode *node = xmlNewNode(NULL, BAD_CAST element.tag_.c_str()); 478fc223305Sopenharmony_ci if (node == nullptr) { 479fc223305Sopenharmony_ci LOG_ERROR("The xmlDoc failed to initialize the array element node."); 480fc223305Sopenharmony_ci return nullptr; 481fc223305Sopenharmony_ci } 482fc223305Sopenharmony_ci 483fc223305Sopenharmony_ci const char *key = element.key_.c_str(); 484fc223305Sopenharmony_ci xmlNewProp(node, BAD_CAST "key", BAD_CAST key); 485fc223305Sopenharmony_ci 486fc223305Sopenharmony_ci if (element.children_.empty()) { 487fc223305Sopenharmony_ci return node; 488fc223305Sopenharmony_ci } 489fc223305Sopenharmony_ci Element flag = element.children_[0]; 490fc223305Sopenharmony_ci if ((flag.tag_.compare("bool") == 0) || (flag.tag_.compare("double") == 0) || 491fc223305Sopenharmony_ci (flag.tag_.compare("uint64_t") == 0)) { 492fc223305Sopenharmony_ci for (Element &child : element.children_) { 493fc223305Sopenharmony_ci xmlNode *childNode = CreatePrimitiveNode(child); 494fc223305Sopenharmony_ci if (childNode == nullptr) { 495fc223305Sopenharmony_ci continue; 496fc223305Sopenharmony_ci } 497fc223305Sopenharmony_ci if (xmlAddChild(node, childNode) == nullptr) { 498fc223305Sopenharmony_ci xmlFreeNode(childNode); 499fc223305Sopenharmony_ci } 500fc223305Sopenharmony_ci } 501fc223305Sopenharmony_ci } else if (flag.tag_.compare("string") == 0) { 502fc223305Sopenharmony_ci for (Element child : element.children_) { 503fc223305Sopenharmony_ci xmlNode *childNode = CreateStringNode(child); 504fc223305Sopenharmony_ci if (childNode == nullptr) { 505fc223305Sopenharmony_ci continue; 506fc223305Sopenharmony_ci } 507fc223305Sopenharmony_ci if (xmlAddChild(node, childNode) == nullptr) { 508fc223305Sopenharmony_ci xmlFreeNode(childNode); 509fc223305Sopenharmony_ci } 510fc223305Sopenharmony_ci } 511fc223305Sopenharmony_ci } 512fc223305Sopenharmony_ci return node; 513fc223305Sopenharmony_ci} 514fc223305Sopenharmony_ci 515fc223305Sopenharmony_civoid PreferencesXmlUtils::LimitXmlPermission(const std::string &fileName) 516fc223305Sopenharmony_ci{ 517fc223305Sopenharmony_ci /* clear execute permission of owner, clear execute permission of group, clear all permission of group. */ 518fc223305Sopenharmony_ci struct stat fileStat = { 0 }; 519fc223305Sopenharmony_ci if (stat(fileName.c_str(), &fileStat) != 0) { 520fc223305Sopenharmony_ci LOG_ERROR("Failed to obtain stat of file, errno:%{public}d.", errno); 521fc223305Sopenharmony_ci return; 522fc223305Sopenharmony_ci } 523fc223305Sopenharmony_ci if ((fileStat.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO)) != 0) { 524fc223305Sopenharmony_ci int result = chmod(fileName.c_str(), fileStat.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); 525fc223305Sopenharmony_ci if (result != 0) { 526fc223305Sopenharmony_ci LOG_ERROR("Failed to chmod file, errno:%{public}d.", errno); 527fc223305Sopenharmony_ci } 528fc223305Sopenharmony_ci } 529fc223305Sopenharmony_ci} 530fc223305Sopenharmony_ci} // End of namespace NativePreferences 531fc223305Sopenharmony_ci} // End of namespace OHOS