Windows: Remove read-only attribute for directory before deleting
If some directory is set to read-only on Windows, DeletePath will fail
to delete that directory even when no one else is using it.
Previously, we only remove the read-only attribute for files before
deleting, we should also do the same for deleting directory.
Fixes https://github.com/bazelbuild/continuous-integration/issues/1012
Closes #11982.
PiperOrigin-RevId: 327774854
diff --git a/src/main/native/windows/file.cc b/src/main/native/windows/file.cc
index 78f63e0..3d55833 100644
--- a/src/main/native/windows/file.cc
+++ b/src/main/native/windows/file.cc
@@ -629,6 +629,15 @@
GetLastError(), error);
}
+ if (attr & FILE_ATTRIBUTE_READONLY) {
+ // Remove the read-only attribute.
+ attr &= ~FILE_ATTRIBUTE_READONLY;
+ if (!SetFileAttributesW(wpath, attr)) {
+ return GetResultFromErrorCode(L"SetFileAttributesW", path, GetLastError(),
+ error);
+ }
+ }
+
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
// It's a directory or a junction, RemoveDirectoryW should be used.
//
@@ -700,14 +709,6 @@
}
} else {
// It's a regular file or symlink, DeleteFileW should be used.
- if (attr & FILE_ATTRIBUTE_READONLY) {
- // Remove the read-only attribute.
- attr &= ~FILE_ATTRIBUTE_READONLY;
- if (!SetFileAttributesW(wpath, attr)) {
- return GetResultFromErrorCode(L"SetFileAttributesW", path,
- GetLastError(), error);
- }
- }
if (!DeleteFileW(wpath)) {
// Failed to delete the file or symlink.
return GetResultFromErrorCode(L"DeleteFileW", path,
diff --git a/src/test/py/bazel/bazel_windows_test.py b/src/test/py/bazel/bazel_windows_test.py
index e87c6d5..7390fc3 100644
--- a/src/test/py/bazel/bazel_windows_test.py
+++ b/src/test/py/bazel/bazel_windows_test.py
@@ -267,6 +267,28 @@
)
self.AssertExitCode(exit_code, 0, stderr)
+ def testDeleteReadOnlyFileAndDirectory(self):
+ self.CreateWorkspaceWithDefaultRepos('WORKSPACE')
+ self.ScratchFile('BUILD', [
+ 'genrule(',
+ ' name = "gen_read_only_dir",',
+ ' cmd_bat = "mkdir $@ && attrib +r $@",',
+ ' outs = ["dir_foo"],',
+ ')',
+ '',
+ 'genrule(',
+ ' name = "gen_read_only_file",',
+ ' cmd_bat = "echo hello > $@ && attrib +r $@",',
+ ' outs = ["file_foo"],',
+ ')',
+ ])
+
+ exit_code, _, stderr = self.RunBazel(['build', '//...'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
+ exit_code, _, stderr = self.RunBazel(['clean'])
+ self.AssertExitCode(exit_code, 0, stderr)
+
if __name__ == '__main__':
unittest.main()