1 /*
2 * Copyright (c) 2022 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 "StoreUtil"
16 #include "store_util.h"
17 #include <dirent.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include "log_print.h"
22 #include "types.h"
23 #include "acl.h"
24 namespace OHOS::DistributedKv {
25 using namespace DATABASE_UTILS;
26 constexpr mode_t DEFAULT_UMASK = 0002;
27 constexpr int32_t HEAD_SIZE = 3;
28 constexpr int32_t END_SIZE = 3;
29 constexpr int32_t MIN_SIZE = HEAD_SIZE + END_SIZE + 3;
30 constexpr int32_t SERVICE_GID = 3012;
31 constexpr const char *REPLACE_CHAIN = "***";
32 constexpr const char *DEFAULT_ANONYMOUS = "******";
33 std::atomic<uint64_t> StoreUtil::sequenceId_ = 0;
34 using DBStatus = DistributedDB::DBStatus;
35 std::map<DBStatus, Status> StoreUtil::statusMap_ = {
36 { DBStatus::BUSY, Status::DB_ERROR },
37 { DBStatus::DB_ERROR, Status::DB_ERROR },
38 { DBStatus::OK, Status::SUCCESS },
39 { DBStatus::INVALID_ARGS, Status::INVALID_ARGUMENT },
40 { DBStatus::NOT_FOUND, Status::NOT_FOUND },
41 { DBStatus::INVALID_VALUE_FIELDS, Status::INVALID_VALUE_FIELDS },
42 { DBStatus::INVALID_FIELD_TYPE, Status::INVALID_FIELD_TYPE },
43 { DBStatus::CONSTRAIN_VIOLATION, Status::CONSTRAIN_VIOLATION },
44 { DBStatus::INVALID_FORMAT, Status::INVALID_FORMAT },
45 { DBStatus::INVALID_QUERY_FORMAT, Status::INVALID_QUERY_FORMAT },
46 { DBStatus::INVALID_QUERY_FIELD, Status::INVALID_QUERY_FIELD },
47 { DBStatus::NOT_SUPPORT, Status::NOT_SUPPORT },
48 { DBStatus::TIME_OUT, Status::TIME_OUT },
49 { DBStatus::OVER_MAX_LIMITS, Status::OVER_MAX_LIMITS },
50 { DBStatus::INVALID_PASSWD_OR_CORRUPTED_DB, Status::DATA_CORRUPTED },
51 { DBStatus::SCHEMA_MISMATCH, Status::SCHEMA_MISMATCH },
52 { DBStatus::INVALID_SCHEMA, Status::INVALID_SCHEMA },
53 { DBStatus::EKEYREVOKED_ERROR, Status::SECURITY_LEVEL_ERROR },
54 { DBStatus::SECURITY_OPTION_CHECK_ERROR, Status::SECURITY_LEVEL_ERROR },
55 { DBStatus::LOG_OVER_LIMITS, Status::WAL_OVER_LIMITS },
56 { DBStatus::SQLITE_CANT_OPEN, Status::DB_CANT_OPEN }
57 };
58
GetDBSecurity(int32_t secLevel)59 StoreUtil::DBSecurity StoreUtil::GetDBSecurity(int32_t secLevel)
60 {
61 if (secLevel < SecurityLevel::NO_LABEL || secLevel > SecurityLevel::S4) {
62 return { DistributedDB::NOT_SET, DistributedDB::ECE };
63 }
64 if (secLevel == SecurityLevel::S3) {
65 return { DistributedDB::S3, DistributedDB::SECE };
66 }
67 if (secLevel == SecurityLevel::S4) {
68 return { DistributedDB::S4, DistributedDB::ECE };
69 }
70 return { secLevel, DistributedDB::ECE };
71 }
72
GetDBIndexType(IndexType type)73 StoreUtil::DBIndexType StoreUtil::GetDBIndexType(IndexType type)
74 {
75 if (type == IndexType::BTREE) {
76 return DistributedDB::BTREE;
77 }
78 return DistributedDB::HASH;
79 }
80
GetSecLevel(StoreUtil::DBSecurity dbSec)81 int32_t StoreUtil::GetSecLevel(StoreUtil::DBSecurity dbSec)
82 {
83 switch (dbSec.securityLabel) {
84 case DistributedDB::NOT_SET: // fallthrough
85 case DistributedDB::S0: // fallthrough
86 case DistributedDB::S1: // fallthrough
87 case DistributedDB::S2: // fallthrough
88 return dbSec.securityLabel;
89 case DistributedDB::S3:
90 return dbSec.securityFlag ? S3 : S3_EX;
91 case DistributedDB::S4:
92 return S4;
93 default:
94 break;
95 }
96 return NO_LABEL;
97 }
98
GetDBMode(SyncMode syncMode)99 StoreUtil::DBMode StoreUtil::GetDBMode(SyncMode syncMode)
100 {
101 DBMode dbMode;
102 if (syncMode == SyncMode::PUSH) {
103 dbMode = DBMode::SYNC_MODE_PUSH_ONLY;
104 } else if (syncMode == SyncMode::PULL) {
105 dbMode = DBMode::SYNC_MODE_PULL_ONLY;
106 } else {
107 dbMode = DBMode::SYNC_MODE_PUSH_PULL;
108 }
109 return dbMode;
110 }
111
GetObserverMode(SubscribeType subType)112 uint32_t StoreUtil::GetObserverMode(SubscribeType subType)
113 {
114 uint32_t mode;
115 if (subType == SubscribeType::SUBSCRIBE_TYPE_LOCAL) {
116 mode = DistributedDB::OBSERVER_CHANGES_NATIVE;
117 } else if (subType == SubscribeType::SUBSCRIBE_TYPE_REMOTE) {
118 mode = DistributedDB::OBSERVER_CHANGES_FOREIGN;
119 } else {
120 mode = DistributedDB::OBSERVER_CHANGES_FOREIGN | DistributedDB::OBSERVER_CHANGES_NATIVE;
121 }
122 return mode;
123 }
124
Anonymous(const std::string & name)125 std::string StoreUtil::Anonymous(const std::string &name)
126 {
127 if (name.length() <= HEAD_SIZE) {
128 return DEFAULT_ANONYMOUS;
129 }
130
131 if (name.length() < MIN_SIZE) {
132 return (name.substr(0, HEAD_SIZE) + REPLACE_CHAIN);
133 }
134
135 return (name.substr(0, HEAD_SIZE) + REPLACE_CHAIN + name.substr(name.length() - END_SIZE, END_SIZE));
136 }
137
Anonymous(const void * ptr)138 uint32_t StoreUtil::Anonymous(const void *ptr)
139 {
140 uint32_t hash = (uintptr_t(ptr) & 0xFFFFFFFF);
141 hash = (hash & 0xFFFF) ^ ((hash >> 16) & 0xFFFF); // 16 is right shift quantity
142 return hash;
143 }
144
ConvertStatus(DBStatus status)145 Status StoreUtil::ConvertStatus(DBStatus status)
146 {
147 auto iter = statusMap_.find(status);
148 if (iter == statusMap_.end()) {
149 ZLOGE("unknown db error:0x%{public}x", status);
150 return Status::ERROR;
151 }
152 return iter->second;
153 }
154
InitPath(const std::string & path)155 bool StoreUtil::InitPath(const std::string &path)
156 {
157 umask(DEFAULT_UMASK);
158 if (access(path.c_str(), F_OK) == 0) {
159 return RemoveRWXForOthers(path);
160 }
161 if (mkdir(path.c_str(), (S_IRWXU | S_IRWXG)) != 0 && errno != EEXIST) {
162 ZLOGE("mkdir error:%{public}d, path:%{public}s", errno, path.c_str());
163 return false;
164 }
165 Acl acl(path);
166 acl.SetDefaultUser(getuid(), Acl::R_RIGHT | Acl::W_RIGHT);
167 acl.SetDefaultGroup(SERVICE_GID, Acl::R_RIGHT | Acl::W_RIGHT);
168 return true;
169 }
170
CreateFile(const std::string & name)171 bool StoreUtil::CreateFile(const std::string &name)
172 {
173 umask(DEFAULT_UMASK);
174 if (access(name.c_str(), F_OK) == 0) {
175 return RemoveRWXForOthers(name);
176 }
177 int fp = open(name.c_str(), (O_WRONLY | O_CREAT), (S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP));
178 if (fp < 0) {
179 ZLOGE("fopen error:%{public}d, path:%{public}s", errno, name.c_str());
180 return false;
181 }
182 close(fp);
183 return true;
184 }
185
GetSubPath(const std::string & path)186 std::vector<std::string> StoreUtil::GetSubPath(const std::string &path)
187 {
188 std::vector<std::string> subPaths;
189 DIR *dirp = opendir(path.c_str());
190 if (dirp == nullptr) {
191 ZLOGE("opendir error:%{public}d, path:%{public}s", errno, path.c_str());
192 return subPaths;
193 }
194 struct dirent *dp;
195 while ((dp = readdir(dirp)) != nullptr) {
196 if (dp->d_type == DT_DIR) {
197 subPaths.push_back(dp->d_name);
198 }
199 }
200 (void)closedir(dirp);
201 return subPaths;
202 }
203
GetFiles(const std::string & path)204 std::vector<StoreUtil::FileInfo> StoreUtil::GetFiles(const std::string &path)
205 {
206 std::vector<FileInfo> fileInfos;
207 DIR *dirp = opendir(path.c_str());
208 if (dirp == nullptr) {
209 ZLOGE("opendir error:%{public}d, path:%{public}s", errno, path.c_str());
210 return fileInfos;
211 }
212 struct dirent *dp;
213 while ((dp = readdir(dirp)) != nullptr) {
214 if (dp->d_type == DT_REG) {
215 struct stat fileStat;
216 auto fullName = path + "/" + dp->d_name;
217 stat(fullName.c_str(), &fileStat);
218 FileInfo fileInfo = { "", 0, 0 };
219 fileInfo.name = dp->d_name;
220 fileInfo.modifyTime = fileStat.st_mtim.tv_sec;
221 fileInfo.size = fileStat.st_size;
222 fileInfos.push_back(fileInfo);
223 }
224 }
225 closedir(dirp);
226 return fileInfos;
227 }
228
Rename(const std::string & oldName,const std::string & newName)229 bool StoreUtil::Rename(const std::string &oldName, const std::string &newName)
230 {
231 if (oldName.empty() || newName.empty()) {
232 return false;
233 }
234 if (!Remove(newName)) {
235 return false;
236 }
237 if (rename(oldName.c_str(), newName.c_str()) != 0) {
238 ZLOGE("rename error:%{public}d, file:%{public}s->%{public}s", errno, oldName.c_str(), newName.c_str());
239 return false;
240 }
241 return true;
242 }
243
IsFileExist(const std::string & name)244 bool StoreUtil::IsFileExist(const std::string &name)
245 {
246 if (name.empty()) {
247 return false;
248 }
249 if (access(name.c_str(), F_OK) != 0) {
250 return false;
251 }
252 return true;
253 }
254
Remove(const std::string & path)255 bool StoreUtil::Remove(const std::string &path)
256 {
257 if (access(path.c_str(), F_OK) != 0) {
258 return true;
259 }
260 if (remove(path.c_str()) != 0) {
261 ZLOGE("remove error:%{public}d, path:%{public}s", errno, path.c_str());
262 return false;
263 }
264 return true;
265 }
266
Flush()267 void StoreUtil::Flush()
268 {
269 sync();
270 }
271
GenSequenceId()272 uint64_t StoreUtil::GenSequenceId()
273 {
274 uint64_t seqId = ++sequenceId_;
275 if (seqId == std::numeric_limits<uint64_t>::max()) {
276 return ++sequenceId_;
277 }
278 return seqId;
279 }
280
RemoveRWXForOthers(const std::string & path)281 bool StoreUtil::RemoveRWXForOthers(const std::string &path)
282 {
283 struct stat buf;
284 if (stat(path.c_str(), &buf) < 0) {
285 ZLOGI("stat error:%{public}d, path:%{public}s", errno, path.c_str());
286 return true;
287 }
288
289 if ((buf.st_mode & S_IRWXO) == 0) {
290 return true;
291 }
292
293 if (S_ISDIR(buf.st_mode)) {
294 DIR *dirp = opendir(path.c_str());
295 struct dirent *dp = nullptr;
296 while ((dp = readdir(dirp)) != nullptr) {
297 if ((std::string(dp->d_name) == ".") || (std::string(dp->d_name) == "..")) {
298 continue;
299 }
300 if (!RemoveRWXForOthers(path + "/" + dp->d_name)) {
301 closedir(dirp);
302 return false;
303 }
304 }
305 closedir(dirp);
306 }
307
308 if (chmod(path.c_str(), (buf.st_mode & ~S_IRWXO)) < 0) {
309 ZLOGE("chmod error:%{public}d, path:%{public}s", errno, path.c_str());
310 return false;
311 }
312 return true;
313 }
314 } // namespace OHOS::DistributedKv