• 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 "directory_ex.h"
17 #include <dirent.h>
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <stack>
21 #include "securec.h"
22 #include "unistd.h"
23 #include "utils_log.h"
24 using namespace std;
25 
26 namespace OHOS {
27 
28 #ifdef UTILS_CXX_RUST
RustGetCurrentProcFullFileName()29 rust::String RustGetCurrentProcFullFileName()
30 {
31     return rust::String(GetCurrentProcFullFileName());
32 }
33 
RustGetCurrentProcPath()34 rust::String RustGetCurrentProcPath()
35 {
36     return rust::String(GetCurrentProcPath());
37 }
38 
RustExtractFilePath(const rust::String & fileFullName)39 rust::String RustExtractFilePath(const rust::String& fileFullName)
40 {
41     std::string tmpName = std::string(fileFullName);
42     return rust::String(ExtractFilePath(tmpName));
43 }
44 
RustExtractFileName(const rust::String & fileFullName)45 rust::String RustExtractFileName(const rust::String& fileFullName)
46 {
47     std::string tmpName = std::string(fileFullName);
48     return rust::String(ExtractFileName(tmpName));
49 }
50 
RustExtractFileExt(const rust::String & fileName)51 rust::String RustExtractFileExt(const rust::String& fileName)
52 {
53     std::string tmpName = std::string(fileName);
54     return rust::String(ExtractFileExt(tmpName));
55 }
56 
RustExcludeTrailingPathDelimiter(const rust::String & path)57 rust::String RustExcludeTrailingPathDelimiter(const rust::String& path)
58 {
59     std::string tmpPath = std::string(path);
60     return rust::String(ExcludeTrailingPathDelimiter(tmpPath));
61 }
62 
RustIncludeTrailingPathDelimiter(const rust::String & path)63 rust::String RustIncludeTrailingPathDelimiter(const rust::String& path)
64 {
65     std::string tmpPath = std::string(path);
66     return rust::String(IncludeTrailingPathDelimiter(tmpPath));
67 }
68 
RustPathToRealPath(const rust::String & path,rust::String & realPath)69 bool RustPathToRealPath(const rust::String& path, rust::String& realPath)
70 {
71     std::string tmpPath = std::string(path);
72     std::string tmpResolved;
73 
74     if (PathToRealPath(tmpPath, tmpResolved)) {
75         realPath = tmpResolved;
76         return true;
77     }
78 
79     return false;
80 }
81 
RustGetDirFiles(const rust::String & path,rust::vec<rust::String> & files)82 void RustGetDirFiles(const rust::String& path, rust::vec<rust::String>& files)
83 {
84     std::string tmpPath(path);
85     std::vector<std::string> tmpFiles(files.begin(), files.end());
86     GetDirFiles(tmpPath, tmpFiles);
87     std::copy(tmpFiles.begin(), tmpFiles.end(), std::back_inserter(files));
88 }
89 #endif
90 
GetCurrentProcFullFileName()91 string GetCurrentProcFullFileName()
92 {
93     char procFile[PATH_MAX + 1] = {0};
94     int ret = readlink("/proc/self/exe", procFile, PATH_MAX);
95     if (ret < 0 || ret > PATH_MAX) {
96         UTILS_LOGD("Get proc name failed, ret is: %{public}d!", ret);
97         return string();
98     }
99     procFile[ret] = '\0';
100     return string(procFile);
101 }
102 
GetCurrentProcPath()103 string GetCurrentProcPath()
104 {
105     return ExtractFilePath(GetCurrentProcFullFileName());
106 }
107 
ExtractFilePath(const string & fileFullName)108 string ExtractFilePath(const string& fileFullName)
109 {
110     return string(fileFullName).substr(0, fileFullName.rfind("/") + 1);
111 }
112 
ExtractFileName(const std::string & fileFullName)113 std::string ExtractFileName(const std::string& fileFullName)
114 {
115     return string(fileFullName).substr(fileFullName.rfind("/") + 1, fileFullName.size());
116 }
117 
ExtractFileExt(const string & fileName)118 string ExtractFileExt(const string& fileName)
119 {
120     string::size_type pos = fileName.rfind(".");
121     if (pos == string::npos) {
122         return "";
123     }
124 
125     return string(fileName).substr(pos + 1, fileName.size());
126 }
127 
ExcludeTrailingPathDelimiter(const std::string & path)128 string ExcludeTrailingPathDelimiter(const std::string& path)
129 {
130     if (path.rfind("/") != path.size() - 1) {
131         return path;
132     }
133 
134     if (!path.empty()) {
135         return path.substr(0, (int)path.size() - 1);
136     }
137 
138     return path;
139 }
140 
IncludeTrailingPathDelimiter(const std::string & path)141 string IncludeTrailingPathDelimiter(const std::string& path)
142 {
143     if (path.rfind("/") != path.size() - 1) {
144         return path + "/";
145     }
146 
147     return path;
148 }
149 
GetDirFiles(const string & path,vector<string> & files)150 void GetDirFiles(const string& path, vector<string>& files)
151 {
152     string pathStringWithDelimiter;
153     DIR *dir = opendir(path.c_str());
154     if (dir == nullptr) {
155         return;
156     }
157 
158     while (true) {
159         struct dirent *ptr = readdir(dir);
160         if (ptr == nullptr) {
161             break;
162         }
163 
164         // current dir or parent dir
165         if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
166             continue;
167         } else if (ptr->d_type == DT_DIR) {
168             pathStringWithDelimiter = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
169             GetDirFiles(pathStringWithDelimiter, files);
170         } else {
171             files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
172         }
173     }
174     closedir(dir);
175 }
176 
ForceCreateDirectory(const string & path)177 bool ForceCreateDirectory(const string& path)
178 {
179     string::size_type index = 0;
180     do {
181         string subPath;
182         index = path.find('/', index + 1);
183         if (index == string::npos) {
184             subPath = path;
185         } else {
186             subPath = path.substr(0, index);
187         }
188 
189         if (access(subPath.c_str(), F_OK) != 0) {
190             if (mkdir(subPath.c_str(), (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) != 0 && errno != EEXIST) {
191                 return false;
192             }
193         }
194     } while (index != string::npos);
195 
196     return access(path.c_str(), F_OK) == 0;
197 }
198 
199 struct DirectoryNode {
200     DIR *dir;
201     int currentFd;
202     char name[256]; // the same max char length with d_name in struct dirent
203 };
204 
ForceRemoveDirectory(const string & path)205 bool ForceRemoveDirectory(const string& path)
206 {
207     bool ret = true;
208     int strRet;
209     DIR *dir = opendir(path.c_str());
210     if (dir == nullptr) {
211         UTILS_LOGD("Failed to open root dir: %{public}s: %{public}s ", path.c_str(), strerror(errno));
212         return false;
213     }
214     stack<DIR *> traversStack;
215     stack<DirectoryNode> removeStack;
216     traversStack.push(dir);
217     while (!traversStack.empty()) {
218         DIR *currentDir = traversStack.top();
219         traversStack.pop();
220         DirectoryNode node;
221         int currentFd = dirfd(currentDir);
222         if (currentFd < 0) {
223             UTILS_LOGD("Failed to get dirfd, fd: %{public}d: %{public}s ", currentFd, strerror(errno));
224             ret = false;
225             continue;
226         }
227 
228         while (true) {
229             struct dirent *ptr = readdir(currentDir);
230             if (ptr == nullptr) {
231                 break;
232             }
233             const char *name = ptr->d_name;
234             // current dir or parent dir
235             if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
236                 continue;
237             }
238 
239             if (ptr->d_type == DT_DIR) {
240                 int subFd = openat(currentFd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
241                 if (subFd < 0) {
242                     UTILS_LOGD("Failed in subFd openat: %{public}s ", name);
243                     ret = false;
244                     continue;
245                 }
246                 DIR *subDir = fdopendir(subFd);
247                 if (subDir == nullptr) {
248                     close(subFd);
249                     UTILS_LOGD("Failed in fdopendir: %{public}s", strerror(errno));
250                     ret = false;
251                     continue;
252                 }
253                 node.dir = subDir;
254                 node.currentFd = currentFd;
255                 strRet = strcpy_s(node.name, sizeof(node.name), name);
256                 if (strRet != EOK) {
257                     UTILS_LOGE("Failed to exec strcpy_s, name= %{public}s, strRet= %{public}d", name, strRet);
258                 }
259                 removeStack.push(node);
260                 traversStack.push(subDir);
261             } else {
262                 if (faccessat(currentFd, name, F_OK, AT_SYMLINK_NOFOLLOW) == 0) {
263                     if (unlinkat(currentFd, name, 0) < 0) {
264                         UTILS_LOGD("Couldn't unlinkat subFile %{public}s: %{public}s", name, strerror(errno));
265                         ret = false;
266                         break;
267                     }
268                 } else {
269                     UTILS_LOGD("Access to file: %{public}s is failed", name);
270                     ret = false;
271                     break;
272                 }
273             }
274         }
275     }
276     if (!ret) {
277         UTILS_LOGD("Failed to remove some subfile under path: %{public}s", path.c_str());
278     }
279     while (!removeStack.empty()) {
280         DirectoryNode node = removeStack.top();
281         removeStack.pop();
282         closedir(node.dir);
283         if (unlinkat(node.currentFd, node.name, AT_REMOVEDIR) < 0) {
284             UTILS_LOGD("Couldn't unlinkat subDir %{public}s: %{public}s", node.name, strerror(errno));
285             continue;
286         }
287     }
288     closedir(dir);
289     if (faccessat(AT_FDCWD, path.c_str(), F_OK, AT_SYMLINK_NOFOLLOW) == 0) {
290         if (remove(path.c_str()) != 0) {
291             UTILS_LOGD("Failed to remove root dir: %{public}s: %{public}s ", path.c_str(), strerror(errno));
292             return false;
293         }
294     }
295     return faccessat(AT_FDCWD, path.c_str(), F_OK, AT_SYMLINK_NOFOLLOW) != 0;
296 }
297 
RemoveFile(const string & fileName)298 bool RemoveFile(const string& fileName)
299 {
300     if (access(fileName.c_str(), F_OK) == 0) {
301         return remove(fileName.c_str()) == 0;
302     }
303 
304     return true;
305 }
306 
IsEmptyFolder(const string & path)307 bool IsEmptyFolder(const string& path)
308 {
309     vector<string> files;
310     GetDirFiles(path, files);
311     return files.empty();
312 }
313 
GetFolderSize(const string & path)314 uint64_t GetFolderSize(const string& path)
315 {
316     vector<string> files;
317     struct stat statbuf = {0};
318     GetDirFiles(path, files);
319     uint64_t totalSize = 0;
320     for (auto& file : files) {
321         if (stat(file.c_str(), &statbuf) == 0) {
322             totalSize += statbuf.st_size;
323         }
324     }
325 
326     return totalSize;
327 }
328 
329 // inner function, and param is legitimate
ChangeMode(const string & fileName,const mode_t & mode)330 bool ChangeMode(const string& fileName, const mode_t& mode)
331 {
332     return (chmod(fileName.c_str(), mode) == 0);
333 }
334 
ChangeModeFile(const string & fileName,const mode_t & mode)335 bool ChangeModeFile(const string& fileName, const mode_t& mode)
336 {
337     if (access(fileName.c_str(), F_OK) != 0) {
338         return false;
339     }
340 
341     return ChangeMode(fileName, mode);
342 }
343 
ChangeModeDirectory(const string & path,const mode_t & mode)344 bool ChangeModeDirectory(const string& path, const mode_t& mode)
345 {
346     string subPath;
347     bool ret = true;
348     DIR *dir = opendir(path.c_str());
349     if (dir == nullptr) {
350         return false;
351     }
352 
353     while (true) {
354         struct dirent *ptr = readdir(dir);
355         if (ptr == nullptr) {
356             break;
357         }
358 
359         // current dir or parent dir
360         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
361             continue;
362         }
363         subPath = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
364         if (ptr->d_type == DT_DIR) {
365             ret = ChangeModeDirectory(subPath, mode);
366         } else {
367             if (access(subPath.c_str(), F_OK) == 0) {
368                 if (!ChangeMode(subPath, mode)) {
369                     UTILS_LOGD("Failed to exec ChangeMode");
370                     closedir(dir);
371                     return false;
372                 }
373             }
374         }
375     }
376     closedir(dir);
377     string currentPath = ExcludeTrailingPathDelimiter(path);
378     if (access(currentPath.c_str(), F_OK) == 0) {
379         if (!ChangeMode(currentPath, mode)) {
380             UTILS_LOGD("Failed to exec ChangeMode");
381             return false;
382         }
383     }
384     return ret;
385 }
386 
PathToRealPath(const string & path,string & realPath)387 bool PathToRealPath(const string& path, string& realPath)
388 {
389     if (path.empty()) {
390         UTILS_LOGD("path is empty!");
391         return false;
392     }
393 
394     if ((path.length() >= PATH_MAX)) {
395         UTILS_LOGD("path len is error, the len is: [%{public}zu]", path.length());
396         return false;
397     }
398 
399     char tmpPath[PATH_MAX] = {0};
400     if (realpath(path.c_str(), tmpPath) == nullptr) {
401         UTILS_LOGD("path to realpath error");
402         return false;
403     }
404 
405     realPath = tmpPath;
406     if (access(realPath.c_str(), F_OK) != 0) {
407         UTILS_LOGD("check realpath (%{private}s) error", realPath.c_str());
408         return false;
409     }
410     return true;
411 }
412 
413 #if defined(IOS_PLATFORM) || defined(_WIN32)
TransformFileName(const string & fileName)414 string TransformFileName(const string& fileName)
415 {
416     string::size_type pos = fileName.find(".");
417     string transformfileName = "";
418     if (pos == string::npos) {
419         transformfileName = fileName;
420 
421 #ifdef _WIN32
422         transformfileName = transformfileName.append(".dll");
423 #elif defined IOS_PLATFORM
424         transformfileName = transformfileName.append(".dylib");
425 #endif
426 
427         return transformfileName;
428     } else {
429         transformfileName = string(fileName).substr(0, pos + 1);
430 
431 #ifdef _WIN32
432         transformfileName = transformfileName.append("dll");
433 #elif defined IOS_PLATFORM
434         transformfileName = transformfileName.append("dylib");
435 #endif
436 
437         return transformfileName;
438     }
439 }
440 #endif
441 
442 } // OHOS
443