From 2d7f7e55c05a92033a1a62fbb6163e2e32aa81c3 Mon Sep 17 00:00:00 2001 From: Jan Niklas Hasse Date: Mon, 7 Dec 2020 19:46:10 +0100 Subject: Delete read-only files on Windows, too Fixes main complaint of #1886. --- src/disk_interface.cc | 21 +++++++++++++++++++-- src/disk_interface_test.cc | 6 ++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/disk_interface.cc b/src/disk_interface.cc index 49af001..8d4cc7f 100644 --- a/src/disk_interface.cc +++ b/src/disk_interface.cc @@ -265,6 +265,23 @@ FileReader::Status RealDiskInterface::ReadFile(const string& path, } int RealDiskInterface::RemoveFile(const string& path) { +#ifdef _WIN32 + DWORD attributes = GetFileAttributes(path.c_str()); + if (attributes == INVALID_FILE_ATTRIBUTES && + GetLastError() == ERROR_FILE_NOT_FOUND) { + return 1; + } + if (attributes & FILE_ATTRIBUTE_READONLY) { + // On non-Windows systems remove will happily delete read-only files. On + // Windows Ninja should behave the same. See + // https://github.com/ninja-build/ninja/issues/1886 + SetFileAttributes(path.c_str(), attributes & ~FILE_ATTRIBUTE_READONLY); + } + if (!DeleteFile(path.c_str())) { + Error("remove(%s): %s", path.c_str(), GetLastErrorString().c_str()); + return -1; + } +#else if (remove(path.c_str()) < 0) { switch (errno) { case ENOENT: @@ -273,9 +290,9 @@ int RealDiskInterface::RemoveFile(const string& path) { Error("remove(%s): %s", path.c_str(), strerror(errno)); return -1; } - } else { - return 0; } +#endif + return 0; } void RealDiskInterface::AllowStatCache(bool allow) { diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc index 066c770..b424243 100644 --- a/src/disk_interface_test.cc +++ b/src/disk_interface_test.cc @@ -211,6 +211,12 @@ TEST_F(DiskInterfaceTest, RemoveFile) { EXPECT_EQ(0, disk_.RemoveFile(kFileName)); EXPECT_EQ(1, disk_.RemoveFile(kFileName)); EXPECT_EQ(1, disk_.RemoveFile("does not exist")); +#ifdef _WIN32 + ASSERT_TRUE(Touch(kFileName)); + EXPECT_EQ(0, system((std::string("attrib +R ") + kFileName).c_str())); + EXPECT_EQ(0, disk_.RemoveFile(kFileName)); + EXPECT_EQ(1, disk_.RemoveFile(kFileName)); +#endif } struct StatTest : public StateTestWithBuiltinRules, -- cgit v0.12