aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/test/cpp/util
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2017-01-05 10:14:09 +0000
committerGravatar John Cater <jcater@google.com>2017-01-05 15:17:37 +0000
commit2459be34c81b6ccac01e05c416b3912a072fb870 (patch)
treec4e9f8729d8b195ebb07ebae0e117a1c534e559a /src/test/cpp/util
parent823091f7516abf7d854021edc765daf1467f1647 (diff)
Bazel client: implement PathExists on Windows
Checking if a path exists is surprisingly hard on Windows. The most convenient API functions are PathFileExists and GetFileAttributes but neither of them follows junctions. To check if a junction is dangling, we have to resolve it all the way. This change adds a JunctionResolver class to file_windows, which can resolve junctions (if they aren't dangling) and non-junctions (in this case just checks their existence). See https://github.com/bazelbuild/bazel/issues/2107 See https://github.com/bazelbuild/bazel/issues/2181 -- PiperOrigin-RevId: 143645274 MOS_MIGRATED_REVID=143645274
Diffstat (limited to 'src/test/cpp/util')
-rw-r--r--src/test/cpp/util/file_windows_test.cc91
1 files changed, 84 insertions, 7 deletions
diff --git a/src/test/cpp/util/file_windows_test.cc b/src/test/cpp/util/file_windows_test.cc
index fe23a92b67..66c1af481f 100644
--- a/src/test/cpp/util/file_windows_test.cc
+++ b/src/test/cpp/util/file_windows_test.cc
@@ -11,8 +11,9 @@
// 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.
+#include <stdio.h>
#include <string.h>
-#include <windows.h> // SetEnvironmentVariableA
+#include <windows.h>
#include "src/main/cpp/util/file.h"
#include "src/main/cpp/util/file_platform.h"
@@ -24,7 +25,9 @@
namespace blaze_util {
-void ReinitMsysRootForTesting(); // defined in file_windows.cc
+using std::string;
+
+void ResetMsysRootForTesting(); // defined in file_windows.cc
TEST(FileTest, TestDirname) {
ASSERT_EQ("", Dirname(""));
@@ -98,7 +101,7 @@ TEST(FileTest, IsRootDirectory) {
TEST(FileTest, TestAsWindowsPath) {
SetEnvironmentVariableA("BAZEL_SH", "c:\\msys\\some\\long\\path\\bash.exe");
- ReinitMsysRootForTesting();
+ ResetMsysRootForTesting();
std::wstring actual;
ASSERT_TRUE(AsWindowsPath("", &actual));
@@ -141,21 +144,95 @@ TEST(FileTest, TestMsysRootRetrieval) {
std::wstring actual;
SetEnvironmentVariableA("BAZEL_SH", "c:/foo/msys/bar/qux.exe");
- ReinitMsysRootForTesting();
+ ResetMsysRootForTesting();
ASSERT_TRUE(AsWindowsPath("/blah", &actual));
ASSERT_EQ(std::wstring(L"c:\\foo\\msys\\blah"), actual);
SetEnvironmentVariableA("BAZEL_SH", "c:/foo/MSYS64/bar/qux.exe");
- ReinitMsysRootForTesting();
+ ResetMsysRootForTesting();
ASSERT_TRUE(AsWindowsPath("/blah", &actual));
ASSERT_EQ(std::wstring(L"c:\\foo\\msys64\\blah"), actual);
SetEnvironmentVariableA("BAZEL_SH", "c:/qux.exe");
- ReinitMsysRootForTesting();
+ ResetMsysRootForTesting();
ASSERT_FALSE(AsWindowsPath("/blah", &actual));
SetEnvironmentVariableA("BAZEL_SH", nullptr);
- ReinitMsysRootForTesting();
+ ResetMsysRootForTesting();
+}
+
+static void RunCommand(const string& cmdline) {
+ STARTUPINFOA startupInfo = {sizeof(STARTUPINFO)};
+ PROCESS_INFORMATION processInfo;
+ // command line maximum size is 32K
+ // Source (on 2017-01-04):
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
+ char mutable_cmdline[0x8000];
+ strncpy(mutable_cmdline, cmdline.c_str(), 0x8000);
+ BOOL ok = CreateProcessA(
+ /* lpApplicationName */ NULL,
+ /* lpCommandLine */ mutable_cmdline,
+ /* lpProcessAttributes */ NULL,
+ /* lpThreadAttributes */ NULL,
+ /* bInheritHandles */ TRUE,
+ /* dwCreationFlags */ 0,
+ /* lpEnvironment */ NULL,
+ /* lpCurrentDirectory */ NULL,
+ /* lpStartupInfo */ &startupInfo,
+ /* lpProcessInformation */ &processInfo);
+ ASSERT_TRUE(ok);
+
+ // Wait 1 second for the process to finish.
+ ASSERT_EQ(WAIT_OBJECT_0, WaitForSingleObject(processInfo.hProcess, 1000));
+
+ DWORD exit_code = 1;
+ ASSERT_TRUE(GetExitCodeProcess(processInfo.hProcess, &exit_code));
+ ASSERT_EQ(0, exit_code);
+}
+
+TEST(FileTest, TestPathExistsWindows) {
+ ASSERT_FALSE(PathExists(""));
+ ASSERT_TRUE(PathExists("."));
+ ASSERT_FALSE(PathExists("non.existent"));
+
+ char buf[MAX_PATH] = {0};
+ DWORD len = GetEnvironmentVariableA("TEST_TMPDIR", buf, MAX_PATH);
+ ASSERT_GT(len, 0);
+ string tmpdir(buf);
+ ASSERT_TRUE(PathExists(tmpdir));
+
+ // Create a fake msys root. We'll also use it as a junction target.
+ string fake_msys_root(tmpdir + "/fake_msys");
+ ASSERT_EQ(0, mkdir(fake_msys_root.c_str()));
+ ASSERT_TRUE(PathExists(fake_msys_root));
+
+ // Set the BAZEL_SH root so we can resolve MSYS paths.
+ SetEnvironmentVariableA("BAZEL_SH",
+ (fake_msys_root + "/fake_bash.exe").c_str());
+ ResetMsysRootForTesting();
+
+ // Assert existence check for MSYS paths.
+ ASSERT_FALSE(PathExists("/this/should/not/exist/mkay"));
+ ASSERT_TRUE(PathExists("/"));
+
+ // Create a junction pointing to an existing directory.
+ RunCommand(string("cmd.exe /C mklink /J \"") + tmpdir + "/junc1\" \"" +
+ fake_msys_root + "\" >NUL 2>NUL");
+ ASSERT_TRUE(PathExists(fake_msys_root));
+ ASSERT_TRUE(PathExists(JoinPath(tmpdir, "junc1")));
+
+ // Create a junction pointing to a non-existent directory.
+ RunCommand(string("cmd.exe /C mklink /J \"") + tmpdir + "/junc2\" \"" +
+ fake_msys_root + "/i.dont.exist\" >NUL 2>NUL");
+ ASSERT_FALSE(PathExists(JoinPath(fake_msys_root, "i.dont.exist")));
+ ASSERT_FALSE(PathExists(JoinPath(tmpdir, "junc2")));
+
+ // Clean up.
+ ASSERT_EQ(0, rmdir(JoinPath(tmpdir, "junc1").c_str()));
+ ASSERT_EQ(0, rmdir(JoinPath(tmpdir, "junc2").c_str()));
+ ASSERT_EQ(0, rmdir(fake_msys_root.c_str()));
+ ASSERT_FALSE(PathExists(JoinPath(tmpdir, "junc1")));
+ ASSERT_FALSE(PathExists(JoinPath(tmpdir, "junc2")));
}
} // namespace blaze_util