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