1 /*
2 * Copyright (c) 2024 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 "RdConnection"
16 #include "rd_connection.h"
17
18 #include <securec.h>
19
20 #include <string>
21
22 #include "grd_api_manager.h"
23 #include "logger.h"
24 #include "rd_statement.h"
25 #include "rdb_errno.h"
26 #include "rdb_security_manager.h"
27 #include "sqlite_global_config.h"
28 #include "sqlite_utils.h"
29 namespace OHOS {
30 namespace NativeRdb {
31 using namespace OHOS::Rdb;
32 __attribute__((used))
33 const int32_t RdConnection::regCreator_ = Connection::RegisterCreator(DB_VECTOR, RdConnection::Create);
34 __attribute__((used))
35 const int32_t RdConnection::regRepairer_ = Connection::RegisterRepairer(DB_VECTOR, RdConnection::Repair);
36 __attribute__((used))
37 const int32_t RdConnection::regDeleter_ = Connection::RegisterDeleter(DB_VECTOR, RdConnection::Delete);
38
Create(const RdbStoreConfig & config,bool isWrite)39 std::pair<int32_t, std::shared_ptr<Connection>> RdConnection::Create(const RdbStoreConfig &config, bool isWrite)
40 {
41 std::pair<int32_t, std::shared_ptr<Connection>> result = { E_ERROR, nullptr };
42 if (!IsUsingArkData() || config.GetStorageMode() == StorageMode::MODE_MEMORY) {
43 result.first = E_NOT_SUPPORT;
44 return result;
45 }
46 auto &[errCode, conn] = result;
47 for (size_t i = 0; i < ITERS_COUNT; i++) {
48 std::shared_ptr<RdConnection> connection = std::make_shared<RdConnection>(config, isWrite);
49 if (connection == nullptr) {
50 LOG_ERROR("SqliteConnection::Open new failed, connection is nullptr.");
51 return result;
52 }
53 errCode = connection->InnerOpen(config);
54 if (errCode == E_OK) {
55 conn = connection;
56 CheckConfig(connection, config);
57 break;
58 }
59 }
60 return result;
61 }
62
CheckConfig(std::shared_ptr<Connection> conn,const RdbStoreConfig & config)63 void RdConnection::CheckConfig(std::shared_ptr<Connection> conn, const RdbStoreConfig &config)
64 {
65 if (config.GetNcandidates() != NCANDIDATES_DEFAULT_NUM) {
66 ExecuteSet(conn, "diskann_probe_ncandidates", config.GetNcandidates());
67 }
68 }
69
ExecuteSet(std::shared_ptr<Connection> conn,const std::string & paramName,int num)70 void RdConnection::ExecuteSet(std::shared_ptr<Connection> conn, const std::string ¶mName, int num)
71 {
72 std::string sql = "SET " + paramName + " = " + std::to_string(num);
73 auto [errCode, stmt] = conn->CreateStatement(sql, conn);
74 if (errCode != E_OK || stmt == nullptr) {
75 LOG_ERROR("Create statement failed, paramName: %{public}s, errCode: %{public}d",
76 paramName.c_str(), errCode);
77 return;
78 }
79 stmt->Step();
80 stmt->Finalize();
81 }
82
Repair(const RdbStoreConfig & config)83 int32_t RdConnection::Repair(const RdbStoreConfig &config)
84 {
85 std::string dbPath = "";
86 auto errCode = SqliteGlobalConfig::GetDbPath(config, dbPath);
87 if (errCode != E_OK) {
88 LOG_ERROR("Can not get db path.");
89 return errCode;
90 }
91 std::vector<uint8_t> key = config.GetEncryptKey();
92 errCode = RdUtils::RdDbRepair(dbPath.c_str(), GetConfigStr(key, config.IsEncrypt()).c_str());
93 key.assign(key.size(), 0);
94 if (errCode != E_OK) {
95 LOG_ERROR("Fail to repair db.");
96 }
97 return errCode;
98 }
99
100 static constexpr const char *RD_POST_FIXES[] = {
101 "",
102 ".redo",
103 ".undo",
104 ".ctrl",
105 ".ctrl.dwr",
106 ".safe",
107 ".map",
108 ".corruptedflg",
109 };
110
Delete(const RdbStoreConfig & config)111 int32_t RdConnection::Delete(const RdbStoreConfig &config)
112 {
113 auto path = config.GetPath();
114 for (auto postFix : RD_POST_FIXES) {
115 std::string shmFilePath = path + postFix;
116 if (access(shmFilePath.c_str(), F_OK) == 0) {
117 remove(shmFilePath.c_str());
118 }
119 }
120 return E_OK;
121 }
122
RdConnection(const RdbStoreConfig & config,bool isWriter)123 RdConnection::RdConnection(const RdbStoreConfig &config, bool isWriter) : isWriter_(isWriter), config_(config)
124 {
125 }
126
~RdConnection()127 RdConnection::~RdConnection()
128 {
129 if (dbHandle_ != nullptr) {
130 int errCode = RdUtils::RdDbClose(dbHandle_, 0);
131 if (errCode != E_OK) {
132 LOG_ERROR("~RdConnection ~RdConnection: could not close database err = %{public}d", errCode);
133 }
134 dbHandle_ = nullptr;
135 }
136 }
137
GetConfigStr(const std::vector<uint8_t> & keys,bool isEncrypt)138 std::string RdConnection::GetConfigStr(const std::vector<uint8_t> &keys, bool isEncrypt)
139 {
140 std::string config = "{";
141 if (isEncrypt) {
142 const size_t keyBuffSize = keys.size() * 2 + 1; // 2 hex number can represent a uint8_t, 1 is for '/0'
143 char keyBuff[keyBuffSize];
144 config += "\"isEncrypted\":1,";
145 config += "\"hexPassword\":\"";
146 config += RdUtils::GetEncryptKey(keys, keyBuff, keyBuffSize);
147 config += "\",";
148 (void)memset_s(keyBuff, keyBuffSize, 0, keyBuffSize);
149 }
150 config += RdConnection::GRD_OPEN_CONFIG_STR;
151 config += "}";
152 return config;
153 }
154
InnerOpen(const RdbStoreConfig & config)155 int RdConnection::InnerOpen(const RdbStoreConfig &config)
156 {
157 std::string dbPath = "";
158 auto errCode = SqliteGlobalConfig::GetDbPath(config, dbPath);
159 if (errCode != E_OK) {
160 LOG_ERROR("Can not get db path.");
161 return errCode;
162 }
163 std::vector<uint8_t> newKey = config.GetNewEncryptKey();
164 if (!newKey.empty()) {
165 newKey.assign(newKey.size(), 0);
166 errCode = ReSetKey(config);
167 if (errCode != E_OK) {
168 LOG_ERROR("Can not reset key %{public}d.", errCode);
169 return errCode;
170 }
171 }
172
173 std::vector<uint8_t> key = config.GetEncryptKey();
174 std::string configStr = GetConfigStr(key, config.IsEncrypt());
175 errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(),
176 GRD_DB_OPEN_CREATE | GRD_DB_OPEN_IGNORE_DATA_CORRPUPTION, &dbHandle_);
177 if (errCode == E_CHANGE_UNENCRYPTED_TO_ENCRYPTED) {
178 errCode = RdUtils::RdDbRekey(dbPath.c_str(), GetConfigStr({}, false).c_str(), key);
179 if (errCode != E_OK) {
180 key.assign(key.size(), 0);
181 RdUtils::ClearAndZeroString(configStr);
182 LOG_ERROR("Can not rekey caylay db %{public}d.", errCode);
183 return errCode;
184 }
185 errCode = RdUtils::RdDbOpen(dbPath.c_str(), configStr.c_str(),
186 GRD_DB_OPEN_CREATE | GRD_DB_OPEN_IGNORE_DATA_CORRPUPTION, &dbHandle_);
187 }
188 key.assign(key.size(), 0);
189 RdUtils::ClearAndZeroString(configStr);
190 if (errCode != E_OK) {
191 LOG_ERROR("Can not open rd db %{public}d.", errCode);
192 return errCode;
193 }
194 errCode = RdUtils::RdSqlRegistryThreadPool(dbHandle_);
195 if (errCode != E_OK) {
196 LOG_ERROR("Can not registry ThreadPool rd db %{public}d.", errCode);
197 return errCode;
198 }
199 return errCode;
200 }
201
VerifyAndRegisterHook(const RdbStoreConfig & config)202 int32_t RdConnection::VerifyAndRegisterHook(const RdbStoreConfig &config)
203 {
204 return E_NOT_SUPPORT;
205 }
206
CreateStatement(const std::string & sql,Connection::SConn conn)207 std::pair<int32_t, RdConnection::Stmt> RdConnection::CreateStatement(const std::string &sql, Connection::SConn conn)
208 {
209 auto stmt = std::make_shared<RdStatement>();
210 stmt->conn_ = conn;
211 stmt->config_ = &config_;
212 stmt->setPragmas_["user_version"] = ([this](const int &value) -> int32_t {
213 return RdUtils::RdDbSetVersion(dbHandle_, GRD_CONFIG_USER_VERSION, value);
214 });
215 stmt->getPragmas_["user_version"] = ([this](int &version) -> int32_t {
216 return RdUtils::RdDbGetVersion(dbHandle_, GRD_CONFIG_USER_VERSION, version);
217 });
218 int32_t ret = stmt->Prepare(dbHandle_, sql);
219 if (ret != E_OK) {
220 return { ret, nullptr };
221 }
222 return { ret, stmt };
223 }
224
GetDBType() const225 int32_t RdConnection::GetDBType() const
226 {
227 return DB_VECTOR;
228 }
229
IsWriter() const230 bool RdConnection::IsWriter() const
231 {
232 return isWriter_;
233 }
234
ReSetKey(const RdbStoreConfig & config)235 int32_t RdConnection::ReSetKey(const RdbStoreConfig &config)
236 {
237 if (!IsWriter()) {
238 return E_OK;
239 }
240 std::string dbPath = "";
241 int errCode = SqliteGlobalConfig::GetDbPath(config, dbPath);
242 if (errCode != E_OK) {
243 LOG_ERROR("Can not get db path.");
244 return errCode;
245 }
246 std::vector<uint8_t> key = config.GetEncryptKey();
247 std::vector<uint8_t> newKey = config.GetNewEncryptKey();
248 std::string configStr = GetConfigStr(key, config.IsEncrypt());
249 errCode = RdUtils::RdDbRekey(dbPath.c_str(), configStr.c_str(), newKey);
250 RdUtils::ClearAndZeroString(configStr);
251 key.assign(key.size(), 0);
252 newKey.assign(newKey.size(), 0);
253 if (errCode != E_OK) {
254 LOG_ERROR("ReKey failed, err = %{public}d, errno = %{public}d", errCode, errno);
255 RdbSecurityManager::GetInstance().DelKeyFile(
256 config.GetPath(), RdbSecurityManager::KeyFileType::PUB_KEY_FILE_NEW_KEY);
257 return E_OK;
258 }
259 config.ChangeEncryptKey();
260 return E_OK;
261 }
262
TryCheckPoint(bool timeout)263 int32_t RdConnection::TryCheckPoint(bool timeout)
264 {
265 return E_NOT_SUPPORT;
266 }
267
LimitWalSize()268 int32_t RdConnection::LimitWalSize()
269 {
270 return E_NOT_SUPPORT;
271 }
272
ConfigLocale(const std::string & localeStr)273 int32_t RdConnection::ConfigLocale(const std::string &localeStr)
274 {
275 return E_NOT_SUPPORT;
276 }
277
CleanDirtyData(const std::string & table,uint64_t cursor)278 int32_t RdConnection::CleanDirtyData(const std::string &table, uint64_t cursor)
279 {
280 return E_NOT_SUPPORT;
281 }
282
SubscribeTableChanges(const Connection::Notifier & notifier)283 int32_t RdConnection::SubscribeTableChanges(const Connection::Notifier ¬ifier)
284 {
285 return E_NOT_SUPPORT;
286 }
287
GetMaxVariable() const288 int32_t RdConnection::GetMaxVariable() const
289 {
290 return MAX_VARIABLE_NUM;
291 }
292
GetJournalMode()293 int32_t RdConnection::GetJournalMode()
294 {
295 return E_NOT_SUPPORT;
296 }
297
ClearCache()298 int32_t RdConnection::ClearCache()
299 {
300 return E_NOT_SUPPORT;
301 }
302
Subscribe(const std::shared_ptr<DistributedDB::StoreObserver> & observer)303 int32_t RdConnection::Subscribe(const std::shared_ptr<DistributedDB::StoreObserver> &observer)
304 {
305 return E_NOT_SUPPORT;
306 }
307
Unsubscribe(const std::shared_ptr<DistributedDB::StoreObserver> & observer)308 int32_t RdConnection::Unsubscribe(const std::shared_ptr<DistributedDB::StoreObserver> &observer)
309 {
310 return E_NOT_SUPPORT;
311 }
312
Backup(const std::string & databasePath,const std::vector<uint8_t> & destEncryptKey,bool isAsync,SlaveStatus & slaveStatus)313 int32_t RdConnection::Backup(const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey, bool isAsync,
314 SlaveStatus &slaveStatus)
315 {
316 if (!destEncryptKey.empty() && !config_.IsEncrypt()) {
317 return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), destEncryptKey);
318 }
319 if (config_.IsEncrypt()) {
320 std::vector<uint8_t> key = config_.GetEncryptKey();
321 int32_t ret = RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), key);
322 key.assign(key.size(), 0);
323 return ret;
324 }
325 return RdUtils::RdDbBackup(dbHandle_, databasePath.c_str(), {});
326 }
327
Restore(const std::string & databasePath,const std::vector<uint8_t> & destEncryptKey,SlaveStatus & slaveStatus)328 int32_t RdConnection::Restore(
329 const std::string &databasePath, const std::vector<uint8_t> &destEncryptKey, SlaveStatus &slaveStatus)
330 {
331 auto ret = RdUtils::RdDbClose(dbHandle_, 0);
332 if (ret != E_OK) {
333 LOG_ERROR("Close db failed");
334 return ret;
335 }
336
337 if (destEncryptKey.empty()) {
338 std::vector<uint8_t> key = config_.GetEncryptKey();
339 ret = RdUtils::RdDbRestore(config_.GetPath().c_str(), databasePath.c_str(), key);
340 key.assign(key.size(), 0);
341 } else {
342 ret = RdUtils::RdDbRestore(config_.GetPath().c_str(), databasePath.c_str(), destEncryptKey);
343 }
344
345 if (ret != E_OK) {
346 LOG_ERROR("Restore failed, original datapath:%{public}s, restorepath:%{public}s, errcode:%{public}d",
347 config_.GetPath().c_str(), databasePath.c_str(), ret);
348 return ret;
349 }
350
351 ret = InnerOpen(config_);
352 if (ret != E_OK) {
353 LOG_ERROR("Reopen db failed:%{public}d", ret);
354 return ret;
355 }
356 return ret;
357 }
358
GenerateExchangeStrategy(const SlaveStatus & status)359 ExchangeStrategy RdConnection::GenerateExchangeStrategy(const SlaveStatus &status)
360 {
361 return ExchangeStrategy::NOT_HANDLE;
362 }
363 } // namespace NativeRdb
364 } // namespace OHOS