diff options
author | George Hazan <george.hazan@gmail.com> | 2023-05-30 20:38:02 +0300 |
---|---|---|
committer | George Hazan <george.hazan@gmail.com> | 2023-05-30 20:38:07 +0300 |
commit | 18b2640d91af23ee1cd03f8aadbb52137298e53d (patch) | |
tree | 61385b3b681ed54e30fb5676d8f76e49580c0566 /protocols | |
parent | 9154bda3c04a2c78340a6a7a4684814fc640a2f4 (diff) |
fixes #3309 (Telegram: crash under WinXP)
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/Telegram/tdlib/td/tdutils/td/utils/port/FileFd.cpp | 192 |
1 files changed, 180 insertions, 12 deletions
diff --git a/protocols/Telegram/tdlib/td/tdutils/td/utils/port/FileFd.cpp b/protocols/Telegram/tdlib/td/tdutils/td/utils/port/FileFd.cpp index 4297e9f368..aabcb0156c 100644 --- a/protocols/Telegram/tdlib/td/tdutils/td/utils/port/FileFd.cpp +++ b/protocols/Telegram/tdlib/td/tdutils/td/utils/port/FileFd.cpp @@ -42,14 +42,61 @@ #endif #if TD_PORT_WINDOWS +#define STATUS_INVALID_INFO_CLASS 0xC0000003L + +typedef enum _FILE_INFORMATION_CLASS +{ + FileDirectoryInformation = 1, + FileFullDirectoryInformation, + FileBothDirectoryInformation, + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, + FileLinkInformation, + FileNamesInformation, + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileCopyOnWriteInformation, + FileCompletionInformation, + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileObjectIdInformation, + FileTrackingInformation, + FileOleDirectoryInformation, + FileContentIndexInformation, + FileInheritContentIndexInformation, + FileOleInformation, + FileMaximumInformation +} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; + + #ifdef WIN32_LEAN_AND_MEAN #include <winioctl.h> #endif // WIN32_LEAN_AND_MEAN typedef struct _IO_STATUS_BLOCK { - union - { + union { NTSTATUS Status; PVOID Pointer; } DUMMYUNIONNAME; @@ -57,8 +104,134 @@ typedef struct _IO_STATUS_BLOCK ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; -typedef NTSTATUS (WINAPI *pfnNtQueryInformationFile)(HANDLE handle, IO_STATUS_BLOCK *io, void *ptr, ULONG len, int class_); -static pfnNtQueryInformationFile fnNtQueryInformationFile = 0; +typedef NTSTATUS (CALLBACK *pfnNtQueryDirectoryFile)( + HANDLE FileHandle, + HANDLE Event, + PVOID ApcRoutine, + PVOID ApcContext, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass, + BOOLEAN ReturnSingleEntry, + WCHAR* FileName, + BOOLEAN RestartScan); + +static pfnNtQueryDirectoryFile fnNtQueryDirectoryFile = nullptr; + +typedef NTSTATUS (CALLBACK *pfnNtQueryInformationFile)( + HANDLE FileHandle, + PIO_STATUS_BLOCK IoStatusBlock, + PVOID FileInformation, + ULONG Length, + FILE_INFORMATION_CLASS FileInformationClass); + +static pfnNtQueryInformationFile fnNtQueryInformationFile = nullptr; + +static BOOL bNtdllInited = false; + +static BOOL WINAPI GetFileInformationByHandleExStub( + _In_ HANDLE hFile, + _In_ FILE_INFO_BY_HANDLE_CLASS FileInformationClass, + _Out_writes_bytes_(dwBufferSize) LPVOID lpFileInformation, + _In_ DWORD dwBufferSize) +{ + FILE_INFORMATION_CLASS NtFileInformationClass; + DWORD cbMinBufferSize; + BOOLEAN RestartScan = false; + + switch (FileInformationClass) // Purosham Sahanu InformationClass + { + case FileBasicInfo: + NtFileInformationClass = FileBasicInformation; + cbMinBufferSize = sizeof(FILE_BASIC_INFO); + break; + case FileStandardInfo: + NtFileInformationClass = FileStandardInformation; + cbMinBufferSize = sizeof(FILE_STANDARD_INFO); + break; + case FileNameInfo: + NtFileInformationClass = FileNameInformation; + cbMinBufferSize = sizeof(FILE_NAME_INFO); + break; + case FileStreamInfo: + NtFileInformationClass = FileStreamInformation; + cbMinBufferSize = sizeof(FILE_STREAM_INFO); + break; + case FileCompressionInfo: + NtFileInformationClass = FileCompressionInformation; + cbMinBufferSize = sizeof(FILE_COMPRESSION_INFO); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + break; + } + + if (cbMinBufferSize > dwBufferSize) { + SetLastError(ERROR_BAD_LENGTH); + return FALSE; + } + + if (!bNtdllInited) { + bNtdllInited = true; + + HINSTANCE hdll = LoadLibraryA("ntdll.dll"); + fnNtQueryDirectoryFile = (pfnNtQueryDirectoryFile)GetProcAddress(hdll, "NtQueryDirectoryFile"); + fnNtQueryInformationFile = (pfnNtQueryInformationFile)GetProcAddress(hdll, "NtQueryInformationFile"); + } + + int Status = ERROR_SUCCESS; + IO_STATUS_BLOCK IoStatusBlock; + if (fnNtQueryDirectoryFile) { + Status = fnNtQueryDirectoryFile( + hFile, + nullptr, + nullptr, + nullptr, + &IoStatusBlock, + lpFileInformation, + dwBufferSize, + NtFileInformationClass, + false, + nullptr, + RestartScan + ); + + if (STATUS_PENDING == Status) { + if (WaitForSingleObjectEx(hFile, 0, FALSE) == WAIT_FAILED) { + return FALSE; + } + + Status = IoStatusBlock.Status; + } + else if (Status == STATUS_INVALID_INFO_CLASS) + goto LBL_CheckFile; + } + else { +LBL_CheckFile: + if (!fnNtQueryInformationFile) { + SetLastError(ERROR_INVALID_FUNCTION); + return FALSE; + } + + Status = fnNtQueryInformationFile(hFile, &IoStatusBlock, lpFileInformation, dwBufferSize, NtFileInformationClass); + } + + if (Status >= ERROR_SUCCESS) { + if (FileStreamInfo == FileInformationClass && IoStatusBlock.Information == 0) { + SetLastError(ERROR_HANDLE_EOF); + return FALSE; + } + else { + return TRUE; + } + } + else { + SetLastError(Status); + return FALSE; + } +} #endif @@ -549,10 +722,7 @@ struct FileSize { Result<FileSize> get_file_size(const FileFd &file_fd) { FILE_STANDARD_INFO standard_info; - IO_STATUS_BLOCK io = {}; - if (fnNtQueryInformationFile == nullptr) - fnNtQueryInformationFile = (pfnNtQueryInformationFile)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationFile"); - if (fnNtQueryInformationFile(file_fd.get_native_fd().fd(), &io, &standard_info, sizeof(standard_info), 5)) { + if (!GetFileInformationByHandleExStub(file_fd.get_native_fd().fd(), FileStandardInfo, &standard_info, sizeof(standard_info))) { return OS_ERROR("Get FileStandardInfo failed"); } @@ -597,10 +767,8 @@ Result<Stat> FileFd::stat() const { Stat res; FILE_BASIC_INFO basic_info; - IO_STATUS_BLOCK io = {}; - if (fnNtQueryInformationFile == nullptr) - fnNtQueryInformationFile = (pfnNtQueryInformationFile)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationFile"); - if (fnNtQueryInformationFile(get_native_fd().fd(), &io, &basic_info, sizeof(basic_info), 4)) { + auto status = GetFileInformationByHandleExStub(get_native_fd().fd(), FileBasicInfo, &basic_info, sizeof(basic_info)); + if (!status) { return OS_ERROR("Get FileStandardInfo failed"); } |