diff --git a/modules/util/fs.cpp b/modules/util/fs.cpp index e1f99790ba68fabafa607cef47feae513a0aaaba..8e99969d35e273db7d388afc3e293a76c45312ee 100644 --- a/modules/util/fs.cpp +++ b/modules/util/fs.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -254,11 +255,63 @@ bool MakeDirectory(const std::string &origin_dir_path, bool allow_log_print) return true; } -bool RemoveDirectory(const std::string &dir) +bool RemoveDirectory(const std::string &dir, bool is_remove_file_only) { - LogUndo(); - (void)dir; - return false; + DIR *dp = ::opendir(dir.c_str()); + if (dp == nullptr) { + // 无法打开目录,直接结束 + if (errno == ENOENT) { + LogWarn("directory %s does not exist", dir.c_str()); + } else { + LogWarn("open directory %s fail, errno:%d, %s", dir.c_str(), errno, strerror(errno)); + } + return false; + } + + SetScopeExitAction([dp] { closedir(dp); }); + + bool is_all_removed = true; + struct dirent *entry = nullptr; + + while ((entry = readdir(dp)) != nullptr) { + std::string entry_name = entry->d_name; + if (entry_name == "." || entry_name == "..") { + // 目录系统的 . 和 .. 内容,直接略过 + continue; + } + + // 依次查看每一个文件或者目录的属性 + std::string full_path = dir + '/' + entry_name; + struct stat statbuf; + if (::stat(full_path.c_str(), &statbuf) == 0) { + if (S_ISDIR(statbuf.st_mode)) { + // 属性为目录,递归删除目录的内容 + if (!RemoveDirectory(full_path, is_remove_file_only)) { + is_all_removed = false; + } + } else { + // 属性为文件,直接删除文件 + if (::remove(full_path.c_str())) { + LogWarn("removing file %s fail, errno:%d, %s", full_path.c_str(), errno, strerror(errno)); + is_all_removed = false; + } + } + } else { + // 无法获取属性,直接结束 + LogWarn("getting state of %s fail, errno:%d, %s", full_path.c_str(), errno, strerror(errno)); + is_all_removed = false; + } + } + + if (!is_remove_file_only) { + // 最后删除目录 + if (::rmdir(dir.c_str())) { + LogWarn("removing directory %s fail, errno:%d, %s", dir.c_str(), errno, strerror(errno)); + is_all_removed = false; + } + } + + return is_all_removed; } std::string Basename(const std::string &full_path) diff --git a/modules/util/fs.h b/modules/util/fs.h index 554d819662b2560977d3efcb262ea4e49826b135..c03099131d105c8bf45e7e84259945f22103b221 100644 --- a/modules/util/fs.h +++ b/modules/util/fs.h @@ -195,14 +195,16 @@ bool IsDirectoryExist(const std::string &dir); bool MakeDirectory(const std::string &dir, bool allow_log_print = true); /** - * 删除目录 + * 递归删除指定目录 + * 等价于shell命令:"rm -rf xxx" * - * \param dir 目录 + * \param dir 需要删除的目录路径,路径需要全路径,如 /data/test + * \param is_remove_file_only 保存目录结构,仅删除文件 * - * \return true 目录删除成功 - * \return false 目录删除失败 - */ -bool RemoveDirectory(const std::string &dir); + * \return true 目录被完全删除 + * \return false 目录未被完全删除 +*/ +bool RemoveDirectory(const std::string &dir, bool is_remove_file_only = false); //////////////////////////////////////////////////////////////////// // 其它 diff --git a/modules/util/fs_test.cpp b/modules/util/fs_test.cpp index a4fa18bb6722ba4d204370a8d706a7513d38c52e..0ab8c4a2a6ee1dbe4d475c1946a029c9bad62caf 100644 --- a/modules/util/fs_test.cpp +++ b/modules/util/fs_test.cpp @@ -167,6 +167,7 @@ TEST(fs, MakeDirectory) { EXPECT_TRUE(MakeDirectory("a/b/c")); EXPECT_TRUE(IsFileExist("a/b/c")); ret = system("rm -rf a b"); + (void)ret; } @@ -189,3 +190,67 @@ TEST(fs, Basename) { EXPECT_EQ(Basename(""), ""); } + +TEST(fs, RemoveDirectory) { + //! 绝对路径测试 + int ret = 0; + ret = ::system("rm -rf /tmp/fs_test_dir"); + ret = ::system("mkdir -p /tmp/fs_test_dir/first_dir"); + (void)ret; + + WriteStringToTextFile("/tmp/fs_test_dir/fs_test_0_1.txt", "hello, this is a test file"); + WriteStringToTextFile("/tmp/fs_test_dir/fs_test_0_2.txt", "hello, this is a test file"); + WriteStringToTextFile("/tmp/fs_test_dir/first_dir/fs_test_1_1.txt", "hello, this is a test file"); + WriteStringToTextFile("/tmp/fs_test_dir/first_dir/fs_test_1_2.txt", "hello, this is a test file"); + + EXPECT_TRUE(RemoveDirectory("/tmp/fs_test_dir", true)); //! 仅删文件,不删目录 + EXPECT_TRUE(IsDirectoryExist("/tmp/fs_test_dir/first_dir/")); + + EXPECT_TRUE(RemoveDirectory("/tmp/fs_test_dir", false)); //! 全部删除 + EXPECT_FALSE(IsDirectoryExist("/tmp/fs_test_dir")); + + //! 相对路径测试,一层目录 + MakeDirectory("./a"); + WriteStringToTextFile("./a/fs_test_a_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/fs_test_a_2.txt", "hello, this is a test file"); + EXPECT_TRUE(RemoveDirectory("./a")); + EXPECT_FALSE(IsDirectoryExist("./a")); + + //! 相对路径测试,多层目录 + MakeDirectory("./a/b/c"); + WriteStringToTextFile("./a/fs_test_a_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/fs_test_a_2.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/fs_test_b_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/fs_test_b_2.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/c/fs_test_c_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/c/fs_test_c_2.txt", "hello, this is a test file"); + EXPECT_TRUE(RemoveDirectory("./a")); + EXPECT_FALSE(IsDirectoryExist("./a")); + + //! 重复的'/' 测试 + MakeDirectory("./a/b"); + WriteStringToTextFile("./a/fs_test_a_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/fs_test_a_2.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/fs_test_b_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/fs_test_b_2.txt", "hello, this is a test file"); + EXPECT_TRUE(RemoveDirectory("./a//b")); + EXPECT_FALSE(IsDirectoryExist("./a/b")); + EXPECT_TRUE(RemoveDirectory("./a/")); + EXPECT_FALSE(IsDirectoryExist("./a")); + + //! 目录尾部多加一个 '/' 测试 + MakeDirectory("./a/b"); + WriteStringToTextFile("./a/fs_test_a_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/fs_test_a_2.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/fs_test_b_1.txt", "hello, this is a test file"); + WriteStringToTextFile("./a/b/fs_test_b_2.txt", "hello, this is a test file"); + EXPECT_TRUE(RemoveDirectory("./a/")); + EXPECT_FALSE(IsDirectoryExist("./a")); + + // 只有目录,没有文件的删除测试 + MakeDirectory("./a/b1/c"); + MakeDirectory("./a/b2/c"); + MakeDirectory("./a/b3/c"); + EXPECT_TRUE(RemoveDirectory("./a")); + EXPECT_FALSE(IsDirectoryExist("./a")); +} diff --git a/version.mk b/version.mk index 3ad48fbe9c4e6af335f53138d8a52510f774f840..59d90f4c764be3f8c97ed7fd3c71f1ce1a975948 100644 --- a/version.mk +++ b/version.mk @@ -1,4 +1,4 @@ # TBOX版本号 TBOX_VERSION_MAJOR := 1 TBOX_VERSION_MINOR := 8 -TBOX_VERSION_REVISION := 2 +TBOX_VERSION_REVISION := 3