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