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 = 5;
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(), 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(alnumStr);
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     constexpr std::string::size_type longDigits = 7;
208     std::string::size_type endDigitsNum = 4;
209     std::string::size_type shortEndDigitsNum = 3;
210     std::string name = fileName;
211     std::string last = "";
212     if (digitsNum >= CONTINUOUS_DIGITS_MINI_SIZE && digitsNum < longDigits) {
213         last = name.substr(name.size() - shortEndDigitsNum);
214     } else {
215         last = name.substr(name.size() - endDigitsNum);
216     }
217 
218     return "***" + last;
219 }
220 
Anonymous(const std::string & srcFile)221 std::string SqliteUtils::Anonymous(const std::string &srcFile)
222 {
223     auto pre = srcFile.find("/");
224     auto end = srcFile.rfind("/");
225     if (pre == std::string::npos || end - pre < FILE_PATH_MINI_SIZE) {
226         return GetAnonymousName(srcFile);
227     }
228     auto path = srcFile.substr(pre, end - pre);
229     auto area = path.find("/el");
230     if (area == std::string::npos || area + AREA_MINI_SIZE > path.size()) {
231         path = "";
232     } else if (area + AREA_OFFSET_SIZE < path.size()) {
233         path = path.substr(area, AREA_MINI_SIZE) + "/***";
234     } else {
235         path = path.substr(area, AREA_MINI_SIZE);
236     }
237     std::string fileName = srcFile.substr(end); // rdb file name
238     fileName = GetAnonymousName(fileName);
239     return srcFile.substr(0, pre + PRE_OFFSET_SIZE) + "***" + path + fileName;
240 }
241 
GetFileSize(const std::string & fileName)242 ssize_t SqliteUtils::GetFileSize(const std::string &fileName)
243 {
244     struct stat fileStat;
245     if (fileName.empty() || stat(fileName.c_str(), &fileStat) < 0) {
246         if (errno != ENOENT) {
247             LOG_ERROR("failed, errno: %{public}d, fileName:%{public}s", errno, Anonymous(fileName).c_str());
248         }
249         return 0;
250     }
251 
252     return fileStat.st_size;
253 }
254 
IsSlaveDbName(const std::string & fileName)255 bool SqliteUtils::IsSlaveDbName(const std::string &fileName)
256 {
257     std::string slaveSuffix("_slave.db");
258     if (fileName.size() < slaveSuffix.size()) {
259         return false;
260     }
261     size_t pos = fileName.rfind(slaveSuffix);
262     return (pos != std::string::npos) && (pos == fileName.size() - slaveSuffix.size());
263 }
264 
TryAccessSlaveLock(const std::string & dbPath,bool isDelete,bool needCreate,bool isSlaveFailure)265 bool SqliteUtils::TryAccessSlaveLock(const std::string &dbPath, bool isDelete, bool needCreate,
266     bool isSlaveFailure)
267 {
268     std::string lockFile = isSlaveFailure ? dbPath + "-slaveFailure" : dbPath + "-syncInterrupt";
269     if (isDelete) {
270         if (std::remove(lockFile.c_str()) != 0) {
271             return false;
272         } else {
273             LOG_INFO("remove %{public}s", Anonymous(lockFile).c_str());
274             return true;
275         }
276     } else {
277         if (access(lockFile.c_str(), F_OK) == 0) {
278             return true;
279         }
280         if (needCreate) {
281             std::ofstream src(lockFile.c_str(), std::ios::binary);
282             if (src.is_open()) {
283                 LOG_INFO("open %{public}s", Anonymous(lockFile).c_str());
284                 src.close();
285                 return true;
286             } else {
287                 LOG_WARN("open errno %{public}d %{public}s", errno, Anonymous(lockFile).c_str());
288                 return false;
289             }
290         }
291         return false;
292     }
293 }
294 
GetSlavePath(const std::string & name)295 std::string SqliteUtils::GetSlavePath(const std::string& name)
296 {
297     std::string suffix(".db");
298     std::string slaveSuffix("_slave.db");
299     auto pos = name.rfind(suffix);
300     if (pos == std::string::npos || pos < name.length() - suffix.length()) {
301         return name + slaveSuffix;
302     }
303     return name.substr(0, pos) + slaveSuffix;
304 }
305 
HmacAlgoDescription(int32_t hmacAlgo)306 const char *SqliteUtils::HmacAlgoDescription(int32_t hmacAlgo)
307 {
308     HmacAlgo hmacEnum = static_cast<HmacAlgo>(hmacAlgo);
309     switch (hmacEnum) {
310         case HmacAlgo::SHA1:
311             return "sha1";
312         case HmacAlgo::SHA256:
313             return "sha256";
314         case HmacAlgo::SHA512:
315             return "sha512";
316         default:
317             return "sha256";
318     }
319 }
320 
KdfAlgoDescription(int32_t kdfAlgo)321 const char *SqliteUtils::KdfAlgoDescription(int32_t kdfAlgo)
322 {
323     KdfAlgo kdfEnum = static_cast<KdfAlgo>(kdfAlgo);
324     switch (kdfEnum) {
325         case KdfAlgo::KDF_SHA1:
326             return "kdf_sha1";
327         case KdfAlgo::KDF_SHA256:
328             return "kdf_sha256";
329         case KdfAlgo::KDF_SHA512:
330             return "kdf_sha512";
331         default:
332             return "kdf_sha256";
333     }
334 }
335 
EncryptAlgoDescription(int32_t encryptAlgo)336 const char *SqliteUtils::EncryptAlgoDescription(int32_t encryptAlgo)
337 {
338     EncryptAlgo encryptEnum = static_cast<EncryptAlgo>(encryptAlgo);
339     switch (encryptEnum) {
340         case EncryptAlgo::AES_256_CBC:
341             return "aes-256-cbc";
342         case EncryptAlgo::AES_256_GCM:
343         default:
344             return "aes-256-gcm";
345     }
346 }
347 
348 } // namespace NativeRdb
349 } // namespace OHOS
350