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_helper.h"
17fc223305Sopenharmony_ci
18fc223305Sopenharmony_ci#include <cerrno>
19fc223305Sopenharmony_ci#include <climits>
20fc223305Sopenharmony_ci#include <cstdlib>
21fc223305Sopenharmony_ci#include <utility>
22fc223305Sopenharmony_ci
23fc223305Sopenharmony_ci#include "log_print.h"
24fc223305Sopenharmony_ci#include "preferences.h"
25fc223305Sopenharmony_ci#include "preferences_db_adapter.h"
26fc223305Sopenharmony_ci#include "preferences_errno.h"
27fc223305Sopenharmony_ci#include "preferences_file_lock.h"
28fc223305Sopenharmony_ci#include "preferences_file_operation.h"
29fc223305Sopenharmony_ci#include "preferences_dfx_adapter.h"
30fc223305Sopenharmony_ci#include "preferences_impl.h"
31fc223305Sopenharmony_ci#include "preferences_enhance_impl.h"
32fc223305Sopenharmony_cinamespace OHOS {
33fc223305Sopenharmony_cinamespace NativePreferences {
34fc223305Sopenharmony_cistd::map<std::string, std::pair<std::shared_ptr<Preferences>, bool>> PreferencesHelper::prefsCache_;
35fc223305Sopenharmony_cistd::mutex PreferencesHelper::prefsCacheMutex_;
36fc223305Sopenharmony_cistatic constexpr const int DB_SUFFIX_NUM = 6;
37fc223305Sopenharmony_cistatic constexpr const char *DB_SUFFIX[DB_SUFFIX_NUM] = { ".ctrl", ".ctrl.dwr", ".redo", ".undo", ".safe", ".map" };
38fc223305Sopenharmony_ci
39fc223305Sopenharmony_cistatic bool IsFileExist(const std::string &path)
40fc223305Sopenharmony_ci{
41fc223305Sopenharmony_ci    struct stat buffer;
42fc223305Sopenharmony_ci    return (stat(path.c_str(), &buffer) == 0);
43fc223305Sopenharmony_ci}
44fc223305Sopenharmony_ci
45fc223305Sopenharmony_cistatic int RemoveEnhanceDb(const std::string &filePath)
46fc223305Sopenharmony_ci{
47fc223305Sopenharmony_ci    if (std::remove(filePath.c_str()) != 0) {
48fc223305Sopenharmony_ci        LOG_ERROR("remove %{public}s failed.", ExtractFileName(filePath).c_str());
49fc223305Sopenharmony_ci        return E_DELETE_FILE_FAIL;
50fc223305Sopenharmony_ci    }
51fc223305Sopenharmony_ci    return E_OK;
52fc223305Sopenharmony_ci}
53fc223305Sopenharmony_ci
54fc223305Sopenharmony_cistatic int RemoveEnhanceDbFileIfNeed(const std::string &filePath)
55fc223305Sopenharmony_ci{
56fc223305Sopenharmony_ci    std::string dbFilePath = filePath + ".db";
57fc223305Sopenharmony_ci    if (IsFileExist(dbFilePath) && RemoveEnhanceDb(dbFilePath) != E_OK) {
58fc223305Sopenharmony_ci        LOG_ERROR("remove dbFilePath failed.");
59fc223305Sopenharmony_ci        return E_DELETE_FILE_FAIL;
60fc223305Sopenharmony_ci    }
61fc223305Sopenharmony_ci    for (int index = 0; index < DB_SUFFIX_NUM; index++) {
62fc223305Sopenharmony_ci        std::string tmpFilePath = dbFilePath + DB_SUFFIX[index];
63fc223305Sopenharmony_ci        if (IsFileExist(tmpFilePath) && RemoveEnhanceDb(tmpFilePath) != E_OK) {
64fc223305Sopenharmony_ci            return E_DELETE_FILE_FAIL;
65fc223305Sopenharmony_ci        }
66fc223305Sopenharmony_ci    }
67fc223305Sopenharmony_ci    LOG_DEBUG("db files has been removed.");
68fc223305Sopenharmony_ci    return E_OK;
69fc223305Sopenharmony_ci}
70fc223305Sopenharmony_ci
71fc223305Sopenharmony_cistd::string PreferencesHelper::GetRealPath(const std::string &path, int &errorCode)
72fc223305Sopenharmony_ci{
73fc223305Sopenharmony_ci    if (path.empty()) {
74fc223305Sopenharmony_ci        LOG_ERROR("The path can not be empty.");
75fc223305Sopenharmony_ci        errorCode = E_EMPTY_FILE_PATH;
76fc223305Sopenharmony_ci        return "";
77fc223305Sopenharmony_ci    }
78fc223305Sopenharmony_ci    if (path.length() > PATH_MAX) {
79fc223305Sopenharmony_ci        LOG_ERROR("The path exceeds max length.");
80fc223305Sopenharmony_ci        errorCode = E_PATH_EXCEED_MAX_LENGTH;
81fc223305Sopenharmony_ci        return "";
82fc223305Sopenharmony_ci    }
83fc223305Sopenharmony_ci    std::string::size_type pos = path.find_last_of('/');
84fc223305Sopenharmony_ci    if (pos == std::string::npos) {
85fc223305Sopenharmony_ci        LOG_ERROR("path can not be relative path.");
86fc223305Sopenharmony_ci        errorCode = E_RELATIVE_PATH;
87fc223305Sopenharmony_ci        return "";
88fc223305Sopenharmony_ci    }
89fc223305Sopenharmony_ci#if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
90fc223305Sopenharmony_ci    if (path.at(1) != ':') {
91fc223305Sopenharmony_ci        LOG_ERROR("The path can not be relative path.");
92fc223305Sopenharmony_ci        errorCode = E_RELATIVE_PATH;
93fc223305Sopenharmony_ci        return "";
94fc223305Sopenharmony_ci    }
95fc223305Sopenharmony_ci    std::string filePath = path.substr(0, pos);
96fc223305Sopenharmony_ci    if (Access(filePath) != 0 && !Mkdir(filePath)) {
97fc223305Sopenharmony_ci        LOG_ERROR("Failed to create path");
98fc223305Sopenharmony_ci        errorCode = E_INVALID_FILE_PATH;
99fc223305Sopenharmony_ci        return "";
100fc223305Sopenharmony_ci    }
101fc223305Sopenharmony_ci#else
102fc223305Sopenharmony_ci    if (path.front() != '/') {
103fc223305Sopenharmony_ci        LOG_ERROR("The path can not be relative path.");
104fc223305Sopenharmony_ci        errorCode = E_RELATIVE_PATH;
105fc223305Sopenharmony_ci        return "";
106fc223305Sopenharmony_ci    }
107fc223305Sopenharmony_ci#endif
108fc223305Sopenharmony_ci    std::string fileName = path.substr(pos + 1, path.length());
109fc223305Sopenharmony_ci    if (fileName.empty()) {
110fc223305Sopenharmony_ci        LOG_ERROR("file name can not be empty.");
111fc223305Sopenharmony_ci        errorCode = E_EMPTY_FILE_NAME;
112fc223305Sopenharmony_ci        return "";
113fc223305Sopenharmony_ci    }
114fc223305Sopenharmony_ci    errorCode = E_OK;
115fc223305Sopenharmony_ci    return path;
116fc223305Sopenharmony_ci}
117fc223305Sopenharmony_ci
118fc223305Sopenharmony_ci#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
119fc223305Sopenharmony_cistatic bool IsUseEnhanceDb(const Options &options)
120fc223305Sopenharmony_ci{
121fc223305Sopenharmony_ci    if (IsFileExist(options.filePath)) {
122fc223305Sopenharmony_ci        return false;
123fc223305Sopenharmony_ci    }
124fc223305Sopenharmony_ci    bool bundleCheck = (options.bundleName.find("uttest") != std::string::npos ||
125fc223305Sopenharmony_ci        options.bundleName.find("alipay") != std::string::npos ||
126fc223305Sopenharmony_ci        options.bundleName.find("com.jd.") != std::string::npos ||
127fc223305Sopenharmony_ci        options.bundleName.find("cmblife") != std::string::npos ||
128fc223305Sopenharmony_ci        options.bundleName.find("os.mms") != std::string::npos ||
129fc223305Sopenharmony_ci        options.bundleName.find("os.ouc") != std::string::npos ||
130fc223305Sopenharmony_ci        options.bundleName.find("meetimeservice") != std::string::npos);
131fc223305Sopenharmony_ci    if (!options.isEnhance && !bundleCheck) {
132fc223305Sopenharmony_ci        return false;
133fc223305Sopenharmony_ci    }
134fc223305Sopenharmony_ci    PreferenceDbAdapter::ApiInit();
135fc223305Sopenharmony_ci    return PreferenceDbAdapter::IsEnhandceDbEnable();
136fc223305Sopenharmony_ci}
137fc223305Sopenharmony_ci#endif
138fc223305Sopenharmony_ci
139fc223305Sopenharmony_cistd::shared_ptr<Preferences> PreferencesHelper::GetPreferences(const Options &options, int &errCode)
140fc223305Sopenharmony_ci{
141fc223305Sopenharmony_ci    std::string realPath = GetRealPath(options.filePath, errCode);
142fc223305Sopenharmony_ci    if (realPath == "" || errCode != E_OK) {
143fc223305Sopenharmony_ci        return nullptr;
144fc223305Sopenharmony_ci    }
145fc223305Sopenharmony_ci
146fc223305Sopenharmony_ci    std::lock_guard<std::mutex> lock(prefsCacheMutex_);
147fc223305Sopenharmony_ci    auto it = prefsCache_.find(realPath);
148fc223305Sopenharmony_ci    if (it != prefsCache_.end()) {
149fc223305Sopenharmony_ci        auto pre = it->second.first;
150fc223305Sopenharmony_ci        if (pre != nullptr) {
151fc223305Sopenharmony_ci            LOG_DEBUG("GetPreferences: found preferences in cache");
152fc223305Sopenharmony_ci            return pre;
153fc223305Sopenharmony_ci        }
154fc223305Sopenharmony_ci        LOG_DEBUG("GetPreferences: found preferences in cache but it's null, erase it.");
155fc223305Sopenharmony_ci        prefsCache_.erase(it);
156fc223305Sopenharmony_ci    }
157fc223305Sopenharmony_ci
158fc223305Sopenharmony_ci    const_cast<Options &>(options).filePath = realPath;
159fc223305Sopenharmony_ci    std::string::size_type pos = realPath.find_last_of('/');
160fc223305Sopenharmony_ci    std::string filePath = realPath.substr(0, pos);
161fc223305Sopenharmony_ci    if (access(filePath.c_str(), F_OK) != 0) {
162fc223305Sopenharmony_ci        LOG_ERROR("The path is invalid, prefName is %{public}s.", ExtractFileName(realPath).c_str());
163fc223305Sopenharmony_ci        errCode = E_INVALID_FILE_PATH;
164fc223305Sopenharmony_ci        return nullptr;
165fc223305Sopenharmony_ci    }
166fc223305Sopenharmony_ci    std::shared_ptr<Preferences> pref = nullptr;
167fc223305Sopenharmony_ci    bool isEnhancePreferences = false;
168fc223305Sopenharmony_ci#if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) &&!defined(IOS_PLATFORM)
169fc223305Sopenharmony_ci    if (IsUseEnhanceDb(options)) {
170fc223305Sopenharmony_ci        LOG_DEBUG("PreferencesHelper::GetPreferences using enhance db.");
171fc223305Sopenharmony_ci        pref = PreferencesEnhanceImpl::GetPreferences(options);
172fc223305Sopenharmony_ci        errCode = std::static_pointer_cast<PreferencesEnhanceImpl>(pref)->Init();
173fc223305Sopenharmony_ci        isEnhancePreferences = true;
174fc223305Sopenharmony_ci    } else {
175fc223305Sopenharmony_ci        pref = PreferencesImpl::GetPreferences(options);
176fc223305Sopenharmony_ci        errCode = std::static_pointer_cast<PreferencesImpl>(pref)->Init();
177fc223305Sopenharmony_ci    }
178fc223305Sopenharmony_ci#else
179fc223305Sopenharmony_ci    pref = PreferencesImpl::GetPreferences(options);
180fc223305Sopenharmony_ci    errCode = std::static_pointer_cast<PreferencesImpl>(pref)->Init();
181fc223305Sopenharmony_ci#endif
182fc223305Sopenharmony_ci    if (errCode != E_OK) {
183fc223305Sopenharmony_ci        return nullptr;
184fc223305Sopenharmony_ci    }
185fc223305Sopenharmony_ci    prefsCache_.insert({realPath, {pref, isEnhancePreferences}});
186fc223305Sopenharmony_ci    return pref;
187fc223305Sopenharmony_ci}
188fc223305Sopenharmony_ci
189fc223305Sopenharmony_ciint PreferencesHelper::DeletePreferences(const std::string &path)
190fc223305Sopenharmony_ci{
191fc223305Sopenharmony_ci    int errCode = E_OK;
192fc223305Sopenharmony_ci    std::string realPath = GetRealPath(path, errCode);
193fc223305Sopenharmony_ci    if (realPath == "" || errCode != E_OK) {
194fc223305Sopenharmony_ci        return errCode;
195fc223305Sopenharmony_ci    }
196fc223305Sopenharmony_ci
197fc223305Sopenharmony_ci    std::string dataGroupId = "";
198fc223305Sopenharmony_ci    {
199fc223305Sopenharmony_ci        std::lock_guard<std::mutex> lock(prefsCacheMutex_);
200fc223305Sopenharmony_ci        std::map<std::string, std::pair<std::shared_ptr<Preferences>, bool>>::iterator it = prefsCache_.find(realPath);
201fc223305Sopenharmony_ci        if (it != prefsCache_.end()) {
202fc223305Sopenharmony_ci            auto pref = it->second.first;
203fc223305Sopenharmony_ci            if (pref != nullptr) {
204fc223305Sopenharmony_ci                LOG_INFO("Begin to Delete Preferences: %{public}s", ExtractFileName(path).c_str());
205fc223305Sopenharmony_ci                dataGroupId = pref->GetGroupId();
206fc223305Sopenharmony_ci                errCode = pref->CloseDb();
207fc223305Sopenharmony_ci                if (errCode != E_OK) {
208fc223305Sopenharmony_ci                    LOG_ERROR("failed to close db when delete preferences.");
209fc223305Sopenharmony_ci                    return errCode;
210fc223305Sopenharmony_ci                }
211fc223305Sopenharmony_ci            }
212fc223305Sopenharmony_ci            pref = nullptr;
213fc223305Sopenharmony_ci            prefsCache_.erase(it);
214fc223305Sopenharmony_ci            LOG_DEBUG("DeletePreferences: found preferences in cache, erase it.");
215fc223305Sopenharmony_ci        } else {
216fc223305Sopenharmony_ci            LOG_DEBUG("DeletePreferences: cache not found, just delete files.");
217fc223305Sopenharmony_ci        }
218fc223305Sopenharmony_ci    }
219fc223305Sopenharmony_ci
220fc223305Sopenharmony_ci    std::string filePath = realPath.c_str();
221fc223305Sopenharmony_ci    std::string backupPath = MakeFilePath(filePath, STR_BACKUP);
222fc223305Sopenharmony_ci    std::string brokenPath = MakeFilePath(filePath, STR_BROKEN);
223fc223305Sopenharmony_ci    std::string lockFilePath = MakeFilePath(filePath, STR_LOCK);
224fc223305Sopenharmony_ci
225fc223305Sopenharmony_ci    PreferencesFileLock fileLock(lockFilePath, dataGroupId);
226fc223305Sopenharmony_ci    std::remove(filePath.c_str());
227fc223305Sopenharmony_ci    std::remove(backupPath.c_str());
228fc223305Sopenharmony_ci    std::remove(brokenPath.c_str());
229fc223305Sopenharmony_ci    if (RemoveEnhanceDbFileIfNeed(path) != E_OK) {
230fc223305Sopenharmony_ci        return E_DELETE_FILE_FAIL;
231fc223305Sopenharmony_ci    }
232fc223305Sopenharmony_ci
233fc223305Sopenharmony_ci    if (!dataGroupId.empty()) {
234fc223305Sopenharmony_ci        std::remove(lockFilePath.c_str());
235fc223305Sopenharmony_ci    }
236fc223305Sopenharmony_ci
237fc223305Sopenharmony_ci    if (IsFileExist(filePath) || IsFileExist(backupPath) || IsFileExist(brokenPath)) {
238fc223305Sopenharmony_ci        return E_DELETE_FILE_FAIL;
239fc223305Sopenharmony_ci    }
240fc223305Sopenharmony_ci    return E_OK;
241fc223305Sopenharmony_ci}
242fc223305Sopenharmony_ci
243fc223305Sopenharmony_ciint PreferencesHelper::RemovePreferencesFromCache(const std::string &path)
244fc223305Sopenharmony_ci{
245fc223305Sopenharmony_ci    int errCode = E_OK;
246fc223305Sopenharmony_ci    std::string realPath = GetRealPath(path, errCode);
247fc223305Sopenharmony_ci    if (realPath == "" || errCode != E_OK) {
248fc223305Sopenharmony_ci        return errCode;
249fc223305Sopenharmony_ci    }
250fc223305Sopenharmony_ci
251fc223305Sopenharmony_ci    std::lock_guard<std::mutex> lock(prefsCacheMutex_);
252fc223305Sopenharmony_ci    std::map<std::string, std::pair<std::shared_ptr<Preferences>, bool>>::iterator it = prefsCache_.find(realPath);
253fc223305Sopenharmony_ci    if (it == prefsCache_.end()) {
254fc223305Sopenharmony_ci        LOG_DEBUG("RemovePreferencesFromCache: preferences not in cache, just return");
255fc223305Sopenharmony_ci        return E_OK;
256fc223305Sopenharmony_ci    }
257fc223305Sopenharmony_ci
258fc223305Sopenharmony_ci    if (it->second.second) {
259fc223305Sopenharmony_ci        auto pref = it->second.first;
260fc223305Sopenharmony_ci        errCode = std::static_pointer_cast<PreferencesEnhanceImpl>(pref)->CloseDb();
261fc223305Sopenharmony_ci        if (errCode != E_OK) {
262fc223305Sopenharmony_ci            LOG_ERROR("RemovePreferencesFromCache: failed to close db.");
263fc223305Sopenharmony_ci            return E_ERROR;
264fc223305Sopenharmony_ci        }
265fc223305Sopenharmony_ci    }
266fc223305Sopenharmony_ci
267fc223305Sopenharmony_ci    prefsCache_.erase(it);
268fc223305Sopenharmony_ci    return E_OK;
269fc223305Sopenharmony_ci}
270fc223305Sopenharmony_ci} // End of namespace NativePreferences
271fc223305Sopenharmony_ci} // End of namespace OHOS