#include #include #include #include #include "debug.h" #include "wine/compiler.h" #include "wine/debug.h" #define FILE_ATTRIBUTE_VALID_FLAGS 0x00007fb7 static UINT get_nt_file_options(DWORD attributes) { UINT options = 0; if (attributes & FILE_FLAG_BACKUP_SEMANTICS) options |= FILE_OPEN_FOR_BACKUP_INTENT; else options |= FILE_NON_DIRECTORY_FILE; if (attributes & FILE_FLAG_DELETE_ON_CLOSE) options |= FILE_DELETE_ON_CLOSE; if (attributes & FILE_FLAG_NO_BUFFERING) options |= FILE_NO_INTERMEDIATE_BUFFERING; if (!(attributes & FILE_FLAG_OVERLAPPED)) options |= FILE_SYNCHRONOUS_IO_NONALERT; if (attributes & FILE_FLAG_RANDOM_ACCESS) options |= FILE_RANDOM_ACCESS; if (attributes & FILE_FLAG_SEQUENTIAL_SCAN) options |= FILE_SEQUENTIAL_ONLY; if (attributes & FILE_FLAG_WRITE_THROUGH) options |= FILE_WRITE_THROUGH; return options; } HANDLE WINAPI CreateFileW(LPCWSTR filename, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template) { UNICODE_STRING filenameU; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK io; HANDLE ret; static const UINT nt_disposition[5] = { FILE_CREATE, FILE_OVERWRITE_IF, FILE_OPEN, FILE_OPEN_IF, FILE_OVERWRITE }; if (!RtlDosPathNameToNtPathName_U(filename, &filenameU, NULL, NULL)) { return INVALID_HANDLE_VALUE; } if (attributes & FILE_FLAG_DELETE_ON_CLOSE) access |= DELETE; InitializeObjectAttributes(&attr, &filenameU, OBJ_CASE_INSENSITIVE, 0, NULL); NTSTATUS status = NtCreateFile(&ret, access | GENERIC_READ | SYNCHRONIZE, &attr, &io, NULL, attributes & FILE_ATTRIBUTE_VALID_FLAGS, sharing, nt_disposition[creation - CREATE_NEW], get_nt_file_options(attributes), NULL, 0); RtlFreeUnicodeString(&filenameU); return status ? INVALID_HANDLE_VALUE : ret; } HANDLE WINAPI CreateFileA(LPCSTR name, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template) { UNICODE_STRING nameU; RtlCreateUnicodeStringFromAsciiz(&nameU, name); HANDLE handle = CreateFileW(nameU.Buffer, access, sharing, sa, creation, attributes, template); RtlFreeUnicodeString(&nameU); return handle; } BOOL WINAPI CloseHandle(HANDLE handle) { return !NtClose(handle); } DWORD WINAPI GetEnvironmentVariableA(LPCSTR name, LPSTR value, DWORD size) { UNICODE_STRING nameU, valueU; PWSTR valueW; NTSTATUS status; DWORD len, ret; if (!(valueW = RtlAllocateHeap(GetProcessHeap(), 0, size * sizeof(WCHAR)))) return 0; RtlCreateUnicodeStringFromAsciiz(&nameU, name); valueU.Length = 0; valueU.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR); valueU.Buffer = valueW; status = RtlQueryEnvironmentVariable_U(NULL, &nameU, &valueU); len = valueU.Length / sizeof(WCHAR); if (status == STATUS_BUFFER_TOO_SMALL) ret = len + 1; else if (status) ret = 0; else if (!size) ret = len + 1; else { if (len) RtlUnicodeToMultiByteN(value, size, &ret, valueW, len * sizeof(WCHAR)); } RtlFreeUnicodeString(&nameU); RtlFreeHeap(GetProcessHeap(), 0, valueW); return ret; } DWORD WINAPI GetFileAttributesW(LPCWSTR name) { FILE_BASIC_INFORMATION info; UNICODE_STRING nameU; OBJECT_ATTRIBUTES attr; NTSTATUS status; if (!RtlDosPathNameToNtPathName_U(name, &nameU, NULL, NULL)) { return INVALID_FILE_ATTRIBUTES; } InitializeObjectAttributes(&attr, &nameU, OBJ_CASE_INSENSITIVE, 0, NULL); status = NtQueryAttributesFile(&attr, &info); RtlFreeUnicodeString(&nameU); if (status == STATUS_SUCCESS) return info.FileAttributes; if (RtlIsDosDeviceName_U(name)) return FILE_ATTRIBUTE_ARCHIVE; return INVALID_FILE_ATTRIBUTES; } DWORD WINAPI GetFileAttributesA(LPCSTR name) { UNICODE_STRING nameU; RtlCreateUnicodeStringFromAsciiz(&nameU, name); DWORD ret = GetFileAttributesW(nameU.Buffer); RtlFreeUnicodeString(&nameU); return ret; } HANDLE WINAPI GetProcessHeap(void) { return ((HANDLE**)NtCurrentTeb())[12][6]; } DWORD WINAPI GetModuleFileNameW(HMODULE module, LPWSTR filename, DWORD size) { ULONG len = 0; UNICODE_STRING filenameU; NTSTATUS status; filenameU.Buffer = filename; filenameU.MaximumLength = min(size, UNICODE_STRING_MAX_CHARS) * sizeof(WCHAR); status = LdrGetDllFullName(module, &filenameU); if (!status || status == STATUS_BUFFER_TOO_SMALL) len = filenameU.Length / sizeof(WCHAR); return len; } DWORD WINAPI GetModuleFileNameA(HMODULE module, LPSTR filename, DWORD size) { LPWSTR filenameW = RtlAllocateHeap(GetProcessHeap(), 0, size * sizeof(WCHAR)); DWORD len, ret = 0; if (!filenameW) return 0; if ((len = GetModuleFileNameW(module, filenameW, size))) { RtlUnicodeToMultiByteN(filename, size, &ret, filenameW, len * sizeof(WCHAR)); if (ret < size) filename[ret] = 0; } RtlFreeHeap(GetProcessHeap(), 0, filenameW); return ret; } BOOL WINAPI ReadFile(HANDLE file, LPVOID buffer, DWORD count, LPDWORD result, LPOVERLAPPED overlapped) { LARGE_INTEGER offset; PLARGE_INTEGER poffset = NULL; IO_STATUS_BLOCK iosb; PIO_STATUS_BLOCK io_status = &iosb; HANDLE event = 0; NTSTATUS status; LPVOID cvalue = NULL; if (result) *result = 0; if (overlapped) { printf_log(LOG_NONE, "unimplemented overlapped in ReadFile\n"); return FALSE; } else io_status->Information = 0; io_status->Status = STATUS_PENDING; status = NtReadFile(file, event, NULL, cvalue, io_status, buffer, count, poffset, NULL); if (status == STATUS_PENDING && !overlapped) { printf_log(LOG_NONE, "unimplemented pending in ReadFile\n"); } if (result) *result = overlapped && status ? 0 : io_status->Information; if (status == STATUS_END_OF_FILE) { if (overlapped != NULL) { return FALSE; } } else if (status && status != STATUS_TIMEOUT) { return FALSE; } return TRUE; } static void fillSystemInfo(SYSTEM_INFO* si, const SYSTEM_BASIC_INFORMATION__* basic_info, const SYSTEM_CPU_INFORMATION* cpu_info) { si->wProcessorArchitecture = cpu_info->ProcessorArchitecture; si->wReserved = 0; si->dwPageSize = basic_info->PageSize; si->lpMinimumApplicationAddress = basic_info->LowestUserAddress; si->lpMaximumApplicationAddress = basic_info->HighestUserAddress; si->dwActiveProcessorMask = basic_info->ActiveProcessorsAffinityMask; si->dwNumberOfProcessors = basic_info->NumberOfProcessors; si->dwAllocationGranularity = basic_info->AllocationGranularity; si->wProcessorLevel = cpu_info->ProcessorLevel; si->wProcessorRevision = cpu_info->ProcessorRevision; switch (cpu_info->ProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_ARM64: si->dwProcessorType = 0; break; default: printf_log(LOG_NONE, "Unknown processor architecture %x\n", cpu_info->ProcessorArchitecture); si->dwProcessorType = 0; break; } } void WINAPI GetSystemInfo(SYSTEM_INFO* si) { SYSTEM_BASIC_INFORMATION__ basic_info; SYSTEM_CPU_INFORMATION cpu_info; if (NtQuerySystemInformation(0 /* SystemBasicInformation */, &basic_info, sizeof(basic_info), NULL) || NtQuerySystemInformation(1 /* SystemCpuInformation */, &cpu_info, sizeof(cpu_info), NULL)) return; fillSystemInfo(si, &basic_info, &cpu_info); } BOOL WINAPI IsProcessorFeaturePresent(DWORD feature) { return RtlIsProcessorFeaturePresent(feature); } LSTATUS WINAPI RegOpenKeyExA(HKEY hkey, LPCSTR name, DWORD options, REGSAM access, PHKEY retkey) { if (hkey != HKEY_LOCAL_MACHINE) { printf_log(LOG_NONE, "Unsupported registry key %p\n", hkey); return ERROR_INVALID_HANDLE; } UNICODE_STRING rootkeyU; UNICODE_STRING nameU; OBJECT_ATTRIBUTES attr; NTSTATUS status; HANDLE handle; RtlInitUnicodeString(&rootkeyU, L"\\Registry\\Machine"); InitializeObjectAttributes(&attr, &rootkeyU, OBJ_CASE_INSENSITIVE, 0, NULL); if (NtOpenKey(&handle, access, &attr)) return RtlNtStatusToDosError(status); RtlCreateUnicodeStringFromAsciiz(&nameU, name); InitializeObjectAttributes(&attr, &nameU, OBJ_CASE_INSENSITIVE, handle, NULL); status = NtOpenKey((HANDLE*)retkey, access, &attr); RtlFreeUnicodeString(&nameU); NtClose(handle); return RtlNtStatusToDosError(status); } LSTATUS WINAPI RegQueryValueExA(HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count) { NTSTATUS status; ANSI_STRING nameA; UNICODE_STRING nameW; DWORD total_size, datalen = 0; char buffer[256]; KEY_VALUE_PARTIAL_INFORMATION* info = (KEY_VALUE_PARTIAL_INFORMATION*)buffer; static const int info_size = offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data); if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER; if (count) datalen = *count; if (!data && count) *count = 0; RtlInitAnsiString(&nameA, name); if ((status = RtlAnsiStringToUnicodeString(&nameW, &nameA, TRUE))) return RtlNtStatusToDosError(status); status = NtQueryValueKey(hkey, &nameW, KeyValuePartialInformation, buffer, sizeof(buffer), &total_size); if (status) { RtlFreeUnicodeString(&nameW); return RtlNtStatusToDosError(status); } if (data) { if (total_size - info_size > datalen) status = STATUS_BUFFER_OVERFLOW; else memcpy(data, buffer + info_size, total_size - info_size); } else status = STATUS_SUCCESS; if (type) *type = info->Type; if (count) *count = total_size - info_size; RtlFreeUnicodeString(&nameW); return RtlNtStatusToDosError(status); } LSTATUS WINAPI RegCloseKey(HKEY hkey) { if (!hkey) return ERROR_INVALID_HANDLE; return RtlNtStatusToDosError(NtClose(hkey)); }