aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/cpp/util/file_posix.cc2
-rw-r--r--src/main/cpp/util/file_windows.cc26
-rw-r--r--src/test/cpp/util/file_windows_test.cc36
3 files changed, 57 insertions, 7 deletions
diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc
index f4890a0294..466bae499d 100644
--- a/src/main/cpp/util/file_posix.cc
+++ b/src/main/cpp/util/file_posix.cc
@@ -248,12 +248,12 @@ bool CanAccess(const string& path, bool read, bool write, bool exec) {
return access(path.c_str(), mode) == 0;
}
+#ifndef __CYGWIN__
bool IsDirectory(const string& path) {
struct stat buf;
return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode);
}
-#ifndef __CYGWIN__
bool IsRootDirectory(const string &path) {
return path.size() == 1 && path[0] == '/';
}
diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc
index 2b4a105f05..3a5b5ac8e4 100644
--- a/src/main/cpp/util/file_windows.cc
+++ b/src/main/cpp/util/file_windows.cc
@@ -38,6 +38,11 @@ using std::wstring;
// The result may have a UNC prefix.
static unique_ptr<WCHAR[]> GetCwdW();
+// 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
+// necessary.
+static bool IsDirectoryW(const wstring& path);
+
// Like `AsWindowsPath` but the result is absolute and has UNC prefix if needed.
static bool AsWindowsPathWithUncPrefix(const string& path, wstring* wpath);
@@ -551,14 +556,23 @@ bool CanAccess(const string& path, bool read, bool write, bool exec) {
#else // not COMPILER_MSVC
#endif // COMPILER_MSVC
-#ifdef COMPILER_MSVC
+static bool IsDirectoryW(const wstring& path) {
+ DWORD attrs = ::GetFileAttributesW(path.c_str());
+ return (attrs != INVALID_FILE_ATTRIBUTES) &&
+ (attrs & FILE_ATTRIBUTE_DIRECTORY) &&
+ JunctionResolver().Resolve(path.c_str(), nullptr);
+}
+
bool IsDirectory(const string& path) {
- // TODO(bazel-team): implement this.
- pdie(255, "blaze_util::IsDirectory is not implemented on Windows");
- return false;
+ if (path.empty()) {
+ return false;
+ }
+ wstring wpath;
+ if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+ return false;
+ }
+ return IsDirectoryW(wpath);
}
-#else // not COMPILER_MSVC
-#endif // COMPILER_MSVC
bool IsRootDirectory(const string& path) {
return IsRootOrAbsolute(path, true);
diff --git a/src/test/cpp/util/file_windows_test.cc b/src/test/cpp/util/file_windows_test.cc
index 1cf49d88c5..5c2f68ee27 100644
--- a/src/test/cpp/util/file_windows_test.cc
+++ b/src/test/cpp/util/file_windows_test.cc
@@ -290,4 +290,40 @@ TEST(FileTest, TestPathExistsWindows) {
ASSERT_FALSE(PathExists(JoinPath(tmpdir, "junc2")));
}
+TEST(FileTest, TestIsDirectory) {
+ ASSERT_FALSE(IsDirectory(""));
+
+ string tmpdir(GetTestTmpDir());
+ ASSERT_LT(0, tmpdir.size());
+ ASSERT_TRUE(IsDirectory(tmpdir));
+ ASSERT_TRUE(IsDirectory("C:\\"));
+ ASSERT_TRUE(IsDirectory("C:/"));
+ ASSERT_TRUE(IsDirectory("/c"));
+
+ ASSERT_FALSE(IsDirectory("non.existent"));
+ // Create a directory under `tempdir`, verify that IsDirectory reports true.
+ // Call it msys_dir1 so we can also use it as a mock msys root.
+ string dir1(JoinPath(tmpdir, "msys_dir1"));
+ ASSERT_EQ(0, mkdir(dir1.c_str()));
+ ASSERT_TRUE(IsDirectory(dir1));
+
+ // Use dir1 as the mock msys root, verify that IsDirectory works for a MSYS
+ // path.
+ SetEnvironmentVariableA("BAZEL_SH", JoinPath(dir1, "bash.exe").c_str());
+ ResetMsysRootForTesting();
+ ASSERT_TRUE(IsDirectory("/"));
+
+ // Verify that IsDirectory works for a junction.
+ string junc1(JoinPath(tmpdir, "junc1"));
+ RunCommand(string("cmd.exe /C mklink /J \"") + junc1 + "\" \"" + dir1 +
+ "\" >NUL 2>NUL");
+ ASSERT_TRUE(IsDirectory(junc1));
+
+ ASSERT_EQ(0, rmdir(dir1.c_str()));
+ ASSERT_FALSE(IsDirectory(dir1));
+ ASSERT_FALSE(IsDirectory(junc1));
+
+ ASSERT_EQ(0, rmdir(junc1.c_str()));
+}
+
} // namespace blaze_util