[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