| // Copyright 2016 The Bazel Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #ifndef WIN32_LEAN_AND_MEAN |
| #define WIN32_LEAN_AND_MEAN |
| #endif |
| #include <windows.h> |
| |
| #include <algorithm> |
| #include <memory> |
| #include <string> |
| |
| #include "src/test/cpp/util/windows_test_util.h" |
| |
| #if !defined(_WIN32) && !defined(__CYGWIN__) |
| #error("This test should only be run on Windows") |
| #endif // !defined(_WIN32) && !defined(__CYGWIN__) |
| |
| namespace blaze_util { |
| |
| using std::unique_ptr; |
| using std::wstring; |
| |
| wstring GetTestTmpDirW() { |
| DWORD size = ::GetEnvironmentVariableW(L"TEST_TMPDIR", nullptr, 0); |
| unique_ptr<WCHAR[]> buf(new WCHAR[size]); |
| ::GetEnvironmentVariableW(L"TEST_TMPDIR", buf.get(), size); |
| wstring result(buf.get()); |
| std::replace(result.begin(), result.end(), '/', '\\'); |
| if (result.back() == '\\') { |
| result.pop_back(); |
| } |
| return result; |
| } |
| |
| bool DeleteAllUnder(wstring path) { |
| static const wstring kDot(L"."); |
| static const wstring kDotDot(L".."); |
| |
| // Prepend UNC prefix if the path doesn't have it already. Don't bother |
| // checking if the path is shorter than MAX_PATH, let's just do it |
| // unconditionally; this is a test after all, performance isn't paramount. |
| if (path.find(L"\\\\?\\") != 0) { |
| path = wstring(L"\\\\?\\") + path; |
| } |
| // Append "\" if necessary. |
| if (path.back() != '\\') { |
| path.push_back('\\'); |
| } |
| |
| WIN32_FIND_DATAW metadata; |
| HANDLE handle = FindFirstFileW((path + L"*").c_str(), &metadata); |
| if (handle == INVALID_HANDLE_VALUE) { |
| return true; // directory doesn't exist |
| } |
| |
| bool result = true; |
| do { |
| wstring childname = metadata.cFileName; |
| if (kDot != childname && kDotDot != childname) { |
| wstring childpath = path + childname; |
| if ((metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) { |
| // If this is not a junction, delete its contents recursively. |
| // Finally delete this directory/junction too. |
| if (((metadata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0 && |
| !DeleteAllUnder(childpath)) || |
| !::RemoveDirectoryW(childpath.c_str())) { |
| result = false; |
| break; |
| } |
| } else { |
| if (!::DeleteFileW(childpath.c_str())) { |
| result = false; |
| break; |
| } |
| } |
| } |
| } while (FindNextFileW(handle, &metadata)); |
| FindClose(handle); |
| return result; |
| } |
| |
| bool CreateDummyFile(const wstring& path, const std::string& content) { |
| return CreateDummyFile(path, content.c_str(), content.size()); |
| } |
| |
| bool CreateDummyFile(const std::wstring& path, const void* content, |
| const DWORD size) { |
| HANDLE handle = |
| ::CreateFileW(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, |
| CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| if (handle == INVALID_HANDLE_VALUE) { |
| return false; |
| } |
| bool result = true; |
| DWORD actually_written = 0; |
| if (!::WriteFile(handle, content, size, &actually_written, nullptr) && |
| actually_written != size) { |
| result = false; |
| } |
| CloseHandle(handle); |
| return result; |
| } |
| |
| } // namespace blaze_util |