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