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
16 #include "sqlite_local_kvdb.h"
17
18 #include <algorithm>
19
20 #include "db_constant.h"
21 #include "db_common.h"
22 #include "log_print.h"
23 #include "platform_specific.h"
24 #include "package_file.h"
25 #include "kvdb_utils.h"
26 #include "local_database_oper.h"
27 #include "sqlite_local_kvdb_connection.h"
28 #include "sqlite_local_storage_engine.h"
29
30 namespace DistributedDB {
31 namespace {
32 const std::string CREATE_SQL =
33 "CREATE TABLE IF NOT EXISTS data(key BLOB PRIMARY key, value BLOB);";
34 }
35
SQLiteLocalKvDB()36 SQLiteLocalKvDB::SQLiteLocalKvDB()
37 : storageEngine_(nullptr)
38 {}
39
~SQLiteLocalKvDB()40 SQLiteLocalKvDB::~SQLiteLocalKvDB()
41 {
42 if (storageEngine_ != nullptr) {
43 delete storageEngine_;
44 storageEngine_ = nullptr;
45 }
46 }
47
Open(const KvDBProperties & kvDBProp)48 int SQLiteLocalKvDB::Open(const KvDBProperties &kvDBProp)
49 {
50 int databaseType = kvDBProp.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE);
51 if (databaseType == KvDBProperties::LOCAL_TYPE) {
52 std::unique_ptr<LocalDatabaseOper> operation = std::make_unique<LocalDatabaseOper>(this, nullptr);
53 (void)operation->ClearExportedTempFiles(kvDBProp);
54 int errCode = operation->RekeyRecover(kvDBProp);
55 if (errCode != E_OK) {
56 LOGE("Recover for open db failed in local db:%d", errCode);
57 return errCode;
58 }
59
60 errCode = operation->ClearImportTempFile(kvDBProp);
61 if (errCode != E_OK) {
62 LOGE("Recover for open db failed in multi version:%d", errCode);
63 return errCode;
64 }
65 }
66
67 bool createIfNecessary = kvDBProp.GetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
68 std::string subDir = KvDBProperties::GetStoreSubDirectory(databaseType);
69 std::string dataDir = kvDBProp.GetStringProp(KvDBProperties::DATA_DIR, "");
70 std::string identifierDir = kvDBProp.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
71 int errCode = DBCommon::CreateStoreDirectory(dataDir, identifierDir, subDir, createIfNecessary);
72 if (errCode != E_OK) {
73 LOGE("Create directory for local database failed:%d", errCode);
74 return errCode;
75 }
76
77 errCode = InitStorageEngine(kvDBProp);
78 if (errCode != E_OK) {
79 return errCode;
80 }
81 MyProp() = kvDBProp;
82 return E_OK;
83 }
84
NewConnection(int & errCode)85 GenericKvDBConnection *SQLiteLocalKvDB::NewConnection(int &errCode)
86 {
87 auto connection = new (std::nothrow) SQLiteLocalKvDBConnection(this);
88 if (connection == nullptr) {
89 errCode = -E_OUT_OF_MEMORY;
90 return nullptr;
91 }
92
93 errCode = E_OK;
94 return connection;
95 }
96
Close()97 void SQLiteLocalKvDB::Close() {}
98
Rekey(const CipherPassword & passwd)99 int SQLiteLocalKvDB::Rekey(const CipherPassword &passwd)
100 {
101 if (storageEngine_ == nullptr) {
102 return -E_INVALID_DB;
103 }
104
105 std::unique_ptr<LocalDatabaseOper> operation = std::make_unique<LocalDatabaseOper>(this, storageEngine_);
106 return operation->Rekey(passwd);
107 }
108
Export(const std::string & filePath,const CipherPassword & passwd)109 int SQLiteLocalKvDB::Export(const std::string &filePath, const CipherPassword &passwd)
110 {
111 int errCode = E_OK;
112 // Exclusively write resources
113 SQLiteLocalStorageExecutor *handle = GetHandle(true, errCode);
114 if (handle == nullptr) {
115 return errCode;
116 }
117 std::string devId = "local";
118
119 std::unique_ptr<LocalDatabaseOper> operation = std::make_unique<LocalDatabaseOper>(this, storageEngine_);
120 operation->SetLocalDevId(DBCommon::TransferHashString(devId));
121 errCode = operation->Export(filePath, passwd);
122
123 ReleaseHandle(handle);
124 return errCode;
125 }
126
Import(const std::string & filePath,const CipherPassword & passwd)127 int SQLiteLocalKvDB::Import(const std::string &filePath, const CipherPassword &passwd)
128 {
129 if (storageEngine_ == nullptr) {
130 return -E_INVALID_DB;
131 }
132
133 int errCode = storageEngine_->TryToDisable(true, OperatePerm::IMPORT_MONOPOLIZE_PERM);
134 if (errCode != E_OK) {
135 LOGE("Failed to disable the database");
136 return errCode;
137 }
138
139 // Need to monopolize the entire process
140 std::unique_ptr<LocalDatabaseOper> operation = std::make_unique<LocalDatabaseOper>(this, storageEngine_);
141 errCode = operation->Import(filePath, passwd);
142 // restore the storage engine and the syncer.
143 storageEngine_->Enable(OperatePerm::IMPORT_MONOPOLIZE_PERM);
144 return errCode;
145 }
146
InitDatabaseContext(const KvDBProperties & kvDBProp)147 int SQLiteLocalKvDB::InitDatabaseContext(const KvDBProperties &kvDBProp)
148 {
149 return InitStorageEngine(kvDBProp);
150 }
151
EnableAutonomicUpgrade()152 void SQLiteLocalKvDB::EnableAutonomicUpgrade()
153 {
154 isAutonomicUpgradeEnable_ = true;
155 }
156
RunExportLogic(CipherType type,const CipherPassword & passwd,const std::string & newDbName)157 int SQLiteLocalKvDB::RunExportLogic(CipherType type, const CipherPassword &passwd, const std::string &newDbName)
158 {
159 OpenDbProperties option;
160 InitDataBaseOption(MyProp(), option);
161 option.createIfNecessary = true;
162 sqlite3 *db = nullptr;
163 int errCode = SQLiteUtils::OpenDatabase(option, db);
164 if (errCode != E_OK) {
165 LOGE("Open db for export error:%d", errCode);
166 return errCode;
167 }
168
169 errCode = SQLiteUtils::ExportDatabase(db, type, passwd, newDbName);
170 if (errCode != E_OK) {
171 goto END;
172 }
173
174 END:
175 (void)sqlite3_close_v2(db);
176 db = nullptr;
177 return errCode;
178 }
179
RunRekeyLogic(CipherType type,const CipherPassword & passwd)180 int SQLiteLocalKvDB::RunRekeyLogic(CipherType type, const CipherPassword &passwd)
181 {
182 OpenDbProperties option;
183 InitDataBaseOption(MyProp(), option);
184 option.createIfNecessary = true;
185 sqlite3 *db = nullptr;
186 int errCode = SQLiteUtils::OpenDatabase(option, db);
187 if (errCode != E_OK) {
188 LOGE("Open db for rekey error:%d", errCode);
189 return errCode;
190 }
191
192 errCode = SQLiteUtils::Rekey(db, passwd);
193 if (errCode != E_OK) {
194 (void)sqlite3_close_v2(db);
195 db = nullptr;
196 return errCode;
197 }
198 (void)sqlite3_close_v2(db);
199 db = nullptr;
200 MyProp().SetPassword(option.cipherType, passwd);
201 if (storageEngine_ != nullptr) {
202 storageEngine_->Release();
203 }
204
205 return InitStorageEngine(MyProp());
206 }
207
GetHandle(bool isWrite,int & errCode,OperatePerm perm) const208 SQLiteLocalStorageExecutor *SQLiteLocalKvDB::GetHandle(bool isWrite, int &errCode, OperatePerm perm) const
209 {
210 if (storageEngine_ == nullptr) {
211 errCode = -E_INVALID_DB;
212 return nullptr;
213 }
214
215 return static_cast<SQLiteLocalStorageExecutor *>(storageEngine_->FindExecutor(isWrite, perm, errCode));
216 }
217
GetVersion(const KvDBProperties & kvDBProp,int & version,bool & isDbExisted) const218 int SQLiteLocalKvDB::GetVersion(const KvDBProperties &kvDBProp, int &version, bool &isDbExisted) const
219 {
220 OpenDbProperties option;
221 InitDataBaseOption(kvDBProp, option);
222 isDbExisted = OS::CheckPathExistence(option.uri);
223
224 int errCode = E_OK;
225 if (isDbExisted) {
226 errCode = SQLiteUtils::GetVersion(option, version);
227 }
228 return errCode;
229 }
230
SetVersion(const KvDBProperties & kvDBProp,int version)231 int SQLiteLocalKvDB::SetVersion(const KvDBProperties &kvDBProp, int version)
232 {
233 OpenDbProperties option;
234 InitDataBaseOption(kvDBProp, option);
235 bool isDbExisted = OS::CheckPathExistence(option.uri);
236 if (!isDbExisted) {
237 return -E_NOT_FOUND;
238 }
239 return SQLiteUtils::SetUserVer(option, version);
240 }
241
GetDbProperties() const242 const KvDBProperties &SQLiteLocalKvDB::GetDbProperties() const
243 {
244 return GetMyProperties();
245 }
246
GetDbPropertyForUpdate()247 KvDBProperties &SQLiteLocalKvDB::GetDbPropertyForUpdate()
248 {
249 return MyProp();
250 }
251
ReleaseHandle(SQLiteLocalStorageExecutor * & handle) const252 void SQLiteLocalKvDB::ReleaseHandle(SQLiteLocalStorageExecutor *&handle) const
253 {
254 if (storageEngine_ != nullptr) {
255 bool isCorrupted = handle->GetCorruptedStatus();
256 StorageExecutor *databaseHandle = handle;
257 storageEngine_->Recycle(databaseHandle);
258 handle = nullptr;
259 if (isCorrupted) {
260 CorruptNotify();
261 }
262 }
263 }
264
InitStorageEngine(const KvDBProperties & kvDBProp)265 int SQLiteLocalKvDB::InitStorageEngine(const KvDBProperties &kvDBProp)
266 {
267 if (storageEngine_ == nullptr) {
268 // Create HandlePool
269 storageEngine_ = new (std::nothrow) SQLiteLocalStorageEngine();
270 if (storageEngine_ == nullptr) {
271 LOGE("Create local sqlite storage engine OOM");
272 return -E_OUT_OF_MEMORY;
273 }
274 }
275
276 OpenDbProperties option;
277 InitDataBaseOption(kvDBProp, option);
278 StorageEngineAttr poolSize = {0, 1, 0, 4}; // 1 write 4 read at most.
279 int errCode = storageEngine_->InitSQLiteStorageEngine(poolSize, option);
280 if (errCode != E_OK) {
281 goto END;
282 }
283
284 // We don't have to do version check here if the SQLiteLocalKvDB does not work as LocalStore.
285 // The isAutonomicUpgradeEnable_ true indicate that it work as LocalStore. Do version check in three case:
286 // Open the database, which call Open then InitStorageEngine.
287 // Import the database, which call InitDatabaseContext then InitStorageEngine.
288 // Rekey the database, which call RunRekeyLogic then InitStorageEngine. (This case is not necessary in fact)
289 errCode = CheckVersionAndUpgradeIfNeed(option);
290 END:
291 if (errCode != E_OK) {
292 LOGE("Init sqlite handler pool failed:%d", errCode);
293 // Transform the errCode.
294 }
295 return errCode;
296 }
297
InitDataBaseOption(const KvDBProperties & kvDBProp,OpenDbProperties & option) const298 void SQLiteLocalKvDB::InitDataBaseOption(const KvDBProperties &kvDBProp, OpenDbProperties &option) const
299 {
300 std::string dataDir = kvDBProp.GetStringProp(KvDBProperties::DATA_DIR, "");
301 std::string identifierDir = kvDBProp.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
302 std::string dbName = kvDBProp.GetStringProp(KvDBProperties::FILE_NAME, DBConstant::LOCAL_DATABASE_NAME);
303 int databaseType = kvDBProp.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE);
304 bool createIfNecessary = kvDBProp.GetBoolProp(KvDBProperties::CREATE_IF_NECESSARY, true);
305 std::string subDir = KvDBProperties::GetStoreSubDirectory(databaseType);
306 // Table name "data" should not be changed in the future, otherwise when an older software open a newer database
307 // with table of other name, we will create an second table as result which is not expected.
308 std::vector<std::string> createTableSqls = {CREATE_SQL};
309 CipherType cipherType;
310 CipherPassword passwd;
311 kvDBProp.GetPassword(cipherType, passwd);
312 std::string uri = dataDir + "/" + identifierDir + "/" + subDir + "/" + dbName + DBConstant::SQLITE_DB_EXTENSION;
313 option = {uri, createIfNecessary, false, createTableSqls, cipherType, passwd};
314 }
315
BackupCurrentDatabase(const KvDBProperties & properties,const std::string & dir)316 int SQLiteLocalKvDB::BackupCurrentDatabase(const KvDBProperties &properties, const std::string &dir)
317 {
318 std::string baseDir;
319 int errCode = GetWorkDir(properties, baseDir);
320 if (errCode != E_OK) {
321 LOGE("[SqlLocalDb][Backup] GetWorkDir fail, errCode=%d.", errCode);
322 return errCode;
323 }
324 std::string dbName = properties.GetStringProp(KvDBProperties::FILE_NAME, DBConstant::LOCAL_DATABASE_NAME);
325 int databaseType = properties.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE);
326 std::string subDir = KvDBProperties::GetStoreSubDirectory(databaseType);
327 std::string currentDb = baseDir + "/" + subDir + "/" + dbName + DBConstant::SQLITE_DB_EXTENSION;
328 std::string dstDb = dir + "/" + dbName + DBConstant::SQLITE_DB_EXTENSION;
329 errCode = DBCommon::CopyFile(currentDb, dstDb);
330 if (errCode != E_OK) {
331 LOGE("Copy the local current db error:%d", errCode);
332 }
333 return errCode;
334 }
335
ImportDatabase(const KvDBProperties & properties,const std::string & dir,const CipherPassword & passwd)336 int SQLiteLocalKvDB::ImportDatabase(const KvDBProperties &properties, const std::string &dir,
337 const CipherPassword &passwd)
338 {
339 std::string baseDir;
340 int errCode = GetWorkDir(properties, baseDir);
341 if (errCode != E_OK) {
342 return errCode;
343 }
344 std::string dbName = properties.GetStringProp(KvDBProperties::FILE_NAME, DBConstant::LOCAL_DATABASE_NAME);
345 int databaseType = properties.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE);
346 std::string subDir = KvDBProperties::GetStoreSubDirectory(databaseType);
347 std::string dstDb = baseDir + "/" + subDir + "/" + dbName + DBConstant::SQLITE_DB_EXTENSION;
348 std::string currentDb = dir + "/" + dbName + DBConstant::SQLITE_DB_EXTENSION;
349 CipherType cipherType;
350 CipherPassword dstPasswd;
351 properties.GetPassword(cipherType, dstPasswd);
352 return SQLiteUtils::ExportDatabase(currentDb, cipherType, passwd, dstDb, dstPasswd);
353 }
354
RemoveKvDB(const KvDBProperties & properties)355 int SQLiteLocalKvDB::RemoveKvDB(const KvDBProperties &properties)
356 {
357 // Only care the data directory and the db name.
358 std::string storeOnlyDir;
359 std::string storeDir;
360 GenericKvDB::GetStoreDirectory(properties, KvDBProperties::LOCAL_TYPE, storeDir, storeOnlyDir);
361 int dbType = properties.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE);
362 return KvDBUtils::RemoveKvDB(storeDir, storeOnlyDir, KvDBProperties::GetStoreSubDirectory(dbType));
363 }
364
GetKvDBSize(const KvDBProperties & properties,uint64_t & size) const365 int SQLiteLocalKvDB::GetKvDBSize(const KvDBProperties &properties, uint64_t &size) const
366 {
367 std::string storeOnlyDir;
368 std::string storeDir;
369 GenericKvDB::GetStoreDirectory(properties, KvDBProperties::LOCAL_TYPE, storeDir, storeOnlyDir);
370 int dbType = properties.GetIntProp(KvDBProperties::DATABASE_TYPE, KvDBProperties::LOCAL_TYPE);
371 return KvDBUtils::GetKvDbSize(storeDir, storeOnlyDir, KvDBProperties::GetStoreSubDirectory(dbType), size);
372 }
373
CheckVersionAndUpgradeIfNeed(const OpenDbProperties & openProp)374 int SQLiteLocalKvDB::CheckVersionAndUpgradeIfNeed(const OpenDbProperties &openProp)
375 {
376 if (!isAutonomicUpgradeEnable_) {
377 return E_OK;
378 }
379 int dbVersion = 0;
380 int errCode = SQLiteUtils::GetVersion(openProp, dbVersion);
381 if (errCode != E_OK) {
382 LOGE("[SqlLocalDb][CheckUpgrade] GetVersion fail, errCode=%d.", errCode);
383 return errCode;
384 }
385 LOGD("[SqlLocalDb][CheckUpgrade] DbFile Version=%d, CurVersion=%d.", dbVersion, LOCAL_STORE_VERSION_CURRENT);
386 if (dbVersion > LOCAL_STORE_VERSION_CURRENT) {
387 return -E_VERSION_NOT_SUPPORT;
388 }
389 // For version equal or less LOCAL_STORE_VERSION_CURRENT except zero, we can do nothing currently
390 if (dbVersion != 0) {
391 return E_OK;
392 }
393 errCode = SQLiteUtils::SetUserVer(openProp, LOCAL_STORE_VERSION_CURRENT);
394 if (errCode != E_OK) {
395 LOGE("[SqlLocalDb][CheckUpgrade] SetUserVer fail, errCode=%d.", errCode);
396 return errCode;
397 }
398 return E_OK;
399 }
400
401 DEFINE_OBJECT_TAG_FACILITIES(SQLiteLocalKvDB)
402 } // namespace DistributedDB
403