diff --git a/src/rp-download/CMakeLists.txt b/src/rp-download/CMakeLists.txt index 276ba884a..04dff63dc 100644 --- a/src/rp-download/CMakeLists.txt +++ b/src/rp-download/CMakeLists.txt @@ -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/ diff --git a/src/rp-download/SetFileOriginInfo_win32.cpp b/src/rp-download/SetFileOriginInfo_win32.cpp index 058a6ffef..6516e5cf1 100644 --- a/src/rp-download/SetFileOriginInfo_win32.cpp +++ b/src/rp-download/SetFileOriginInfo_win32.cpp @@ -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(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(_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(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;