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 #define LOG_TAG "SqliteUtils"
16 #include "sqlite_utils.h"
17
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22
23 #include <algorithm>
24 #include <cerrno>
25 #include <climits>
26 #include <cstdio>
27 #include <cstring>
28 #include <fstream>
29 #include <regex>
30
31 #include "logger.h"
32 #include "rdb_errno.h"
33 #include "rdb_store_config.h"
34 namespace OHOS {
35 namespace NativeRdb {
36 using namespace OHOS::Rdb;
37
38 /* A continuous number must contain at least eight digits, because the employee ID has eight digits,
39 and the mobile phone number has 11 digits. The UUID is longer */
40 constexpr int32_t CONTINUOUS_DIGITS_MINI_SIZE = 6;
41 constexpr int32_t FILE_PATH_MINI_SIZE = 6;
42 constexpr int32_t AREA_MINI_SIZE = 4;
43 constexpr int32_t AREA_OFFSET_SIZE = 5;
44 constexpr int32_t PRE_OFFSET_SIZE = 1;
45
46 constexpr SqliteUtils::SqlType SqliteUtils::SQL_TYPE_MAP[];
47 constexpr const char *SqliteUtils::ON_CONFLICT_CLAUSE[];
48
GetSqlStatementType(const std::string &sql)49 int SqliteUtils::GetSqlStatementType(const std::string &sql)
50 {
51 /* the sql string length less than 3 can not be any type sql */
52 auto alnum = std::find_if(sql.begin(), sql.end(), [](int ch) { return !std::isspace(ch) && !std::iscntrl(ch); });
53 if (alnum == sql.end()) {
54 return STATEMENT_ERROR;
55 }
56 auto pos = static_cast<std::string::size_type>(alnum - sql.begin());
57 /* 3 represents the number of prefix characters that need to be extracted and checked */
58 if (pos + 3 >= sql.length()) {
59 return STATEMENT_ERROR;
60 }
61 /* analyze the sql type through first 3 characters */
62 std::string prefixSql = StrToUpper(sql.substr(pos, 3));
63 SqlType type = { prefixSql.c_str(), STATEMENT_OTHER };
64 auto comp = [](const SqlType &first, const SqlType &second) {
65 return strcmp(first.sql, second.sql) < 0;
66 };
67 auto it = std::lower_bound(SQL_TYPE_MAP, SQL_TYPE_MAP + TYPE_SIZE, type, comp);
68 if (it < SQL_TYPE_MAP + TYPE_SIZE && !comp(type, *it)) {
69 return it->type;
70 }
71 return STATEMENT_OTHER;
72 }
73
StrToUpper(std::string s)74 std::string SqliteUtils::StrToUpper(std::string s)
75 {
76 std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::toupper(c); });
77 return s;
78 }
79
Replace(std::string &src, const std::string &rep, const std::string &dst)80 void SqliteUtils::Replace(std::string &src, const std::string &rep, const std::string &dst)
81 {
82 if (src.empty() || rep.empty()) {
83 return;
84 }
85 size_t pos = 0;
86 while ((pos = src.find(rep, pos)) != std::string::npos) {
87 src.replace(pos, rep.length(), dst);
88 pos += dst.length();
89 }
90 }
91
IsSupportSqlForExecute(int sqlType)92 bool SqliteUtils::IsSupportSqlForExecute(int sqlType)
93 {
94 return (sqlType == STATEMENT_DDL || sqlType == STATEMENT_INSERT || sqlType == STATEMENT_UPDATE ||
95 sqlType == STATEMENT_PRAGMA);
96 }
97
IsSqlReadOnly(int sqlType)98 bool SqliteUtils::IsSqlReadOnly(int sqlType)
99 {
100 return (sqlType == STATEMENT_SELECT);
101 }
102
IsSpecial(int sqlType)103 bool SqliteUtils::IsSpecial(int sqlType)
104 {
105 if (sqlType == STATEMENT_BEGIN || sqlType == STATEMENT_COMMIT || sqlType == STATEMENT_ROLLBACK) {
106 return true;
107 }
108 return false;
109 }
110
GetConflictClause(int conflictResolution)111 const char *SqliteUtils::GetConflictClause(int conflictResolution)
112 {
113 if (conflictResolution < 0 || conflictResolution >= CONFLICT_CLAUSE_COUNT) {
114 return nullptr;
115 }
116 return ON_CONFLICT_CLAUSE[conflictResolution];
117 }
118
DeleteFile(const std::string &filePath)119 bool SqliteUtils::DeleteFile(const std::string &filePath)
120 {
121 if (access(filePath.c_str(), F_OK) != 0) {
122 return true;
123 }
124 auto ret = remove(filePath.c_str());
125 if (ret != 0) {
126 LOG_WARN("remove file failed errno %{public}d ret %{public}d %{public}s", errno, ret,
127 Anonymous(filePath).c_str());
128 return false;
129 }
130 return true;
131 }
132
RenameFile(const std::string &srcFile, const std::string &destFile)133 bool SqliteUtils::RenameFile(const std::string &srcFile, const std::string &destFile)
134 {
135 auto ret = rename(srcFile.c_str(), destFile.c_str());
136 if (ret != 0) {
137 LOG_WARN("rename failed errno %{public}d ret %{public}d %{public}s -> %{public}s", errno, ret,
138 SqliteUtils::Anonymous(destFile).c_str(), SqliteUtils::Anonymous(srcFile).c_str());
139 return false;
140 }
141 return true;
142 }
143
CopyFile(const std::string &srcFile, const std::string &destFile)144 bool SqliteUtils::CopyFile(const std::string &srcFile, const std::string &destFile)
145 {
146 std::ifstream src(srcFile.c_str(), std::ios::binary);
147 if (!src.is_open()) {
148 LOG_WARN("open srcFile failed errno %{public}d %{public}s", errno, SqliteUtils::Anonymous(srcFile).c_str());
149 return false;
150 }
151 std::ofstream dst(destFile.c_str(), std::ios::binary);
152 if (!dst.is_open()) {
153 src.close();
154 LOG_WARN("open destFile failed errno %{public}d %{public}s", errno, SqliteUtils::Anonymous(destFile).c_str());
155 return false;
156 }
157 dst << src.rdbuf();
158 src.close();
159 dst.close();
160 return true;
161 }
162
GetAnonymousName(const std::string &fileName)163 std::string SqliteUtils::GetAnonymousName(const std::string &fileName)
164 {
165 std::vector<std::string> alnum;
166 std::vector<std::string> noAlnum;
167 std::string alnumStr;
168 std::string noAlnumStr;
169 for (const auto &letter : fileName) {
170 if (isxdigit(letter)) {
171 if (!noAlnumStr.empty()) {
172 noAlnum.push_back(noAlnumStr);
173 noAlnumStr.clear();
174 alnum.push_back("");
175 }
176 alnumStr += letter;
177 } else {
178 if (!alnumStr.empty()) {
179 alnum.push_back(alnumStr);
180 alnumStr.clear();
181 noAlnum.push_back("");
182 }
183 noAlnumStr += letter;
184 }
185 }
186 if (!alnumStr.empty()) {
187 alnum.push_back(alnumStr);
188 noAlnum.push_back("");
189 }
190 if (!noAlnumStr.empty()) {
191 noAlnum.push_back(noAlnumStr);
192 alnum.push_back("");
193 }
194 std::string res = "";
195 for (size_t i = 0; i < alnum.size(); ++i) {
196 res += (AnonyDigits(alnum[i]) + noAlnum[i]);
197 }
198 return res;
199 }
200
AnonyDigits(const std::string &fileName)201 std::string SqliteUtils::AnonyDigits(const std::string &fileName)
202 {
203 std::string::size_type digitsNum = fileName.size();
204 if (digitsNum < CONTINUOUS_DIGITS_MINI_SIZE) {
205 return fileName;
206 }
207 std::string::size_type endDigitsNum = 4;
208 std::string::size_type shortEndDigitsNum = 3;
209 std::string name = fileName;
210 std::string last = "";
211 if (digitsNum == CONTINUOUS_DIGITS_MINI_SIZE) {
212 last = name.substr(name.size() - shortEndDigitsNum);
213 } else {
214 last = name.substr(name.size() - endDigitsNum);
215 }
216 return "***" + last;
217 }
218
Anonymous(const std::string &srcFile)219 std::string SqliteUtils::Anonymous(const std::string &srcFile)
220 {
221 auto pre = srcFile.find("/");
222 auto end = srcFile.rfind("/");
223 if (pre == std::string::npos || end - pre < FILE_PATH_MINI_SIZE) {
224 return GetAnonymousName(srcFile);
225 }
226 auto path = srcFile.substr(pre, end - pre);
227 auto area = path.find("/el");
228 if (area == std::string::npos || area + AREA_MINI_SIZE > path.size()) {
229 path = "";
230 } else if (area + AREA_OFFSET_SIZE < path.size()) {
231 path = path.substr(area, AREA_MINI_SIZE) + "/***";
232 } else {
233 path = path.substr(area, AREA_MINI_SIZE);
234 }
235 std::string fileName = srcFile.substr(end); // rdb file name
236 fileName = GetAnonymousName(fileName);
237 return srcFile.substr(0, pre + PRE_OFFSET_SIZE) + "***" + path + fileName;
238 }
239
GetFileSize(const std::string &fileName)240 ssize_t SqliteUtils::GetFileSize(const std::string &fileName)
241 {
242 struct stat fileStat;
243 if (fileName.empty() || stat(fileName.c_str(), &fileStat) < 0) {
244 if (errno != ENOENT) {
245 LOG_ERROR("failed, errno: %{public}d, fileName:%{public}s", errno, Anonymous(fileName).c_str());
246 }
247 return 0;
248 }
249
250 return fileStat.st_size;
251 }
252
IsSlaveDbName(const std::string &fileName)253 bool SqliteUtils::IsSlaveDbName(const std::string &fileName)
254 {
255 std::string slaveSuffix("_slave.db");
256 if (fileName.size() < slaveSuffix.size()) {
257 return false;
258 }
259 size_t pos = fileName.rfind(slaveSuffix);
260 return (pos != std::string::npos) && (pos == fileName.size() - slaveSuffix.size());
261 }
262
TryAccessSlaveLock(const std::string &dbPath, bool isDelete, bool needCreate, bool isSlaveFailure)263 bool SqliteUtils::TryAccessSlaveLock(const std::string &dbPath, bool isDelete, bool needCreate,
264 bool isSlaveFailure)
265 {
266 std::string lockFile = isSlaveFailure ? dbPath + "-slaveFailure" : dbPath + "-syncInterrupt";
267 if (isDelete) {
268 if (std::remove(lockFile.c_str()) != 0) {
269 return false;
270 } else {
271 LOG_INFO("remove %{public}s", Anonymous(lockFile).c_str());
272 return true;
273 }
274 } else {
275 if (access(lockFile.c_str(), F_OK) == 0) {
276 return true;
277 }
278 if (needCreate) {
279 std::ofstream src(lockFile.c_str(), std::ios::binary);
280 if (src.is_open()) {
281 LOG_INFO("open %{public}s", Anonymous(lockFile).c_str());
282 src.close();
283 return true;
284 } else {
285 LOG_WARN("open errno %{public}d %{public}s", errno, Anonymous(lockFile).c_str());
286 return false;
287 }
288 }
289 return false;
290 }
291 }
292
GetSlavePath(const std::string& name)293 std::string SqliteUtils::GetSlavePath(const std::string& name)
294 {
295 std::string suffix(".db");
296 std::string slaveSuffix("_slave.db");
297 auto pos = name.rfind(suffix);
298 if (pos == std::string::npos || pos < name.length() - suffix.length()) {
299 return name + slaveSuffix;
300 }
301 return name.substr(0, pos) + slaveSuffix;
302 }
303
HmacAlgoDescription(int32_t hmacAlgo)304 const char *SqliteUtils::HmacAlgoDescription(int32_t hmacAlgo)
305 {
306 HmacAlgo hmacEnum = static_cast<HmacAlgo>(hmacAlgo);
307 switch (hmacEnum) {
308 case HmacAlgo::SHA1:
309 return "sha1";
310 case HmacAlgo::SHA256:
311 return "sha256";
312 case HmacAlgo::SHA512:
313 return "sha512";
314 default:
315 return "sha256";
316 }
317 }
318
KdfAlgoDescription(int32_t kdfAlgo)319 const char *SqliteUtils::KdfAlgoDescription(int32_t kdfAlgo)
320 {
321 KdfAlgo kdfEnum = static_cast<KdfAlgo>(kdfAlgo);
322 switch (kdfEnum) {
323 case KdfAlgo::KDF_SHA1:
324 return "kdf_sha1";
325 case KdfAlgo::KDF_SHA256:
326 return "kdf_sha256";
327 case KdfAlgo::KDF_SHA512:
328 return "kdf_sha512";
329 default:
330 return "kdf_sha256";
331 }
332 }
333
EncryptAlgoDescription(int32_t encryptAlgo)334 const char *SqliteUtils::EncryptAlgoDescription(int32_t encryptAlgo)
335 {
336 EncryptAlgo encryptEnum = static_cast<EncryptAlgo>(encryptAlgo);
337 switch (encryptEnum) {
338 case EncryptAlgo::AES_256_CBC:
339 return "aes-256-cbc";
340 case EncryptAlgo::AES_256_GCM:
341 default:
342 return "aes-256-gcm";
343 }
344 }
345
346 } // namespace NativeRdb
347 } // namespace OHOS
348