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