[llvm] [Support] Handle delete_pending case for Windows fs::status (PR #90655)

Alexandre Ganea via llvm-commits llvm-commits at lists.llvm.org
Fri May 10 08:51:47 PDT 2024


================
@@ -236,14 +236,41 @@ void LLVMResetFatalErrorHandler() {
 
 #ifdef _WIN32
 
+#define WIN32_NO_STATUS
+#include "llvm/Support/Windows/WindowsSupport.h"
+#undef WIN32_NO_STATUS
+#include <ntstatus.h>
 #include <winerror.h>
 
+// This is equivalent to NtCurrentTeb()->LastStatusValue, but the public
+// _TEB definition does not expose the LastStatusValue field directly.
+// Avoid offsetting into this structure by calling RtlGetLastNtStatus
+// from ntdll.dll.
+//
+// The return of this function will roughly match that of
+// GetLastError, but this lower level API disambiguates some cases
+// that GetLastError does not.
+//
+// For more information, see:
+// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
+// https://github.com/llvm/llvm-project/issues/89137
+extern "C" NTSYSAPI NTSTATUS NTAPI RtlGetLastNtStatus();
+
 // I'd rather not double the line count of the following.
 #define MAP_ERR_TO_COND(x, y)                                                  \
   case x:                                                                      \
     return make_error_code(errc::y)
 
 std::error_code llvm::mapWindowsError(unsigned EV) {
+  // The mapping of NTSTATUS to Win32 error loses some information; special
+  // case the generic ERROR_ACCESS_DENIED code to check the underlying
+  // NTSTATUS and potentially return a more accurate error code.
+  if (EV == ERROR_ACCESS_DENIED) {
----------------
aganea wrote:

That's a good point. In most cases we indeed call `mapWindowsError(::GetLastError())`. Maybe instead we can create another variant of that function that calls both `::GetLastError()` and `RtlGetLastNtStatus()`. 
```
std::error_code llvm::mapLastWindowsError() {
  unsigned EV = ::GetLastError();
  if (EV == ERROR_ACCESS_DENIED) {
    llvm::errc code = RtlGetLastNtStatus() == STATUS_DELETE_PENDING
                          ? errc::delete_pending
                          : errc::permission_denied;
    return make_error_code(code);
  }
...
```
Then the code here becomes:
```
static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
...
handle_status_error:
  std::error_code Err = mapLastWindowsError();
  if (Err == std::errc::no_such_file_or_directory || LastError == std::errc::no_such_file_or_directory)
    Result = file_status(file_type::file_not_found);
  else if (Err == std::errc::permission_denied)
    Result = file_status(file_type::type_unknown);
  else
    Result = file_status(file_type::status_error);
  return Err;
}
```

https://github.com/llvm/llvm-project/pull/90655


More information about the llvm-commits mailing list