Sweden-Number/dlls/advapi32/tests/eventlog.c

1175 lines
42 KiB
C

/*
* Unit tests for Event Logging functions
*
* Copyright (c) 2009 Paul Vriens
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winnt.h"
#include "winreg.h"
#include "sddl.h"
#include "wine/test.h"
static BOOL (WINAPI *pCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*);
static BOOL (WINAPI *pGetEventLogInformation)(HANDLE,DWORD,LPVOID,DWORD,LPDWORD);
static BOOL (WINAPI *pGetComputerNameExA)(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD);
static BOOL (WINAPI *pWow64DisableWow64FsRedirection)(PVOID *);
static BOOL (WINAPI *pWow64RevertWow64FsRedirection)(PVOID);
static void init_function_pointers(void)
{
HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
pCreateWellKnownSid = (void*)GetProcAddress(hadvapi32, "CreateWellKnownSid");
pGetEventLogInformation = (void*)GetProcAddress(hadvapi32, "GetEventLogInformation");
pGetComputerNameExA = (void*)GetProcAddress(hkernel32, "GetComputerNameExA");
pWow64DisableWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64DisableWow64FsRedirection");
pWow64RevertWow64FsRedirection = (void*)GetProcAddress(hkernel32, "Wow64RevertWow64FsRedirection");
}
static BOOL create_backup(const char *filename)
{
HANDLE handle;
DWORD rc, attribs;
DeleteFileA(filename);
handle = OpenEventLogA(NULL, "Application");
rc = BackupEventLogA(handle, filename);
if (!rc && GetLastError() == ERROR_PRIVILEGE_NOT_HELD)
{
skip("insufficient privileges to backup the eventlog\n");
CloseEventLog(handle);
return FALSE;
}
ok(rc, "BackupEventLogA failed, le=%u\n", GetLastError());
CloseEventLog(handle);
attribs = GetFileAttributesA(filename);
todo_wine
ok(attribs != INVALID_FILE_ATTRIBUTES, "Expected a backup file attribs=%#x le=%u\n", attribs, GetLastError());
return TRUE;
}
static void test_open_close(void)
{
HANDLE handle;
BOOL ret;
SetLastError(0xdeadbeef);
ret = CloseEventLog(NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE ||
GetLastError() == ERROR_NOACCESS, /* W2K */
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
handle = OpenEventLogA(NULL, NULL);
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
handle = OpenEventLogA("IDontExist", NULL);
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
handle = OpenEventLogA("IDontExist", "deadbeef");
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE ||
GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */
"Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError());
/* This one opens the Application log */
handle = OpenEventLogA(NULL, "deadbeef");
ok(handle != NULL, "Expected a handle\n");
ret = CloseEventLog(handle);
ok(ret, "Expected success\n");
/* Close a second time */
SetLastError(0xdeadbeef);
ret = CloseEventLog(handle);
todo_wine
{
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
}
/* Empty servername should be read as local server */
handle = OpenEventLogA("", "Application");
ok(handle != NULL, "Expected a handle\n");
CloseEventLog(handle);
handle = OpenEventLogA(NULL, "Application");
ok(handle != NULL, "Expected a handle\n");
CloseEventLog(handle);
}
static void test_info(void)
{
HANDLE handle;
BOOL ret;
DWORD needed;
BYTE buffer[2 * sizeof(EVENTLOG_FULL_INFORMATION)];
EVENTLOG_FULL_INFORMATION *efi = (void *)buffer;
if (!pGetEventLogInformation)
{
/* NT4 */
win_skip("GetEventLogInformation is not available\n");
return;
}
SetLastError(0xdeadbeef);
ret = pGetEventLogInformation(NULL, 1, NULL, 0, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_LEVEL, "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = pGetEventLogInformation(NULL, EVENTLOG_FULL_INFO, NULL, 0, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
handle = OpenEventLogA(NULL, "Application");
SetLastError(0xdeadbeef);
ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, NULL, 0, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, NULL, 0, &needed);
ok(!ret, "Expected failure\n");
ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, efi, 0, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == RPC_X_NULL_REF_POINTER, "Expected RPC_X_NULL_REF_POINTER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
needed = 0xdeadbeef;
efi->dwFull = 0xdeadbeef;
ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, efi, 0, &needed);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
ok(needed == sizeof(EVENTLOG_FULL_INFORMATION), "Expected sizeof(EVENTLOG_FULL_INFORMATION), got %d\n", needed);
ok(efi->dwFull == 0xdeadbeef, "Expected no change to the dwFull member\n");
/* Not that we care, but on success last error is set to ERROR_IO_PENDING */
efi->dwFull = 0xdeadbeef;
needed = sizeof(buffer);
ret = pGetEventLogInformation(handle, EVENTLOG_FULL_INFO, efi, needed, &needed);
ok(ret, "Expected success\n");
ok(needed == sizeof(EVENTLOG_FULL_INFORMATION), "Expected sizeof(EVENTLOG_FULL_INFORMATION), got %d\n", needed);
ok(efi->dwFull == 0 || efi->dwFull == 1, "Expected 0 (not full) or 1 (full), got %d\n", efi->dwFull);
CloseEventLog(handle);
}
static void test_count(void)
{
HANDLE handle;
BOOL ret;
DWORD count;
const char backup[] = "backup.evt";
SetLastError(0xdeadbeef);
ret = GetNumberOfEventLogRecords(NULL, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(NULL, &count);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
ok(count == 0xdeadbeef, "Expected count to stay unchanged\n");
handle = OpenEventLogA(NULL, "Application");
SetLastError(0xdeadbeef);
ret = GetNumberOfEventLogRecords(handle, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected success\n");
ok(count != 0xdeadbeef, "Expected the number of records\n");
CloseEventLog(handle);
/* Make a backup eventlog to work with */
if (create_backup(backup))
{
handle = OpenBackupEventLogA(NULL, backup);
todo_wine
ok(handle != NULL, "Expected a handle, le=%d\n", GetLastError());
/* Does GetNumberOfEventLogRecords work with backup eventlogs? */
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(handle, &count);
todo_wine
{
ok(ret, "Expected success\n");
ok(count != 0xdeadbeef, "Expected the number of records\n");
}
CloseEventLog(handle);
DeleteFileA(backup);
}
}
static void test_oldest(void)
{
HANDLE handle;
BOOL ret;
DWORD oldest;
const char backup[] = "backup.evt";
SetLastError(0xdeadbeef);
ret = GetOldestEventLogRecord(NULL, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
oldest = 0xdeadbeef;
ret = GetOldestEventLogRecord(NULL, &oldest);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
ok(oldest == 0xdeadbeef, "Expected oldest to stay unchanged\n");
handle = OpenEventLogA(NULL, "Application");
SetLastError(0xdeadbeef);
ret = GetOldestEventLogRecord(handle, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
oldest = 0xdeadbeef;
ret = GetOldestEventLogRecord(handle, &oldest);
ok(ret, "Expected success\n");
ok(oldest != 0xdeadbeef, "Expected the number of the oldest record\n");
CloseEventLog(handle);
/* Make a backup eventlog to work with */
if (create_backup(backup))
{
handle = OpenBackupEventLogA(NULL, backup);
todo_wine
ok(handle != NULL, "Expected a handle\n");
/* Does GetOldestEventLogRecord work with backup eventlogs? */
oldest = 0xdeadbeef;
ret = GetOldestEventLogRecord(handle, &oldest);
todo_wine
{
ok(ret, "Expected success\n");
ok(oldest != 0xdeadbeef, "Expected the number of the oldest record\n");
}
CloseEventLog(handle);
DeleteFileA(backup);
}
}
static void test_backup(void)
{
HANDLE handle;
BOOL ret;
const char backup[] = "backup.evt";
const char backup2[] = "backup2.evt";
SetLastError(0xdeadbeef);
ret = BackupEventLogA(NULL, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = BackupEventLogA(NULL, backup);
ok(!ret, "Expected failure\n");
ok(GetFileAttributesA(backup) == INVALID_FILE_ATTRIBUTES, "Expected no backup file\n");
handle = OpenEventLogA(NULL, "Application");
SetLastError(0xdeadbeef);
ret = BackupEventLogA(handle, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
ret = BackupEventLogA(handle, backup);
if (!ret && GetLastError() == ERROR_PRIVILEGE_NOT_HELD)
{
skip("insufficient privileges for backup tests\n");
CloseEventLog(handle);
return;
}
ok(ret, "Expected success\n");
todo_wine
ok(GetFileAttributesA(backup) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n");
/* Try to overwrite */
SetLastError(0xdeadbeef);
ret = BackupEventLogA(handle, backup);
todo_wine
{
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_ALREADY_EXISTS, "Expected ERROR_ALREADY_EXISTS, got %d\n", GetLastError());
}
CloseEventLog(handle);
/* Can we make a backup of a backup? */
handle = OpenBackupEventLogA(NULL, backup);
todo_wine
ok(handle != NULL, "Expected a handle\n");
ret = BackupEventLogA(handle, backup2);
todo_wine
{
ok(ret, "Expected success\n");
ok(GetFileAttributesA(backup2) != INVALID_FILE_ATTRIBUTES, "Expected a backup file\n");
}
CloseEventLog(handle);
DeleteFileA(backup);
DeleteFileA(backup2);
}
static void test_read(void)
{
HANDLE handle;
BOOL ret;
DWORD count, toread, read, needed;
void *buf;
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, 0, 0, NULL, 0, NULL, NULL);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
read = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, 0, 0, NULL, 0, &read, NULL);
ok(!ret, "Expected failure\n");
ok(read == 0xdeadbeef, "Expected 'read' parameter to remain unchanged\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
needed = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, 0, 0, NULL, 0, NULL, &needed);
ok(!ret, "Expected failure\n");
ok(needed == 0xdeadbeef, "Expected 'needed' parameter to remain unchanged\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* 'read' and 'needed' are only filled when the needed buffer size is passed back or when the call succeeds */
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, 0, 0, NULL, 0, &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, NULL, 0, NULL, NULL);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, NULL, 0, &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
buf = NULL;
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
SetLastError(0xdeadbeef);
ret = ReadEventLogA(NULL, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, buf);
handle = OpenEventLogA(NULL, "Application");
/* Show that we need the proper dwFlags with a (for the rest) proper call */
buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, 0, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ, 0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ | EVENTLOG_BACKWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEEK_READ | EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
todo_wine
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, buf);
/* First check if there are any records (in practice only on Wine: FIXME) */
count = 0;
GetNumberOfEventLogRecords(handle, &count);
if (!count)
{
skip("No records in the 'Application' log\n");
CloseEventLog(handle);
return;
}
/* Get the buffer size for the first record */
buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
read = needed = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
ok(!ret, "Expected failure\n");
ok(read == 0, "Expected no bytes read\n");
ok(needed > sizeof(EVENTLOGRECORD), "Expected the needed buffersize to be bigger than sizeof(EVENTLOGRECORD)\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Read the first record */
toread = needed;
buf = HeapReAlloc(GetProcessHeap(), 0, buf, toread);
read = needed = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, buf, toread, &read, &needed);
ok(ret, "Expected success\n");
ok(read == toread ||
broken(read < toread), /* NT4 wants a buffer size way bigger than just 1 record */
"Expected the requested size to be read\n");
ok(needed == 0, "Expected no extra bytes to be read\n");
HeapFree(GetProcessHeap(), 0, buf);
CloseEventLog(handle);
}
static void test_openbackup(void)
{
HANDLE handle, handle2, file;
DWORD written;
const char backup[] = "backup.evt";
const char text[] = "Just some text";
SetLastError(0xdeadbeef);
handle = OpenBackupEventLogA(NULL, NULL);
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
handle = OpenBackupEventLogA(NULL, "idontexist.evt");
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == ERROR_FILE_NOT_FOUND, "Expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
handle = OpenBackupEventLogA("IDontExist", NULL);
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
SetLastError(0xdeadbeef);
handle = OpenBackupEventLogA("IDontExist", "idontexist.evt");
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE ||
GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */
"Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError());
/* Make a backup eventlog to work with */
if (create_backup(backup))
{
/* FIXME: Wine stops here */
if (GetFileAttributesA(backup) == INVALID_FILE_ATTRIBUTES)
{
skip("We don't have a backup eventlog to work with\n");
return;
}
SetLastError(0xdeadbeef);
handle = OpenBackupEventLogA("IDontExist", backup);
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE ||
GetLastError() == RPC_S_INVALID_NET_ADDR, /* Some Vista and Win7 */
"Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError());
/* Empty servername should be read as local server */
handle = OpenBackupEventLogA("", backup);
ok(handle != NULL, "Expected a handle\n");
CloseEventLog(handle);
handle = OpenBackupEventLogA(NULL, backup);
ok(handle != NULL, "Expected a handle\n");
/* Can we open that same backup eventlog more than once? */
handle2 = OpenBackupEventLogA(NULL, backup);
ok(handle2 != NULL, "Expected a handle\n");
ok(handle2 != handle, "Didn't expect the same handle\n");
CloseEventLog(handle2);
CloseEventLog(handle);
DeleteFileA(backup);
}
/* Is there any content checking done? */
file = CreateFileA(backup, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
CloseHandle(file);
SetLastError(0xdeadbeef);
handle = OpenBackupEventLogA(NULL, backup);
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == ERROR_NOT_ENOUGH_MEMORY ||
GetLastError() == ERROR_EVENTLOG_FILE_CORRUPT, /* Vista and Win7 */
"Expected ERROR_NOT_ENOUGH_MEMORY, got %d\n", GetLastError());
CloseEventLog(handle);
DeleteFileA(backup);
file = CreateFileA(backup, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);
WriteFile(file, text, sizeof(text), &written, NULL);
CloseHandle(file);
SetLastError(0xdeadbeef);
handle = OpenBackupEventLogA(NULL, backup);
ok(handle == NULL, "Didn't expect a handle\n");
ok(GetLastError() == ERROR_EVENTLOG_FILE_CORRUPT, "Expected ERROR_EVENTLOG_FILE_CORRUPT, got %d\n", GetLastError());
CloseEventLog(handle);
DeleteFileA(backup);
}
static void test_clear(void)
{
HANDLE handle;
BOOL ret;
const char backup[] = "backup.evt";
const char backup2[] = "backup2.evt";
SetLastError(0xdeadbeef);
ret = ClearEventLogA(NULL, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
/* Make a backup eventlog to work with */
if (!create_backup(backup))
return;
SetLastError(0xdeadbeef);
ret = ClearEventLogA(NULL, backup);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
handle = OpenBackupEventLogA(NULL, backup);
todo_wine
ok(handle != NULL, "Expected a handle\n");
/* A real eventlog would fail with ERROR_ALREADY_EXISTS */
SetLastError(0xdeadbeef);
ret = ClearEventLogA(handle, backup);
ok(!ret, "Expected failure\n");
/* The eventlog service runs under an account that doesn't have the necessary
* permissions on the users home directory on a default Vista+ system.
*/
ok(GetLastError() == ERROR_INVALID_HANDLE ||
GetLastError() == ERROR_ACCESS_DENIED, /* Vista+ */
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
/* Show that ClearEventLog only works for real eventlogs. */
SetLastError(0xdeadbeef);
ret = ClearEventLogA(handle, backup2);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
ok(GetFileAttributesA(backup2) == INVALID_FILE_ATTRIBUTES, "Expected no backup file\n");
SetLastError(0xdeadbeef);
ret = ClearEventLogA(handle, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
CloseEventLog(handle);
todo_wine
ok(DeleteFileA(backup), "Could not delete the backup file\n");
}
static const char eventlogsvc[] = "SYSTEM\\CurrentControlSet\\Services\\Eventlog";
static const char eventlogname[] = "Wine";
static const char eventsources[][11] = { "WineSrc", "WineSrc1", "WineSrc20", "WineSrc300" };
static BOOL create_new_eventlog(void)
{
HKEY key, eventkey;
BOOL bret = FALSE;
LONG lret;
DWORD i;
/* First create our eventlog */
lret = RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key);
if (lret != ERROR_SUCCESS)
{
skip("Could not open the EventLog service registry key\n");
return FALSE;
}
lret = RegCreateKeyA(key, eventlogname, &eventkey);
if (lret != ERROR_SUCCESS)
{
skip("Could not create the eventlog '%s' registry key\n", eventlogname);
goto cleanup;
}
/* Create some event sources, the registry value 'Sources' is updated automatically */
for (i = 0; i < sizeof(eventsources)/sizeof(eventsources[0]); i++)
{
HKEY srckey;
lret = RegCreateKeyA(eventkey, eventsources[i], &srckey);
if (lret != ERROR_SUCCESS)
{
skip("Could not create the eventsource '%s' registry key\n", eventsources[i]);
goto cleanup;
}
RegFlushKey(srckey);
RegCloseKey(srckey);
}
bret = TRUE;
/* The flushing of the registry (here and above) gives us some assurance
* that we are not to quickly writing events as 'Sources' could still be
* not updated.
*/
RegFlushKey(eventkey);
cleanup:
RegCloseKey(eventkey);
RegCloseKey(key);
return bret;
}
static const char *one_string[] = { "First string" };
static const char *two_strings[] = { "First string", "Second string" };
static const struct
{
const char *evt_src;
WORD evt_type;
WORD evt_cat;
DWORD evt_id;
BOOL evt_sid;
WORD evt_numstrings;
const char **evt_strings;
} read_write [] =
{
{ eventlogname, EVENTLOG_INFORMATION_TYPE, 1, 1, FALSE, 1, one_string },
{ eventsources[0], EVENTLOG_WARNING_TYPE, 1, 2, FALSE, 0, NULL },
{ eventsources[1], EVENTLOG_AUDIT_FAILURE, 1, 3, FALSE, 2, two_strings },
{ eventsources[2], EVENTLOG_ERROR_TYPE, 1, 4, FALSE, 0, NULL },
{ eventsources[3], EVENTLOG_WARNING_TYPE, 1, 5, FALSE, 1, one_string },
{ eventlogname, EVENTLOG_SUCCESS, 2, 6, TRUE, 2, two_strings },
{ eventsources[0], EVENTLOG_AUDIT_FAILURE, 2, 7, TRUE, 0, NULL },
{ eventsources[1], EVENTLOG_AUDIT_SUCCESS, 2, 8, TRUE, 2, two_strings },
{ eventsources[2], EVENTLOG_WARNING_TYPE, 2, 9, TRUE, 0, NULL },
{ eventsources[3], EVENTLOG_ERROR_TYPE, 2, 10, TRUE, 1, one_string }
};
static void test_readwrite(void)
{
HANDLE handle;
PSID user;
DWORD sidsize, count;
BOOL ret, sidavailable;
BOOL on_vista = FALSE; /* Used to indicate Vista, W2K8 or Win7 */
DWORD i;
char *localcomputer = NULL;
DWORD size;
if (pCreateWellKnownSid)
{
sidsize = SECURITY_MAX_SID_SIZE;
user = HeapAlloc(GetProcessHeap(), 0, sidsize);
SetLastError(0xdeadbeef);
pCreateWellKnownSid(WinInteractiveSid, NULL, user, &sidsize);
sidavailable = TRUE;
}
else
{
win_skip("Skipping some SID related tests\n");
sidavailable = FALSE;
user = NULL;
}
/* Write an event with an incorrect event type. This will fail on Windows 7
* but succeed on all others, hence it's not part of the struct.
*/
handle = OpenEventLogA(NULL, eventlogname);
if (!handle)
{
/* Intermittently seen on NT4 when tests are run immediately after boot */
win_skip("Could not get a handle to the eventlog\n");
goto cleanup;
}
count = 0xdeadbeef;
GetNumberOfEventLogRecords(handle, &count);
if (count != 0)
{
/* Needed for W2K3 without a service pack */
win_skip("We most likely opened the Application eventlog\n");
CloseEventLog(handle);
Sleep(2000);
handle = OpenEventLogA(NULL, eventlogname);
count = 0xdeadbeef;
GetNumberOfEventLogRecords(handle, &count);
if (count != 0)
{
win_skip("We didn't open our new eventlog\n");
CloseEventLog(handle);
goto cleanup;
}
}
SetLastError(0xdeadbeef);
ret = ReportEventA(handle, 0x20, 0, 0, NULL, 0, 0, NULL, NULL);
if (!ret && GetLastError() == ERROR_CRC)
{
win_skip("Win7 fails when using incorrect event types\n");
ret = ReportEventA(handle, 0, 0, 0, NULL, 0, 0, NULL, NULL);
ok(ret, "Expected success : %d\n", GetLastError());
}
else
{
void *buf;
DWORD read, needed = 0;
EVENTLOGRECORD *record;
ok(ret, "Expected success : %d\n", GetLastError());
/* Needed to catch earlier Vista (with no ServicePack for example) */
buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
if (!(ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed)) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
buf = HeapReAlloc(GetProcessHeap(), 0, buf, needed);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, needed, &read, &needed);
}
if (ret)
{
record = (EVENTLOGRECORD *)buf;
/* Vista and W2K8 return EVENTLOG_SUCCESS, Windows versions before return
* the written eventtype (0x20 in this case).
*/
if (record->EventType == EVENTLOG_SUCCESS)
on_vista = TRUE;
}
HeapFree(GetProcessHeap(), 0, buf);
}
/* This will clear the eventlog. The record numbering for new
* events however differs on Vista SP1+. Before Vista the first
* event would be numbered 1, on Vista SP1+ it's higher as we already
* had at least one event (more in case of multiple test runs without
* a reboot).
*/
ClearEventLogA(handle, NULL);
CloseEventLog(handle);
/* Write a bunch of events while using different event sources */
for (i = 0; i < sizeof(read_write)/sizeof(read_write[0]); i++)
{
DWORD oldest;
BOOL run_sidtests = read_write[i].evt_sid & sidavailable;
/* We don't need to use RegisterEventSource to report events */
if (i % 2)
handle = OpenEventLogA(NULL, read_write[i].evt_src);
else
handle = RegisterEventSourceA(NULL, read_write[i].evt_src);
ok(handle != NULL, "Expected a handle\n");
SetLastError(0xdeadbeef);
ret = ReportEventA(handle, read_write[i].evt_type, read_write[i].evt_cat,
read_write[i].evt_id, run_sidtests ? user : NULL,
read_write[i].evt_numstrings, 0, read_write[i].evt_strings, NULL);
ok(ret, "Expected ReportEvent success : %d\n", GetLastError());
count = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected GetNumberOfEventLogRecords success : %d\n", GetLastError());
todo_wine
ok(count == (i + 1), "Expected %d records, got %d\n", i + 1, count);
oldest = 0xdeadbeef;
ret = GetOldestEventLogRecord(handle, &oldest);
ok(ret, "Expected GetOldestEventLogRecord success : %d\n", GetLastError());
todo_wine
ok(oldest == 1 ||
(oldest > 1 && oldest != 0xdeadbeef), /* Vista SP1+, W2K8 and Win7 */
"Expected oldest to be 1 or higher, got %d\n", oldest);
if (oldest > 1 && oldest != 0xdeadbeef)
on_vista = TRUE;
SetLastError(0xdeadbeef);
if (i % 2)
ret = CloseEventLog(handle);
else
ret = DeregisterEventSource(handle);
ok(ret, "Expected success : %d\n", GetLastError());
}
handle = OpenEventLogA(NULL, eventlogname);
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected success\n");
todo_wine
ok(count == i, "Expected %d records, got %d\n", i, count);
CloseEventLog(handle);
if (count == 0)
{
skip("No events were written to the eventlog\n");
goto cleanup;
}
/* Report only once */
if (on_vista)
skip("There is no DWORD alignment enforced for UserSid on Vista, W2K8 or Win7\n");
if (on_vista && pGetComputerNameExA)
{
/* New Vista+ behavior */
size = 0;
SetLastError(0xdeadbeef);
pGetComputerNameExA(ComputerNameDnsFullyQualified, NULL, &size);
localcomputer = HeapAlloc(GetProcessHeap(), 0, size);
pGetComputerNameExA(ComputerNameDnsFullyQualified, localcomputer, &size);
}
else
{
size = MAX_COMPUTERNAME_LENGTH + 1;
localcomputer = HeapAlloc(GetProcessHeap(), 0, size);
GetComputerNameA(localcomputer, &size);
}
/* Read all events from our created eventlog, one by one */
handle = OpenEventLogA(NULL, eventlogname);
i = 0;
for (;;)
{
void *buf;
DWORD read, needed;
EVENTLOGRECORD *record;
char *sourcename, *computername;
int k;
char *ptr;
BOOL run_sidtests = read_write[i].evt_sid & sidavailable;
buf = HeapAlloc(GetProcessHeap(), 0, sizeof(EVENTLOGRECORD));
SetLastError(0xdeadbeef);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, sizeof(EVENTLOGRECORD), &read, &needed);
if (!ret && GetLastError() == ERROR_HANDLE_EOF)
{
HeapFree(GetProcessHeap(), 0, buf);
break;
}
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INVALID_PARAMETER, got %d\n",GetLastError());
buf = HeapReAlloc(GetProcessHeap(), 0, buf, needed);
ret = ReadEventLogA(handle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0, buf, needed, &read, &needed);
ok(ret, "Expected success: %d\n", GetLastError());
record = (EVENTLOGRECORD *)buf;
ok(record->Length == read,
"Expected %d, got %d\n", read, record->Length);
ok(record->Reserved == 0x654c664c,
"Expected 0x654c664c, got %d\n", record->Reserved);
ok(record->RecordNumber == i + 1 ||
(on_vista && (record->RecordNumber > i + 1)),
"Expected %d or higher, got %d\n", i + 1, record->RecordNumber);
ok(record->EventID == read_write[i].evt_id,
"Expected %d, got %d\n", read_write[i].evt_id, record->EventID);
ok(record->EventType == read_write[i].evt_type,
"Expected %d, got %d\n", read_write[i].evt_type, record->EventType);
ok(record->NumStrings == read_write[i].evt_numstrings,
"Expected %d, got %d\n", read_write[i].evt_numstrings, record->NumStrings);
ok(record->EventCategory == read_write[i].evt_cat,
"Expected %d, got %d\n", read_write[i].evt_cat, record->EventCategory);
sourcename = (char *)((BYTE *)buf + sizeof(EVENTLOGRECORD));
ok(!lstrcmpA(sourcename, read_write[i].evt_src), "Expected '%s', got '%s'\n",
read_write[i].evt_src, sourcename);
computername = (char *)((BYTE *)buf + sizeof(EVENTLOGRECORD) + lstrlenA(sourcename) + 1);
ok(!lstrcmpiA(computername, localcomputer), "Expected '%s', got '%s'\n",
localcomputer, computername);
/* Before Vista, UserSid was aligned on a DWORD boundary. Next to that if
* no padding was actually required a 0 DWORD was still used for padding. No
* application should be relying on the padding as we are working with offsets
* anyway.
*/
if (!on_vista)
{
DWORD calculated_sidoffset = sizeof(EVENTLOGRECORD) + lstrlenA(sourcename) + 1 + lstrlenA(computername) + 1;
/* We are already DWORD aligned, there should still be some padding */
if ((((UINT_PTR)buf + calculated_sidoffset) % sizeof(DWORD)) == 0)
ok(*(DWORD *)((BYTE *)buf + calculated_sidoffset) == 0, "Expected 0\n");
ok((((UINT_PTR)buf + record->UserSidOffset) % sizeof(DWORD)) == 0, "Expected DWORD alignment\n");
}
if (run_sidtests)
{
ok(record->UserSidLength == sidsize, "Expected %d, got %d\n", sidsize, record->UserSidLength);
}
else
{
ok(record->StringOffset == record->UserSidOffset, "Expected offsets to be the same\n");
ok(record->UserSidLength == 0, "Expected 0, got %d\n", record->UserSidLength);
}
ok(record->DataLength == 0, "Expected 0, got %d\n", record->DataLength);
ptr = (char *)((BYTE *)buf + record->StringOffset);
for (k = 0; k < record->NumStrings; k++)
{
ok(!lstrcmpA(ptr, two_strings[k]), "Expected '%s', got '%s'\n", two_strings[k], ptr);
ptr += lstrlenA(ptr) + 1;
}
ok(record->Length == *(DWORD *)((BYTE *)buf + record->Length - sizeof(DWORD)),
"Expected the closing DWORD to contain the length of the record\n");
HeapFree(GetProcessHeap(), 0, buf);
i++;
}
CloseEventLog(handle);
/* Test clearing a real eventlog */
handle = OpenEventLogA(NULL, eventlogname);
SetLastError(0xdeadbeef);
ret = ClearEventLogA(handle, NULL);
ok(ret, "Expected success\n");
count = 0xdeadbeef;
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected success\n");
ok(count == 0, "Expected an empty eventlog, got %d records\n", count);
CloseEventLog(handle);
cleanup:
HeapFree(GetProcessHeap(), 0, localcomputer);
HeapFree(GetProcessHeap(), 0, user);
}
/* Before Vista:
*
* Creating an eventlog on Windows (via the registry) automatically leads
* to creation of a REG_MULTI_SZ named 'Sources'. This value lists all the
* potential event sources for this eventlog. 'Sources' is automatically
* updated when a new key (aka event source) is created.
*
* Although the updating of registry keys is almost instantaneously, we
* check it after some other tests to assure we are not querying the
* registry or file system to quickly.
*
* NT4 and higher:
*
* The eventlog file itself is also automatically created, even before we
* start writing events.
*/
static char eventlogfile[MAX_PATH];
static void test_autocreation(void)
{
HKEY key, eventkey;
DWORD type, size;
LONG ret;
int i;
char *p;
char sources[sizeof(eventsources)];
char sysdir[MAX_PATH];
void *redir = 0;
RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key);
RegOpenKeyA(key, eventlogname, &eventkey);
size = sizeof(sources);
sources[0] = 0;
ret = RegQueryValueExA(eventkey, "Sources", NULL, &type, (LPBYTE)sources, &size);
if (ret == ERROR_SUCCESS)
{
char sources_verify[sizeof(eventsources)];
ok(type == REG_MULTI_SZ, "Expected a REG_MULTI_SZ, got %d\n", type);
/* Build the expected string */
memset(sources_verify, 0, sizeof(sources_verify));
p = sources_verify;
for (i = sizeof(eventsources)/sizeof(eventsources[0]); i > 0; i--)
{
lstrcpyA(p, eventsources[i - 1]);
p += (lstrlenA(eventsources[i - 1]) + 1);
}
lstrcpyA(p, eventlogname);
ok(!memcmp(sources, sources_verify, size),
"Expected a correct 'Sources' value (size : %d)\n", size);
}
RegCloseKey(eventkey);
RegCloseKey(key);
/* The directory that holds the eventlog files could be redirected */
if (pWow64DisableWow64FsRedirection)
pWow64DisableWow64FsRedirection(&redir);
/* On Windows we also automatically get an eventlog file */
GetSystemDirectoryA(sysdir, sizeof(sysdir));
/* NT4 - W2K3 */
lstrcpyA(eventlogfile, sysdir);
lstrcatA(eventlogfile, "\\config\\");
lstrcatA(eventlogfile, eventlogname);
lstrcatA(eventlogfile, ".evt");
if (GetFileAttributesA(eventlogfile) == INVALID_FILE_ATTRIBUTES)
{
/* Vista+ */
lstrcpyA(eventlogfile, sysdir);
lstrcatA(eventlogfile, "\\winevt\\Logs\\");
lstrcatA(eventlogfile, eventlogname);
lstrcatA(eventlogfile, ".evtx");
}
todo_wine
ok(GetFileAttributesA(eventlogfile) != INVALID_FILE_ATTRIBUTES,
"Expected an eventlog file\n");
if (pWow64RevertWow64FsRedirection)
pWow64RevertWow64FsRedirection(redir);
}
static void cleanup_eventlog(void)
{
BOOL bret;
LONG lret;
HKEY key;
DWORD i;
char winesvc[MAX_PATH];
/* Delete the registry tree */
lstrcpyA(winesvc, eventlogsvc);
lstrcatA(winesvc, "\\");
lstrcatA(winesvc, eventlogname);
RegOpenKeyA(HKEY_LOCAL_MACHINE, winesvc, &key);
for (i = 0; i < sizeof(eventsources)/sizeof(eventsources[0]); i++)
RegDeleteKeyA(key, eventsources[i]);
RegDeleteValueA(key, "Sources");
RegCloseKey(key);
lret = RegDeleteKeyA(HKEY_LOCAL_MACHINE, winesvc);
ok(lret == ERROR_SUCCESS, "Could not delete the registry tree : %d\n", lret);
/* A handle to the eventlog is locked by services.exe. We can only
* delete the eventlog file after reboot.
*/
bret = MoveFileExA(eventlogfile, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
ok(bret, "Expected MoveFileEx to succeed: %d\n", GetLastError());
}
START_TEST(eventlog)
{
SetLastError(0xdeadbeef);
CloseEventLog(NULL);
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
win_skip("Event log functions are not implemented\n");
return;
}
init_function_pointers();
/* Parameters only */
test_open_close();
test_info();
test_count();
test_oldest();
test_backup();
test_openbackup();
test_read();
test_clear();
/* Functional tests */
if (create_new_eventlog())
{
test_readwrite();
test_autocreation();
cleanup_eventlog();
}
}