diff options
author | laszlocsomor <laszlocsomor@google.com> | 2018-07-06 02:16:34 -0700 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-07-06 02:17:54 -0700 |
commit | b57ba275c0d67482f8bedc2888c34215721ee50e (patch) | |
tree | 30e6132db8dcb3603730f27cbab13c8e319b38dc /src/test/native | |
parent | bc52a18a16d378193fd18a76fb58cc5e50414e37 (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.cc | 127 |
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 |