1 /*
2  * Copyright (c) 2023 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 "single_ver_utils.h"
17 
18 #include "db_common.h"
19 #include "platform_specific.h"
20 #include "runtime_context.h"
21 #include "sqlite_utils.h"
22 
23 namespace DistributedDB {
24 
GetPathSecurityOption(const std::string & filePath,SecurityOption & secOpt)25 int GetPathSecurityOption(const std::string &filePath, SecurityOption &secOpt)
26 {
27     return RuntimeContext::GetInstance()->GetSecurityOption(filePath, secOpt);
28 }
29 
GetDbDir(const std::string & subDir,DbType type)30 std::string GetDbDir(const std::string &subDir, DbType type)
31 {
32     switch (type) {
33         case DbType::MAIN:
34             return subDir + "/" + DBConstant::MAINDB_DIR;
35         case DbType::META:
36             return subDir + "/" + DBConstant::METADB_DIR;
37         case DbType::CACHE:
38             return subDir + "/" + DBConstant::CACHEDB_DIR;
39         default:
40             break;
41     }
42     return "";
43 }
44 
GetDatabasePath(const KvDBProperties & kvDBProp)45 std::string GetDatabasePath(const KvDBProperties &kvDBProp)
46 {
47     return GetSubDirPath(kvDBProp) + "/" + DBConstant::MAINDB_DIR + "/" + DBConstant::SINGLE_VER_DATA_STORE +
48         DBConstant::DB_EXTENSION;
49 }
50 
GetSubDirPath(const KvDBProperties & kvDBProp)51 std::string GetSubDirPath(const KvDBProperties &kvDBProp)
52 {
53     std::string dataDir = kvDBProp.GetStringProp(KvDBProperties::DATA_DIR, "");
54     std::string identifierDir = kvDBProp.GetStringProp(KvDBProperties::IDENTIFIER_DIR, "");
55     return dataDir + "/" + identifierDir + "/" + DBConstant::SINGLE_SUB_DIR;
56 }
57 
ClearIncompleteDatabase(const KvDBProperties & kvDBPro)58 int ClearIncompleteDatabase(const KvDBProperties &kvDBPro)
59 {
60     std::string dbSubDir = GetSubDirPath(kvDBPro);
61     if (OS::CheckPathExistence(dbSubDir + DBConstant::PATH_POSTFIX_DB_INCOMPLETE)) {
62         int errCode = DBCommon::RemoveAllFilesOfDirectory(dbSubDir);
63         if (errCode != E_OK) {
64             LOGE("Remove the incomplete database dir failed!");
65             return -E_REMOVE_FILE;
66         }
67     }
68     return E_OK;
69 }
70 
CreateNewDirsAndSetSecOption(const OpenDbProperties & option)71 int CreateNewDirsAndSetSecOption(const OpenDbProperties &option)
72 {
73     std::vector<std::string> dbDir { DBConstant::MAINDB_DIR, DBConstant::METADB_DIR, DBConstant::CACHEDB_DIR };
74     for (const auto &item : dbDir) {
75         if (OS::CheckPathExistence(option.subdir + "/" + item)) {
76             continue;
77         }
78 
79         // Dir and old db file not existed, it means that the database is newly created
80         // need create flag of database not incomplete
81         if (!OS::CheckPathExistence(option.subdir + DBConstant::PATH_POSTFIX_DB_INCOMPLETE) &&
82             !OS::CheckPathExistence(option.subdir + "/" + DBConstant::SINGLE_VER_DATA_STORE +
83             DBConstant::DB_EXTENSION) &&
84             OS::CreateFileByFileName(option.subdir + DBConstant::PATH_POSTFIX_DB_INCOMPLETE) != E_OK) {
85             LOGE("Fail to create the token of database incompleted! errCode = [E_SYSTEM_API_FAIL]");
86             return -E_SYSTEM_API_FAIL;
87         }
88 
89         if (DBCommon::CreateDirectory(option.subdir + "/" + item) != E_OK) {
90             LOGE("Create sub-directory for single ver failed, errno:%d", errno);
91             return -E_SYSTEM_API_FAIL;
92         }
93 
94         if (option.securityOpt.securityLabel == NOT_SET) {
95             continue;
96         }
97 
98         SecurityOption secOption = option.securityOpt;
99         if (item == DBConstant::METADB_DIR) {
100             secOption.securityLabel = ((option.securityOpt.securityLabel >= SecurityLabel::S2) ?
101                 SecurityLabel::S2 : option.securityOpt.securityLabel);
102             secOption.securityFlag = SecurityFlag::ECE;
103         }
104 
105         int errCode = RuntimeContext::GetInstance()->SetSecurityOption(option.subdir + "/" + item, secOption);
106         if (errCode != E_OK && errCode != -E_NOT_SUPPORT) {
107             LOGE("Set the security option of sub-directory failed[%d]", errCode);
108             return errCode;
109         }
110     }
111     return E_OK;
112 }
113 
GetExistedSecOpt(const OpenDbProperties & opt,SecurityOption & secOption)114 int GetExistedSecOpt(const OpenDbProperties &opt, SecurityOption &secOption)
115 {
116     // Check the existence of the database, include the origin database and the database in the 'main' directory.
117     auto mainDbDir = GetDbDir(opt.subdir, DbType::MAIN);
118     auto mainDbFilePath = mainDbDir + "/" + DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION;
119     auto origDbFilePath = opt.subdir + "/" + DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION;
120     if (!OS::CheckPathExistence(origDbFilePath) && !OS::CheckPathExistence(mainDbFilePath)) {
121         secOption = opt.securityOpt;
122         return E_OK;
123     }
124 
125     // the main database file has high priority of the security option.
126     int errCode;
127     if (OS::CheckPathExistence(mainDbFilePath)) {
128         errCode = GetPathSecurityOption(mainDbFilePath, secOption);
129     } else {
130         errCode = GetPathSecurityOption(origDbFilePath, secOption);
131     }
132     if (errCode == E_OK) {
133         return E_OK;
134     }
135     secOption = SecurityOption();
136     if (errCode == -E_NOT_SUPPORT) {
137         return E_OK;
138     }
139     LOGE("Get the security option of the existed database failed.");
140     return errCode;
141 }
142 
InitCommitNotifyDataKeyStatus(SingleVerNaturalStoreCommitNotifyData * committedData,const Key & hashKey,const DataOperStatus & dataStatus)143 void InitCommitNotifyDataKeyStatus(SingleVerNaturalStoreCommitNotifyData *committedData, const Key &hashKey,
144     const DataOperStatus &dataStatus)
145 {
146     if (committedData == nullptr) {
147         return;
148     }
149 
150     ExistStatus existedStatus = ExistStatus::NONE;
151     if (dataStatus.preStatus == DataStatus::DELETED) {
152         existedStatus = ExistStatus::DELETED;
153     } else if (dataStatus.preStatus == DataStatus::EXISTED) {
154         existedStatus = ExistStatus::EXIST;
155     }
156 
157     committedData->InitKeyPropRecord(hashKey, existedStatus);
158 }
159 
CheckStoreStatus(const OpenDbProperties & opt)160 int CheckStoreStatus(const OpenDbProperties &opt)
161 {
162     // Check the existence of the database, include the origin database and the database in the 'main' directory.
163     auto mainDbDir = GetDbDir(opt.subdir, DbType::MAIN);
164     auto mainDbFilePath = mainDbDir + "/" + DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION;
165     auto origDbFilePath = opt.subdir + "/" + DBConstant::SINGLE_VER_DATA_STORE + DBConstant::DB_EXTENSION;
166     if (!OS::CheckPathExistence(origDbFilePath) && !OS::CheckPathExistence(mainDbFilePath)) {
167         return E_OK;
168     }
169     sqlite3 *db = nullptr;
170     OpenDbProperties checkOpt = opt;
171     if (OS::CheckPathExistence(mainDbFilePath)) {
172         checkOpt.uri = mainDbFilePath;
173     } else {
174         checkOpt.uri = origDbFilePath;
175     }
176     int errCode = SQLiteUtils::OpenDatabase(checkOpt, db);
177     if (db != nullptr) {
178         int ret = sqlite3_close_v2(db);
179         if (ret != E_OK) {
180             LOGW("close db failed %d when check db status", ret);
181         }
182     }
183     if (errCode != E_OK && errCode != -E_EKEYREVOKED) {
184         LOGE("check db status failed %d", errCode);
185     } else {
186         errCode = E_OK;
187     }
188     return errCode;
189 }
190 } // namespace DistributedDB