aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/cpp/util/errors.cc9
-rw-r--r--src/main/cpp/util/errors.h1
-rw-r--r--src/main/cpp/util/file_platform.h20
-rw-r--r--src/main/cpp/util/file_posix.cc5
-rw-r--r--src/main/cpp/util/file_windows.cc89
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java6
6 files changed, 122 insertions, 8 deletions
diff --git a/src/main/cpp/util/errors.cc b/src/main/cpp/util/errors.cc
index 49248a15fc..8497545e0b 100644
--- a/src/main/cpp/util/errors.cc
+++ b/src/main/cpp/util/errors.cc
@@ -41,4 +41,13 @@ void pdie(const int exit_status, const char *format, ...) {
exit(exit_status);
}
+void PrintError(const char *format, ...) {
+ fprintf(stderr, "Error: ");
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ fprintf(stderr, ": %s\n", strerror(errno));
+}
+
} // namespace blaze_util
diff --git a/src/main/cpp/util/errors.h b/src/main/cpp/util/errors.h
index 84de39d715..833a6ee473 100644
--- a/src/main/cpp/util/errors.h
+++ b/src/main/cpp/util/errors.h
@@ -28,6 +28,7 @@ void die(const int exit_status, const char *format, ...) ATTRIBUTE_NORETURN
// Prints "Error: <formatted-message>: <strerror(errno)>\n", and exits nonzero.
void pdie(const int exit_status, const char *format, ...) ATTRIBUTE_NORETURN
PRINTF_ATTRIBUTE(2, 3);
+void PrintError(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
} // namespace blaze_util
diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h
index e6df884ea0..15bfd5d737 100644
--- a/src/main/cpp/util/file_platform.h
+++ b/src/main/cpp/util/file_platform.h
@@ -120,6 +120,26 @@ class DirectoryEntryConsumer {
void ForEachDirectoryEntry(const std::string &path,
DirectoryEntryConsumer *consume);
+#if defined(COMPILER_MSVC) || defined(__CYGWIN__)
+// Converts a UTF8-encoded `path` to a widechar Windows path.
+//
+// Returns true if conversion succeeded and sets the contents of `result` to it.
+//
+// The `path` may be absolute or relative, and may be a Windows or MSYS path.
+// In every case, this method replaces forward slashes with backslashes if
+// necessary.
+//
+// Recognizes the drive letter in MSYS paths, so e.g. "/c/windows" becomes
+// "c:\windows". Prepends the MSYS root (computed from the BAZEL_SH envvar) to
+// absolute MSYS paths, so e.g. "/usr" becomes "c:\tools\msys64\usr".
+//
+// The result may be longer than MAX_PATH. It's the caller's responsibility to
+// prepend the long path prefix ("\\?\") in case they need to pass it to a
+// Windows API function (some require the prefix, some don't), or to quote the
+// path if necessary.
+bool AsWindowsPath(const std::string &path, std::wstring *result);
+#endif // defined(COMPILER_MSVC) || defined(__CYGWIN__)
+
} // namespace blaze_util
#endif // BAZEL_SRC_MAIN_CPP_UTIL_FILE_PLATFORM_H_
diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc
index b256a68eef..81e9bd65c3 100644
--- a/src/main/cpp/util/file_posix.cc
+++ b/src/main/cpp/util/file_posix.cc
@@ -278,11 +278,8 @@ bool IsRootDirectory(const string &path) {
}
bool IsAbsolute(const string &path) { return !path.empty() && path[0] == '/'; }
-#endif // not __CYGWIN__
void SyncFile(const string& path) {
-// fsync always fails on Cygwin with "Permission denied" for some reason.
-#ifndef __CYGWIN__
const char* file_path = path.c_str();
int fd = open(file_path, O_RDONLY);
if (fd < 0) {
@@ -294,8 +291,8 @@ void SyncFile(const string& path) {
file_path);
}
close(fd);
-#endif // not __CYGWIN__
}
+#endif // not __CYGWIN__
time_t GetMtimeMillisec(const string& path) {
struct stat buf;
diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc
index bf6e79cf1e..021e96d9a9 100644
--- a/src/main/cpp/util/file_windows.cc
+++ b/src/main/cpp/util/file_windows.cc
@@ -16,14 +16,19 @@
#include <ctype.h> // isalpha
#include <windows.h>
+#include <memory> // unique_ptr
+
#include "src/main/cpp/util/errors.h"
#include "src/main/cpp/util/exit_code.h"
#include "src/main/cpp/util/file.h"
+#include "src/main/cpp/util/strings.h"
namespace blaze_util {
using std::pair;
using std::string;
+using std::unique_ptr;
+using std::wstring;
class WindowsPipe : public IPipe {
public:
@@ -132,6 +137,86 @@ pair<string, string> SplitPath(const string& path) {
return std::make_pair("", path);
}
+class MsysRoot {
+ public:
+ MsysRoot() : data_(Get()) {}
+ bool IsValid() const { return data_.first; }
+ const string& GetPath() const { return data_.second; }
+
+ private:
+ const std::pair<bool, string> data_;
+ static std::pair<bool, string> Get();
+};
+
+std::pair<bool, string> MsysRoot::Get() {
+ string result;
+ char value[MAX_PATH];
+ DWORD len = GetEnvironmentVariableA("BAZEL_SH", value, MAX_PATH);
+ if (len > 0) {
+ result = value;
+ } else {
+ const char* value2 = getenv("BAZEL_SH");
+ if (value2 == nullptr || value2[0] == '\0') {
+ PrintError(
+ "BAZEL_SH environment variable is not defined, cannot convert MSYS "
+ "paths to Windows paths");
+ return std::make_pair(false, "");
+ }
+ result = value2;
+ }
+ // BAZEL_SH is usually "c:\tools\msys64\bin\bash.exe", we need to return
+ // "c:\tools\msys64".
+ return std::make_pair(true, std::move(Dirname(Dirname(result))));
+}
+
+bool AsWindowsPath(const string& path, wstring* result) {
+ if (path.empty()) {
+ result->clear();
+ return true;
+ }
+
+ string mutable_path = path;
+ if (path[0] == '/') {
+ // This is an absolute MSYS path.
+ if (path.size() == 2 || (path.size() > 2 && path[2] == '/')) {
+ // The path is either "/x" or "/x/" or "/x/something". In all three cases
+ // "x" is the drive letter.
+ // TODO(laszlocsomor): use GetLogicalDrives to retrieve the list of drives
+ // and only apply this heuristic for the valid drives. It's possible that
+ // the user has a directory "/a" but no "A:\" drive, so in that case we
+ // should prepend the MSYS root.
+ mutable_path = path.substr(1, 1) + ":\\";
+ if (path.size() > 2) {
+ mutable_path += path.substr(3);
+ }
+ } else {
+ // The path is a normal MSYS path e.g. "/usr". Prefix it with the MSYS
+ // root.
+ // Define kMsysRoot only in this scope. This way we only initialize it
+ // and thus check for BAZEL_SH if we really need to, i.e. the caller
+ // passed an MSYS path and we have to convert it. If all paths ever passed
+ // are Windows paths, we don't need to check whether BAZEL_SH is defined.
+ static const MsysRoot kMsysRoot;
+ if (!kMsysRoot.IsValid()) {
+ return false;
+ }
+ mutable_path = JoinPath(kMsysRoot.GetPath(), path);
+ }
+ } // otherwise this is a relative path, or absolute Windows path.
+
+ unique_ptr<WCHAR[]> mutable_wpath(CstringToWstring(mutable_path.c_str()));
+ WCHAR* p = mutable_wpath.get();
+ // Replace forward slashes with backslashes.
+ while (*p != L'\0') {
+ if (*p == L'/') {
+ *p = L'\\';
+ }
+ ++p;
+ }
+ result->assign(mutable_wpath.get());
+ return true;
+}
+
#ifdef COMPILER_MSVC
bool ReadFile(const string& filename, string* content, int max_size) {
// TODO(bazel-team): implement this.
@@ -209,12 +294,10 @@ bool IsRootDirectory(const string& path) {
bool IsAbsolute(const string& path) { return IsRootOrAbsolute(path, false); }
-#ifdef COMPILER_MSVC
void SyncFile(const string& path) {
// No-op on Windows native; unsupported by Cygwin.
+ // fsync always fails on Cygwin with "Permission denied" for some reason.
}
-#else // not COMPILER_MSVC
-#endif // COMPILER_MSVC
#ifdef COMPILER_MSVC
time_t GetMtimeMillisec(const string& path) {
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java
index 6ac62c0ea0..9b8ba02ca9 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java
@@ -62,7 +62,11 @@ public class WindowsFileSystem extends JavaIoFileSystem {
//
// This heuristic ignores other mount points as well as procfs.
- // TODO(bazel-team): get rid of this heuristic and translate paths using /etc/mtab.
+ // TODO(laszlocsomor): use GetLogicalDrives to retrieve the list of drives and only apply
+ // this heuristic for the valid drives. It's possible that the user has a directory "/a"
+ // but no "A:\" drive, so in that case we should prepend the MSYS root.
+
+ // TODO(laszlocsomor): get rid of this heuristic and translate paths using /etc/mtab.
// Figure out how to handle non-top-level mount points (e.g. "/usr/bin" is mounted to
// "/bin"), which is problematic because Paths are created segment by segment, so
// individual Path objects don't know they are parts of a mount point path.