Windows: Native launcher now works with unicode.

The native launcher can now launch Java and Bash binary in
directory with non-English characters.

Unfortunately, python doesn't support running python zip file under
directory with non-English characters. eg. python ./??/bin.zip will
still fail.

See https://github.com/bazelbuild/bazel/issues/4473

Change-Id: I77fe9cdaabffc2e0d25c7097da5c0c9333a9c4a3
PiperOrigin-RevId: 201939391
diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h
index d7538fd..76e94d1 100644
--- a/src/main/cpp/util/file_platform.h
+++ b/src/main/cpp/util/file_platform.h
@@ -19,6 +19,7 @@
 
 #include <cinttypes>
 #include <string>
+#include <vector>
 
 namespace blaze_util {
 
@@ -206,6 +207,38 @@
 
 #if defined(_WIN32) || defined(__CYGWIN__)
 std::wstring GetCwdW();
+bool MakeDirectoriesW(const std::wstring &path, unsigned int mode);
+
+// Interface to be implemented by ForEachDirectoryEntryW clients.
+class DirectoryEntryConsumerW {
+ public:
+  virtual ~DirectoryEntryConsumerW() {}
+
+  // This method is called for each entry in a directory.
+  // `name` is the full path of the entry.
+  // `is_directory` is true if this entry is a directory (but false if this is a
+  // symlink pointing to a directory).
+  virtual void Consume(const std::wstring &name, bool is_directory) = 0;
+};
+
+// Lists all files in `path` and all of its subdirectories.
+//
+// Does not follow symlinks / junctions.
+//
+// Populates `result` with the full paths of the files. Every entry will have
+// `path` as its prefix. If `path` is a file, `result` contains just this
+// file.
+void GetAllFilesUnderW(const std::wstring &path,
+                       std::vector<std::wstring> *result);
+
+// Visible for testing only.
+typedef void (*_ForEachDirectoryEntryW)(const std::wstring &path,
+                                        DirectoryEntryConsumerW *consume);
+
+// Visible for testing only.
+void _GetAllFilesUnderW(const std::wstring &path,
+                        std::vector<std::wstring> *result,
+                        _ForEachDirectoryEntryW walk_entries);
 #endif  // defined(_WIN32) || defined(__CYGWIN__)
 
 }  // namespace blaze_util
diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc
index d81ada1..d266f96 100644
--- a/src/main/cpp/util/file_windows.cc
+++ b/src/main/cpp/util/file_windows.cc
@@ -32,17 +32,16 @@
 
 namespace blaze_util {
 
-using std::basic_string;
-using std::pair;
-using std::string;
-using std::unique_ptr;
-using std::wstring;
 using bazel::windows::AutoHandle;
 using bazel::windows::GetLongPath;
 using bazel::windows::HasUncPrefix;
 using bazel::windows::OpenDirectory;
-
-
+using std::basic_string;
+using std::pair;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+using std::wstring;
 
 // Returns true if `path` refers to a directory or (non-dangling) junction.
 // `path` must be a normalized Windows path, with UNC prefix (and absolute) if
@@ -55,8 +54,6 @@
 // necessary.
 static bool UnlinkPathW(const wstring& path);
 
-static bool MakeDirectoriesW(const wstring& path);
-
 static bool CanReadFileW(const wstring& path);
 
 template <typename char_type>
@@ -806,7 +803,7 @@
   // fsync always fails on Cygwin with "Permission denied" for some reason.
 }
 
-static bool MakeDirectoriesW(const wstring& path) {
+bool MakeDirectoriesW(const wstring& path, unsigned int mode) {
   if (path.empty()) {
     return false;
   }
@@ -821,7 +818,7 @@
         << "MakeDirectoriesW(" << blaze_util::WstringToString(path)
         << ") could not find dirname: " << GetLastErrorString();
   }
-  return MakeDirectoriesW(parent) &&
+  return MakeDirectoriesW(parent, mode) &&
          ::CreateDirectoryW(path.c_str(), NULL) == TRUE;
 }
 
@@ -841,7 +838,7 @@
         << "): AsAbsoluteWindowsPath failed: " << error;
     return false;
   }
-  return MakeDirectoriesW(wpath);
+  return MakeDirectoriesW(wpath, mode);
 }
 
 std::wstring GetCwdW() {
@@ -872,6 +869,79 @@
   return ::SetCurrentDirectoryA(spath.c_str()) == TRUE;
 }
 
+class DirectoryTreeWalkerW : public DirectoryEntryConsumerW {
+ public:
+  DirectoryTreeWalkerW(vector<wstring>* files,
+                       _ForEachDirectoryEntryW walk_entries)
+      : _files(files), _walk_entries(walk_entries) {}
+
+  void Consume(const wstring& path, bool follow_directory) override {
+    if (follow_directory) {
+      Walk(path);
+    } else {
+      _files->push_back(path);
+    }
+  }
+
+  void Walk(const wstring& path) { _walk_entries(path, this); }
+
+ private:
+  vector<wstring>* _files;
+  _ForEachDirectoryEntryW _walk_entries;
+};
+
+void ForEachDirectoryEntryW(const wstring& path,
+                            DirectoryEntryConsumerW* consume) {
+  wstring wpath;
+  if (path.empty() || IsDevNull(path.c_str())) {
+    return;
+  }
+  string error;
+  if (!AsWindowsPath(path, &wpath, &error)) {
+    BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
+        << "ForEachDirectoryEntryW(" << path
+        << "): AsWindowsPath failed: " << GetLastErrorString();
+  }
+
+  static const wstring kUncPrefix(L"\\\\?\\");
+  static const wstring kDot(L".");
+  static const wstring kDotDot(L"..");
+  // Always add an UNC prefix to ensure we can work with long paths.
+  if (!HasUncPrefix(wpath.c_str())) {
+    wpath = kUncPrefix + wpath;
+  }
+  // Unconditionally add a trailing backslash. We know `wpath` has no trailing
+  // backslash because it comes from AsWindowsPath whose output is always
+  // normalized (see NormalizeWindowsPath).
+  wpath.append(L"\\");
+  WIN32_FIND_DATAW metadata;
+  HANDLE handle = ::FindFirstFileW((wpath + L"*").c_str(), &metadata);
+  if (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;
+      wstring name(/* omit prefix */ 4 + wname.c_str());
+      bool is_dir = (metadata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+      bool is_junc =
+          (metadata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0;
+      consume->Consume(name, is_dir && !is_junc);
+    }
+  } while (::FindNextFileW(handle, &metadata));
+  ::FindClose(handle);
+}
+
+void GetAllFilesUnderW(const wstring& path, vector<wstring>* result) {
+  _GetAllFilesUnderW(path, result, &ForEachDirectoryEntryW);
+}
+
+void _GetAllFilesUnderW(const wstring& path, vector<wstring>* result,
+                        _ForEachDirectoryEntryW walk_entries) {
+  DirectoryTreeWalkerW(result, walk_entries).Walk(path);
+}
+
 void ForEachDirectoryEntry(const string &path,
                            DirectoryEntryConsumer *consume) {
   wstring wpath;
diff --git a/src/main/cpp/util/path_platform.h b/src/main/cpp/util/path_platform.h
index e2efe09..b0fb88d 100644
--- a/src/main/cpp/util/path_platform.h
+++ b/src/main/cpp/util/path_platform.h
@@ -70,7 +70,12 @@
 // is that this would add more complexity to the implementation file(s)? of
 // path.h, which would have to have the platform-specific implementations.
 #if defined(_WIN32) || defined(__CYGWIN__)
+bool IsDevNull(const wchar_t *path);
+
+bool IsAbsolute(const std::wstring &path);
+
 const wchar_t *RemoveUncPrefixMaybe(const wchar_t *ptr);
+
 void AddUncPrefixMaybe(std::wstring *path);
 
 std::pair<std::wstring, std::wstring> SplitPathW(const std::wstring &path);
diff --git a/src/main/cpp/util/path_windows.cc b/src/main/cpp/util/path_windows.cc
index d115b6e..c7afe40 100644
--- a/src/main/cpp/util/path_windows.cc
+++ b/src/main/cpp/util/path_windows.cc
@@ -396,6 +396,10 @@
   return IsRootOrAbsolute(path, false);
 }
 
+bool IsAbsolute(const std::wstring& path) {
+  return IsRootOrAbsolute(path, false);
+}
+
 bool IsRootDirectoryW(const std::wstring& path) {
   return IsRootOrAbsolute(path, true);
 }
diff --git a/src/main/cpp/util/strings.cc b/src/main/cpp/util/strings.cc
index e98b5d2..649156a 100644
--- a/src/main/cpp/util/strings.cc
+++ b/src/main/cpp/util/strings.cc
@@ -308,4 +308,8 @@
   return UstringToVstring<char, wchar_t>(input, mbstowcs, "%s");
 }
 
+std::wstring CstringToWstring(const std::string &input) {
+  return wstring(CstringToWstring(input.c_str()).get());
+}
+
 }  // namespace blaze_util
diff --git a/src/main/cpp/util/strings.h b/src/main/cpp/util/strings.h
index 0a761e1..cd54181 100644
--- a/src/main/cpp/util/strings.h
+++ b/src/main/cpp/util/strings.h
@@ -115,6 +115,7 @@
 // Convert a char string to a wchar_t string. Useful when passing arguments to
 // widechar Windows API functions.
 std::unique_ptr<wchar_t[]> CstringToWstring(const char *input);
+std::wstring CstringToWstring(const std::string &input);
 
 }  // namespace blaze_util