From ab853e1fcf640ffa120afdb6f2b9dcc917b6b213 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 12 Apr 2020 13:38:57 -0700 Subject: [PATCH] Update dir traversal code --- native/jni/utils/file.cpp | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/native/jni/utils/file.cpp b/native/jni/utils/file.cpp index 138a4c581..e25189bb3 100644 --- a/native/jni/utils/file.cpp +++ b/native/jni/utils/file.cpp @@ -50,7 +50,7 @@ if (entry->d_name == "."sv || entry->d_name == ".."sv) \ continue;\ } -static void post_order_walk(int dirfd, const function &&fn) { +static void post_order_walk(int dirfd, const function &&fn) { auto dir = xopen_dir(dirfd); if (!dir) return; @@ -62,8 +62,21 @@ static void post_order_walk(int dirfd, const function &&fn) } } -static int remove_at(int dirfd, struct dirent *entry) { - return unlinkat(dirfd, entry->d_name, entry->d_type == DT_DIR ? AT_REMOVEDIR : 0); +static void pre_order_walk(int dirfd, const function &&fn) { + auto dir = xopen_dir(dirfd); + if (!dir) return; + + for (dirent *entry; (entry = xreaddir(dir.get()));) { + SKIP_DOTS + if (!fn(dirfd, entry)) + continue; + if (entry->d_type == DT_DIR) + pre_order_walk(xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC), std::move(fn)); + } +} + +static void remove_at(int dirfd, struct dirent *entry) { + unlinkat(dirfd, entry->d_name, entry->d_type == DT_DIR ? AT_REMOVEDIR : 0); } void rm_rf(const char *path) { @@ -361,17 +374,17 @@ void backup_folder(const char *dir, vector &files) { char path[4096]; xrealpath(dir, path); int len = strlen(path); - post_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> int { + pre_order_walk(xopen(dir, O_RDONLY), [&](int dfd, dirent *entry) -> bool { int fd = xopenat(dfd, entry->d_name, O_RDONLY); if (fd < 0) - return -1; + return false; run_finally f([&]{ close(fd); }); if (fd_path(fd, path, sizeof(path)) < 0) - return -1; + return false; raw_file file; file.path = path + len + 1; if (fgetattr(fd, &file.attr) < 0) - return -1; + return false; if (entry->d_type == DT_REG) { fd_full_read(fd, file.buf, file.sz); } else if (entry->d_type == DT_LNK) { @@ -381,14 +394,14 @@ void backup_folder(const char *dir, vector &files) { memcpy(file.buf, path, file.sz); } files.emplace_back(std::move(file)); - return 0; + return true; }); } void restore_folder(const char *dir, vector &files) { string base(dir); - // Reversed post-order means folders will always be first - for (raw_file &file : reversed(files)) { + // Pre-order means folders will always be first + for (raw_file &file : files) { string path = base + "/" + file.path; if (S_ISDIR(file.attr.st.st_mode)) { mkdirs(path.data(), 0);