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