Windows: clean up error reporting

In this commit:
- remove blaze::PrintError in favor of
  blaze_util::PrintError
- remove Ijar's PrintLastErrorMessage in favor of
  blaze_util::PrintError
- use pdie every time path conversion fails,
  because that indicates a fatal error (bad user
  input for a path flag, or downright bug)
- remove explicitly printing GetLastErrror; pdie
  and PrintError do it already
- unify the pdie/PrintError message formats

Fixes https://github.com/bazelbuild/bazel/issues/2935

Change-Id: I5feaf73885cab95c43a28c529ada6942e037b162
PiperOrigin-RevId: 162587490
diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc
index df672e4..1598152 100644
--- a/src/main/cpp/blaze_util_windows.cc
+++ b/src/main/cpp/blaze_util_windows.cc
@@ -260,29 +260,6 @@
   }
 }
 
-static void PrintError(const string& op) {
-    DWORD last_error = ::GetLastError();
-    if (last_error == 0) {
-        return;
-    }
-
-    char* message_buffer;
-    size_t size = FormatMessageA(
-        FORMAT_MESSAGE_ALLOCATE_BUFFER
-            | FORMAT_MESSAGE_FROM_SYSTEM
-            | FORMAT_MESSAGE_IGNORE_INSERTS,
-        NULL,
-        last_error,
-        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-        (LPSTR) &message_buffer,
-        0,
-        NULL);
-
-    fprintf(stderr, "ERROR: %s: %s (%d)\n",
-            op.c_str(), message_buffer, last_error);
-    LocalFree(message_buffer);
-}
-
 static void PrintErrorW(const wstring& op) {
   DWORD last_error = ::GetLastError();
   if (last_error == 0) {
@@ -315,7 +292,8 @@
 string GetSelfPath() {
   WCHAR buffer[kWindowsPathBufferSize] = {0};
   if (!GetModuleFileNameW(0, buffer, kWindowsPathBufferSize)) {
-    pdie(255, "Error %u getting executable file name\n", GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "GetSelfPath: GetModuleFileNameW");
   }
   return string(blaze_util::WstringToCstring(buffer).get());
 }
@@ -336,8 +314,8 @@
 
   WCHAR buffer[kWindowsPathBufferSize] = {0};
   if (!::GetTempPathW(kWindowsPathBufferSize, buffer)) {
-    PrintErrorW(L"GetTempPathW");
-    pdie(255, "Could not retrieve the temp directory path");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "GetOutputRoot: GetTempPathW");
   }
   return string(blaze_util::WstringToCstring(buffer).get());
 #else  // not COMPILER_MSVC
@@ -434,8 +412,7 @@
   string short_exe;
   if (!blaze_util::AsShortWindowsPath(exe, &short_exe)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "CreateCommandLine: AsShortWindowsPath(%s) failed, err=%d",
-         exe.c_str(), GetLastError());
+         "CreateCommandLine: AsShortWindowsPath(%s)", exe.c_str());
   }
   bool first = true;
   for (const auto& s : args_vector) {
@@ -486,8 +463,8 @@
 
   string cmdline_str = cmdline.str();
   if (cmdline_str.size() >= MAX_CMDLINE_LENGTH) {
-    pdie(blaze_exit_code::INTERNAL_ERROR, "Command line too long: %s",
-         cmdline_str.c_str());
+    pdie(blaze_exit_code::INTERNAL_ERROR, "Command line too long (%d > %d): %s",
+         cmdline_str.size(), MAX_CMDLINE_LENGTH, cmdline_str.c_str());
   }
 
   // Copy command line into a mutable buffer.
@@ -503,13 +480,15 @@
 
   SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
   if (!::CreatePipe(&pipe_read, &pipe_write, &sa, 0)) {
-    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "CreatePipe");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "GetJvmVersion: CreatePipe");
   }
 
   if (!SetHandleInformation(pipe_read, HANDLE_FLAG_INHERIT, 0)) {
     CloseHandle(pipe_read);
     CloseHandle(pipe_write);
-    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "SetHandleInformation");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "GetJvmVersion: SetHandleInformation");
   }
 
   PROCESS_INFORMATION processInfo = {0};
@@ -545,8 +524,7 @@
     CloseHandle(pipe_read);
     CloseHandle(pipe_write);
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "RunProgram/CreateProcess: Error %d while retrieving java version",
-         GetLastError());
+         "RunProgram: CreateProcess(%s)", cmdline);
   }
 
   CloseHandle(pipe_write);
@@ -613,14 +591,15 @@
   uint64_t start_time = 0;
   if (!GetProcessStartupTime(process, &start_time)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "Cannot get start time of process in server dir %s",
+         "WriteProcessStartupTime(%s): GetProcessStartupTime",
          server_dir.c_str());
   }
 
   string start_time_file = blaze_util::JoinPath(server_dir, "server.starttime");
   if (!blaze_util::WriteFile(ToString(start_time), start_time_file)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "Cannot write start time in server dir %s", server_dir.c_str());
+         "WriteProcessStartupTime(%s): WriteFile(%s)", server_dir.c_str(),
+         start_time_file.c_str());
   }
 }
 
@@ -707,7 +686,8 @@
   wstring wdaemon_output;
   if (!blaze_util::AsWindowsPathWithUncPrefix(daemon_output, &wdaemon_output)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "AsWindowsPathWithUncPrefix");
+         "ExecuteDaemon(%s): AsWindowsPathWithUncPrefix(%s)", exe.c_str(),
+         daemon_output.c_str());
   }
 
   SECURITY_ATTRIBUTES sa;
@@ -722,13 +702,14 @@
                                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
   if (!devnull.IsValid()) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "ExecuteDaemon: Could not open NUL device");
+         "ExecuteDaemon(%s): CreateFileA(NUL)", exe.c_str());
   }
 
   AutoHandle stdout_file(CreateJvmOutputFile(wdaemon_output.c_str(), &sa));
   if (!stdout_file.IsValid()) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "ExecuteDaemon: CreateJvmOutputFile %ls", wdaemon_output.c_str());
+         "ExecuteDaemon(%s): CreateJvmOutputFile(%ls)", exe.c_str(),
+         wdaemon_output.c_str());
   }
   HANDLE stderr_handle;
   // We must duplicate the handle to stdout, otherwise "bazel clean --expunge"
@@ -744,7 +725,8 @@
           /* bInheritHandle */ TRUE,
           /* dwOptions */ DUPLICATE_SAME_ACCESS)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "ExecuteDaemon: DuplicateHandle %ls", wdaemon_output.c_str());
+         "ExecuteDaemon(%s): DuplicateHandle(%ls)", exe.c_str(),
+         wdaemon_output.c_str());
   }
   AutoHandle stderr_file(stderr_handle);
 
@@ -776,8 +758,7 @@
 
   if (!ok) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "ExecuteDaemon/CreateProcess: error %u executing: %s\n",
-         GetLastError(), cmdline.cmdline);
+         "ExecuteDaemon(%s): CreateProcess(%s)", exe.c_str(), cmdline.cmdline);
   }
 
   WriteProcessStartupTime(server_dir, processInfo.hProcess);
@@ -830,7 +811,8 @@
 static bool IsFailureDueToNestedJobsNotSupported(HANDLE process) {
   BOOL is_in_job;
   if (!IsProcessInJob(process, NULL, &is_in_job)) {
-    PrintError("IsProcessInJob()");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "IsFailureDueToNestedJobsNotSupported: IsProcessInJob");
     return false;
   }
 
@@ -860,7 +842,8 @@
 
   HANDLE job = CreateJobObject(NULL, NULL);
   if (job == NULL) {
-    pdie(255, "ExecuteProgram/CreateJobObject: error %u\n", GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ExecuteProgram(%s): CreateJobObject", exe.c_str());
   }
 
   JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = {0};
@@ -869,8 +852,8 @@
 
   if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation,
                                &job_info, sizeof(job_info))) {
-    pdie(255, "ExecuteProgram/SetInformationJobObject: error %u\n",
-         GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ExecuteProgram(%s): SetInformationJobObject", exe.c_str());
   }
 
   BOOL success = CreateProcessA(
@@ -886,8 +869,8 @@
       /* lpProcessInformation */ &processInfo);
 
   if (!success) {
-    pdie(255, "ExecuteProgram/CreateProcess: error %u executing: %s\n",
-         GetLastError(), cmdline.cmdline);
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ExecuteProgram(%s): CreateProcess(%s)", exe.c_str(), cmdline.cmdline);
   }
 
   // We will try to put the launched process into a Job object. This will make
@@ -898,14 +881,15 @@
   // handling process management for us.
   if (!AssignProcessToJobObject(job, processInfo.hProcess) &&
       !IsFailureDueToNestedJobsNotSupported(processInfo.hProcess)) {
-    pdie(255, "ExecuteProgram/AssignProcessToJobObject: error %u\n",
-         GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ExecuteProgram(%s): AssignProcessToJobObject", exe.c_str());
   }
 
   // Now that we potentially put the process into a new job object, we can start
   // running it.
   if (ResumeThread(processInfo.hThread) == -1) {
-    pdie(255, "ExecuteProgram/ResumeThread: error %u\n", GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ExecuteProgram(%s): ResumeThread", exe.c_str());
   }
 
   // msys doesn't deliver signals while a Win32 call is pending so we need to
@@ -934,7 +918,8 @@
 string PathAsJvmFlag(const string& path) {
   string spath;
   if (!blaze_util::AsShortWindowsPath(path, &spath)) {
-    pdie(255, "PathAsJvmFlag(%s): AsShortWindowsPath failed", path.c_str());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "PathAsJvmFlag(%s): AsShortWindowsPath", path.c_str());
   }
   // Convert backslashes to forward slashes, in order to avoid the JVM parsing
   // Windows paths as if they contained escaped characters.
@@ -948,7 +933,7 @@
   // The path may not be Windows-style and may not be normalized, so convert it.
   wstring wpath;
   if (!blaze_util::AsWindowsPathWithUncPrefix(path, &wpath)) {
-    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "ConvertPath(path=%s)",
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "ConvertPath(%s)",
          path.c_str());
   }
   std::transform(wpath.begin(), wpath.end(), wpath.begin(), ::towlower);
@@ -993,19 +978,22 @@
   wstring name;
   wstring target;
   if (!blaze_util::AsWindowsPathWithUncPrefix(posix_name, &name)) {
-    PrintError("SymlinkDirectories: AsWindowsPathWithUncPrefix(" + posix_name +
-               ")");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "SymlinkDirectories(%s, %s): AsWindowsPathWithUncPrefix(%s)",
+         posix_target.c_str(), posix_name.c_str(), posix_target.c_str());
     return false;
   }
   if (!blaze_util::AsWindowsPathWithUncPrefix(posix_target, &target)) {
-    PrintError("SymlinkDirectories: AsWindowsPathWithUncPrefix(" +
-               posix_target + ")");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "SymlinkDirectories(%s, %s): AsWindowsPathWithUncPrefix(%s)",
+         posix_target.c_str(), posix_name.c_str(), posix_name.c_str());
     return false;
   }
   string error(CreateJunction(name, target));
   if (!error.empty()) {
-    PrintError("SymlinkDirectories(name=" + posix_name +
-               ", target=" + posix_target + "): " + error);
+    blaze_util::PrintError("SymlinkDirectories(%s, %s): CreateJunction: %s",
+                           posix_target.c_str(), posix_name.c_str(),
+                           error.c_str());
     return false;
   }
   return true;
@@ -1064,7 +1052,8 @@
   if (!result || !AwaitServerProcessTermination(pid, output_base,
                                                 kPostKillGracePeriodSeconds)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "Cannot terminate server process with PID %d", pid);
+         "Cannot terminate server process with PID %d, output_base=(%s)", pid,
+         output_base.c_str());
   }
   return result;
 }
@@ -1106,8 +1095,7 @@
   const char* root = path.c_str();
   if (!blaze_util::MakeDirectories(path, 0755)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "MakeDirectories(%s) failed: %s", root,
-         blaze_util::GetLastErrorString());
+         "MakeDirectories(%s) failed", root);
   }
 
 #ifndef COMPILER_MSVC
@@ -1237,14 +1225,16 @@
 LARGE_INTEGER WindowsClock::GetFrequency() {
   LARGE_INTEGER result;
   if (!QueryPerformanceFrequency(&result)) {
-    PrintError("QueryPerformanceFrequency");
-    pdie(255, "Error getting time resolution\n");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "WindowsClock::GetFrequency: QueryPerformanceFrequency");
   }
 
   // On ancient Windows versions (pre-XP) and specific hardware the result may
   // be 0. Since this is pre-XP, we don't handle that, just error out.
   if (result.QuadPart <= 0) {
-    pdie(255, "QueryPerformanceFrequency returned invalid result (%llu)\n",
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "WindowsClock::GetFrequency: QueryPerformanceFrequency returned "
+         "invalid result (%llu)\n",
          result.QuadPart);
   }
 
@@ -1255,8 +1245,8 @@
     const LARGE_INTEGER& freq) {
   LARGE_INTEGER counter;
   if (!QueryPerformanceCounter(&counter)) {
-    PrintError("QueryPerformanceCounter");
-    pdie(255, "Error getting performance counter\n");
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "WindowsClock::GetMillisecondsAsLargeInt: QueryPerformanceCounter");
   }
 
   LARGE_INTEGER result;
@@ -1289,7 +1279,8 @@
   wstring wlockfile;
   if (!blaze_util::AsWindowsPathWithUncPrefix(lockfile, &wlockfile)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "AcquireLock, lockfile=(%s)", lockfile.c_str());
+         "AcquireLock(%s): AsWindowsPathWithUncPrefix(%s)", output_base.c_str(),
+         lockfile.c_str());
   }
 
   blaze_lock->handle = INVALID_HANDLE_VALUE;
@@ -1323,8 +1314,8 @@
       Sleep(/* dwMilliseconds */ 200);
     } else {
       pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-           "cannot open lockfile '%s', and not because it's held",
-           lockfile.c_str());
+           "AcquireLock(%s): CreateFileW(%ls)", lockfile.c_str(),
+           wlockfile.c_str());
     }
   }
   uint64_t wait_time = GetMillisecondsMonotonic() - st;
@@ -1339,7 +1330,8 @@
           /* nNumberOfBytesToLockHigh */ 0,
           /* lpOverlapped */ &overlapped)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "cannot lock the lockfile '%s'", lockfile.c_str());
+         "AcquireLock(%s): LockFileEx(%ls)", lockfile.c_str(),
+         wlockfile.c_str());
   }
   // On other platforms we write some info about this process into the lock file
   // such as the server PID. On Windows we don't do that because the file is
@@ -1364,9 +1356,8 @@
 string GetUserName() {
   WCHAR buffer[UNLEN + 1];
   DWORD len = UNLEN + 1;
-  if (!GetUserNameW(buffer, &len)) {
-    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "ERROR: GetUserNameW failed, err=%d\n", GetLastError());
+  if (!::GetUserNameW(buffer, &len)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "GetUserNameW");
   }
   return string(blaze_util::WstringToCstring(buffer).get());
 }
diff --git a/src/main/cpp/util/errors_windows.cc b/src/main/cpp/util/errors_windows.cc
index b77ae21..292bb8a 100644
--- a/src/main/cpp/util/errors_windows.cc
+++ b/src/main/cpp/util/errors_windows.cc
@@ -25,7 +25,7 @@
 string GetLastErrorString() {
   DWORD last_error = ::GetLastError();
   if (last_error == 0) {
-    return string();
+    return "success";
   }
 
   char* message_buffer;
diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc
index 17b4264..ae15b71 100644
--- a/src/main/cpp/util/file_windows.cc
+++ b/src/main/cpp/util/file_windows.cc
@@ -148,8 +148,7 @@
   HANDLE read_handle = INVALID_HANDLE_VALUE;
   HANDLE write_handle = INVALID_HANDLE_VALUE;
   if (!CreatePipe(&read_handle, &write_handle, &sa, 0)) {
-    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "CreatePipe failed, err=%d", GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "CreatePipe");
   }
   return new WindowsPipe(read_handle, write_handle);
 }
@@ -184,7 +183,10 @@
   }
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
-    return false;
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "WindowsFileMtime::GetIfInDistantFuture(%s): "
+         "AsWindowsPathWithUncPrefix",
+         path.c_str());
   }
 
   AutoHandle handle(::CreateFileW(
@@ -234,6 +236,8 @@
   }
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "WindowsFileMtime::Set(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
 
@@ -264,8 +268,7 @@
   FILETIME file_time;
   if (!::SystemTimeToFileTime(&sys_time, &file_time)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "WindowsFileMtime::GetNow: SystemTimeToFileTime failed, err=%d",
-         GetLastError());
+         "WindowsFileMtime::GetNow: SystemTimeToFileTime");
   }
   return file_time;
 }
@@ -284,8 +287,7 @@
   FILETIME file_time;
   if (!::SystemTimeToFileTime(&future_time, &file_time)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "WindowsFileMtime::GetFuture: SystemTimeToFileTime failed, err=%d",
-         GetLastError());
+         "WindowsFileMtime::GetFuture: SystemTimeToFileTime");
   }
   return file_time;
 }
@@ -498,8 +500,6 @@
   }
 
   if (!AsWindowsPath(path, wpath)) {
-    PrintError("AsWindowsPathWithUncPrefix(%s): AsWindowsPath failed, err=%d\n",
-               path.c_str(), GetLastError());
     return false;
   }
   if (!IsAbsolute(path)) {
@@ -519,6 +519,8 @@
   wstring wpath;
   wstring wsuffix;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "AsShortWindowsPath(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
   DWORD size = ::GetShortPathNameW(wpath.c_str(), nullptr, 0);
@@ -559,8 +561,8 @@
         new WCHAR[size]);  // size includes null-terminator
     if (size - 1 != ::GetShortPathNameW(wpath.c_str(), wshort.get(), size)) {
       pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-           "AsShortWindowsPath(%s): GetShortPathNameW(%S) failed, err=%d",
-           path.c_str(), wpath.c_str(), GetLastError());
+           "AsShortWindowsPath(%s): GetShortPathNameW(%S)", path.c_str(),
+           wpath.c_str());
     }
     // GetShortPathNameW may preserve the UNC prefix in the result, so strip it.
     wresult = wstring(RemoveUncPrefixMaybe(wshort.get())) + wsuffix;
@@ -575,12 +577,15 @@
   if (filename.empty()) {
     return false;
   }
+  // TODO(laszlocsomor): remove the following check; it won't allow opening NUL.
   if (IsDevNull(filename)) {
     return true;
   }
   wstring wfilename;
   if (!AsWindowsPathWithUncPrefix(filename, &wfilename)) {
-    return false;
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "OpenFileForReading(%s): AsWindowsPathWithUncPrefix",
+         filename.c_str());
   }
   *result = ::CreateFileW(
       /* lpFileName */ wfilename.c_str(),
@@ -648,6 +653,8 @@
   }
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(filename, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "WriteFile(%s): AsWindowsPathWithUncPrefix", filename.c_str());
     return false;
   }
 
@@ -688,19 +695,17 @@
 int RenameDirectory(const std::string& old_name, const std::string& new_name) {
   wstring wold_name;
   if (!AsWindowsPathWithUncPrefix(old_name, &wold_name)) {
-    PrintError(
-        "RenameDirectory(%s, %s): AsWindowsPathWithUncPrefix failed for"
-        " old_name",
-        old_name.c_str(), new_name.c_str());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "RenameDirectory(%s, %s): AsWindowsPathWithUncPrefix(%s)",
+         old_name.c_str(), new_name.c_str(), old_name.c_str());
     return kRenameDirectoryFailureOtherError;
   }
 
   wstring wnew_name;
   if (!AsWindowsPathWithUncPrefix(new_name, &wnew_name)) {
-    PrintError(
-        "RenameDirectory(%s, %s): AsWindowsPathWithUncPrefix failed for"
-        " new_name",
-        old_name.c_str(), new_name.c_str());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "RenameDirectory(%s, %s): AsWindowsPathWithUncPrefix(%s)",
+         old_name.c_str(), new_name.c_str(), new_name.c_str());
     return kRenameDirectoryFailureOtherError;
   }
 
@@ -740,6 +745,8 @@
 
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(file_path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "UnlinkPath(%s): AsWindowsPathWithUncPrefix", file_path.c_str());
     return false;
   }
   return UnlinkPathW(wpath);
@@ -870,8 +877,8 @@
 bool ReadDirectorySymlink(const string& name, string* result) {
   wstring wname;
   if (!AsWindowsPathWithUncPrefix(name, &wname)) {
-    PrintError("ReadDirectorySymlink: AsWindowsPathWithUncPrefix(%s)",
-               name.c_str());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ReadDirectorySymlink(%s): AsWindowsPathWithUncPrefix", name.c_str());
     return false;
   }
   unique_ptr<WCHAR[]> result_ptr;
@@ -891,8 +898,8 @@
   }
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
-    PrintError("PathExists(%s): AsWindowsPathWithUncPrefix failed, err=%d\n",
-               path.c_str(), GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "PathExists(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
   return JunctionResolver().Resolve(wpath.c_str(), nullptr);
@@ -903,13 +910,13 @@
     return "NUL";
   }
   wstring wpath;
-  if (path == nullptr || path[0] == 0 ||
-      !AsWindowsPathWithUncPrefix(path, &wpath)) {
-    if (path != nullptr && path[0] != 0) {
-      PrintError("MakeCanonical(%s): AsWindowsPathWithUncPrefix failed", path);
-    }
+  if (path == nullptr || path[0] == 0) {
     return "";
   }
+  if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "MakeCanonical(%s): AsWindowsPathWithUncPrefix", path);
+  }
 
   // Resolve all segments of the path. Do this from leaf to root, so we always
   // know that the path's tail is resolved and junctions may be found only in
@@ -1010,6 +1017,8 @@
 bool CanReadFile(const std::string& path) {
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "CanReadFile(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
   return CanReadFileW(wpath);
@@ -1018,6 +1027,8 @@
 bool CanExecuteFile(const std::string& path) {
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "CanExecuteFile(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
   return CanReadFileW(wpath) && (ends_with(wpath, wstring(L".exe")) ||
@@ -1029,6 +1040,8 @@
 bool CanAccessDirectory(const std::string& path) {
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "CanAccessDirectory(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
   DWORD attr = ::GetFileAttributesW(wpath.c_str());
@@ -1090,6 +1103,8 @@
   }
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "IsDirectory(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
   return IsDirectoryW(wpath);
@@ -1121,18 +1136,12 @@
   if (last_separator < 0) {
     // Since `path` is not a root directory, there must be at least one
     // directory above it.
-    pdie(255, "MakeDirectoriesW(%S), could not find dirname", path.c_str());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "MakeDirectoriesW(%S), could not find dirname", path.c_str());
   }
   wstring parent = path.substr(0, last_separator);
-  if (!MakeDirectoriesW(parent)) {
-    return false;
-  }
-  if (!::CreateDirectoryW(path.c_str(), nullptr)) {
-    PrintError("MakeDirectoriesW(%S), CreateDirectoryW failed, err=%d",
-               path.c_str(), GetLastError());
-    return false;
-  }
-  return true;
+  return MakeDirectoriesW(parent) &&
+         ::CreateDirectoryW(path.c_str(), NULL) == TRUE;
 }
 
 bool MakeDirectories(const string& path, unsigned int mode) {
@@ -1145,6 +1154,8 @@
   // According to MSDN, CreateDirectory's limit without the UNC prefix is
   // 248 characters (so it could fit another filename before reaching MAX_PATH).
   if (!AsWindowsPathWithUncPrefix(path, &wpath, 248)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "MakeDirectories(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
   return MakeDirectoriesW(wpath);
@@ -1154,7 +1165,7 @@
   DWORD len = ::GetCurrentDirectoryW(0, nullptr);
   unique_ptr<WCHAR[]> cwd(new WCHAR[len]);
   if (!::GetCurrentDirectoryW(len, cwd.get())) {
-    die(255, "GetCurrentDirectoryW failed, err=%d\n", GetLastError());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR, "GetCurrentDirectoryW");
   }
   return std::move(cwd);
 }
@@ -1166,15 +1177,11 @@
 bool ChangeDirectory(const string& path) {
   wstring wpath;
   if (!AsWindowsPathWithUncPrefix(path, &wpath)) {
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "ChangeDirectory(%s): AsWindowsPathWithUncPrefix", path.c_str());
     return false;
   }
-  if (!::SetCurrentDirectoryW(wpath.c_str())) {
-    PrintError(
-        "ChangeDirectory(%s): SetCurrentDirectoryW(%S), failed, err=%d\n",
-        path.c_str(), wpath.c_str(), GetLastError());
-    return false;
-  }
-  return true;
+  return ::SetCurrentDirectoryW(wpath.c_str()) == TRUE;
 }
 
 void ForEachDirectoryEntry(const string &path,
@@ -1185,7 +1192,7 @@
   }
   if (!AsWindowsPath(path, &wpath)) {
     pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
-         "ForEachDirectoryEntry(%s): AsWindowsPath failed", path.c_str());
+         "ForEachDirectoryEntry(%s): AsWindowsPath", path.c_str());
   }
 
   static const wstring kUncPrefix(L"\\\\?\\");
@@ -1222,8 +1229,8 @@
   }
   if (path[0] == '/') {
     // This is an absolute MSYS path, error out.
-    pdie(255, "NormalizeWindowsPath: expected a Windows path, path=(%s)",
-         path.c_str());
+    pdie(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR,
+         "NormalizeWindowsPath(%s): expected a Windows path", path.c_str());
   }
   if (path.size() >= 4 && HasUncPrefix(path.c_str())) {
     path = path.substr(4);
diff --git a/src/main/native/windows/file.h b/src/main/native/windows/file.h
index b1a5710..a8cbe71c 100644
--- a/src/main/native/windows/file.h
+++ b/src/main/native/windows/file.h
@@ -28,8 +28,11 @@
 
 template <typename char_type>
 bool HasUncPrefix(const char_type* path) {
-  return path[0] == '\\' && (path[1] == '\\' || path[1] == '?') &&
-         (path[2] == '.' || path[2] == '?') && path[3] == '\\';
+  // Return true iff `path` starts with "\\?\", "\\.\", or "\??\".
+  return path[0] == '\\' &&
+         ((path[1] == '\\' && (path[2] == '?' || path[2] == '.')) ||
+          (path[1] == '?' && path[2] == '?')) &&
+         path[3] == '\\';
 }
 
 // Keep in sync with j.c.g.devtools.build.lib.windows.WindowsFileOperations
diff --git a/src/test/cpp/util/BUILD b/src/test/cpp/util/BUILD
index bc995bf..119d993 100644
--- a/src/test/cpp/util/BUILD
+++ b/src/test/cpp/util/BUILD
@@ -35,7 +35,6 @@
             "file_posix_test.cc",
         ],
     }),
-    tags = ["manual"],
     deps = [
         ":test_util",
         "//src/main/cpp/util:file",
diff --git a/third_party/ijar/mapped_file_windows.cc b/third_party/ijar/mapped_file_windows.cc
index b3fdd99..253065e 100644
--- a/third_party/ijar/mapped_file_windows.cc
+++ b/third_party/ijar/mapped_file_windows.cc
@@ -29,20 +29,6 @@
 
 static char errmsg[MAX_ERROR] = "";
 
-void PrintLastError(const char* op) {
-  char *message;
-  DWORD err = GetLastError();
-  FormatMessage(
-      FORMAT_MESSAGE_ALLOCATE_BUFFER
-          | FORMAT_MESSAGE_FROM_SYSTEM
-          | FORMAT_MESSAGE_IGNORE_INSERTS,
-      NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-      reinterpret_cast<char *>(&message),
-      0, NULL);
-  snprintf(errmsg, MAX_ERROR, "%s: %s", op, message);
-  LocalFree(message);
-}
-
 struct MappedInputFileImpl {
   HANDLE file_;
   HANDLE mapping_;
@@ -60,37 +46,30 @@
 
   wstring wname;
   if (!blaze_util::AsWindowsPathWithUncPrefix(name, &wname)) {
-    blaze_util::die(
-        255, "MappedInputFile(%s): AsWindowsPathWithUncPrefix failed", name);
+    blaze_util::pdie(255, "MappedInputFile(%s): AsWindowsPathWithUncPrefix",
+                     name);
   }
   HANDLE file = CreateFileW(wname.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL,
                             OPEN_EXISTING, 0, NULL);
   if (file == INVALID_HANDLE_VALUE) {
-    PrintLastError("CreateFile()");
-    return;
+    blaze_util::pdie(255, "MappedInputFile(%s): CreateFileW(%S)", name,
+                     wname.c_str());
   }
 
   LARGE_INTEGER size;
   if (!GetFileSizeEx(file, &size)) {
-    PrintLastError("GetFileSizeEx()");
-    CloseHandle(file);
-    return;
+    blaze_util::pdie(255, "MappedInputFile(%s): GetFileSizeEx", name);
   }
 
   HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY,
       size.HighPart, size.LowPart, NULL);
   if (mapping == NULL || mapping == INVALID_HANDLE_VALUE) {
-    PrintLastError("CreateFileMapping()");
-    CloseHandle(file);
-    return;
+    blaze_util::pdie(255, "MappedInputFile(%s): CreateFileMapping", name);
   }
 
   void *view = MapViewOfFileEx(mapping, FILE_MAP_READ, 0, 0, 0, NULL);
   if (view == NULL) {
-    PrintLastError("MapViewOfFileEx()");
-    CloseHandle(mapping);
-    CloseHandle(file);
-    return;
+    blaze_util::pdie(255, "MappedInputFile(%s): MapViewOfFileEx", name);
   }
 
   impl_ = new MappedInputFileImpl(file, mapping);
@@ -111,18 +90,15 @@
 
 int MappedInputFile::Close() {
   if (!UnmapViewOfFile(buffer_)) {
-    PrintLastError("UnmapViewOfFile()");
-    return -1;
+    blaze_util::pdie(255, "MappedInputFile::Close: UnmapViewOfFile");
   }
 
   if (!CloseHandle(impl_->mapping_)) {
-    PrintLastError("CloseHandle(mapping)");
-    return -1;
+    blaze_util::pdie(255, "MappedInputFile::Close: CloseHandle for mapping");
   }
 
   if (!CloseHandle(impl_->file_)) {
-    PrintLastError("CloseHandle(file)");
-    return -1;
+    blaze_util::pdie(255, "MappedInputFile::Close: CloseHandle for file");
   }
 
   return 0;
@@ -145,27 +121,25 @@
 
   wstring wname;
   if (!blaze_util::AsWindowsPathWithUncPrefix(name, &wname)) {
-    blaze_util::die(
-        255, "MappedOutputFile(%s): AsWindowsPathWithUncPrefix failed", name);
+    blaze_util::pdie(255, "MappedOutputFile(%s): AsWindowsPathWithUncPrefix",
+                     name);
   }
   HANDLE file = CreateFileW(wname.c_str(), GENERIC_READ | GENERIC_WRITE, 0,
                             NULL, CREATE_ALWAYS, 0, NULL);
   if (file == INVALID_HANDLE_VALUE) {
-    PrintLastError("CreateFile()");
-    return;
+    blaze_util::pdie(255, "MappedOutputFile(%s): CreateFileW(%S)", name,
+                     wname.c_str());
   }
 
   HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READWRITE,
       estimated_size >> 32, estimated_size & 0xffffffffUL, NULL);
   if (mapping == NULL || mapping == INVALID_HANDLE_VALUE) {
-    PrintLastError("CreateFileMapping()");
-    CloseHandle(file);
-    return;
+    blaze_util::pdie(255, "MappedOutputFile(%s): CreateFileMapping", name);
   }
 
   void *view = MapViewOfFileEx(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
   if (view == NULL) {
-    PrintLastError("MapViewOfFileEx()");
+    blaze_util::pdie(255, "MappedOutputFile(%s): MapViewOfFileEx", name);
     CloseHandle(mapping);
     CloseHandle(file);
     return;
@@ -182,28 +156,23 @@
 
 int MappedOutputFile::Close(int size) {
   if (!UnmapViewOfFile(buffer_)) {
-    PrintLastError("UnmapViewOfFile()");
-    return -1;
+    blaze_util::pdie(255, "MappedOutputFile::Close: UnmapViewOfFile");
   }
 
   if (!CloseHandle(impl_->mapping_)) {
-    PrintLastError("CloseHandle(mapping)");
-    return -1;
+    blaze_util::pdie(255, "MappedOutputFile::Close: CloseHandle for mapping");
   }
 
   if (!SetFilePointer(impl_->file_, size, NULL, FILE_BEGIN)) {
-    PrintLastError("SetFilePointer()");
-    return -1;
+    blaze_util::pdie(255, "MappedOutputFile::Close: SetFilePointer");
   }
 
   if (!SetEndOfFile(impl_->file_)) {
-    PrintLastError("SetEndOfFile()");
-    return -1;
+    blaze_util::pdie(255, "MappedOutputFile::Close: SetEndOfFile");
   }
 
   if (!CloseHandle(impl_->file_)) {
-    PrintLastError("CloseHandle(file)");
-    return -1;
+    blaze_util::pdie(255, "MappedOutputFile::Close: CloseHandle for file");
   }
 
   return 0;
diff --git a/third_party/ijar/platform_utils.cc b/third_party/ijar/platform_utils.cc
index 29d468a..a998cab 100644
--- a/third_party/ijar/platform_utils.cc
+++ b/third_party/ijar/platform_utils.cc
@@ -39,8 +39,7 @@
 #if defined(COMPILER_MSVC) || defined(__CYGWIN__)
   std::wstring wpath;
   if (!blaze_util::AsWindowsPathWithUncPrefix(path, &wpath)) {
-    blaze_util::die(255, "stat_file: AsWindowsPathWithUncPrefix(%s) failed",
-                    path);
+    blaze_util::pdie(255, "stat_file: AsWindowsPathWithUncPrefix(%s)", path);
   }
   bool success = false;
   BY_HANDLE_FILE_INFORMATION info;