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