From 03e02f71013eb957f0c6c09db5982106558fdeb2 Mon Sep 17 00:00:00 2001 From: huangyuchen Date: Sun, 25 Jun 2023 16:49:20 +0800 Subject: [PATCH] Fix failing to remove a dangling symlink file in `ForceRemoveDirectory`. 1. Replace `access` to `faccessat` 2. Add related test cases. Issue:I7FUB2 Test:UT Signed-off-by: huangyuchen Change-Id: I8409f783ed9eb88a06517c26f7120989278c70b3 --- base/src/directory_ex.cpp | 9 +-- .../unittest/common/utils_directory_test.cpp | 72 ++++++++++++++++++- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/base/src/directory_ex.cpp b/base/src/directory_ex.cpp index dd8e6f7..9e79b9b 100644 --- a/base/src/directory_ex.cpp +++ b/base/src/directory_ex.cpp @@ -15,7 +15,8 @@ #include "directory_ex.h" #include -#include +#include +#include #include "securec.h" #include "unistd.h" #include "utils_log.h" @@ -217,7 +218,7 @@ bool ForceRemoveDirectory(const string& path) if (ptr->d_type == DT_DIR) { ret = ForceRemoveDirectory(subPath); } else { - if (access(subPath.c_str(), F_OK) == 0) { + if (faccessat(AT_FDCWD, subPath.c_str(), F_OK, AT_SYMLINK_NOFOLLOW) == 0) { if (remove(subPath.c_str()) != 0) { closedir(dir); return false; @@ -228,13 +229,13 @@ bool ForceRemoveDirectory(const string& path) closedir(dir); string currentPath = ExcludeTrailingPathDelimiter(path); - if (access(currentPath.c_str(), F_OK) == 0) { + if (faccessat(AT_FDCWD, currentPath.c_str(), F_OK, AT_SYMLINK_NOFOLLOW) == 0) { if (remove(currentPath.c_str()) != 0) { return false; } } - return ret && (access(path.c_str(), F_OK) != 0); + return ret && (faccessat(AT_FDCWD, path.c_str(), F_OK, AT_SYMLINK_NOFOLLOW) != 0); } bool RemoveFile(const string& fileName) diff --git a/base/test/unittest/common/utils_directory_test.cpp b/base/test/unittest/common/utils_directory_test.cpp index d8d0f95..3ac7148 100644 --- a/base/test/unittest/common/utils_directory_test.cpp +++ b/base/test/unittest/common/utils_directory_test.cpp @@ -12,11 +12,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include + #include "directory_ex.h" +#include +#include #include #include #include + using namespace testing::ext; using namespace std; @@ -212,6 +215,73 @@ HWTEST_F(UtilsDirectoryTest, testRemoveFile001, TestSize.Level0) EXPECT_EQ(ret, true); } +/* + * @tc.name: testRemoveFile002 + * @tc.desc: Remove soft link file. + */ +HWTEST_F(UtilsDirectoryTest, testRemoveFile002, TestSize.Level0) +{ + string dirpath = "/data/test_dir"; + bool ret = ForceCreateDirectory(dirpath); + EXPECT_EQ(ret, true); + + string targetname = "/data/test_target.txt"; + FILE *fp = fopen(targetname.c_str(), "w"); + if (NULL != fp) { + fclose(fp); + } + + // symlink to a directory + string linkpath = "/data/test_symlink_dir"; + int res = symlink(dirpath.c_str(), linkpath.c_str()); + EXPECT_EQ(res, 0); + + ret = ForceRemoveDirectory(linkpath); + EXPECT_EQ(ret, true); + + // Target dir is not removed. + ret = faccessat(AT_FDCWD, dirpath.c_str(), F_OK, AT_SYMLINK_NOFOLLOW); + EXPECT_EQ(ret, 0); + + // symlink to a file + string filename = dirpath + "/test.txt"; + res = symlink(targetname.c_str(), filename.c_str()); + EXPECT_EQ(res, 0); + + ret = ForceRemoveDirectory(dirpath); + EXPECT_EQ(ret, true); + + // Target file is not removed. + ret = faccessat(AT_FDCWD, targetname.c_str(), F_OK, AT_SYMLINK_NOFOLLOW); + EXPECT_EQ(ret, 0); + + ret = RemoveFile(targetname); + EXPECT_EQ(ret, true); +} + +/* + * @tc.name: testRemoveFile003 + * @tc.desc: Remove dangling soft link file. + */ +HWTEST_F(UtilsDirectoryTest, testRemoveFile003, TestSize.Level0) +{ + string dirpath = "/data/test_dir"; + bool ret = ForceCreateDirectory(dirpath); + EXPECT_EQ(ret, true); + + // symlink to a file + string targetname = "/data/nonexisted.txt"; + string filename = dirpath + "/test.txt"; + int res = symlink(targetname.c_str(), filename.c_str()); + EXPECT_EQ(res, 0); + + ret = ForceRemoveDirectory(dirpath); + EXPECT_EQ(ret, true); + + ret = RemoveFile(targetname); + EXPECT_EQ(ret, true); +} + /* * @tc.name: testGetFolderSize001 * @tc.desc: directory unit test -- Gitee