diff --git a/base/src/directory_ex.cpp b/base/src/directory_ex.cpp index 2ef101b7aef0e8bc408af51f191c668293150fb5..3b713a44077fa66d81d732ab4473500889af4154 100644 --- a/base/src/directory_ex.cpp +++ b/base/src/directory_ex.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "securec.h" #include "unistd.h" #include "utils_log.h" @@ -253,6 +255,13 @@ bool ForceRemoveDirectoryInternal(DIR *dir) return ret; } +struct DirectoryNdoe +{ + int directoryFd; + const char *name; + DIR *dir; +}; + bool ForceRemoveDirectory(const string& path) { bool ret = true; @@ -261,13 +270,77 @@ bool ForceRemoveDirectory(const string& path) UTILS_LOGD("Failed to open root dir: %{public}s: %{public}s ", path.c_str(), strerror(errno)); return false; } - ret = ForceRemoveDirectoryInternal(dir); + + std::queue dirQueue; + std::stack dirStack; + dirQueue.push(dir); + while (!dirQueue.empty()){ + int size = dirQueue.size(); + for (int i = 0; i < size; i++){ + DIR *currentDir = dirQueue.front(); + DirectoryNdoe node; + int currentFd = dirfd(currentDir); + dirQueue.pop(); + while (true){ + struct dirent *ptr = readdir(currentDir); + if (ptr == nullptr){ + break; + } + const char *name = ptr->d_name; + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + continue; + } + if (ptr->d_type == DT_DIR) { + node.name = name; + node.directoryFd = currentFd; + node.dir = currentDir; + dirStack.push(node); + int subFd = openat(currentFd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (subFd < 0) { + UTILS_LOGD("Failed in subFd openat: %{public}s ", name); + ret = false; + break; + } + DIR *subDir = fdopendir(subFd); + if (subDir == nullptr) { + close(subFd); + UTILS_LOGD("Failed in fdopendir: %{public}s", strerror(errno)); + ret = false; + break; + } + dirQueue.push(subDir); + }else { + if (faccessat(currentFd, name, F_OK, AT_SYMLINK_NOFOLLOW) == 0) { + if (unlinkat(currentFd, name, 0) < 0) { + UTILS_LOGD("Couldn't unlinkat subFile %{public}s: %{public}s", name, strerror(errno)); + ret = false; + break; + } + } else { + UTILS_LOGD("Access to file: %{public}s is failed", name); + ret = false; + break; + } + } + } + } + } if (!ret) { UTILS_LOGD("Failed to remove some subfile under path: %{public}s", path.c_str()); + return ret; + } + + while (!dirStack.empty()) { + DirectoryNdoe node = dirStack.top(); + dirStack.pop(); + if (unlinkat(node.directoryFd, node.name, AT_REMOVEDIR) < 0) { + UTILS_LOGD("Couldn't unlinkat subDir %{public}s: %{public}s", name, strerror(errno)); + break; + } + closedir(node.dir); } - closedir(dir); if (faccessat(AT_FDCWD, path.c_str(), F_OK, AT_SYMLINK_NOFOLLOW) == 0) { - if (remove(path.c_str()) != 0) { + if (unlinkat(AT_FDCWD, path.c_str(), 0) != 0) { UTILS_LOGD("Failed to remove root dir: %{public}s: %{public}s ", path.c_str(), strerror(errno)); return false; } @@ -330,35 +403,58 @@ bool ChangeModeDirectory(const string& path, const mode_t& mode) if (dir == nullptr) { return false; } - - while (true) { - struct dirent *ptr = readdir(dir); - if (ptr == nullptr) { - break; - } - - // current dir or parent dir - if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) { - continue; - } - subPath = IncludeTrailingPathDelimiter(path) + string(ptr->d_name); - if (ptr->d_type == DT_DIR) { - ret = ChangeModeDirectory(subPath, mode); - } else { - if (access(subPath.c_str(), F_OK) == 0) { - if (!ChangeMode(subPath, mode)) { - UTILS_LOGD("Failed to exec ChangeMode"); - closedir(dir); - return false; + std::stack dirStack1; + std::stack dirStack2; + while (!dirStack2.empty()) { + DIR *currentDir = dirStack1.top(); + dirStack1.pop(); + DirectoryNdoe node; + int currentFd = dirfd(currentDir); + while (true) { + struct dirent *ptr = readdir(currentDir); + if (ptr == nullptr) { + break; + } + const char *name = ptr->d_name; + if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { + continue; + } + if (ptr->d_type == DT_DIR) { + node.name = name; + node.directoryFd = currentFd; + node.dir = currentDir; + dirStack2.push(node); + int subFd = openat(currentFd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC); + if (subFd < 0) { + UTILS_LOGD("Failed in subFd openat: %{public}s ", name); + ret = false; + break; + } + DIR *subDir = fdopendir(subFd); + if (subDir == nullptr) { + close(subFd); + UTILS_LOGD("Failed in fdopendir: %{public}s", strerror(errno)); + ret = false; + break; } + dirStack1.push(subDir); } + } } - closedir(dir); - string currentPath = ExcludeTrailingPathDelimiter(path); - if (access(currentPath.c_str(), F_OK) == 0) { - if (!ChangeMode(currentPath, mode)) { - UTILS_LOGD("Failed to exec ChangeMode"); + while (!dirStack2.empty()) { + DirectoryNdoe node = dirStack2.top(); + dirStack2.pop(); + if (fchmodat(node.directoryFd, node.name, mode, 0) < 0){ + UTILS_LOGD("Failed to exec fchmodat"); + return false; + } + close(node.directoryFd); + closedir(node.dir); + } + if (access(path.c_str(), F_OK) == 0) { + if (fchmodat(AT_FDCWD, path.c_str(), mode, 0) < 0) { + UTILS_LOGD("Failed to change mode root dir: %{public}s: %{public}s ", path.c_str(), strerror(errno)); return false; } }