[rp-download] SetFileOriginInfo_win32.cpp: Load NTDLL.DLL function pointers using GetProcAddress().

AppVeyor's MSVC 2015 image doesn't have ntdll.lib for some reason.
This commit is contained in:
David Korth 2025-06-13 18:14:49 -04:00
parent 1da1c39c18
commit e5c512ca92
2 changed files with 31 additions and 8 deletions

View File

@ -110,10 +110,6 @@ TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME}
IF(WIN32)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE win32common rptext-noi18n)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE wininet advapi32)
# NTDLL is used to open Alternate Data Streams without requiring the original filename.
# NOTE: Only works in Unicode builds. Non-Unicode builds would be for Win9x, which
# doesn't support Alternate Data Streams, anyway.
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE ntdll)
# Delay-load shell32.dll and ole32.dll to prevent a performance penalty due to gdi32.dll.
# Reference: https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/

View File

@ -59,6 +59,11 @@ __kernel_entry NTSYSCALLAPI NTSTATUS NtDeleteFile(
PCOBJECT_ATTRIBUTES ObjectAttributes
);
typedef __typeof__(NtCreateFile) *pfn_NtCreateFile_t;
typedef __typeof__(NtWriteFile) *pfn_NtWriteFile_t;
typedef __typeof__(NtClose) *pfn_NtClose_t;
typedef __typeof__(NtDeleteFile) *pfn_NtDeleteFile_t;
}
#endif /* UNICODE */
@ -135,6 +140,28 @@ int setFileOriginInfo(FILE *file, const TCHAR *url, time_t mtime)
// - https://cqureacademy.com/blog/alternate-data-streams
// - https://stackoverflow.com/questions/46141321/open-alternate-data-stream-ads-from-file-handle-or-file-id
// - https://stackoverflow.com/a/46141949
// NOTE: ntdll.lib isn't present in all build environments.
// Use GetModuleHandle() and GetProcAddress() instead.
HMODULE hNtDll = GetModuleHandle(_T("ntdll.dll"));
if (!hNtDll) {
// No NTDLL.DLL? Maybe this is Win9x...
break;
}
#define NTDLL_LOAD(fn) pfn_##fn##_t pfn_##fn = reinterpret_cast<pfn_##fn##_t>(GetProcAddress(hNtDll, #fn))
NTDLL_LOAD(NtCreateFile);
NTDLL_LOAD(NtWriteFile);
NTDLL_LOAD(NtClose);
NTDLL_LOAD(NtDeleteFile);
if (!pfn_NtCreateFile || !pfn_NtWriteFile ||
!pfn_NtClose || !pfn_NtDeleteFile)
{
// At least one function pointer is missing.
break;
}
HANDLE hFile = reinterpret_cast<HANDLE>(_get_osfhandle(fileno(file)));
IO_STATUS_BLOCK iosb;
UNICODE_STRING ObjectName = RTL_CONSTANT_STRING(L":Zone.Identifier");
@ -143,7 +170,7 @@ int setFileOriginInfo(FILE *file, const TCHAR *url, time_t mtime)
InitializeObjectAttributes(&oa, &ObjectName, 0, hFile, nullptr);
HANDLE hAds = nullptr;
NTSTATUS status = NtCreateFile(
NTSTATUS status = pfn_NtCreateFile(
&hAds, // FileHandle
FILE_GENERIC_WRITE, // DesiredAccess
&oa, // ObjectAttributes
@ -177,7 +204,7 @@ int setFileOriginInfo(FILE *file, const TCHAR *url, time_t mtime)
s_zoneID += T2U8(url);
s_zoneID += "\r\n";
status = NtWriteFile(
status = pfn_NtWriteFile(
hAds, // FileHandle
nullptr, // Event
nullptr, // ApcRoutine
@ -187,12 +214,12 @@ int setFileOriginInfo(FILE *file, const TCHAR *url, time_t mtime)
static_cast<DWORD>(s_zoneID.size()), // Length
nullptr, // ByteOffset
nullptr); // Key
NtClose(hAds);
pfn_NtClose(hAds);
if (status < 0) {
// Error writing the stream data.
// Delete the stream.
NtDeleteFile(&oa);
pfn_NtDeleteFile(&oa);
// TODO: Convert NTSTATUS to Win32?
err = -EIO;