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 #include "utils_directory.h"
17 
18 #include <cstring>
19 #include <dirent.h>
20 #include <sys/types.h>
21 #include <system_error>
22 #include <unistd.h>
23 
24 #include "dfs_error.h"
25 #include "directory_ex.h"
26 #include "hisysevent.h"
27 #include "utils_log.h"
28 
29 namespace OHOS {
30 namespace Storage {
31 namespace DistributedFile {
32 namespace Utils {
33 using namespace std;
34 
35 namespace {
36     static const uint32_t STAT_MODE_DIR = 0771;
37 }
38 
GetAnonyString(const std::string & value)39 std::string GetAnonyString(const std::string &value)
40 {
41     constexpr size_t shortIdLength = 20;
42     constexpr size_t plaintextLength = 4;
43     constexpr size_t minIdLength = 3;
44     std::string res;
45     std::string tmpStr("******");
46     size_t strLen = value.length();
47     if (strLen < minIdLength) {
48         return tmpStr;
49     }
50 
51     if (strLen <= shortIdLength) {
52         res += value[0];
53         res += tmpStr;
54         res += value[strLen - 1];
55     } else {
56         res.append(value, 0, plaintextLength);
57         res += tmpStr;
58         res.append(value, strLen - plaintextLength, plaintextLength);
59     }
60     return res;
61 }
62 
SysEventWrite(string & uid)63 void SysEventWrite(string &uid)
64 {
65     if (uid.empty()) {
66         LOGE("uid is empty.");
67         return;
68     }
69     int32_t ret = DEMO_SYNC_SYS_EVENT("PERMISSION_EXCEPTION",
70         HiviewDFX::HiSysEvent::EventType::SECURITY,
71         "CALLER_UID", uid,
72         "PERMISSION_NAME", "account");
73     if (ret != ERR_OK) {
74         LOGE("report PERMISSION_EXCEPTION error %{public}d", ret);
75     }
76 }
77 
SysEventFileParse(int64_t maxTime)78 void SysEventFileParse(int64_t maxTime)
79 {
80     int32_t ret = DEMO_SYNC_SYS_EVENT("INDEX_FILE_PARSE",
81         HiviewDFX::HiSysEvent::EventType::STATISTIC,
82         "MAX_TIME", maxTime);
83     if (ret != ERR_OK) {
84         LOGE("report INDEX_FILE_PARSE error %{public}d", ret);
85     }
86 }
87 
RadarDotsReportOpenSession(struct RadarInfo & info)88 void RadarDotsReportOpenSession(struct RadarInfo &info)
89 {
90     int32_t res = ERR_OK;
91     if (info.state == StageRes::STAGE_SUCCESS) {
92         res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
93             HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
94             "ORG_PKG", ORGPKGNAME,
95             "TO_CALL_PKG", SOFTBUSNAME,
96             "FUNC", info.funcName,
97             "BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
98             "BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_OPEN_SESSION),
99             "BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_START),
100             "STAGE_RES", static_cast<int32_t>(StageRes::STAGE_SUCCESS),
101             "LOCAL_SESS_NAME", info.localSessionName,
102             "PEER_SESS_NAME", info.peerSessionName);
103     } else {
104         res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
105             HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
106             "ORG_PKG", ORGPKGNAME,
107             "TO_CALL_PKG", SOFTBUSNAME,
108             "FUNC", info.funcName,
109             "BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
110             "BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_OPEN_SESSION),
111             "BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_END),
112             "STAGE_RES", static_cast<int32_t>(StageRes::STAGE_FAIL),
113             "LOCAL_SESS_NAME", info.localSessionName,
114             "PEER_SESS_NAME", info.peerSessionName,
115             "ERROR_CODE", std::abs(info.errCode));
116     }
117     if (res != ERR_OK) {
118         LOGE("report RadarDotsReportOpenSession error %{public}d", res);
119     }
120 }
121 
RadarDotsOpenSession(const std::string funcName,const std::string & sessionName,const std::string & peerSssionName,int32_t errCode,StageRes state)122 void RadarDotsOpenSession(const std::string funcName, const std::string &sessionName,
123     const std::string &peerSssionName, int32_t errCode, StageRes state)
124 {
125     struct RadarInfo info = {
126         .funcName = funcName,
127         .localSessionName = sessionName,
128         .peerSessionName = peerSssionName,
129         .errCode = errCode,
130         .state = state,
131     };
132     RadarDotsReportOpenSession(info);
133 }
134 
RadarDotsReportSendFile(struct RadarInfo & info)135 void RadarDotsReportSendFile(struct RadarInfo &info)
136 {
137     int32_t res = ERR_OK;
138     if (info.state == StageRes::STAGE_SUCCESS) {
139         res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
140             HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
141             "ORG_PKG", ORGPKGNAME,
142             "TO_CALL_PKG", SOFTBUSNAME,
143             "FUNC", info.funcName,
144             "BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
145             "BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_SENDFILE),
146             "BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_END),
147             "STAGE_RES", static_cast<int32_t>(StageRes::STAGE_SUCCESS),
148             "LOCAL_SESS_NAME", info.localSessionName,
149             "PEER_SESS_NAME", info.peerSessionName);
150     } else {
151         res = DEMO_SYNC_SYS_EVENT(DISTRIBUTEDFILE_CONNECT_BEHAVIOR,
152             HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
153             "ORG_PKG", ORGPKGNAME,
154             "TO_CALL_PKG", SOFTBUSNAME,
155             "FUNC", info.funcName,
156             "BIZ_SCENE", static_cast<int32_t>(BizScene::DFS_CONNECT),
157             "BIZ_STAGE", static_cast<int32_t>(BizStage::DFS_SENDFILE),
158             "BIZ_STATE", static_cast<int32_t>(BizState::BIZ_STATE_END),
159             "STAGE_RES", static_cast<int32_t>(StageRes::STAGE_FAIL),
160             "LOCAL_SESS_NAME", info.localSessionName,
161             "PEER_SESS_NAME", info.peerSessionName,
162             "ERROR_CODE", std::abs(info.errCode));
163     }
164     if (res != ERR_OK) {
165         LOGE("report RadarDotsReportSendFile error %{public}d", res);
166     }
167 }
168 
RadarDotsSendFile(const std::string funcName,const std::string & sessionName,const std::string & peerSssionName,int32_t errCode,StageRes state)169 void RadarDotsSendFile(const std::string funcName, const std::string &sessionName,
170     const std::string &peerSssionName, int32_t errCode, StageRes state)
171 {
172     struct RadarInfo info = {
173         .funcName = funcName,
174         .localSessionName = sessionName,
175         .peerSessionName = peerSssionName,
176         .errCode = errCode,
177         .state = state,
178     };
179     RadarDotsReportSendFile(info);
180 }
181 
ForceCreateDirectory(const string & path,function<void (const string &)> onSubDirCreated)182 void ForceCreateDirectory(const string &path, function<void(const string &)> onSubDirCreated)
183 {
184     string::size_type index = 0;
185     do {
186         string subPath;
187         index = path.find('/', index + 1);
188         if (index == string::npos) {
189             subPath = path;
190         } else {
191             subPath = path.substr(0, index);
192         }
193 
194         if (access(subPath.c_str(), F_OK) != 0) {
195             if (mkdir(subPath.c_str(), STAT_MODE_DIR) != 0) {
196                 LOGE("failed to mkdir, errno:%{public}d", errno);
197                 return;
198             }
199             onSubDirCreated(subPath);
200         }
201     } while (index != string::npos);
202 }
203 
ForceCreateDirectory(const string & path)204 void ForceCreateDirectory(const string &path)
205 {
206     ForceCreateDirectory(path, nullptr);
207 }
208 
ForceCreateDirectory(const string & path,mode_t mode)209 void ForceCreateDirectory(const string &path, mode_t mode)
210 {
211     ForceCreateDirectory(path, [mode](const string &subPath) {
212         if (chmod(subPath.c_str(), mode) == -1) {
213             LOGE("failed to chmod, errno:%{public}d", errno);
214         }
215     });
216 }
217 
ForceCreateDirectory(const string & path,mode_t mode,uid_t uid,gid_t gid)218 void ForceCreateDirectory(const string &path, mode_t mode, uid_t uid, gid_t gid)
219 {
220     ForceCreateDirectory(path, [mode, uid, gid](const string &subPath) {
221         if (chmod(subPath.c_str(), mode) == -1 || chown(subPath.c_str(), uid, gid) == -1) {
222             LOGE("failed to chmod or chown, errno:%{public}d", errno);
223         }
224     });
225 }
226 
ForceRemoveDirectory(const string & path)227 void ForceRemoveDirectory(const string &path)
228 {
229     if (!OHOS::ForceRemoveDirectory(path)) {
230         LOGE("failed to forcibly remove directory, errno:%{public}d", errno);
231     }
232 }
233 
ForceRemoveDirectoryDeepFirst(const string & path)234 bool ForceRemoveDirectoryDeepFirst(const string& path)
235 {
236     string subPath;
237     bool ret = true;
238     DIR *dir = opendir(path.c_str());
239     if (dir == nullptr) {
240         LOGE("opendir failed, path = %{public}s, err:%{public}d", GetAnonyString(path).c_str(), errno);
241         return false;
242     }
243 
244     while (true) {
245         struct dirent *ptr = readdir(dir);
246         if (ptr == nullptr) {
247             break;
248         }
249 
250         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
251             continue;
252         }
253         subPath = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
254         if (ptr->d_type == DT_DIR) {
255             if (!ForceRemoveDirectoryDeepFirst(subPath)) {
256                 ret = false;
257             }
258         } else if (access(subPath.c_str(), F_OK) == 0) {
259             if (remove(subPath.c_str()) != 0) {
260                 closedir(dir);
261                 LOGE("remove failed, subPath = %{public}s, err:%{public}d",
262                     GetAnonyString(subPath).c_str(), errno);
263                 return false;
264             }
265         }
266     }
267     closedir(dir);
268 
269     string currentPath = ExcludeTrailingPathDelimiter(path);
270     if (access(currentPath.c_str(), F_OK) == 0) {
271         if (remove(currentPath.c_str()) != 0) {
272             LOGE("remove failed, currentPath = %{public}s, err:%{public}d",
273                 GetAnonyString(currentPath).c_str(), errno);
274             return false;
275         }
276     }
277 
278     return ret && (access(path.c_str(), F_OK) != 0);
279 }
280 
IsFile(const std::string & path)281 bool IsFile(const std::string &path)
282 {
283     if (path.empty()) {
284         return false;
285     }
286     struct stat buf = {};
287     if (stat(path.c_str(), &buf) != 0) {
288         LOGE("stat failed, errno = %{public}d", errno);
289         return false;
290     }
291     return S_ISREG(buf.st_mode);
292 }
293 
IsFolder(const std::string & name)294 bool IsFolder(const std::string &name)
295 {
296     if (name.empty()) {
297         return false;
298     }
299     struct stat buf = {};
300     if (stat(name.c_str(), &buf) != 0) {
301         LOGE("stat failed, errno = %{public}d", errno);
302         return false;
303     }
304     return S_ISDIR(buf.st_mode);
305 }
306 
GetFilePath(const std::string & name)307 std::vector<std::string> GetFilePath(const std::string &name)
308 {
309     std::vector<std::string> path;
310     if (!IsFolder(name)) {
311         path.emplace_back(name);
312         return path;
313     }
314     auto dir = opendir(name.data());
315     struct dirent *ent = nullptr;
316     if (dir) {
317         while ((ent = readdir(dir)) != nullptr) {
318             auto tmpPath = std::string(name).append("/").append(ent->d_name);
319             if (strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".") == 0) {
320                 continue;
321             } else if (IsFolder(tmpPath)) {
322                 auto dirPath = GetFilePath(tmpPath);
323                 path.insert(path.end(), dirPath.begin(), dirPath.end());
324             } else {
325                 path.emplace_back(tmpPath);
326             }
327         }
328         closedir(dir);
329     }
330     return path;
331 }
332 
ChangeOwnerRecursive(const std::string & path,uid_t uid,gid_t gid)333 int32_t ChangeOwnerRecursive(const std::string &path, uid_t uid, gid_t gid)
334 {
335     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), &closedir);
336     if (dir == nullptr) {
337         LOGE("Directory is null");
338         return -1;
339     }
340 
341     struct dirent *entry = nullptr;
342     while ((entry = readdir(dir.get())) != nullptr) {
343         if (entry->d_type == DT_DIR) {
344             if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
345                 continue;
346             }
347             std::string subPath = path + "/" + entry->d_name;
348             if (chown(subPath.c_str(), uid, gid) == -1) {
349                 LOGE("Change owner recursive failed");
350                 return -1;
351             }
352             return ChangeOwnerRecursive(subPath, uid, gid);
353         } else {
354             std::string filePath = path + "/" + entry->d_name;
355             if (chown(filePath.c_str(), uid, gid) == -1) {
356                 LOGE("Change owner recursive failed");
357                 return -1;
358             }
359         }
360     }
361     return 0;
362 }
363 
IsInt32(const nlohmann::json & jsonObj,const std::string & key)364 bool IsInt32(const nlohmann::json &jsonObj, const std::string &key)
365 {
366     bool res = jsonObj.contains(key) && jsonObj[key].is_number_integer() && jsonObj[key] >= INT32_MIN &&
367         jsonObj[key] <= INT32_MAX;
368     if (!res) {
369         LOGE("the key %{public}s in jsonObj is invalid.", key.c_str());
370     }
371     return res;
372 }
373 } // namespace Utils
374 } // namespace DistributedFile
375 } // namespace Storage
376 } // namespace OHOS