1 /*
2  * Copyright (c) 2021-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 
16 #include <cassert>
17 #include "directory_ex.h"
18 #include <dirent.h>
19 #include <errno.h>
20 #include "securec.h"
21 #include "unistd.h"
22 #include "utils_log.h"
23 using namespace std;
24 
25 namespace OHOS {
26 
27 #if !defined(__APPLE__) && !defined(_WIN32)
GetCurrentProcFullFileName()28 string GetCurrentProcFullFileName()
29 {
30     char procFile[PATH_MAX + 1] = {0};
31     int ret = readlink("/proc/self/exe", procFile, PATH_MAX);
32     if (ret < 0 || ret > PATH_MAX) {
33         UTILS_LOGD("Get proc name failed, ret is: %{public}d!", ret);
34         return string();
35     }
36     procFile[ret] = '\0';
37     return string(procFile);
38 }
39 #else
40 string GetCurrentProcFullFileName()
41 {
42     assert("GetCurrentProcFullFileName Not Implement");
43     return "";
44 }
45 #endif
46 
GetCurrentProcPath()47 string GetCurrentProcPath()
48 {
49     return ExtractFilePath(GetCurrentProcFullFileName());
50 }
51 
ExtractFilePath(const string & fileFullName)52 string ExtractFilePath(const string& fileFullName)
53 {
54     return string(fileFullName).substr(0, fileFullName.rfind("/") + 1);
55 }
56 
ExtractFileName(const std::string & fileFullName)57 std::string ExtractFileName(const std::string& fileFullName)
58 {
59     return string(fileFullName).substr(fileFullName.rfind("/") + 1, fileFullName.size());
60 }
61 
ExtractFileExt(const string & fileName)62 string ExtractFileExt(const string& fileName)
63 {
64     string::size_type pos = fileName.rfind(".");
65     if (pos == string::npos) {
66         return "";
67     }
68 
69     return string(fileName).substr(pos + 1, fileName.size());
70 }
71 
ExcludeTrailingPathDelimiter(const std::string & path)72 string ExcludeTrailingPathDelimiter(const std::string& path)
73 {
74     if (path.rfind("/") != path.size() - 1) {
75         return path;
76     }
77 
78     if (!path.empty()) {
79         return path.substr(0, static_cast<int>(path.size()) - 1);
80     }
81 
82     return path;
83 }
84 
IncludeTrailingPathDelimiter(const std::string & path)85 string IncludeTrailingPathDelimiter(const std::string& path)
86 {
87     if (path.rfind("/") != path.size() - 1) {
88         return path + "/";
89     }
90 
91     return path;
92 }
93 
94 #if !defined(__APPLE__) && !defined(_WIN32)
GetDirFiles(const string & path,vector<string> & files)95 void GetDirFiles(const string& path, vector<string>& files)
96 {
97     string pathStringWithDelimiter;
98     DIR *dir = opendir(path.c_str());
99     if (dir == nullptr) {
100         return;
101     }
102 
103     while (true) {
104         struct dirent *ptr = readdir(dir);
105         if (ptr == nullptr) {
106             break;
107         }
108 
109         // current dir OR parent dir
110         if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
111             continue;
112         } else if (ptr->d_type == DT_DIR) {
113             pathStringWithDelimiter = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
114             GetDirFiles(pathStringWithDelimiter, files);
115         } else {
116             files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
117         }
118     }
119     closedir(dir);
120 }
121 #else
GetDirFiles(const string & path,vector<string> & files)122 void GetDirFiles(const string& path, vector<string>& files)
123 {
124     assert("GetCurrentProcFullFileName Not Implement");
125 }
126 #endif
127 
128 #if !defined(__APPLE__) && !defined(_WIN32)
ForceCreateDirectory(const string & path)129 bool ForceCreateDirectory(const string& path)
130 {
131     string::size_type index = 0;
132     do {
133         string subPath;
134         index = path.find('/', index + 1);
135         if (index == string::npos) {
136             subPath = path;
137         } else {
138             subPath = path.substr(0, index);
139         }
140 
141         if (access(subPath.c_str(), F_OK) != 0) {
142             if (mkdir(subPath.c_str(), (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != 0 && errno != EEXIST) {
143                 return false;
144             }
145         }
146     } while (index != string::npos);
147 
148     return access(path.c_str(), F_OK) == 0;
149 }
150 #else
ForceCreateDirectory(const string & path)151 bool ForceCreateDirectory(const string& path)
152 {
153     assert("GetCurrentProcFullFileName Not Implement");
154     return false;
155 }
156 #endif
157 
158 #if !defined(__APPLE__) && !defined(_WIN32)
ForceRemoveDirectory(const string & path)159 bool ForceRemoveDirectory(const string& path)
160 {
161     string subPath;
162     bool ret = true;
163     DIR *dir = opendir(path.c_str());
164     if (dir == nullptr) {
165         return false;
166     }
167 
168     while (true) {
169         struct dirent *ptr = readdir(dir);
170         if (ptr == nullptr) {
171             break;
172         }
173 
174         // current dir OR parent dir
175         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
176             continue;
177         }
178         subPath = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
179         if (ptr->d_type == DT_DIR) {
180             ret = ForceRemoveDirectory(subPath);
181         } else {
182             if (access(subPath.c_str(), F_OK) == 0) {
183                 if (remove(subPath.c_str()) != 0) {
184                     closedir(dir);
185                     return false;
186                 }
187             }
188         }
189     }
190     closedir(dir);
191 
192     string currentPath = ExcludeTrailingPathDelimiter(path);
193     if (access(currentPath.c_str(), F_OK) == 0) {
194         if (remove(currentPath.c_str()) != 0) {
195             return false;
196         }
197     }
198 
199     return ret && (access(path.c_str(), F_OK) != 0);
200 }
201 #endif
202 
RemoveFile(const string & fileName)203 bool RemoveFile(const string& fileName)
204 {
205     if (access(fileName.c_str(), F_OK) == 0) {
206         return remove(fileName.c_str()) == 0;
207     }
208 
209     return true;
210 }
211 
IsEmptyFolder(const string & path)212 bool IsEmptyFolder(const string& path)
213 {
214     vector<string> files;
215     GetDirFiles(path, files);
216     return files.empty();
217 }
218 
GetFolderSize(const string & path)219 uint64_t GetFolderSize(const string& path)
220 {
221     vector<string> files;
222     struct stat statbuf = {0};
223     GetDirFiles(path, files);
224     uint64_t totalSize = 0;
225     for (auto& file : files) {
226         if (stat(file.c_str(), &statbuf) == 0) {
227             totalSize += statbuf.st_size;
228         }
229     }
230 
231     return totalSize;
232 }
233 
234 // inner function, and param is legitimate
ChangeMode(const string & fileName,const mode_t & mode)235 bool ChangeMode(const string& fileName, const mode_t& mode)
236 {
237     return (chmod(fileName.c_str(), mode) == 0);
238 }
239 
ChangeModeFile(const string & fileName,const mode_t & mode)240 bool ChangeModeFile(const string& fileName, const mode_t& mode)
241 {
242     if (access(fileName.c_str(), F_OK) != 0) {
243         return false;
244     }
245 
246     return ChangeMode(fileName, mode);
247 }
248 
249 #if !defined(__APPLE__) && !defined(_WIN32)
ChangeModeDirectory(const string & path,const mode_t & mode)250 bool ChangeModeDirectory(const string& path, const mode_t& mode)
251 {
252     string subPath;
253     bool ret = true;
254     DIR *dir = opendir(path.c_str());
255     if (dir == nullptr) {
256         return false;
257     }
258 
259     while (true) {
260         struct dirent *ptr = readdir(dir);
261         if (ptr == nullptr) {
262             break;
263         }
264 
265         // current dir OR parent dir
266         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
267             continue;
268         }
269         subPath = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
270         if (ptr->d_type == DT_DIR) {
271             ret = ChangeModeDirectory(subPath, mode);
272         } else {
273             if (access(subPath.c_str(), F_OK) == 0) {
274                 if (!ChangeMode(subPath, mode)) {
275                     UTILS_LOGD("Failed to exec ChangeMode");
276                     closedir(dir);
277                     return false;
278                 }
279             }
280         }
281     }
282     closedir(dir);
283     string currentPath = ExcludeTrailingPathDelimiter(path);
284     if (access(currentPath.c_str(), F_OK) == 0) {
285         if (!ChangeMode(currentPath, mode)) {
286             UTILS_LOGD("Failed to exec ChangeMode");
287             return false;
288         }
289     }
290     return ret;
291 }
292 #endif
293 
PathToRealPath(const string & path,string & realPath)294 bool PathToRealPath(const string& path, string& realPath)
295 {
296     if (path.empty()) {
297         UTILS_LOGD("path is empty!");
298         return false;
299     }
300 
301     if ((path.length() >= PATH_MAX)) {
302         UTILS_LOGD("path len is error, the len is: [%{public}zu]", path.length());
303         return false;
304     }
305 
306     char tmpPath[PATH_MAX] = {0};
307 #ifdef _WIN32
308     auto ret = _fullpath(tmpPath, path.c_str(), sizeof(tmpPath));
309 #else
310     auto ret = realpath(path.c_str(), tmpPath);
311 #endif
312     if (ret == nullptr) {
313         UTILS_LOGD("path to realpath error");
314         return false;
315     }
316 
317     realPath = tmpPath;
318     if (access(realPath.c_str(), F_OK) != 0) {
319         UTILS_LOGD("check realpath (%{private}s) error", realPath.c_str());
320         return false;
321     }
322     return true;
323 }
324 
325 } // OHOS
326