Skip to content

Commit 698cb24

Browse files
authored
Merge pull request #8850 from z2oh/cherrypick-windows-status-pending-delete
[🍒 stable/20230725] [Support] Handle delete_pending case for Windows fs::status (llvm#90655)
2 parents 07ac8d6 + 3a9af81 commit 698cb24

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

llvm/include/llvm/Support/Errc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ enum class errc {
3838
bad_address = int(std::errc::bad_address),
3939
bad_file_descriptor = int(std::errc::bad_file_descriptor),
4040
broken_pipe = int(std::errc::broken_pipe),
41+
// There is no delete_pending in std::errc; this error code is negative to
42+
// avoid conflicts. This error roughly corresponds with Windows'
43+
// STATUS_DELETE_PENDING 0xC0000056.
44+
delete_pending = -56,
4145
device_or_resource_busy = int(std::errc::device_or_resource_busy),
4246
directory_not_empty = int(std::errc::directory_not_empty),
4347
executable_format_error = int(std::errc::executable_format_error),

llvm/include/llvm/Support/WindowsError.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <system_error>
1313

1414
namespace llvm {
15+
std::error_code mapLastWindowsError();
1516
std::error_code mapWindowsError(unsigned EV);
1617
}
1718

llvm/lib/Support/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ endif()
4040
if( MSVC OR MINGW )
4141
# libuuid required for FOLDERID_Profile usage in lib/Support/Windows/Path.inc.
4242
# advapi32 required for CryptAcquireContextW in lib/Support/Windows/Path.inc.
43-
set(system_libs ${system_libs} psapi shell32 ole32 uuid advapi32)
43+
# ntdll required for RtlGetLastNtStatus in lib/Support/ErrorHandling.cpp.
44+
set(system_libs ${system_libs} psapi shell32 ole32 uuid advapi32 ws2_32 ntdll)
4445
elseif( CMAKE_HOST_UNIX )
4546
if( HAVE_LIBRT )
4647
set(system_libs ${system_libs} rt)

llvm/lib/Support/ErrorHandling.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,43 @@ void LLVMResetFatalErrorHandler() {
235235

236236
#ifdef _WIN32
237237

238+
#define WIN32_NO_STATUS
239+
#include "llvm/Support/Windows/WindowsSupport.h"
240+
#undef WIN32_NO_STATUS
241+
#include <ntstatus.h>
238242
#include <winerror.h>
239243

244+
// This is equivalent to NtCurrentTeb()->LastStatusValue, but the public
245+
// _TEB definition does not expose the LastStatusValue field directly.
246+
// Avoid offsetting into this structure by calling RtlGetLastNtStatus
247+
// from ntdll.dll.
248+
//
249+
// The return of this function will roughly match that of
250+
// GetLastError, but this lower level API disambiguates some cases
251+
// that GetLastError does not.
252+
//
253+
// For more information, see:
254+
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
255+
// https://github.com/llvm/llvm-project/issues/89137
256+
extern "C" NTSYSAPI NTSTATUS NTAPI RtlGetLastNtStatus();
257+
258+
// This function obtains the last error code and maps it. It may call
259+
// RtlGetLastNtStatus, which is a lower level API that can return a
260+
// more specific error code than GetLastError.
261+
std::error_code llvm::mapLastWindowsError() {
262+
unsigned EV = ::GetLastError();
263+
// The mapping of NTSTATUS to Win32 error loses some information; special
264+
// case the generic ERROR_ACCESS_DENIED code to check the underlying
265+
// NTSTATUS and potentially return a more accurate error code.
266+
if (EV == ERROR_ACCESS_DENIED) {
267+
llvm::errc code = RtlGetLastNtStatus() == STATUS_DELETE_PENDING
268+
? errc::delete_pending
269+
: errc::permission_denied;
270+
return make_error_code(code);
271+
}
272+
return mapWindowsError(EV);
273+
}
274+
240275
// I'd rather not double the line count of the following.
241276
#define MAP_ERR_TO_COND(x, y) \
242277
case x: \

llvm/lib/Support/Windows/Path.inc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -745,14 +745,14 @@ static std::error_code getStatus(HANDLE FileHandle, file_status &Result) {
745745
return std::error_code();
746746

747747
handle_status_error:
748-
DWORD LastError = ::GetLastError();
749-
if (LastError == ERROR_FILE_NOT_FOUND || LastError == ERROR_PATH_NOT_FOUND)
748+
std::error_code Err = mapLastWindowsError();
749+
if (Err == std::errc::no_such_file_or_directory)
750750
Result = file_status(file_type::file_not_found);
751-
else if (LastError == ERROR_SHARING_VIOLATION)
751+
else if (Err == std::errc::permission_denied)
752752
Result = file_status(file_type::type_unknown);
753753
else
754754
Result = file_status(file_type::status_error);
755-
return mapWindowsError(LastError);
755+
return Err;
756756
}
757757

758758
std::error_code status(const Twine &path, file_status &result, bool Follow) {

0 commit comments

Comments
 (0)