[PATCH 3/3] Add tests for reading and writing to a real eventlog
Paul Vriens
Paul.Vriens.Wine at gmail.com
Fri Nov 13 06:24:11 CST 2009
---
dlls/advapi32/tests/eventlog.c | 423 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 423 insertions(+), 0 deletions(-)
diff --git a/dlls/advapi32/tests/eventlog.c b/dlls/advapi32/tests/eventlog.c
index e5b0370..c989d4a 100644
--- a/dlls/advapi32/tests/eventlog.c
+++ b/dlls/advapi32/tests/eventlog.c
@@ -24,15 +24,19 @@
#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 void init_function_pointers(void)
{
HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
+ pCreateWellKnownSid = (void*)GetProcAddress(hadvapi32, "CreateWellKnownSid");
pGetEventLogInformation = (void*)GetProcAddress(hadvapi32, "GetEventLogInformation");
}
@@ -611,6 +615,417 @@ static void test_clear(void)
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;
+ int i;
+
+ /* First create our eventlog */
+ lret = RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key);
+ /* FIXME: Wine stops here */
+ 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 or higher */
+ int i;
+ char localcomputer[MAX_COMPUTERNAME_LENGTH + 1];
+ DWORD len = sizeof(localcomputer);
+
+ 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;
+ }
+
+ GetComputerNameA(localcomputer, &len);
+
+ /* 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);
+
+ SetLastError(0xdeadbeef);
+ ret = ReportEvent(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 = ReportEvent(handle, 0, 0, 0, NULL, 0, 0, NULL, NULL);
+ }
+ ok(ret, "Expected success : %d\n", GetLastError());
+
+ /* This will clear the eventlog. The record numbering for new
+ * events however differs on Vista+. Before Vista the first
+ * event would be numbered 1, on Vista+ it's now 2 as we already
+ * had one event.
+ */
+ 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 = ReportEvent(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);
+
+ count = 0xdeadbeef;
+ ret = GetNumberOfEventLogRecords(handle, &count);
+ ok(ret, "Expected success\n");
+ ok(count == (i + 1), "Expected %d records, got %d\n", i + 1, count);
+
+ oldest = 0xdeadbeef;
+ ret = GetOldestEventLogRecord(handle, &oldest);
+ ok(ret, "Expected success\n");
+ ok(oldest == 1 ||
+ oldest == 2, /* Vista+ */
+ "Expected oldest to be 1 or 2, got %d\n", oldest);
+ if (oldest == 2)
+ on_vista = TRUE;
+
+ 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");
+ 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");
+ return;
+ }
+
+ /* Report only once */
+ if (on_vista)
+ skip("There is no DWORD alignment for UserSid on Vista or higher\n");
+
+ /* 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 + 2)),
+ "Expected %d or %d, got %d\n", i + 1, i + 2, 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_PTR *)((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_PTR *)((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);
+
+ HeapFree(GetProcessHeap(), 0, user);
+
+ /* 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);
+}
+
+/* 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];
+
+ 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\n");
+ }
+
+ RegCloseKey(eventkey);
+ RegCloseKey(key);
+
+ /* 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");
+ }
+
+ ok(GetFileAttributesA(eventlogfile) != INVALID_FILE_ATTRIBUTES,
+ "Expected an eventlog file\n");
+}
+
+static void cleanup_eventlog(void)
+{
+ BOOL bret;
+ LONG lret;
+ HKEY key;
+ int 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);
+ todo_wine
+ 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);
+ todo_wine
+ ok(bret, "Expected MoveFileEx to succeed: %d\n", GetLastError());
+}
+
START_TEST(eventlog)
{
SetLastError(0xdeadbeef);
@@ -632,4 +1047,12 @@ START_TEST(eventlog)
test_openbackup();
test_read();
test_clear();
+
+ /* Functional tests */
+ if (create_new_eventlog())
+ {
+ test_readwrite();
+ test_autocreation();
+ }
+ cleanup_eventlog();
}
--
1.6.2.5
--------------080908090103000903090904--
More information about the wine-patches
mailing list