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