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