2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ps/apphelp.c
5 * PURPOSE: SHIM engine caching.
6 * This caching speeds up checks for the apphelp compatibility layer.
7 * PROGRAMMERS: Mark Jansen
12 https://github.com/mandiant/ShimCacheParser/blob/master/ShimCacheParser.py
13 http://technet.microsoft.com/en-us/library/dd837644(v=ws.10).aspx
14 http://msdn.microsoft.com/en-us/library/bb432182(v=vs.85).aspx
15 http://www.alex-ionescu.com/?p=43
16 http://recxltd.blogspot.nl/2012/04/windows-appcompat-research-notes-part-1.html
17 http://journeyintoir.blogspot.ch/2013/12/revealing-recentfilecachebcf-file.html
18 https://dl.mandiant.com/EE/library/Whitepaper_ShimCacheParser.pdf
21 /* INCLUDES ******************************************************************/
27 /* GLOBALS *******************************************************************/
29 static BOOLEAN ApphelpCacheEnabled
= FALSE
;
30 static ERESOURCE ApphelpCacheLock
;
31 static RTL_AVL_TABLE ApphelpShimCache
;
32 static LIST_ENTRY ApphelpShimCacheAge
;
34 extern ULONG InitSafeBootMode
;
36 static UNICODE_STRING AppCompatCacheKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatCache");
37 static OBJECT_ATTRIBUTES AppCompatKeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatCacheKey
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
);
38 static UNICODE_STRING AppCompatCacheValue
= RTL_CONSTANT_STRING(L
"AppCompatCache");
40 #define EMPTY_SHIM_ENTRY { { 0 }, { { 0 } }, 0 }
41 #define MAX_SHIM_ENTRIES 0x200
42 #define TAG_SHIM 'MIHS'
44 #ifndef INVALID_HANDLE_VALUE
45 #define INVALID_HANDLE_VALUE (HANDLE)(-1)
50 typedef struct SHIM_PERSISTENT_CACHE_HEADER_52
54 } SHIM_PERSISTENT_CACHE_HEADER_52
, *PSHIM_PERSISTENT_CACHE_HEADER_52
;
56 /* The data that is present in the registry (Win2k3 version) */
57 typedef struct SHIM_PERSISTENT_CACHE_ENTRY_52
59 UNICODE_STRING ImageName
;
60 LARGE_INTEGER DateTime
;
61 LARGE_INTEGER FileSize
;
62 } SHIM_PERSISTENT_CACHE_ENTRY_52
, *PSHIM_PERSISTENT_CACHE_ENTRY_52
;
66 #define CACHE_MAGIC_NT_52 0xbadc0ffe
67 #define CACHE_HEADER_SIZE_NT_52 0x8
68 #define NT52_PERSISTENT_ENTRY_SIZE32 0x18
69 #define NT52_PERSISTENT_ENTRY_SIZE64 0x20
71 //#define CACHE_MAGIC_NT_61 0xbadc0fee
72 //#define CACHE_HEADER_SIZE_NT_61 0x80
73 //#define NT61_PERSISTENT_ENTRY_SIZE32 0x20
74 //#define NT61_PERSISTENT_ENTRY_SIZE64 0x30
76 #define SHIM_CACHE_MAGIC CACHE_MAGIC_NT_52
77 #define SHIM_CACHE_HEADER_SIZE CACHE_HEADER_SIZE_NT_52
79 #define SHIM_PERSISTENT_CACHE_ENTRY_SIZE NT52_PERSISTENT_ENTRY_SIZE64
81 #define SHIM_PERSISTENT_CACHE_ENTRY_SIZE NT52_PERSISTENT_ENTRY_SIZE32
83 #define SHIM_PERSISTENT_CACHE_HEADER SHIM_PERSISTENT_CACHE_HEADER_52
84 #define PSHIM_PERSISTENT_CACHE_HEADER PSHIM_PERSISTENT_CACHE_HEADER_52
85 #define SHIM_PERSISTENT_CACHE_ENTRY SHIM_PERSISTENT_CACHE_ENTRY_52
86 #define PSHIM_PERSISTENT_CACHE_ENTRY PSHIM_PERSISTENT_CACHE_ENTRY_52
88 C_ASSERT(sizeof(SHIM_PERSISTENT_CACHE_ENTRY
) == SHIM_PERSISTENT_CACHE_ENTRY_SIZE
);
89 C_ASSERT(sizeof(SHIM_PERSISTENT_CACHE_HEADER
) == SHIM_CACHE_HEADER_SIZE
);
91 /* The struct we keep in memory */
92 typedef struct SHIM_CACHE_ENTRY
95 SHIM_PERSISTENT_CACHE_ENTRY Persistent
;
97 } SHIM_CACHE_ENTRY
, *PSHIM_CACHE_ENTRY
;
99 /* PRIVATE FUNCTIONS *********************************************************/
105 return ExAllocatePoolWithTag(PagedPool
, ByteSize
, TAG_SHIM
);
112 ExFreePoolWithTag(Data
, TAG_SHIM
);
116 ApphelpCacheAcquireLock(VOID
)
118 KeEnterCriticalRegion();
119 ExAcquireResourceExclusiveLite(&ApphelpCacheLock
, TRUE
);
123 ApphelpCacheTryAcquireLock(VOID
)
125 KeEnterCriticalRegion();
126 if (!ExTryToAcquireResourceExclusiveLite(&ApphelpCacheLock
))
128 KeLeaveCriticalRegion();
135 ApphelpCacheReleaseLock(VOID
)
137 ExReleaseResourceLite(&ApphelpCacheLock
);
138 KeLeaveCriticalRegion();
142 ApphelpDuplicateUnicodeString(
143 _Out_ PUNICODE_STRING Destination
,
144 _In_ PCUNICODE_STRING Source
)
146 Destination
->Length
= Source
->Length
;
147 if (Destination
->Length
)
149 Destination
->MaximumLength
= Destination
->Length
+ sizeof(WCHAR
);
150 Destination
->Buffer
= ApphelpAlloc(Destination
->MaximumLength
);
151 RtlCopyMemory(Destination
->Buffer
, Source
->Buffer
, Destination
->Length
);
152 Destination
->Buffer
[Destination
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
156 Destination
->MaximumLength
= 0;
157 Destination
->Buffer
= NULL
;
162 ApphelpFreeUnicodeString(
163 _Inout_ PUNICODE_STRING String
)
167 ApphelpFree(String
->Buffer
);
170 String
->MaximumLength
= 0;
171 String
->Buffer
= NULL
;
174 /* Query file info from a handle, storing it in Entry */
176 ApphelpCacheQueryInfo(
177 _In_ HANDLE ImageHandle
,
178 _Out_ PSHIM_CACHE_ENTRY Entry
)
180 IO_STATUS_BLOCK IoStatusBlock
;
181 FILE_BASIC_INFORMATION FileBasic
;
182 FILE_STANDARD_INFORMATION FileStandard
;
185 Status
= ZwQueryInformationFile(ImageHandle
, &IoStatusBlock
,
186 &FileBasic
, sizeof(FileBasic
), FileBasicInformation
);
187 if (NT_SUCCESS(Status
))
189 Status
= ZwQueryInformationFile(ImageHandle
, &IoStatusBlock
,
190 &FileStandard
, sizeof(FileStandard
), FileStandardInformation
);
191 if (NT_SUCCESS(Status
))
193 Entry
->Persistent
.DateTime
= FileBasic
.LastWriteTime
;
194 Entry
->Persistent
.FileSize
= FileStandard
.EndOfFile
;
200 RTL_GENERIC_COMPARE_RESULTS
202 ApphelpShimCacheCompareRoutine(
203 _In_ PRTL_AVL_TABLE Table
,
204 _In_ PVOID FirstStruct
,
205 _In_ PVOID SecondStruct
)
207 LONG lResult
= RtlCompareUnicodeString(
208 &((PSHIM_CACHE_ENTRY
)FirstStruct
)->Persistent
.ImageName
,
209 &((PSHIM_CACHE_ENTRY
)SecondStruct
)->Persistent
.ImageName
, TRUE
);
212 return GenericLessThan
;
213 else if (lResult
== 0)
215 return GenericGreaterThan
;
220 ApphelpShimCacheAllocateRoutine(
221 _In_ PRTL_AVL_TABLE Table
,
224 return ApphelpAlloc(ByteSize
);
229 ApphelpShimCacheFreeRoutine(
230 _In_ PRTL_AVL_TABLE Table
,
238 _In_reads_(DataLength
) PUCHAR Data
,
239 _In_ ULONG DataLength
)
241 PSHIM_PERSISTENT_CACHE_HEADER Header
= (PSHIM_PERSISTENT_CACHE_HEADER
)Data
;
243 if (DataLength
< CACHE_HEADER_SIZE_NT_52
)
245 DPRINT1("SHIMS: ApphelpCacheParse not enough data for a minimal header (0x%x)\n", DataLength
);
246 return STATUS_INVALID_PARAMETER
;
248 if (Header
->Magic
== SHIM_CACHE_MAGIC
)
251 ULONG NumEntries
= Header
->NumEntries
;
252 DPRINT1("SHIMS: ApphelpCacheParse walking %d entries\n", NumEntries
);
253 for (Cur
= 0; Cur
< NumEntries
; ++Cur
)
255 UNICODE_STRING String
;
256 SHIM_CACHE_ENTRY Entry
= EMPTY_SHIM_ENTRY
;
257 PSHIM_CACHE_ENTRY Result
;
258 PSHIM_PERSISTENT_CACHE_ENTRY pPersistent
=
259 (PSHIM_PERSISTENT_CACHE_ENTRY
)(Data
+ SHIM_CACHE_HEADER_SIZE
+
260 (Cur
* SHIM_PERSISTENT_CACHE_ENTRY_SIZE
));
261 /* The entry in the Persitent storage is not really a UNICODE_STRING,
262 so we have to convert the offset into a real pointer before using it. */
263 String
.Length
= pPersistent
->ImageName
.Length
;
264 String
.MaximumLength
= pPersistent
->ImageName
.MaximumLength
;
265 String
.Buffer
= (PWCHAR
)((ULONG_PTR
)pPersistent
->ImageName
.Buffer
+ Data
);
267 /* Now we copy all data to a local buffer, that can be safely duplicated by RtlInsert */
268 Entry
.Persistent
= *pPersistent
;
269 ApphelpDuplicateUnicodeString(&Entry
.Persistent
.ImageName
, &String
);
270 Result
= RtlInsertElementGenericTableAvl(&ApphelpShimCache
, &Entry
, sizeof(Entry
), NULL
);
273 DPRINT1("SHIMS: ApphelpCacheParse insert failed\n");
274 ApphelpFreeUnicodeString(&Entry
.Persistent
.ImageName
);
275 return STATUS_INVALID_PARAMETER
;
277 InsertTailList(&ApphelpShimCacheAge
, &Result
->List
);
279 return STATUS_SUCCESS
;
281 DPRINT1("SHIMS: ApphelpCacheParse found invalid magic (0x%x)\n", Header
->Magic
);
282 return STATUS_INVALID_PARAMETER
;
286 ApphelpCacheRead(VOID
)
290 KEY_VALUE_PARTIAL_INFORMATION KeyValueObject
;
291 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= &KeyValueObject
;
292 ULONG KeyInfoSize
, ResultSize
;
294 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &AppCompatKeyAttributes
);
296 if (!NT_SUCCESS(Status
))
298 DPRINT1("SHIMS: ApphelpCacheRead could not even open Session Manager\\AppCompatCache (0x%x)\n", Status
);
302 Status
= ZwQueryValueKey(KeyHandle
, &AppCompatCacheValue
,
303 KeyValuePartialInformation
, KeyValueInformation
,
304 sizeof(KeyValueObject
), &ResultSize
);
306 if (Status
== STATUS_BUFFER_OVERFLOW
)
308 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyValueInformation
->DataLength
;
309 KeyValueInformation
= ApphelpAlloc(KeyInfoSize
);
310 if (KeyValueInformation
!= NULL
)
312 Status
= ZwQueryValueKey(KeyHandle
, &AppCompatCacheValue
,
313 KeyValuePartialInformation
, KeyValueInformation
,
314 KeyInfoSize
, &ResultSize
);
318 if (NT_SUCCESS(Status
) && KeyValueInformation
->Type
== REG_BINARY
)
320 Status
= ApphelpCacheParse(KeyValueInformation
->Data
,
321 KeyValueInformation
->DataLength
);
325 DPRINT1("SHIMS: ApphelpCacheRead not loaded from registry (0x%x)\n", Status
);
328 if (KeyValueInformation
!= &KeyValueObject
&& KeyValueInformation
!= NULL
)
329 ApphelpFree(KeyValueInformation
);
332 return NT_SUCCESS(Status
);
336 ApphelpCacheWrite(VOID
)
338 ULONG Length
= SHIM_CACHE_HEADER_SIZE
;
339 ULONG NumEntries
= 0;
340 PLIST_ENTRY ListEntry
;
341 PUCHAR Buffer
, BufferNamePos
;
342 PSHIM_PERSISTENT_CACHE_HEADER Header
;
343 PSHIM_PERSISTENT_CACHE_ENTRY WriteEntry
;
347 /* First we have to calculate the required size. */
348 ApphelpCacheAcquireLock();
349 ListEntry
= ApphelpShimCacheAge
.Flink
;
350 while (ListEntry
!= &ApphelpShimCacheAge
)
352 PSHIM_CACHE_ENTRY Entry
= CONTAINING_RECORD(ListEntry
, SHIM_CACHE_ENTRY
, List
);
353 Length
+= SHIM_PERSISTENT_CACHE_ENTRY_SIZE
;
354 Length
+= Entry
->Persistent
.ImageName
.MaximumLength
;
356 ListEntry
= ListEntry
->Flink
;
358 DPRINT1("SHIMS: ApphelpCacheWrite, %d Entries, total size: %d\n", NumEntries
, Length
);
359 Length
= ROUND_UP(Length
, sizeof(ULONGLONG
));
360 DPRINT1("SHIMS: ApphelpCacheWrite, Rounded to: %d\n", Length
);
362 /* Now we allocate and prepare some helpers */
363 Buffer
= ApphelpAlloc(Length
);
364 BufferNamePos
= Buffer
+ Length
;
365 Header
= (PSHIM_PERSISTENT_CACHE_HEADER
)Buffer
;
366 WriteEntry
= (PSHIM_PERSISTENT_CACHE_ENTRY
)(Buffer
+ SHIM_CACHE_HEADER_SIZE
);
368 Header
->Magic
= SHIM_CACHE_MAGIC
;
369 Header
->NumEntries
= NumEntries
;
371 ListEntry
= ApphelpShimCacheAge
.Flink
;
372 while (ListEntry
!= &ApphelpShimCacheAge
)
374 PSHIM_CACHE_ENTRY Entry
= CONTAINING_RECORD(ListEntry
, SHIM_CACHE_ENTRY
, List
);
375 USHORT ImageNameLen
= Entry
->Persistent
.ImageName
.MaximumLength
;
376 /* Copy the Persistent structure over */
377 *WriteEntry
= Entry
->Persistent
;
378 BufferNamePos
-= ImageNameLen
;
379 /* Copy the image name over */
380 RtlCopyMemory(BufferNamePos
, Entry
->Persistent
.ImageName
.Buffer
, ImageNameLen
);
381 /* Fix the Persistent structure, so that Buffer is once again an offset */
382 WriteEntry
->ImageName
.Buffer
= (PWCH
)(BufferNamePos
- Buffer
);
385 ListEntry
= ListEntry
->Flink
;
387 ApphelpCacheReleaseLock();
389 Status
= ZwOpenKey(&KeyHandle
, KEY_SET_VALUE
, &AppCompatKeyAttributes
);
390 if (NT_SUCCESS(Status
))
392 Status
= ZwSetValueKey(KeyHandle
, &AppCompatCacheValue
, 0, REG_BINARY
, Buffer
, Length
);
397 DPRINT1("SHIMS: ApphelpCacheWrite could not even open Session Manager\\AppCompatCache (0x%x)\n", Status
);
401 return NT_SUCCESS(Status
);
408 ApphelpCacheInitialize(VOID
)
410 DPRINT1("SHIMS: ApphelpCacheInitialize\n");
411 /* If we are booting in safemode we do not want to use the apphelp cache */
412 if (InitSafeBootMode
)
414 DPRINT1("SHIMS: Safe mode detected, disabling cache.\n");
415 ApphelpCacheEnabled
= FALSE
;
419 ExInitializeResourceLite(&ApphelpCacheLock
);
420 RtlInitializeGenericTableAvl(&ApphelpShimCache
,
421 ApphelpShimCacheCompareRoutine
,
422 ApphelpShimCacheAllocateRoutine
,
423 ApphelpShimCacheFreeRoutine
,
425 InitializeListHead(&ApphelpShimCacheAge
);
426 ApphelpCacheEnabled
= ApphelpCacheRead();
428 DPRINT1("SHIMS: ApphelpCacheInitialize: %d\n", ApphelpCacheEnabled
);
429 return STATUS_SUCCESS
;
434 ApphelpCacheShutdown(VOID
)
436 if (ApphelpCacheEnabled
)
444 _In_opt_ PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData
,
445 _Out_ PUNICODE_STRING ImageName
,
446 _Out_ PHANDLE ImageHandle
)
448 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
452 UNICODE_STRING LocalImageName
;
455 ProbeForRead(ServiceData
, sizeof(APPHELP_CACHE_SERVICE_LOOKUP
), sizeof(ULONG
));
456 LocalImageName
= ServiceData
->ImageName
;
457 *ImageHandle
= ServiceData
->ImageHandle
;
458 if (LocalImageName
.Length
&& LocalImageName
.Buffer
)
460 ProbeForRead(LocalImageName
.Buffer
, LocalImageName
.Length
* sizeof(WCHAR
), 1);
461 ApphelpDuplicateUnicodeString(ImageName
, &LocalImageName
);
462 Status
= STATUS_SUCCESS
;
465 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
467 _SEH2_YIELD(return _SEH2_GetExceptionCode());
471 if (!NT_SUCCESS(Status
))
473 DPRINT1("SHIMS: ApphelpValidateData: invalid data passed\n");
479 ApphelpCacheRemoveEntryNolock(
480 _In_ PSHIM_CACHE_ENTRY Entry
)
484 PWSTR Buffer
= Entry
->Persistent
.ImageName
.Buffer
;
485 RemoveEntryList(&Entry
->List
);
486 if (RtlDeleteElementGenericTableAvl(&ApphelpShimCache
, Entry
))
488 return STATUS_SUCCESS
;
490 return STATUS_NOT_FOUND
;
494 ApphelpCacheLookupEntry(
495 _In_ PUNICODE_STRING ImageName
,
496 _In_ HANDLE ImageHandle
)
498 NTSTATUS Status
= STATUS_NOT_FOUND
;
500 if (ApphelpCacheTryAcquireLock())
502 SHIM_CACHE_ENTRY Lookup
= EMPTY_SHIM_ENTRY
;
503 PSHIM_CACHE_ENTRY Entry
;
504 Lookup
.Persistent
.ImageName
= *ImageName
;
505 Entry
= RtlLookupElementGenericTableAvl(&ApphelpShimCache
, &Lookup
);
508 DPRINT1("SHIMS: ApphelpCacheLookupEntry: found %wZ\n", ImageName
);
509 if (ImageHandle
== INVALID_HANDLE_VALUE
)
511 DPRINT1("SHIMS: ApphelpCacheLookupEntry: ok\n");
512 /* just return if we know it, do not query file info */
513 Status
= STATUS_SUCCESS
;
515 else if (NT_SUCCESS(ApphelpCacheQueryInfo(ImageHandle
, &Lookup
)) &&
516 Lookup
.Persistent
.DateTime
.QuadPart
== Entry
->Persistent
.DateTime
.QuadPart
&&
517 Lookup
.Persistent
.FileSize
.QuadPart
== Entry
->Persistent
.FileSize
.QuadPart
)
519 DPRINT1("SHIMS: ApphelpCacheLookupEntry: found & validated\n");
520 Status
= STATUS_SUCCESS
;
521 /* move it to the front to keep it alive */
522 RemoveEntryList(&Entry
->List
);
523 InsertHeadList(&ApphelpShimCacheAge
, &Entry
->List
);
527 DPRINT1("SHIMS: ApphelpCacheLookupEntry: file info mismatch\n");
528 /* Could not read file info, or it did not match, drop it from the cache */
529 ApphelpCacheRemoveEntryNolock(Entry
);
534 DPRINT1("SHIMS: ApphelpCacheLookupEntry: could not find %wZ\n", ImageName
);
536 ApphelpCacheReleaseLock();
542 ApphelpCacheRemoveEntry(
543 _In_ PUNICODE_STRING ImageName
)
545 PSHIM_CACHE_ENTRY Entry
;
548 ApphelpCacheAcquireLock();
549 Entry
= RtlLookupElementGenericTableAvl(&ApphelpShimCache
, ImageName
);
550 Status
= ApphelpCacheRemoveEntryNolock(Entry
);
551 ApphelpCacheReleaseLock();
555 /* Validate that we are either called from r0, or from a service-like context */
557 ApphelpCacheAccessCheck(VOID
)
559 if (ExGetPreviousMode() != KernelMode
)
561 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, UserMode
))
563 DPRINT1("SHIMS: ApphelpCacheAccessCheck failed\n");
564 return STATUS_ACCESS_DENIED
;
567 return STATUS_SUCCESS
;
571 ApphelpCacheUpdateEntry(
572 _In_ PUNICODE_STRING ImageName
,
573 _In_ HANDLE ImageHandle
)
575 NTSTATUS Status
= STATUS_SUCCESS
;
576 SHIM_CACHE_ENTRY Entry
= EMPTY_SHIM_ENTRY
;
577 PSHIM_CACHE_ENTRY Lookup
;
579 TABLE_SEARCH_RESULT SearchResult
;
581 ApphelpCacheAcquireLock();
583 /* If we got a file handle, query it for info */
584 if (ImageHandle
!= INVALID_HANDLE_VALUE
)
586 Status
= ApphelpCacheQueryInfo(ImageHandle
, &Entry
);
589 if (NT_SUCCESS(Status
))
591 /* Use ImageName for the lookup, don't actually duplicate it */
592 Entry
.Persistent
.ImageName
= *ImageName
;
593 Lookup
= RtlLookupElementGenericTableFullAvl(&ApphelpShimCache
, &Entry
,
594 &NodeOrParent
, &SearchResult
);
597 DPRINT1("SHIMS: ApphelpCacheUpdateEntry: Entry already exists, reusing it\n");
598 /* Unlink the found item, so we can put it back at the front,
599 and copy the earlier obtained file info*/
600 RemoveEntryList(&Lookup
->List
);
601 Lookup
->Persistent
.DateTime
= Entry
.Persistent
.DateTime
;
602 Lookup
->Persistent
.FileSize
= Entry
.Persistent
.FileSize
;
606 DPRINT1("SHIMS: ApphelpCacheUpdateEntry: Inserting new Entry\n");
607 /* Insert a new entry, with its own copy of the ImageName */
608 ApphelpDuplicateUnicodeString(&Entry
.Persistent
.ImageName
, ImageName
);
609 Lookup
= RtlInsertElementGenericTableFullAvl(&ApphelpShimCache
,
610 &Entry
, sizeof(Entry
), 0, NodeOrParent
, SearchResult
);
613 ApphelpFreeUnicodeString(&Entry
.Persistent
.ImageName
);
614 Status
= STATUS_NO_MEMORY
;
619 /* Either we re-used an existing item, or we inserted a new one, keep it alive */
620 InsertHeadList(&ApphelpShimCacheAge
, &Lookup
->List
);
621 if (RtlNumberGenericTableElementsAvl(&ApphelpShimCache
) > MAX_SHIM_ENTRIES
)
623 PSHIM_CACHE_ENTRY Remove
;
624 DPRINT1("SHIMS: ApphelpCacheUpdateEntry: Cache growing too big, dropping oldest item\n");
625 Remove
= CONTAINING_RECORD(ApphelpShimCacheAge
.Blink
, SHIM_CACHE_ENTRY
, List
);
626 Status
= ApphelpCacheRemoveEntryNolock(Remove
);
630 ApphelpCacheReleaseLock();
635 ApphelpCacheFlush(VOID
)
639 DPRINT1("SHIMS: ApphelpCacheFlush\n");
640 ApphelpCacheAcquireLock();
641 while ((p
= RtlEnumerateGenericTableAvl(&ApphelpShimCache
, TRUE
)))
643 ApphelpCacheRemoveEntryNolock((PSHIM_CACHE_ENTRY
)p
);
645 ApphelpCacheReleaseLock();
646 return STATUS_SUCCESS
;
650 ApphelpCacheDump(VOID
)
652 PLIST_ENTRY ListEntry
;
654 DPRINT1("SHIMS: NtApphelpCacheControl( Dumping entries, newset to oldest )\n");
655 ApphelpCacheAcquireLock();
656 ListEntry
= ApphelpShimCacheAge
.Flink
;
657 while (ListEntry
!= &ApphelpShimCacheAge
)
659 PSHIM_CACHE_ENTRY Entry
= CONTAINING_RECORD(ListEntry
, SHIM_CACHE_ENTRY
, List
);
660 DPRINT1("Entry: %S\n", Entry
->Persistent
.ImageName
.Buffer
);
661 DPRINT1("DateTime High: 0x%x, Low: 0x%x\n",
662 Entry
->Persistent
.DateTime
.HighPart
, Entry
->Persistent
.DateTime
.LowPart
);
663 DPRINT1("FileSize High: 0x%x, Low: 0x%x\n",
664 Entry
->Persistent
.FileSize
.HighPart
, Entry
->Persistent
.FileSize
.LowPart
);
665 DPRINT1("Flags: 0x%x\n", Entry
->CompatFlags
);
666 ListEntry
= ListEntry
->Flink
;
668 ApphelpCacheReleaseLock();
669 return STATUS_SUCCESS
;
672 /* PUBLIC FUNCTIONS **********************************************************/
676 NtApphelpCacheControl(
677 _In_ APPHELPCACHESERVICECLASS Service
,
678 _In_opt_ PAPPHELP_CACHE_SERVICE_LOOKUP ServiceData
)
680 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
681 UNICODE_STRING ImageName
= { 0 };
682 HANDLE Handle
= INVALID_HANDLE_VALUE
;
684 if (!ApphelpCacheEnabled
)
686 DPRINT1("NtApphelpCacheControl: ApphelpCacheEnabled == 0\n");
691 case ApphelpCacheServiceLookup
:
692 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceLookup )\n");
693 Status
= ApphelpValidateData(ServiceData
, &ImageName
, &Handle
);
694 if (NT_SUCCESS(Status
))
695 Status
= ApphelpCacheLookupEntry(&ImageName
, Handle
);
697 case ApphelpCacheServiceRemove
:
698 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceRemove )\n");
699 Status
= ApphelpValidateData(ServiceData
, &ImageName
, &Handle
);
700 if (NT_SUCCESS(Status
))
701 Status
= ApphelpCacheRemoveEntry(&ImageName
);
703 case ApphelpCacheServiceUpdate
:
704 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpCacheServiceUpdate )\n");
705 Status
= ApphelpCacheAccessCheck();
706 if (NT_SUCCESS(Status
))
708 Status
= ApphelpValidateData(ServiceData
, &ImageName
, &Handle
);
709 if (NT_SUCCESS(Status
))
710 Status
= ApphelpCacheUpdateEntry(&ImageName
, Handle
);
713 case ApphelpCacheServiceFlush
:
714 Status
= ApphelpCacheFlush();
716 case ApphelpCacheServiceDump
:
717 Status
= ApphelpCacheDump();
719 case ApphelpDBGReadRegistry
:
720 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGReadRegistry ): flushing cache.\n");
722 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGReadRegistry ): reading cache.\n");
723 Status
= ApphelpCacheRead() ? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
725 case ApphelpDBGWriteRegistry
:
726 DPRINT1("SHIMS: NtApphelpCacheControl( ApphelpDBGWriteRegistry ): writing cache.\n");
727 Status
= ApphelpCacheWrite() ? STATUS_SUCCESS
: STATUS_NOT_FOUND
;
730 DPRINT1("SHIMS: NtApphelpCacheControl( Invalid service requested )\n");
733 if (ImageName
.Buffer
)
735 ApphelpFreeUnicodeString(&ImageName
);