aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/native
diff options
context:
space:
mode:
authorGravatar laszlocsomor <laszlocsomor@google.com>2018-07-06 02:16:34 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-07-06 02:17:54 -0700
commitb57ba275c0d67482f8bedc2888c34215721ee50e (patch)
tree30e6132db8dcb3603730f27cbab13c8e319b38dc /src/test/native
parentbc52a18a16d378193fd18a76fb58cc5e50414e37 (diff)
Windows,JNI: implement native DeletePath method
Implement a native DeletePath method that can delete files, directories, and junctions. The method should tolerate when concurrent processes delete the file. The new JNI function is more robust than Java IO file deletion function because it can also delete readonly files. See https://github.com/bazelbuild/bazel/issues/5513 Closes #5520. Change-Id: I21ea36dd64960b294e2b51600273bf4290ad7c0f PiperOrigin-RevId: 203448581
Diffstat (limited to 'src/test/native')
-rw-r--r--src/test/native/windows/file_test.cc127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/test/native/windows/file_test.cc b/src/test/native/windows/file_test.cc
index 9c4e23388c..cfbb5d2f4a 100644
--- a/src/test/native/windows/file_test.cc
+++ b/src/test/native/windows/file_test.cc
@@ -30,6 +30,11 @@
namespace bazel {
namespace windows {
+#define TOSTRING(x) #x
+#define TOWSTRING1(x) L##x
+#define TOWSTRING(x) TOWSTRING1(x)
+#define WLINE TOWSTRING(TOSTRING(__LINE__))
+
using blaze_util::DeleteAllUnder;
using blaze_util::GetTestTmpDirW;
using std::unique_ptr;
@@ -108,5 +113,127 @@ TEST_F(WindowsFileOperationsTest, TestCreateJunction) {
::GetFileAttributesW((name + L"4\\bar").c_str()));
}
+TEST_F(WindowsFileOperationsTest, TestCanDeleteExistingFile) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring path = tmp + L"\\file" WLINE;
+ EXPECT_TRUE(blaze_util::CreateDummyFile(path));
+ ASSERT_EQ(DeletePath(path.c_str(), nullptr), DELETE_PATH_SUCCESS);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCanDeleteExistingDirectory) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring path = tmp + L"\\dir" WLINE;
+ EXPECT_TRUE(CreateDirectoryW(path.c_str(), NULL));
+ ASSERT_EQ(DeletePath(path.c_str(), nullptr), DELETE_PATH_SUCCESS);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCanDeleteExistingJunction) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring name = tmp + L"\\junc" WLINE;
+ wstring target = tmp + L"\\target" WLINE;
+ EXPECT_TRUE(CreateDirectoryW(target.c_str(), NULL));
+ EXPECT_EQ(L"", CreateJunction(name, target));
+ ASSERT_EQ(DeletePath(name.c_str(), nullptr), DELETE_PATH_SUCCESS);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCanDeleteExistingJunctionWithoutTarget) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring name = tmp + L"\\junc" WLINE;
+ wstring target = tmp + L"\\target" WLINE;
+ EXPECT_TRUE(CreateDirectoryW(target.c_str(), NULL));
+ EXPECT_EQ(L"", CreateJunction(name, target));
+ EXPECT_TRUE(RemoveDirectoryW(target.c_str()));
+ // The junction still exists, its target does not.
+ EXPECT_NE(GetFileAttributesW(name.c_str()), INVALID_FILE_ATTRIBUTES);
+ EXPECT_EQ(GetFileAttributesW(target.c_str()), INVALID_FILE_ATTRIBUTES);
+ // We can delete the dangling junction.
+ ASSERT_EQ(DeletePath(name.c_str(), nullptr), DELETE_PATH_SUCCESS);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCannotDeleteNonExistentPath) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring path = tmp + L"\\dummy" WLINE;
+ EXPECT_EQ(GetFileAttributesW(path.c_str()), INVALID_FILE_ATTRIBUTES);
+ ASSERT_EQ(DeletePath(path.c_str(), nullptr), DELETE_PATH_DOES_NOT_EXIST);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCannotDeletePathWhereParentIsFile) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring parent = tmp + L"\\file" WLINE;
+ wstring child = parent + L"\\file" WLINE;
+ EXPECT_TRUE(blaze_util::CreateDummyFile(parent));
+ ASSERT_EQ(DeletePath(child.c_str(), nullptr), DELETE_PATH_DOES_NOT_EXIST);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCannotDeleteNonEmptyDirectory) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring parent = tmp + L"\\dir" WLINE;
+ wstring child = parent + L"\\file" WLINE;
+ EXPECT_TRUE(CreateDirectoryW(parent.c_str(), NULL));
+ EXPECT_TRUE(blaze_util::CreateDummyFile(child));
+ ASSERT_EQ(DeletePath(parent.c_str(), nullptr),
+ DELETE_PATH_DIRECTORY_NOT_EMPTY);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCannotDeleteBusyFile) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring path = tmp + L"\\file" WLINE;
+ EXPECT_TRUE(blaze_util::CreateDummyFile(path));
+ HANDLE h = CreateFileW(path.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ EXPECT_NE(h, INVALID_HANDLE_VALUE);
+ int actual = DeletePath(path.c_str(), nullptr);
+ CloseHandle(h);
+ ASSERT_EQ(actual, DELETE_PATH_ACCESS_DENIED);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCannotDeleteBusyDirectory) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring path = tmp + L"\\dir" WLINE;
+ EXPECT_TRUE(CreateDirectoryW(path.c_str(), NULL));
+ HANDLE h = CreateFileW(path.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ EXPECT_NE(h, INVALID_HANDLE_VALUE);
+ int actual = DeletePath(path.c_str(), nullptr);
+ CloseHandle(h);
+ ASSERT_EQ(actual, DELETE_PATH_ACCESS_DENIED);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCannotDeleteBusyJunction) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring name = tmp + L"\\junc" WLINE;
+ wstring target = tmp + L"\\target" WLINE;
+ EXPECT_TRUE(CreateDirectoryW(target.c_str(), NULL));
+ EXPECT_EQ(L"", CreateJunction(name, target));
+ // Open the junction itself (do not follow symlinks).
+ HANDLE h = CreateFileW(
+ name.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
+ EXPECT_NE(h, INVALID_HANDLE_VALUE);
+ int actual = DeletePath(name.c_str(), nullptr);
+ CloseHandle(h);
+ ASSERT_EQ(actual, DELETE_PATH_ACCESS_DENIED);
+}
+
+TEST_F(WindowsFileOperationsTest, TestCanDeleteJunctionWhoseTargetIsBusy) {
+ wstring tmp(kUncPrefix + GetTestTmpDirW());
+ wstring name = tmp + L"\\junc" WLINE;
+ wstring target = tmp + L"\\target" WLINE;
+ EXPECT_TRUE(CreateDirectoryW(target.c_str(), NULL));
+ EXPECT_EQ(L"", CreateJunction(name, target));
+ // Open the junction's target (follow symlinks).
+ HANDLE h = CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ EXPECT_NE(h, INVALID_HANDLE_VALUE);
+ int actual = DeletePath(name.c_str(), nullptr);
+ CloseHandle(h);
+ ASSERT_EQ(actual, DELETE_PATH_SUCCESS);
+}
+
+#undef TOSTRING
+#undef TOWSTRING1
+#undef TOWSTRING
+#undef WLINE
+
} // namespace windows
} // namespace bazel