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_errno.h"
26 #include "preferences_file_operation.h"
27 #include "preferences_impl.h"
28 #include "securec.h"
29
30 namespace OHOS {
31 namespace NativePreferences {
32 std::map<std::string, std::shared_ptr<Preferences>> PreferencesHelper::prefsCache_;
33 std::mutex PreferencesHelper::prefsCacheMutex_;
IsFileExist(const std::string & path)34 static bool IsFileExist(const std::string &path)
35 {
36 struct stat buffer;
37 return (stat(path.c_str(), &buffer) == 0);
38 }
39
GetRealPath(const std::string & path,int & errorCode)40 std::string PreferencesHelper::GetRealPath(const std::string &path, int &errorCode)
41 {
42 if (path.empty()) {
43 LOG_ERROR("The path can not be empty.");
44 errorCode = E_EMPTY_FILE_PATH;
45 return "";
46 }
47 if (path.front() != '/' && path.at(1) != ':') {
48 LOG_ERROR("The path can not be relative path.");
49 errorCode = E_RELATIVE_PATH;
50 return "";
51 }
52 if (strlen(path.c_str()) > PATH_MAX) {
53 LOG_ERROR("The path exceeds max length.");
54 errorCode = E_PATH_EXCEED_MAX_LENGTH;
55 return "";
56 }
57 std::string::size_type pos = path.find_last_of('/');
58 if (pos == std::string::npos) {
59 LOG_ERROR("path can not be relative path.");
60 errorCode = E_RELATIVE_PATH;
61 return "";
62 }
63 std::string filePath = path.substr(0, pos);
64 #if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
65 if (Access(filePath) != 0 && Mkdir(filePath)) {
66 LOG_ERROR("Failed to create path");
67 errorCode = E_INVALID_FILE_PATH;
68 return "";
69 }
70 #endif
71 std::string fileName = path.substr(pos + 1, path.length());
72 if (fileName.empty()) {
73 LOG_ERROR("file name can not be empty.");
74 errorCode = E_EMPTY_FILE_NAME;
75 return "";
76 }
77 errorCode = E_OK;
78 return path;
79 }
80
GetPreferences(const Options & options,int & errCode)81 std::shared_ptr<Preferences> PreferencesHelper::GetPreferences(const Options &options, int &errCode)
82 {
83 std::string realPath = GetRealPath(options.filePath, errCode);
84 if (realPath == "" || errCode != E_OK) {
85 return nullptr;
86 }
87
88 std::lock_guard<std::mutex> lock(prefsCacheMutex_);
89 std::map<std::string, std::shared_ptr<Preferences>>::iterator it = prefsCache_.find(realPath);
90 if (it != prefsCache_.end()) {
91 return it->second;
92 }
93
94 const_cast<Options &>(options).filePath = realPath;
95 std::shared_ptr<PreferencesImpl> pref = PreferencesImpl::GetPreferences(options);
96 errCode = pref->Init();
97 if (errCode != E_OK) {
98 return nullptr;
99 }
100 prefsCache_.insert(make_pair(realPath, pref));
101 return pref;
102 }
103
DeletePreferences(const std::string & path)104 int PreferencesHelper::DeletePreferences(const std::string &path)
105 {
106 int errCode = E_OK;
107 std::string realPath = GetRealPath(path, errCode);
108 if (realPath == "" || errCode != E_OK) {
109 return errCode;
110 }
111
112 std::lock_guard<std::mutex> lock(prefsCacheMutex_);
113 std::map<std::string, std::shared_ptr<Preferences>>::iterator it = prefsCache_.find(realPath);
114 if (it != prefsCache_.end()) {
115 prefsCache_.erase(it);
116 }
117
118 std::string filePath = realPath.c_str();
119 std::string backupPath = PreferencesImpl::MakeFilePath(filePath, STR_BACKUP);
120 std::string brokenPath = PreferencesImpl::MakeFilePath(filePath, STR_BROKEN);
121 std::string lockFilePath = PreferencesImpl::MakeFilePath(filePath, STR_LOCK);
122
123 std::remove(filePath.c_str());
124 std::remove(backupPath.c_str());
125 std::remove(brokenPath.c_str());
126
127 if (IsFileExist(filePath) || IsFileExist(backupPath) || IsFileExist(brokenPath)) {
128 return E_DELETE_FILE_FAIL;
129 }
130 return E_OK;
131 }
132
RemovePreferencesFromCache(const std::string & path)133 int PreferencesHelper::RemovePreferencesFromCache(const std::string &path)
134 {
135 int errCode = E_OK;
136 std::string realPath = GetRealPath(path, errCode);
137 if (realPath == "" || errCode != E_OK) {
138 return errCode;
139 }
140
141 std::lock_guard<std::mutex> lock(prefsCacheMutex_);
142 std::map<std::string, std::shared_ptr<Preferences>>::iterator it = prefsCache_.find(realPath);
143 if (it == prefsCache_.end()) {
144 return E_OK;
145 }
146 prefsCache_.erase(it);
147 return E_OK;
148 }
149 } // End of namespace NativePreferences
150 } // End of namespace OHOS
151