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