Author: tfaber
Date: Sat Sep 5 11:49:54 2015
New Revision: 69022
URL:
http://svn.reactos.org/svn/reactos?rev=69022&view=rev
Log:
[NTOS:PS]
- Implement NtApphelpCacheControl. Patch by Mark Jansen
CORE-9914 #resolve
Added:
trunk/reactos/ntoskrnl/ps/apphelp.c (with props)
trunk/rostests/apitests/ntdll/NtApphelpCacheControl.c (with props)
Modified:
trunk/reactos/boot/bootdata/hivesys.inf
trunk/reactos/ntoskrnl/include/internal/ps.h
trunk/reactos/ntoskrnl/io/iomgr/iomgr.c
trunk/reactos/ntoskrnl/ntos.cmake
trunk/reactos/ntoskrnl/po/poshtdwn.c
trunk/reactos/ntoskrnl/ps/psmgr.c
trunk/rostests/apitests/ntdll/CMakeLists.txt
trunk/rostests/apitests/ntdll/testlist.c
Modified: trunk/reactos/boot/bootdata/hivesys.inf
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/boot/bootdata/hivesys.inf?…
==============================================================================
--- trunk/reactos/boot/bootdata/hivesys.inf [iso-8859-1] (original)
+++ trunk/reactos/boot/bootdata/hivesys.inf [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -1280,6 +1280,9 @@
HKLM,"SYSTEM\CurrentControlSet\Control\Session
Manager","ObjectDirectories",0x00010000, \
"\Windows", \
"\RPC Control"
+# This is an empty app compat cache
+HKLM,"SYSTEM\CurrentControlSet\Control\Session
Manager\AppCompatCache","AppCompatCache", 0x00000001, \
+ fe,0f,dc,ba,00,00,00,00
; DOS devices
HKLM,"SYSTEM\CurrentControlSet\Control\Session Manager\DOS
Devices","AUX",0x00000000,"\DosDevices\COM1"
Modified: trunk/reactos/ntoskrnl/include/internal/ps.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ps.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/ps.h [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -411,6 +411,18 @@
BOOLEAN
NTAPI
PspIsProcessExiting(IN PEPROCESS Process);
+
+//
+// Apphelp functions
+//
+NTSTATUS
+NTAPI
+INIT_FUNCTION
+ApphelpCacheInitialize(VOID);
+
+VOID
+NTAPI
+ApphelpCacheShutdown(VOID);
//
// Global data inside the Process Manager
Modified: trunk/reactos/ntoskrnl/io/iomgr/iomgr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/iomgr.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/iomgr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/iomgr.c [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -531,6 +531,9 @@
/* Initialize PnP manager */
IopInitializePlugPlayServices();
+ /* Initialize SHIM engine */
+ ApphelpCacheInitialize();
+
/* Initialize WMI */
WmiInitialize();
Modified: trunk/reactos/ntoskrnl/ntos.cmake
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ntos.cmake?rev=69…
==============================================================================
--- trunk/reactos/ntoskrnl/ntos.cmake [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ntos.cmake [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -248,6 +248,7 @@
${REACTOS_SOURCE_DIR}/ntoskrnl/ps/job.c
${REACTOS_SOURCE_DIR}/ntoskrnl/ps/kill.c
${REACTOS_SOURCE_DIR}/ntoskrnl/ps/process.c
+ ${REACTOS_SOURCE_DIR}/ntoskrnl/ps/apphelp.c
${REACTOS_SOURCE_DIR}/ntoskrnl/ps/psmgr.c
${REACTOS_SOURCE_DIR}/ntoskrnl/ps/psnotify.c
${REACTOS_SOURCE_DIR}/ntoskrnl/ps/query.c
Modified: trunk/reactos/ntoskrnl/po/poshtdwn.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/po/poshtdwn.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/po/poshtdwn.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/po/poshtdwn.c [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -266,6 +266,9 @@
/* First, the HAL handles any "end of boot" special functionality */
DPRINT("HAL shutting down\n");
HalEndOfBoot();
+
+ /* Shut down the Shim cache if enabled */
+ ApphelpCacheShutdown();
/* In this step, the I/O manager does first-chance shutdown notification */
DPRINT("I/O manager shutting down in phase 0\n");
Added: trunk/reactos/ntoskrnl/ps/apphelp.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/apphelp.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/ps/apphelp.c (added)
+++ trunk/reactos/ntoskrnl/ps/apphelp.c [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -0,0 +1,739 @@
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
+ * FILE: ntoskrnl/ps/apphelp.c
+ * PURPOSE: SHIM engine caching.
+ * This caching speeds up checks for the apphelp compatibility layer.
+ * PROGRAMMERS: Mark Jansen
+ */
+
+/*
+Useful references:
+https://github.com/mandiant/ShimCacheParser/blob/master/ShimCacheParser.py
+http://technet.microsoft.com/en-us/library/dd837644(v=ws.10).aspx
+http://msdn.microsoft.com/en-us/library/bb432182(v=vs.85).aspx
+http://www.alex-ionescu.com/?p=43
+http://recxltd.blogspot.nl/2012/04/windows-appcompat-research-notes-part-1.html
+http://journeyintoir.blogspot.ch/2013/12/revealing-recentfilecachebcf-file.html
+https://dl.mandiant.com/EE/library/Whitepaper_ShimCacheParser.pdf
+*/
+
+/* INCLUDES ******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+static BOOLEAN ApphelpCacheEnabled = FALSE;
+static ERESOURCE ApphelpCacheLock;
+static RTL_AVL_TABLE ApphelpShimCache;
+static LIST_ENTRY ApphelpShimCacheAge;
+
+extern ULONG InitSafeBootMode;
+
+static UNICODE_STRING AppCompatCacheKey =
RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session
Manager\\AppCompatCache");
+static OBJECT_ATTRIBUTES AppCompatKeyAttributes =
RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatCacheKey, OBJ_CASE_INSENSITIVE |
OBJ_KERNEL_HANDLE);
+static UNICODE_STRING AppCompatCacheValue =
RTL_CONSTANT_STRING(L"AppCompatCache");
+
+#define EMPTY_SHIM_ENTRY { { 0 }, { { 0 } }, 0 }
+#define MAX_SHIM_ENTRIES 0x200
+#define TAG_SHIM 'MIHS'
+
+#ifndef INVALID_HANDLE_VALUE
+#define INVALID_HANDLE_VALUE (HANDLE)(-1)
+#endif
+
+#include <pshpack1.h>
+
+typedef struct SHIM_PERSISTENT_CACHE_HEADER_52
+{
+ ULONG Magic;
+ ULONG NumEntries;
+} SHIM_PERSISTENT_CACHE_HEADER_52, *PSHIM_PERSISTENT_CACHE_HEADER_52;
+
+/* The data that is present in the registry (Win2k3 version) */
+typedef struct SHIM_PERSISTENT_CACHE_ENTRY_52
+{
+ UNICODE_STRING ImageName;
+ LARGE_INTEGER DateTime;
+ LARGE_INTEGER FileSize;
+} SHIM_PERSISTENT_CACHE_ENTRY_52, *PSHIM_PERSISTENT_CACHE_ENTRY_52;
+
+#include <poppack.h>
+
+#define CACHE_MAGIC_NT_52 0xbadc0ffe
+#define CACHE_HEADER_SIZE_NT_52 0x8
+#define NT52_PERSISTENT_ENTRY_SIZE32 0x18
+#define NT52_PERSISTENT_ENTRY_SIZE64 0x20
+
+//#define CACHE_MAGIC_NT_61 0xbadc0fee
+//#define CACHE_HEADER_SIZE_NT_61 0x80
+//#define NT61_PERSISTENT_ENTRY_SIZE32 0x20
+//#define NT61_PERSISTENT_ENTRY_SIZE64 0x30
+
+#define SHIM_CACHE_MAGIC CACHE_MAGIC_NT_52
+#define SHIM_CACHE_HEADER_SIZE CACHE_HEADER_SIZE_NT_52
+#ifdef _WIN64
+#define SHIM_PERSISTENT_CACHE_ENTRY_SIZE NT52_PERSISTENT_ENTRY_SIZE64
+#else
+#define SHIM_PERSISTENT_CACHE_ENTRY_SIZE NT52_PERSISTENT_ENTRY_SIZE32
+#endif
+#define SHIM_PERSISTENT_CACHE_HEADER SHIM_PERSISTENT_CACHE_HEADER_52
+#define PSHIM_PERSISTENT_CACHE_HEADER PSHIM_PERSISTENT_CACHE_HEADER_52
+#define SHIM_PERSISTENT_CACHE_ENTRY SHIM_PERSISTENT_CACHE_ENTRY_52
+#define PSHIM_PERSISTENT_CACHE_ENTRY PSHIM_PERSISTENT_CACHE_ENTRY_52
+
+C_ASSERT(sizeof(SHIM_PERSISTENT_CACHE_ENTRY) == SHIM_PERSISTENT_CACHE_ENTRY_SIZE);
+C_ASSERT(sizeof(SHIM_PERSISTENT_CACHE_HEADER) == SHIM_CACHE_HEADER_SIZE);
+
+/* The struct we keep in memory */
+typedef struct SHIM_CACHE_ENTRY
+{
+ LIST_ENTRY List;
+ SHIM_PERSISTENT_CACHE_ENTRY Persistent;
+ ULONG CompatFlags;
+} SHIM_CACHE_ENTRY, *PSHIM_CACHE_ENTRY;
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+PVOID
+ApphelpAlloc(
+ _In_ ULONG ByteSize)
+{
+ return ExAllocatePoolWithTag(PagedPool, ByteSize, TAG_SHIM);
+}
+
+VOID
+ApphelpFree(
+ _In_ PVOID Data)
+{
+ ExFreePoolWithTag(Data, TAG_SHIM);
+}
+
+VOID
+ApphelpCacheAcquireLock(VOID)
+{
+ KeEnterCriticalRegion();
+ ExAcquireResourceExclusiveLite(&ApphelpCacheLock, TRUE);
+}
+
+BOOLEAN
+ApphelpCacheTryAcquireLock(VOID)
+{
+ KeEnterCriticalRegion();
+ if (!ExTryToAcquireResourceExclusiveLite(&ApphelpCacheLock))
+ {
+ KeLeaveCriticalRegion();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+VOID
+ApphelpCacheReleaseLock(VOID)
+{
+ ExReleaseResourceLite(&ApphelpCacheLock);
+ KeLeaveCriticalRegion();
+}
+
+VOID
+ApphelpDuplicateUnicodeString(
+ _Out_ PUNICODE_STRING Destination,
+ _In_ PCUNICODE_STRING Source)
+{
+ Destination->Length = Source->Length;
+ if (Destination->Length)
+ {
+ Destination->MaximumLength = Destination->Length + sizeof(WCHAR);
+ Destination->Buffer = ApphelpAlloc(Destination->MaximumLength);
+ RtlCopyMemory(Destination->Buffer, Source->Buffer,
Destination->Length);
+ Destination->Buffer[Destination->Length / sizeof(WCHAR)] = UNICODE_NULL;
+ }
+ else
+ {
+ Destination->MaximumLength = 0;
+ Destination->Buffer = NULL;
+ }
+}
+
+VOID
+ApphelpFreeUnicodeString(
+ _Inout_ PUNICODE_STRING String)
+{
+ if (String->Buffer)
+ {
+ ApphelpFree(String->Buffer);
+ }
+ String->Length = 0;
+ String->MaximumLength = 0;
+ String->Buffer = NULL;
+}
+
+/* Query file info from a handle, storing it in Entry */
+NTSTATUS
+ApphelpCacheQueryInfo(
+ _In_ HANDLE ImageHandle,
+ _Out_ PSHIM_CACHE_ENTRY Entry)
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_BASIC_INFORMATION FileBasic;
+ FILE_STANDARD_INFORMATION FileStandard;
+ NTSTATUS Status;
+
+ Status = ZwQueryInformationFile(ImageHandle, &IoStatusBlock,
+ &FileBasic, sizeof(FileBasic), FileBasicInformation);
+ if (NT_SUCCESS(Status))
+ {
+ Status = ZwQueryInformationFile(ImageHandle, &IoStatusBlock,
+ &FileStandard, sizeof(FileStandard), FileStandardInformation);
+ if (NT_SUCCESS(Status))
+ {
+ Entry->Persistent.DateTime = FileBasic.LastWriteTime;
+ Entry->Persistent.FileSize = FileStandard.EndOfFile;
+ }
+ }
+ return Status;
+}
+
+RTL_GENERIC_COMPARE_RESULTS
+NTAPI
+ApphelpShimCacheCompareRoutine(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ PVOID FirstStruct,
+ _In_ PVOID SecondStruct)
+{
+ LONG lResult = RtlCompareUnicodeString(
+ &((PSHIM_CACHE_ENTRY)FirstStruct)->Persistent.ImageName,
+ &((PSHIM_CACHE_ENTRY)SecondStruct)->Persistent.ImageName, TRUE);
+
+ if (lResult < 0)
+ return GenericLessThan;
+ else if (lResult == 0)
+ return GenericEqual;
+ return GenericGreaterThan;
+}
+
+PVOID
+NTAPI
+ApphelpShimCacheAllocateRoutine(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ CLONG ByteSize)
+{
+ return ApphelpAlloc(ByteSize);
+}
+
+VOID
+NTAPI
+ApphelpShimCacheFreeRoutine(
+ _In_ PRTL_AVL_TABLE Table,
+ _In_ PVOID Buffer)
+{
+ ApphelpFree(Buffer);
+}
+
+NTSTATUS
+ApphelpCacheParse(
+ _In_reads_(DataLength) PUCHAR Data,
+ _In_ ULONG DataLength)
+{
+ PSHIM_PERSISTENT_CACHE_HEADER Header = (PSHIM_PERSISTENT_CACHE_HEADER)Data;
+
+ if (DataLength < CACHE_HEADER_SIZE_NT_52)
+ {
+ DPRINT1("SHIMS: ApphelpCacheParse not enough data for a minimal header
(0x%x)\n", DataLength);
+ return STATUS_INVALID_PARAMETER;
+ }
+ if (Header->Magic == SHIM_CACHE_MAGIC)
+ {
+ ULONG Cur;
+ ULONG NumEntries = Header->NumEntries;
+ DPRINT1("SHIMS: ApphelpCacheParse walking %d entries\n", NumEntries);
+ for (Cur = 0; Cur < NumEntries; ++Cur)
+ {
+ UNICODE_STRING String;
+ SHIM_CACHE_ENTRY Entry = EMPTY_SHIM_ENTRY;
+ PSHIM_CACHE_ENTRY Result;
+ PSHIM_PERSISTENT_CACHE_ENTRY pPersistent =
+ (PSHIM_PERSISTENT_CACHE_ENTRY)(Data + SHIM_CACHE_HEADER_SIZE +
+ (Cur *
SHIM_PERSISTENT_CACHE_ENTRY_SIZE));
+ /* The entry in the Persitent storage is not really a UNICODE_STRING,
+ so we have to convert the offset into a real pointer before using it. */
+ String.Length = pPersistent->ImageName.Length;
+ String.MaximumLength = pPersistent->ImageName.MaximumLength;
+ String.Buffer = (PWCHAR)((ULONG_PTR)pPersistent->ImageName.Buffer +
Data);
+
+ /* Now we copy all data to a local buffer, that can be safely duplicated by
RtlInsert */
+ Entry.Persistent = *pPersistent;
+ ApphelpDuplicateUnicodeString(&Entry.Persistent.ImageName, &String);
+ Result = RtlInsertElementGenericTableAvl(&ApphelpShimCache, &Entry,
sizeof(Entry), NULL);
+ if (!Result)
+ {
+ DPRINT1("SHIMS: ApphelpCacheParse insert failed\n");
+ ApphelpFreeUnicodeString(&Entry.Persistent.ImageName);
+ return STATUS_INVALID_PARAMETER;
+ }
+ InsertTailList(&ApphelpShimCacheAge, &Result->List);
+ }
+ return STATUS_SUCCESS;
+ }
+ DPRINT1("SHIMS: ApphelpCacheParse found invalid magic (0x%x)\n",
Header->Magic);
+ return STATUS_INVALID_PARAMETER;
+}
+
+BOOLEAN
+ApphelpCacheRead(VOID)
+{
+ HANDLE KeyHandle;
+ NTSTATUS Status;
+ KEY_VALUE_PARTIAL_INFORMATION KeyValueObject;
+ PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = &KeyValueObject;
+ ULONG KeyInfoSize, ResultSize;
+
+ Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &AppCompatKeyAttributes);
+
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("SHIMS: ApphelpCacheRead could not even open Session
Manager\\AppCompatCache (0x%x)\n", Status);
+ return FALSE;
+ }
+
+ Status = ZwQueryValueKey(KeyHandle, &AppCompatCacheValue,
+ KeyValuePartialInformation, KeyValueInformation,
+ sizeof(KeyValueObject), &ResultSize);
+
+ if (Status == STATUS_BUFFER_OVERFLOW)
+ {
+ KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
KeyValueInformation->DataLength;
+ KeyValueInformation = ApphelpAlloc(KeyInfoSize);
+ if (KeyValueInformation != NULL)
+ {
+ Status = ZwQueryValueKey(KeyHandle, &AppCompatCacheValue,
+ KeyValuePartialInformation, KeyValueInformation,
+ KeyInfoSize, &ResultSize);
+ }
+ }
+
+ if (NT_SUCCESS(Status) && KeyValueInformation->Type == REG_BINARY)
+ {
+ Status = ApphelpCacheParse(KeyValueInformation->Data,
+ KeyValueInformation->DataLength);
+ }
+ else
+ {
+ DPRINT1("SHIMS: ApphelpCacheRead not loaded from registry (0x%x)\n",
Status);
+ }
+
+ if (KeyValueInformation != &KeyValueObject && KeyValueInformation !=
NULL)
+ ApphelpFree(KeyValueInformation);
+
+ ZwClose(KeyHandle);
+ return NT_SUCCESS(Status);
+}
+
+BOOLEAN
+ApphelpCacheWrite(VOID)
+{
+ ULONG Length = SHIM_CACHE_HEADER_SIZE;
+ ULONG NumEntries = 0;
+ PLIST_ENTRY ListEntry;
+ PUCHAR Buffer, BufferNamePos;
+ PSHIM_PERSISTENT_CACHE_HEADER Header;
+ PSHIM_PERSISTENT_CACHE_ENTRY WriteEntry;
+ HANDLE KeyHandle;
+ NTSTATUS Status;
+
+ /* First we have to calculate the required size. */
+ ApphelpCacheAcquireLock();
+ ListEntry = ApphelpShimCacheAge.Flink;
+ while (ListEntry != &ApphelpShimCacheAge)
+ {
+ PSHIM_CACHE_ENTRY Entry = CONTAINING_RECORD(ListEntry, SHIM_CACHE_ENTRY, List);
+ Length += SHIM_PERSISTENT_CACHE_ENTRY_SIZE;
+ Length += Entry->Persistent.ImageName.MaximumLength;
+ ++NumEntries;
+ ListEntry = ListEntry->Flink;
+ }
+ DPRINT1("SHIMS: ApphelpCacheWrite, %d Entries, total size: %d\n",
NumEntries, Length);
+ Length = ROUND_UP(Length, sizeof(ULONGLONG));
+ DPRINT1("SHIMS: ApphelpCacheWrite, Rounded to: %d\n", Length);
+
+ /* Now we allocate and prepare some helpers */
+ Buffer = ApphelpAlloc(Length);
+ BufferNamePos = Buffer + Length;
+ Header = (PSHIM_PERSISTENT_CACHE_HEADER)Buffer;
+ WriteEntry = (PSHIM_PERSISTENT_CACHE_ENTRY)(Buffer + SHIM_CACHE_HEADER_SIZE);
+
+ Header->Magic = SHIM_CACHE_MAGIC;
+ Header->NumEntries = NumEntries;
+
+ ListEntry = ApphelpShimCacheAge.Flink;
+ while (ListEntry != &ApphelpShimCacheAge)
+ {
+ PSHIM_CACHE_ENTRY Entry = CONTAINING_RECORD(ListEntry, SHIM_CACHE_ENTRY, List);
+ USHORT ImageNameLen = Entry->Persistent.ImageName.MaximumLength;
+ /* Copy the Persistent structure over */
+ *WriteEntry = Entry->Persistent;
+ BufferNamePos -= ImageNameLen;
+ /* Copy the image name over */
+ RtlCopyMemory(BufferNamePos, Entry->Persistent.ImageName.Buffer,
ImageNameLen);
+ /* Fix the Persistent structure, so that Buffer is once again an offset */
+ WriteEntry->ImageName.Buffer = (PWCH)(BufferNamePos - Buffer);
+
+ ++WriteEntry;
+ ListEntry = ListEntry->Flink;
+ }
+ ApphelpCacheReleaseLock();
+
+ Status = ZwOpenKey(&KeyHandle, KEY_SET_VALUE, &AppCompatKeyAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ Status = ZwSetValueKey(KeyHandle, &AppCompatCacheValue, 0, REG_BINARY,
Buffer, Length);
+ ZwClose(KeyHandle);
+ }
+ else
+ {
+ DPRINT1("SHIMS: ApphelpCacheWrite could not even open Session
Manager\\AppCompatCache (0x%x)\n", Status);
+ }
+
+ ApphelpFree(Buffer);
+ return NT_SUCCESS(Status);
+}
+
+
+NTSTATUS
+NTAPI
+INIT_FUNCTION
+ApphelpCacheInitialize(VOID)
+{
+ DPRINT1("SHIMS: ApphelpCacheInitialize\n");
+ /* If we are booting in safemode we do not want to use the apphelp cache */
+ if (InitSafeBootMode)
+ {
+ DPRINT1("SHIMS: Safe mode detected, disabling cache.\n");
+ ApphelpCacheEnabled = FALSE;
+ }
+ else
+ {
+ ExInitializeResourceLite(&ApphelpCacheLock);
+ RtlInitializeGenericTableAvl(&ApphelpShimCache,
+ ApphelpShimCacheCompareRoutine,
+ ApphelpShimCacheAllocateRoutine,
+ ApphelpShimCacheFreeRoutine,
+ NULL);
+ InitializeListHead(&ApphelpShimCacheAge);
+ ApphelpCacheEnabled = ApphelpCacheRead();
+ }
+ DPRINT1("SHIMS: ApphelpCacheInitialize: %d\n", ApphelpCacheEnabled);
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+ApphelpCacheShutdown(VOID)
+{
+ if (ApphelpCacheEnabled)
+ {
+ ApphelpCacheWrite();
+ }
+}
+
+NTSTATUS
+ApphelpValidateData(
+ _In_opt_ PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData,
+ _Out_ PUNICODE_STRING ImageName,
+ _Out_ PHANDLE ImageHandle)
+{
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+ if (ServiceData)
+ {
+ UNICODE_STRING LocalImageName;
+ _SEH2_TRY
+ {
+ ProbeForRead(ServiceData, sizeof(APPHELP_CACHE_SERVICE_LOOKUP),
sizeof(ULONG));
+ LocalImageName = ServiceData->ImageName;
+ *ImageHandle = ServiceData->ImageHandle;
+ if (LocalImageName.Length && LocalImageName.Buffer)
+ {
+ ProbeForRead(LocalImageName.Buffer, LocalImageName.Length *
sizeof(WCHAR), 1);
+ ApphelpDuplicateUnicodeString(ImageName, &LocalImageName);
+ Status = STATUS_SUCCESS;
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("SHIMS: ApphelpValidateData: invalid data passed\n");
+ }
+ return Status;
+}
+
+NTSTATUS
+ApphelpCacheRemoveEntryNolock(
+ _In_ PSHIM_CACHE_ENTRY Entry)
+{
+ if (Entry)
+ {
+ PWSTR Buffer = Entry->Persistent.ImageName.Buffer;
+ RemoveEntryList(&Entry->List);
+ if (RtlDeleteElementGenericTableAvl(&ApphelpShimCache, Entry))
+ ApphelpFree(Buffer);
+ return STATUS_SUCCESS;
+ }
+ return STATUS_NOT_FOUND;
+}
+
+NTSTATUS
+ApphelpCacheLookupEntry(
+ _In_ PUNICODE_STRING ImageName,
+ _In_ HANDLE ImageHandle)
+{
+ NTSTATUS Status = STATUS_NOT_FOUND;
+
+ if (ApphelpCacheTryAcquireLock())
+ {
+ SHIM_CACHE_ENTRY Lookup = EMPTY_SHIM_ENTRY;
+ PSHIM_CACHE_ENTRY Entry;
+ Lookup.Persistent.ImageName = *ImageName;
+ Entry = RtlLookupElementGenericTableAvl(&ApphelpShimCache, &Lookup);
+ if (Entry)
+ {
+ DPRINT1("SHIMS: ApphelpCacheLookupEntry: found %wZ\n", ImageName);
+ if (ImageHandle == INVALID_HANDLE_VALUE)
+ {
+ DPRINT1("SHIMS: ApphelpCacheLookupEntry: ok\n");
+ /* just return if we know it, do not query file info */
+ Status = STATUS_SUCCESS;
+ }
+ else if (NT_SUCCESS(ApphelpCacheQueryInfo(ImageHandle, &Lookup))
&&
+ Lookup.Persistent.DateTime.QuadPart ==
Entry->Persistent.DateTime.QuadPart &&
+ Lookup.Persistent.FileSize.QuadPart ==
Entry->Persistent.FileSize.QuadPart)
+ {
+ DPRINT1("SHIMS: ApphelpCacheLookupEntry: found &
validated\n");
+ Status = STATUS_SUCCESS;
+ /* move it to the front to keep it alive */
+ RemoveEntryList(&Entry->List);
+ InsertHeadList(&ApphelpShimCacheAge, &Entry->List);
+ }
+ else
+ {
+ DPRINT1("SHIMS: ApphelpCacheLookupEntry: file info
mismatch\n");
+ /* Could not read file info, or it did not match, drop it from the cache
*/
+ ApphelpCacheRemoveEntryNolock(Entry);
+ }
+ }
+ else
+ {
+ DPRINT1("SHIMS: ApphelpCacheLookupEntry: could not find %wZ\n",
ImageName);
+ }
+ ApphelpCacheReleaseLock();
+ }
+ return Status;
+}
+
+NTSTATUS
+ApphelpCacheRemoveEntry(
+ _In_ PUNICODE_STRING ImageName)
+{
+ PSHIM_CACHE_ENTRY Entry;
+ NTSTATUS Status;
+
+ ApphelpCacheAcquireLock();
+ Entry = RtlLookupElementGenericTableAvl(&ApphelpShimCache, ImageName);
+ Status = ApphelpCacheRemoveEntryNolock(Entry);
+ ApphelpCacheReleaseLock();
+ return Status;
+}
+
+/* Validate that we are either called from r0, or from a service-like context */
+NTSTATUS
+ApphelpCacheAccessCheck(VOID)
+{
+ if (ExGetPreviousMode() != KernelMode)
+ {
+ if (!SeSinglePrivilegeCheck(SeTcbPrivilege, UserMode))
+ {
+ DPRINT1("SHIMS: ApphelpCacheAccessCheck failed\n");
+ return STATUS_ACCESS_DENIED;
+ }
+ }
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+ApphelpCacheUpdateEntry(
+ _In_ PUNICODE_STRING ImageName,
+ _In_ HANDLE ImageHandle)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ SHIM_CACHE_ENTRY Entry = EMPTY_SHIM_ENTRY;
+ PSHIM_CACHE_ENTRY Lookup;
+ PVOID NodeOrParent;
+ TABLE_SEARCH_RESULT SearchResult;
+
+ ApphelpCacheAcquireLock();
+
+ /* If we got a file handle, query it for info */
+ if (ImageHandle != INVALID_HANDLE_VALUE)
+ {
+ Status = ApphelpCacheQueryInfo(ImageHandle, &Entry);
+ }
+
+ if (NT_SUCCESS(Status))
+ {
+ /* Use ImageName for the lookup, don't actually duplicate it */
+ Entry.Persistent.ImageName = *ImageName;
+ Lookup = RtlLookupElementGenericTableFullAvl(&ApphelpShimCache, &Entry,
+ &NodeOrParent,
&SearchResult);
+ if (Lookup)
+ {
+ DPRINT1("SHIMS: ApphelpCacheUpdateEntry: Entry already exists, reusing
it\n");
+ /* Unlink the found item, so we can put it back at the front,
+ and copy the earlier obtained file info*/
+ RemoveEntryList(&Lookup->List);
+ Lookup->Persistent.DateTime = Entry.Persistent.DateTime;
+ Lookup->Persistent.FileSize = Entry.Persistent.FileSize;
+ }
+ else
+ {
+ DPRINT1("SHIMS: ApphelpCacheUpdateEntry: Inserting new Entry\n");
+ /* Insert a new entry, with its own copy of the ImageName */
+ ApphelpDuplicateUnicodeString(&Entry.Persistent.ImageName, ImageName);
+ Lookup = RtlInsertElementGenericTableFullAvl(&ApphelpShimCache,
+ &Entry, sizeof(Entry), 0, NodeOrParent, SearchResult);
+ if (!Lookup)
+ {
+ ApphelpFreeUnicodeString(&Entry.Persistent.ImageName);
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+ if (Lookup)
+ {
+ /* Either we re-used an existing item, or we inserted a new one, keep it
alive */
+ InsertHeadList(&ApphelpShimCacheAge, &Lookup->List);
+ if (RtlNumberGenericTableElementsAvl(&ApphelpShimCache) >
MAX_SHIM_ENTRIES)
+ {
+ PSHIM_CACHE_ENTRY Remove;
+ DPRINT1("SHIMS: ApphelpCacheUpdateEntry: Cache growing too big,
dropping oldest item\n");
+ Remove = CONTAINING_RECORD(ApphelpShimCacheAge.Blink, SHIM_CACHE_ENTRY,
List);
+ Status = ApphelpCacheRemoveEntryNolock(Remove);
+ }
+ }
+ }
+ ApphelpCacheReleaseLock();
+ return Status;
+}
+
+NTSTATUS
+ApphelpCacheFlush(VOID)
+{
+ PVOID p;
+
+ DPRINT1("SHIMS: ApphelpCacheFlush\n");
+ ApphelpCacheAcquireLock();
+ while ((p = RtlEnumerateGenericTableAvl(&ApphelpShimCache, TRUE)))
+ {
+ ApphelpCacheRemoveEntryNolock((PSHIM_CACHE_ENTRY)p);
+ }
+ ApphelpCacheReleaseLock();
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+ApphelpCacheDump(VOID)
+{
+ PLIST_ENTRY ListEntry;
+
+ DPRINT1("SHIMS: NtApphelpCacheControl( Dumping entries, newset to oldest
)\n");
+ ApphelpCacheAcquireLock();
+ ListEntry = ApphelpShimCacheAge.Flink;
+ while (ListEntry != &ApphelpShimCacheAge)
+ {
+ PSHIM_CACHE_ENTRY Entry = CONTAINING_RECORD(ListEntry, SHIM_CACHE_ENTRY, List);
+ DPRINT1("Entry: %S\n", Entry->Persistent.ImageName.Buffer);
+ DPRINT1("DateTime High: 0x%x, Low: 0x%x\n",
+ Entry->Persistent.DateTime.HighPart,
Entry->Persistent.DateTime.LowPart);
+ DPRINT1("FileSize High: 0x%x, Low: 0x%x\n",
+ Entry->Persistent.FileSize.HighPart,
Entry->Persistent.FileSize.LowPart);
+ DPRINT1("Flags: 0x%x\n", Entry->CompatFlags);
+ ListEntry = ListEntry->Flink;
+ }
+ ApphelpCacheReleaseLock();
+ return STATUS_SUCCESS;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+NTSTATUS
+NTAPI
+NtApphelpCacheControl(
+ _In_ APPHELPCACHESERVICECLASS Service,
+ _In_opt_ PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData)
+{
+ NTSTATUS Status = STATUS_INVALID_PARAMETER;
+ UNICODE_STRING ImageName = { 0 };
+ HANDLE Handle = INVALID_HANDLE_VALUE;
+
+ if (!ApphelpCacheEnabled)
+ {
+ DPRINT1("NtApphelpCacheControl: ApphelpCacheEnabled == 0\n");
+ return Status;
+ }
+ switch (Service)
+ {
+ case ApphelpCacheServiceLookup:
+ DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceLookup
)\n");
+ Status = ApphelpValidateData(ServiceData, &ImageName, &Handle);
+ if (NT_SUCCESS(Status))
+ Status = ApphelpCacheLookupEntry(&ImageName, Handle);
+ break;
+ case ApphelpCacheServiceRemove:
+ DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceRemove
)\n");
+ Status = ApphelpValidateData(ServiceData, &ImageName, &Handle);
+ if (NT_SUCCESS(Status))
+ Status = ApphelpCacheRemoveEntry(&ImageName);
+ break;
+ case ApphelpCacheServiceUpdate:
+ DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceUpdate
)\n");
+ Status = ApphelpCacheAccessCheck();
+ if (NT_SUCCESS(Status))
+ {
+ Status = ApphelpValidateData(ServiceData, &ImageName, &Handle);
+ if (NT_SUCCESS(Status))
+ Status = ApphelpCacheUpdateEntry(&ImageName, Handle);
+ }
+ break;
+ case ApphelpCacheServiceFlush:
+ Status = ApphelpCacheFlush();
+ break;
+ case ApphelpCacheServiceDump:
+ Status = ApphelpCacheDump();
+ break;
+ case ApphelpDBGReadRegistry:
+ DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGReadRegistry ):
flushing cache.\n");
+ ApphelpCacheFlush();
+ DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGReadRegistry ): reading
cache.\n");
+ Status = ApphelpCacheRead() ? STATUS_SUCCESS : STATUS_NOT_FOUND;
+ break;
+ case ApphelpDBGWriteRegistry:
+ DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGWriteRegistry ):
writing cache.\n");
+ Status = ApphelpCacheWrite() ? STATUS_SUCCESS : STATUS_NOT_FOUND;
+ break;
+ default:
+ DPRINT1("SHIMS: NtApphelpCacheControl( Invalid service requested
)\n");
+ break;
+ }
+ if (ImageName.Buffer)
+ {
+ ApphelpFreeUnicodeString(&ImageName);
+ }
+ return Status;
+}
+
Propchange: trunk/reactos/ntoskrnl/ps/apphelp.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/ntoskrnl/ps/psmgr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ps/psmgr.c?rev=69…
==============================================================================
--- trunk/reactos/ntoskrnl/ps/psmgr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ps/psmgr.c [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -250,7 +250,7 @@
LARGE_INTEGER Offset = {{0, 0}};
SIZE_T ViewSize = 0;
PVOID ImageBase = 0;
-
+
/* Map the System DLL */
Status = MmMapViewOfSection(PspSystemDllSection,
Process,
@@ -267,7 +267,7 @@
/* Normalize status code */
Status = STATUS_CONFLICTING_ADDRESSES;
}
-
+
/* Write the image base and return status */
if (DllBase) *DllBase = ImageBase;
return Status;
@@ -677,13 +677,4 @@
return (NtBuildNumber >> 28) == 0xC;
}
-NTSTATUS
-NTAPI
-NtApphelpCacheControl(IN APPHELPCACHESERVICECLASS Service,
- IN PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
/* EOF */
Modified: trunk/rostests/apitests/ntdll/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/CMakeLists…
==============================================================================
--- trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/rostests/apitests/ntdll/CMakeLists.txt [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -2,6 +2,7 @@
list(APPEND SOURCE
LdrEnumResources.c
NtAllocateVirtualMemory.c
+ NtApphelpCacheControl.c
NtContinue.c
NtCreateFile.c
NtCreateThread.c
Added: trunk/rostests/apitests/ntdll/NtApphelpCacheControl.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/NtApphelpC…
==============================================================================
--- trunk/rostests/apitests/ntdll/NtApphelpCacheControl.c (added)
+++ trunk/rostests/apitests/ntdll/NtApphelpCacheControl.c [iso-8859-1] Sat Sep 5 11:49:54
2015
@@ -0,0 +1,367 @@
+/*
+ * PROJECT: ReactOS API Tests
+ * LICENSE: LGPL - See COPYING.LIB in the top level directory
+ * PURPOSE: Tests for SHIM engine caching.
+ * PROGRAMMER: Mark Jansen
+ */
+
+#include <apitest.h>
+
+#include <windows.h>
+
+#define WIN32_NO_STATUS
+#include <ntndk.h>
+
+enum ServiceCommands
+{
+ RegisterShimCacheWithHandle = 128,
+ RegisterShimCacheWithoutHandle = 129,
+};
+
+
+NTSTATUS CallCacheControl(UNICODE_STRING* PathName, BOOLEAN WithMapping,
APPHELPCACHESERVICECLASS Service)
+{
+ APPHELP_CACHE_SERVICE_LOOKUP CacheEntry = { {0} };
+ NTSTATUS Status;
+ CacheEntry.ImageName = *PathName;
+ if (WithMapping)
+ {
+ OBJECT_ATTRIBUTES LocalObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ InitializeObjectAttributes(&LocalObjectAttributes, PathName,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+ Status = NtOpenFile(&CacheEntry.ImageHandle,
+ SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_EXECUTE,
+ &LocalObjectAttributes, &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ }
+ else
+ {
+ CacheEntry.ImageHandle = INVALID_HANDLE_VALUE;
+ }
+ Status = NtApphelpCacheControl(Service, &CacheEntry);
+ if (CacheEntry.ImageHandle != INVALID_HANDLE_VALUE)
+ NtClose(CacheEntry.ImageHandle);
+ return Status;
+}
+
+int InitEnv(UNICODE_STRING* PathName)
+{
+ NTSTATUS Status = CallCacheControl(PathName, FALSE, ApphelpCacheServiceRemove);
+ if (Status == STATUS_INVALID_PARAMETER)
+ {
+ /* Windows Vista+ has a different layout for APPHELP_CACHE_SERVICE_LOOKUP */
+ return 0;
+ }
+ ok(Status == STATUS_SUCCESS || Status == STATUS_NOT_FOUND,
+ "Wrong value for Status, expected: SUCCESS or NOT_FOUND, got:
0x%lx\n",
+ Status);
+ return 1;
+}
+
+void CheckValidation(UNICODE_STRING* PathName)
+{
+ APPHELP_CACHE_SERVICE_LOOKUP CacheEntry = { {0} };
+ NTSTATUS Status;
+
+ /* Validate the handling of a NULL pointer */
+ Status = NtApphelpCacheControl(ApphelpCacheServiceRemove, NULL);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER);
+ Status = NtApphelpCacheControl(ApphelpCacheServiceLookup, NULL);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER);
+
+ /* Validate the handling of a NULL pointer inside the struct */
+ Status = NtApphelpCacheControl(ApphelpCacheServiceRemove, &CacheEntry);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER);
+ Status = NtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER);
+
+ /* Just call the dump function */
+ Status = NtApphelpCacheControl(ApphelpCacheServiceDump, NULL);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* Validate the handling of an invalid handle inside the struct */
+ CacheEntry.ImageName = *PathName;
+ CacheEntry.ImageHandle = (HANDLE)2;
+ Status = NtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+
+ /* Validate the handling of an invalid service number */
+ Status = NtApphelpCacheControl(999, NULL);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER);
+ Status = NtApphelpCacheControl(999, &CacheEntry);
+ ok_ntstatus(Status, STATUS_INVALID_PARAMETER);
+}
+
+static BOOLEAN RequestAddition(SC_HANDLE service_handle, BOOLEAN WithMapping)
+{
+ SERVICE_STATUS Status;
+ ControlService(service_handle, WithMapping ? RegisterShimCacheWithHandle :
+ RegisterShimCacheWithoutHandle, &Status);
+ /* TODO: how to get a return code from the service? */
+ return TRUE;
+}
+
+static void RunApphelpCacheControlTests(SC_HANDLE service_handle)
+{
+ WCHAR szPath[MAX_PATH];
+ UNICODE_STRING ntPath;
+ BOOLEAN Result;
+ NTSTATUS Status;
+ APPHELP_CACHE_SERVICE_LOOKUP CacheEntry;
+
+ GetModuleFileNameW(NULL, szPath, sizeof(szPath) / sizeof(szPath[0]));
+ Result = RtlDosPathNameToNtPathName_U(szPath, &ntPath, NULL, NULL);
+ ok(Result == TRUE, "RtlDosPathNameToNtPathName_U\n");
+ if (!InitEnv(&ntPath))
+ {
+ skip("NtApphelpCacheControl expects a different structure layout\n");
+ return;
+ }
+ /* At this point we have made sure that our binary is not present in the cache,
+ and that the NtApphelpCacheControl function expects the struct layout we use. */
+ CheckValidation(&ntPath);
+
+ /* We expect not to find it */
+ Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+ Status = CallCacheControl(&ntPath, FALSE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+
+ /* First we add our process without a file handle (so it will be registered without
file info) */
+ RequestAddition(service_handle, FALSE);
+
+ /* now we try to find it without validating file info */
+ Status = CallCacheControl(&ntPath, FALSE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ /* when validating file info the cache notices the file is wrong, so it is dropped
from the cache */
+ Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+ /* making the second check without info also fail. */
+ Status = CallCacheControl(&ntPath, FALSE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+
+
+ /* Now we add the file with file info */
+ RequestAddition(service_handle, TRUE);
+
+ /* so both checks should succeed */
+ Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ Status = CallCacheControl(&ntPath, FALSE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+
+ /* We know the file is in the cache now (assuming previous tests succeeded,
+ let's test invalid handle behavior */
+ CacheEntry.ImageName = ntPath;
+ CacheEntry.ImageHandle = 0;
+ Status = NtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+
+ /* re-add it for the next test */
+ RequestAddition(service_handle, TRUE);
+ Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ CacheEntry.ImageHandle = (HANDLE)1;
+ Status = NtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+
+ /* and again */
+ RequestAddition(service_handle, TRUE);
+ Status = CallCacheControl(&ntPath, TRUE, ApphelpCacheServiceLookup);
+ ok_ntstatus(Status, STATUS_SUCCESS);
+ CacheEntry.ImageHandle = (HANDLE)0x80000000;
+ Status = NtApphelpCacheControl(ApphelpCacheServiceLookup, &CacheEntry);
+ ok_ntstatus(Status, STATUS_NOT_FOUND);
+
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ntPath.Buffer);
+}
+
+
+/* Most service related code was taken from services_winetest:service and modified for
usage here
+ The rest came from MSDN */
+
+static SERVICE_STATUS_HANDLE (WINAPI
*pRegisterServiceCtrlHandlerExA)(LPCSTR,LPHANDLER_FUNCTION_EX,LPVOID);
+static char service_name[100] = "apphelp_test_service";
+static HANDLE service_stop_event;
+static SERVICE_STATUS_HANDLE service_status;
+
+static BOOLEAN RegisterInShimCache(BOOLEAN WithMapping)
+{
+ WCHAR szPath[MAX_PATH];
+ UNICODE_STRING ntPath;
+ BOOLEAN Result;
+ NTSTATUS Status;
+ GetModuleFileNameW(NULL, szPath, sizeof(szPath) / sizeof(szPath[0]));
+ Result = RtlDosPathNameToNtPathName_U(szPath, &ntPath, NULL, NULL);
+ if (!Result)
+ {
+ DbgPrint("RegisterInShimCache: RtlDosPathNameToNtPathName_U
failed\n");
+ return FALSE;
+ }
+
+ Status = CallCacheControl(&ntPath, WithMapping, ApphelpCacheServiceUpdate);
+ if (!NT_SUCCESS(Status))
+ {
+ DbgPrint("RegisterInShimCache: CallCacheControl failed\n");
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ntPath.Buffer);
+ return FALSE;
+ }
+ RtlFreeHeap(RtlGetProcessHeap(), 0, ntPath.Buffer);
+ return TRUE;
+}
+
+
+static DWORD WINAPI service_handler(DWORD ctrl, DWORD event_type, void *event_data, void
*context)
+{
+ SERVICE_STATUS status = {0};
+ status.dwServiceType = SERVICE_WIN32;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+
+ switch(ctrl)
+ {
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+ status.dwCurrentState = SERVICE_STOP_PENDING;
+ status.dwControlsAccepted = 0;
+ SetServiceStatus(service_status, &status);
+ SetEvent(service_stop_event);
+ return NO_ERROR;
+ case RegisterShimCacheWithHandle:
+ if (!RegisterInShimCache(TRUE))
+ {
+ /* TODO: how should we communicate a failure? */
+ }
+ break;
+ case RegisterShimCacheWithoutHandle:
+ if (!RegisterInShimCache(FALSE))
+ {
+ /* TODO: how should we communicate a failure? */
+ }
+ break;
+ default:
+ DbgPrint("Unhandled: %d\n", ctrl);
+ break;
+ }
+ status.dwCurrentState = SERVICE_RUNNING;
+ SetServiceStatus(service_status, &status);
+ return NO_ERROR;
+}
+
+static void WINAPI service_main(DWORD argc, char **argv)
+{
+ SERVICE_STATUS status = {0};
+ service_status = pRegisterServiceCtrlHandlerExA(service_name, service_handler,
NULL);
+ if(!service_status)
+ return;
+
+ status.dwServiceType = SERVICE_WIN32;
+ status.dwCurrentState = SERVICE_RUNNING;
+ status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+ SetServiceStatus(service_status, &status);
+
+ WaitForSingleObject(service_stop_event, INFINITE);
+
+ status.dwCurrentState = SERVICE_STOPPED;
+ status.dwControlsAccepted = 0;
+ SetServiceStatus(service_status, &status);
+}
+
+static SC_HANDLE InstallService(SC_HANDLE scm_handle)
+{
+ char service_cmd[MAX_PATH+150], *ptr;
+ SC_HANDLE service;
+
+ ptr = service_cmd + GetModuleFileNameA(NULL, service_cmd, MAX_PATH);
+ strcpy(ptr, " NtApphelpCacheControl service");
+ ptr += strlen(ptr);
+
+ service = CreateServiceA(scm_handle, service_name, service_name, GENERIC_ALL,
+ SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
SERVICE_ERROR_IGNORE,
+ service_cmd, NULL, NULL, NULL, NULL, NULL);
+ if (!service)
+ {
+ skip("Could not create helper service\n");
+ return NULL;
+ }
+ return service;
+}
+
+static void WaitService(SC_HANDLE service_handle, DWORD Status, SERVICE_STATUS_PROCESS*
ssp)
+{
+ DWORD dwBytesNeeded;
+ DWORD dwStartTime = GetTickCount();
+ while (ssp->dwCurrentState != Status)
+ {
+ Sleep(40);
+ if (!QueryServiceStatusEx(service_handle, SC_STATUS_PROCESS_INFO,
+ (LPBYTE)ssp, sizeof(SERVICE_STATUS_PROCESS), &dwBytesNeeded ))
+ {
+ ok(0, "QueryServiceStatusEx failed waiting for %lu\n", Status);
+ break;
+ }
+ if ((GetTickCount() - dwStartTime) > 1000)
+ {
+ ok(0, "Timeout waiting for (%lu) from service, is: %lu.\n",
+ Status, ssp->dwCurrentState);
+ break;
+ }
+ }
+}
+
+static void RunTest()
+{
+ SC_HANDLE scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ SC_HANDLE service_handle = InstallService(scm_handle);
+ if (service_handle)
+ {
+ SERVICE_STATUS_PROCESS ssp = {0};
+ BOOL res = StartServiceA(service_handle, 0, NULL);
+ if (res)
+ {
+ WaitService(service_handle, SERVICE_RUNNING, &ssp);
+ RunApphelpCacheControlTests(service_handle);
+ ControlService(service_handle, SERVICE_CONTROL_STOP,
(LPSERVICE_STATUS)&ssp);
+ WaitService(service_handle, SERVICE_STOPPED, &ssp);
+ }
+ else
+ {
+ skip("Could not start helper service\n");
+ }
+ DeleteService(service_handle);
+ }
+ CloseServiceHandle(scm_handle);
+}
+
+START_TEST(NtApphelpCacheControl)
+{
+ char **argv;
+ int argc;
+
+ pRegisterServiceCtrlHandlerExA =
(void*)GetProcAddress(GetModuleHandleA("advapi32.dll"),
"RegisterServiceCtrlHandlerExA");
+ if (!pRegisterServiceCtrlHandlerExA)
+ {
+ win_skip("RegisterServiceCtrlHandlerExA not available, skipping
tests\n");
+ return;
+ }
+ argc = winetest_get_mainargs(&argv);
+ if(argc < 3)
+ {
+ RunTest();
+ }
+ else
+ {
+ SERVICE_TABLE_ENTRYA servtbl[] = {
+ {service_name, service_main},
+ {NULL, NULL}
+ };
+ service_stop_event = CreateEventA(NULL, TRUE, FALSE, NULL);
+ StartServiceCtrlDispatcherA(servtbl);
+ Sleep(50);
+ CloseHandle(service_stop_event);
+ }
+}
+
+
Propchange: trunk/rostests/apitests/ntdll/NtApphelpCacheControl.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/rostests/apitests/ntdll/testlist.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/apitests/ntdll/testlist.c…
==============================================================================
--- trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] (original)
+++ trunk/rostests/apitests/ntdll/testlist.c [iso-8859-1] Sat Sep 5 11:49:54 2015
@@ -5,6 +5,7 @@
extern void func_LdrEnumResources(void);
extern void func_NtAllocateVirtualMemory(void);
+extern void func_NtApphelpCacheControl(void);
extern void func_NtContinue(void);
extern void func_NtCreateFile(void);
extern void func_NtCreateThread(void);
@@ -40,6 +41,7 @@
{
{ "LdrEnumResources", func_LdrEnumResources },
{ "NtAllocateVirtualMemory", func_NtAllocateVirtualMemory },
+ { "NtApphelpCacheControl", func_NtApphelpCacheControl },
{ "NtContinue", func_NtContinue },
{ "NtCreateFile", func_NtCreateFile },
{ "NtCreateThread", func_NtCreateThread },