|
21 | 21 | #include <cstdio> |
22 | 22 | #include <cstdlib> |
23 | 23 | #include <cerrno> |
| 24 | +#include <filesystem> |
24 | 25 | #include <memory> |
25 | 26 | #include <utility> |
26 | 27 |
|
@@ -532,24 +533,35 @@ ArchGetFileName(FILE *file) |
532 | 533 | } |
533 | 534 | return result; |
534 | 535 | #elif defined (ARCH_OS_WINDOWS) |
535 | | - static constexpr DWORD bufSize = |
536 | | - sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * 4096; |
537 | | - HANDLE hfile = _FileToWinHANDLE(file); |
538 | | - auto fileNameInfo = reinterpret_cast<PFILE_NAME_INFO>(malloc(bufSize)); |
539 | 536 | string result; |
540 | | - if (GetFileInformationByHandleEx( |
541 | | - hfile, FileNameInfo, static_cast<void *>(fileNameInfo), bufSize)) { |
| 537 | + std::vector<WCHAR> filePath(MAX_PATH); |
| 538 | + HANDLE hfile = _FileToWinHANDLE(file); |
| 539 | + DWORD dwSize = GetFinalPathNameByHandleW(hfile, filePath.data(), MAX_PATH, VOLUME_NAME_DOS); |
| 540 | + // * dwSize == 0. Fail. |
| 541 | + // * dwSize < MAX_PATH. Success, and dwSize returns the size without null terminator. |
| 542 | + // * dwSize >= MAX_PATH. Buffer is too small, and dwSize returns the size with null terminator. |
| 543 | + if (dwSize >= MAX_PATH) { |
| 544 | + filePath.resize(dwSize); |
| 545 | + dwSize = GetFinalPathNameByHandleW(hfile, filePath.data(), dwSize, VOLUME_NAME_DOS); |
| 546 | + } |
| 547 | + |
| 548 | + if (dwSize != 0) { |
542 | 549 | size_t outSize = WideCharToMultiByte( |
543 | | - CP_UTF8, 0, fileNameInfo->FileName, |
544 | | - fileNameInfo->FileNameLength/sizeof(WCHAR), |
| 550 | + CP_UTF8, 0, filePath.data(), |
| 551 | + dwSize, |
545 | 552 | NULL, 0, NULL, NULL); |
546 | 553 | result.resize(outSize); |
547 | 554 | WideCharToMultiByte( |
548 | | - CP_UTF8, 0, fileNameInfo->FileName, |
549 | | - fileNameInfo->FileNameLength/sizeof(WCHAR), |
| 555 | + CP_UTF8, 0, filePath.data(), |
| 556 | + -1, |
550 | 557 | &result.front(), outSize, NULL, NULL); |
| 558 | + |
| 559 | + // Strip path prefix if necessary. |
| 560 | + // See https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats |
| 561 | + // for format of DOS device paths. |
| 562 | + auto canonicalPath = std::filesystem::canonical(result); |
| 563 | + result = canonicalPath.string(); |
551 | 564 | } |
552 | | - free(fileNameInfo); |
553 | 565 | return result; |
554 | 566 | #else |
555 | 567 | #error Unknown system architecture |
|
0 commit comments