From d5527469ca629f806a7576783289cc0613bf418b Mon Sep 17 00:00:00 2001 From: Laszlo Csomor Date: Fri, 20 Jan 2017 10:05:18 +0000 Subject: Bazel client, Windows: impl. ForEachDirectoryEntry Implement ForEachDirectoryEntry on Windows using FindFirstFileW / FindNextFileW. Supports long paths and traversing junctions. See https://github.com/bazelbuild/bazel/issues/2107 See https://github.com/bazelbuild/bazel/issues/2181 -- PiperOrigin-RevId: 145062749 MOS_MIGRATED_REVID=145062749 --- src/main/cpp/util/file_posix.cc | 2 +- src/main/cpp/util/file_windows.cc | 33 ++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) (limited to 'src/main/cpp/util') diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc index a1d806a9d9..c45eb3915c 100644 --- a/src/main/cpp/util/file_posix.cc +++ b/src/main/cpp/util/file_posix.cc @@ -364,7 +364,6 @@ string GetCwd() { bool ChangeDirectory(const string& path) { return chdir(path.c_str()) == 0; } -#endif // not __CYGWIN__ void ForEachDirectoryEntry(const string &path, DirectoryEntryConsumer *consume) { @@ -398,5 +397,6 @@ void ForEachDirectoryEntry(const string &path, closedir(dir); } +#endif // not __CYGWIN__ } // namespace blaze_util diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc index b1fadddf4a..bea092d9ff 100644 --- a/src/main/cpp/util/file_windows.cc +++ b/src/main/cpp/util/file_windows.cc @@ -993,14 +993,37 @@ bool ChangeDirectory(const string& path) { return true; } -#ifdef COMPILER_MSVC void ForEachDirectoryEntry(const string &path, DirectoryEntryConsumer *consume) { - // TODO(bazel-team): implement this. - pdie(255, "blaze_util::ForEachDirectoryEntry is not implemented on Windows"); + wstring wpath; + if (path.empty() || IsDevNull(path)) { + return; + } + if (!AsWindowsPath(path, &wpath)) { + pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, + "ForEachDirectoryEntry(%s): AsWindowsPath failed", path.c_str()); + } + + static const wstring kDot(L"."); + static const wstring kDotDot(L".."); + + wpath = L"\\\\?\\" + wpath + L"\\"; + WIN32_FIND_DATAW metadata; + windows_util::AutoHandle handle( + FindFirstFileW((wpath + L"*").c_str(), &metadata)); + if (handle.handle == INVALID_HANDLE_VALUE) { + return; // directory does not exist or is empty + } + + do { + if (kDot != metadata.cFileName && kDotDot != metadata.cFileName) { + wstring wname = wpath + metadata.cFileName; + string name(WstringToCstring(/* omit prefix */ 4 + wname.c_str()).get()); + bool is_dir = (metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + consume->Consume(name, is_dir); + } + } while (FindNextFileW(handle.handle, &metadata)); } -#else // not COMPILER_MSVC -#endif // COMPILER_MSVC string NormalizeWindowsPath(string path) { if (path.empty()) { -- cgit v1.2.3