[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