|
|
/*****************************************************************************
* Module Name: fntcache.cxx * * Font Cahce API's for NT font engine. * * History: * 4-15-99 We need to add the code for WTS (Hydra) * There are 3 major changes, * (1) We can not write to fntcache.dat in read mode. So we have modified the code * to make sure there there is no writing to fntcache in read mode. * (2) Implement a lock algorithm so than no remote session can open the fntcache.dat * during write mode of console. * (3) Check the time stamp of win32k.sys and atmfd.dll * 4-3-98 Yung-Jen Tony Tsai Wrote it. * * Copyright (c) 1998-1999 Microsoft Corporation *****************************************************************************/
#include "precomp.hxx"
#include <ntverp.h>
FLONG gflFntCacheState; FNTCACHE *gFntCache; HSEMAPHORE ghsemFntCache = NULL;
extern "C" gbJpn98FixPitch;
extern BOOL G_fConsole;
#define FNTCACHEPATH L"\\SystemRoot\\system32\\FNTCACHE.DAT"
#define WIN32KPATH L"\\SystemRoot\\system32\\win32k.sys"
#define ATMFDPATH L"\\SystemRoot\\system32\\atmfd.dll"
#define DISABLE_REMOTE_FONT_BOOT_CACHE L"DisableRemoteFontBootCache"
#define LASTBOOTTIME_FONT_CACHE_STATE L"LastBootTimeFontCacheState"
#define FNT_CACHE_EXTRA_SIZE (16*512)
#define RESERVE_LINKS 200
#if DBG
VOID DebugGreTrackRemoveMapView(PVOID ViewBase);
#define FNTCACHE_DBG_LEVEL_0 0
#define FNTCACHE_DBG_LEVEL_1 1
#define FNTCACHE_DBG_LEVEL_2 2
#define FNTCACHE_DBG_LEVEL_3 3
ULONG gFntTest = FNTCACHE_DBG_LEVEL_3;
#define FNT_KdBreakPoint(d, s1) \
{ \ if (d >= gFntTest) \ { \ DbgPrint s1; \ \ if (d >= FNTCACHE_DBG_LEVEL_1) \ DbgBreakPoint(); \ } \ } #else
#define FNT_KdBreakPoint(d, s1)
#endif
extern "C" ULONG ComputeFileviewCheckSum(PVOID, ULONG);
#define FNTCacheFileCheckSum(pTableView, cjView) ComputeFileviewCheckSum((PVOID)((PBYTE) pTableView + 4), (cjView -4))
#define FNTINDEX_INVALID 0xffffffff
ULONG ComupteFNTCacheFastCheckSum(ULONG cwc, PWSZ pwsz, PFONTFILEVIEW *ppfv,ULONG cFiles, DESIGNVECTOR *pdv, ULONG cjDV); VOID SearchFNTCacheHlink(ULONG ulFastCheckSum, FNTHLINK **ppfntHLink, FNTCACHEHEADER *pTable); BOOL bFntCacheCreateHLink(ULONG ulFastCheckSum); VOID PutFNTCacheIFI(ULONG ulFastCheckSum, PBYTE pIfi, ULONG ulSize); FNTHLINK * SearchFntCacheNewLink(ULONG ulFastCheckSum); BOOL bInitCacheTable(ULONG ulTTFonts, ULONG ulT1FOnts, LARGE_INTEGER FntRegLWT, LARGE_INTEGER T1RegLWT, ULONG CodePage);
// Here is only for performance evaluation
#define KEY_GRE_INITIALIZE L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Gre_Initialize"
#define KEY_NT_CURRENTVERSION L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion"
#define FNT_DISABLEFONTCACHE L"DisableFontBootCache"
#define CURRENT_BUILDNUMBER L"CurrentBuildNumber"
BOOL bQueryValueKey(PWSZ pwszValue, HANDLE RegistryKey, PKEY_VALUE_PARTIAL_INFORMATION ValueKeyInfo, ULONG ValueLength); BOOL bOpenKey(PWSZ pwszKey, HANDLE *pRegistryKey); VOID vUnmapFontCacheFile(VOID);
#define EXTRA_BUFFER 48
#define BUFF_LENGTH (sizeof(KEY_VALUE_PARTIAL_INFORMATION) + EXTRA_BUFFER)
typedef union _KVINFO { KEY_VALUE_PARTIAL_INFORMATION kv; BYTE aj[BUFF_LENGTH]; } KVINFO;
VOID vCleanUpFntCache(VOID) {
if (ghsemFntCache == NULL) return;
HSEMAPHORE hsemTmp = ghsemFntCache;
{ SEMOBJ so(ghsemFntCache);
if (gFntCache) { if (gFntCache->pTable) { vUnmapFontCacheFile(); }
VFREEMEM((PVOID) gFntCache); gFntCache = NULL; }
gflFntCacheState = 0; ghsemFntCache = NULL; }
// delete the semaphore, no longer needed
GreDeleteSemaphore(hsemTmp); }
BOOL bFntCacheDriverLWT( PCWSTR pcwFontDriverFileName, LARGE_INTEGER *pLastWriteTime) { UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS NtStatus; HANDLE FileHandle = 0; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION FileBasicInfo;
BOOL bRet = FALSE;
pLastWriteTime->QuadPart = 0;
RtlInitUnicodeString(&UnicodeString, pcwFontDriverFileName);
InitializeObjectAttributes( &ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, 0, 0);
NtStatus = IoCreateFile( &FileHandle, FILE_GENERIC_READ | FILE_GENERIC_EXECUTE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, // Flag for file open.
FILE_SYNCHRONOUS_IO_ALERT, 0, 0, CreateFileTypeNone, NULL, IO_FORCE_ACCESS_CHECK | // Ensure the user has access to the file
IO_NO_PARAMETER_CHECKING | // All of the buffers are kernel buffers
IO_CHECK_CREATE_PARAMETERS);
if (!NT_SUCCESS(NtStatus)) { return(FALSE); }
// Get the time stamp
NtStatus = ZwQueryInformationFile( FileHandle, &IoStatusBlock, &FileBasicInfo, sizeof(FileBasicInfo), FileBasicInformation);
ZwClose(FileHandle);
if (NT_SUCCESS(NtStatus)) { *pLastWriteTime = FileBasicInfo.LastWriteTime; bRet = TRUE; }
return bRet; }
VOID vGetFontDriverLWT(LARGE_INTEGER *pWin32kLWT, LARGE_INTEGER *pAtmfdLWT) { LARGE_INTEGER LastWriteTime;
if (bFntCacheDriverLWT( WIN32KPATH, &LastWriteTime)) { pWin32kLWT->QuadPart = LastWriteTime.QuadPart; }
if (bFntCacheDriverLWT( ATMFDPATH, &LastWriteTime)) { pAtmfdLWT->QuadPart = LastWriteTime.QuadPart; } }
NTSTATUS GetGreRegKey(HANDLE *phkRegistry, ACCESS_MASK dwDesiredAccess, PCWSTR pcwsz) { OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString;
RtlInitUnicodeString(&UnicodeString, pcwsz);
InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
return ZwOpenKey(phkRegistry, dwDesiredAccess, &ObjectAttributes); }
BOOL bSetFntCacheReg(PCWSTR pcwsz, DWORD dwValue) { HANDLE hkRegistry; UNICODE_STRING UnicodeString; NTSTATUS status; BOOL bRet = FALSE;
status = GetGreRegKey(&hkRegistry, GENERIC_WRITE, KEY_GRE_INITIALIZE);
if (NT_SUCCESS(status)) { RtlInitUnicodeString(&UnicodeString, pcwsz);
status = ZwSetValueKey(hkRegistry, &UnicodeString, 0, REG_DWORD, &dwValue, sizeof(DWORD));
if (NT_SUCCESS(status)) bRet = TRUE; else WARNING(" Failed to set DisableRemoteFontBootCache registry");
ZwCloseKey(hkRegistry); }
return bRet; }
DWORD bQueryFntCacheReg (HANDLE hkRegistry, PCWSTR pcwsz, DWORD *pdwDisableMode) { UNICODE_STRING UnicodeString; NTSTATUS status; DWORD Length; PKEY_VALUE_FULL_INFORMATION Information; BOOL bRet = FALSE;
RtlInitUnicodeString(&UnicodeString, pcwsz);
Length = sizeof(KEY_VALUE_FULL_INFORMATION) + (wcslen(pcwsz) + 1) * 2 + sizeof(DWORD);
Information = (PKEY_VALUE_FULL_INFORMATION) PALLOCMEM(Length, 'CFTT');
if (Information) { status = ZwQueryValueKey(hkRegistry, &UnicodeString, KeyValueFullInformation, Information, Length, &Length);
if (NT_SUCCESS(status)) { *pdwDisableMode = *(LPDWORD) ((((PUCHAR)Information) + Information->DataOffset)); bRet = TRUE; }
VFREEMEM(Information); }
return bRet; }
VOID vGetLastBootTimeStatus(void) { HANDLE hkRegistry; NTSTATUS status; DWORD dwReg = 0;
status = GetGreRegKey(&hkRegistry, GENERIC_READ, KEY_GRE_INITIALIZE);
gFntCache->flPrevBoot = 0;
if (NT_SUCCESS(status)) { if (bQueryFntCacheReg(hkRegistry, LASTBOOTTIME_FONT_CACHE_STATE, &dwReg)) { gFntCache->flPrevBoot = (FLONG) dwReg; } ZwCloseKey(hkRegistry); }
// If we are going to be opening the fntcache.dat in read mode than current boot time state
// will be the same as the previous boot time state. But flThisBoot will change
// if we will be opening the file CREATE (write) mode.
gFntCache->flThisBoot = gFntCache->flPrevBoot; }
/*****************************************************************************
* BOOL bFntCacheDisabled() * * Tempary routine for performance evaluation * * History * 10-15-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
BOOL bFntCacheDisabled() { HANDLE hkRegistry; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; NTSTATUS status; DWORD Length; PKEY_VALUE_FULL_INFORMATION Information; DWORD dwDisableMode = 0; BOOL bRet = FALSE;
status = GetGreRegKey(&hkRegistry, GENERIC_READ, KEY_GRE_INITIALIZE);
if (NT_SUCCESS(status)) { // let us check if somebody wanted to disable fontcache.dat by setting the
// DisableFontBootCache in the registry:
if (bQueryFntCacheReg(hkRegistry, L"DisableFontBootCache", &dwDisableMode)) { if (dwDisableMode) bRet = TRUE; }
if (!bRet && !G_fConsole) { // we may still want to disable the use of font cache for this remote hydra session.
// We would do this if the console session is writing to the font cache at this time
// (the console session would set the dwDisableMode to 1 in the registry so that
// remote sessions do not try to access the cache)
// or
// if the font cache is in a suspcious state, so that whoever read from or wrote to
// the cache before set the dwDisableMode to 1 in the registry
if (bQueryFntCacheReg(hkRegistry, DISABLE_REMOTE_FONT_BOOT_CACHE, &dwDisableMode)) { if (dwDisableMode) bRet = TRUE; } else { // for some reason, to read the registry failed. So it would be safe to
// disable the font cache.
bRet = TRUE; } }
ZwCloseKey(hkRegistry); }
return bRet; }
/*****************************************************************************
* BOOL bFntCacheDisabled() * * This routine to get the registry only for JPN fix pitch compatible width * * History * 2-3-2000 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
VOID vGetJpn98FixPitch() { HANDLE hkRegistry; NTSTATUS status; DWORD dwFixPitch = 0; status = GetGreRegKey(&hkRegistry, GENERIC_READ, KEY_GRE_INITIALIZE);
if (NT_SUCCESS(status)) { if (bQueryFntCacheReg(hkRegistry, L"Jpn98FixPitch", &dwFixPitch)) { if (dwFixPitch) gbJpn98FixPitch = TRUE; else gbJpn98FixPitch = FALSE; }
ZwCloseKey(hkRegistry); } }
/*****************************************************************************
* VOID FntCacheHDEV() * * Cache the font driver handle, include TT, OT, BMP and VT * * History * 10-15-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
VOID FntCacheHDEV(PPDEV hdev, ULONG ulDrv) { // There is no cache
if (!(gflFntCacheState & FNT_CACHE_MASK)) { return; }
ASSERTGDI (ulDrv && hdev, " Fnt Cache HDEV is wrong \n");
if (ulDrv) gFntCache->hDev[ulDrv] = hdev;
}
/*****************************************************************************
* extern "C" VOID EngFntCacheFault(ULONG ulFastCheckSum, FLONG fl) * * Fault reprot for Engine font cache. * * History * 10-15-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
extern "C" VOID EngFntCacheFault(ULONG ulFastCheckSum, FLONG fl) { FNTHLINK *pFntHlink = NULL; BOOL bExcept = FALSE;
// There is no cache
if (ghsemFntCache == NULL) return;
SEMOBJ so(ghsemFntCache);
if (!(gflFntCacheState & FNT_CACHE_MASK)) { return; }
BOOL bUpdate = FALSE;
switch (fl) { case ENG_FNT_CACHE_READ_FAULT: case ENG_FNT_CACHE_WRITE_FAULT:
// if we have already marked the font cache as bad, do not need to do it again
if (!(gFntCache->flThisBoot & FNT_CACHE_STATE_ERROR)) bUpdate = TRUE;
break;
default: break; }
if (bUpdate) { // we do need to mark the cache invalid
gFntCache->flThisBoot |= FNT_CACHE_STATE_ERROR; bSetFntCacheReg (LASTBOOTTIME_FONT_CACHE_STATE, gFntCache->flThisBoot); } }
/*****************************************************************************
* VOID PutFntCacheDrv(ULONG ulFastCheckSum, PPDEV hdev) * * Each font file is mapped to one font driver and cache it. * * History * 10-15-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
VOID PutFntCacheDrv(ULONG ulFastCheckSum, PPDEV hdev) { if (ghsemFntCache == NULL) return;
SEMOBJ so(ghsemFntCache);
// There is no cache
if (!(gflFntCacheState & FNT_CACHE_MASK)) { return; }
// No checksum mean nothing we can do
if (ulFastCheckSum) { ULONG i, ulMode;
ulMode = FNT_DUMMY_DRV;
// Serched the cached device handle
for (i = FNT_TT_DRV; i <= FNT_OT_DRV; i++) { if (hdev == gFntCache->hDev[i]) { ulMode = i; break; } }
// some unknown font driver has been used for the system, and we will not cache it.
if (ulMode == FNT_DUMMY_DRV) return;
// We cached it when FNTCache is in write mode
if (gflFntCacheState & FNT_CACHE_CREATE_MODE) { FNTHLINK *pFntHlink = NULL;
pFntHlink = SearchFntCacheNewLink(ulFastCheckSum);
if (pFntHlink) { // If fast check sum is in conflict, we can not cache it.
if (pFntHlink->ulDrvMode == FNT_DUMMY_DRV) // uninitialized link
{ pFntHlink->ulDrvMode = ulMode; } else { // Ok, fast checksum conflict
WARNING("Checksum conflict in PutFntCacheDrv"); pFntHlink->flLink |= FNT_CACHE_CHECKSUM_CONFLICT; } } else { gFntCache->flThisBoot |= FNT_CACHE_STATE_FULL; }
gFntCache->bWrite = TRUE; } else { ASSERTGDI(gflFntCacheState & FNT_CACHE_LOOKUP_MODE, "PutFntCacheDrv: gflFntCacheState\n");
// attempting to write during the read mode.
// This may happen if somebody overwrote the file in the fonts directory
// without updating the [Fonts] section in the registry. In this (infrequent) case we
// want to force the rebuild of the cache at the next boot time.
gFntCache->flThisBoot |= FNT_CACHE_STATE_FULL; } } }
VOID vUnmapFontCacheFile(VOID) { NTSTATUS ntStatus;
ASSERTGDI(gFntCache->pSection, "vUnmapFontCacheFile: gFntCache->pSection is NULL\n"); ASSERTGDI(gFntCache->pTable, "vUnmapFontCacheFile: gFntCache->pTable is NULL\n"); #if defined(_GDIPLUS_)
ntStatus = UnmapViewInProcessSpace(gFntCache->pTable);
#elif defined(_HYDRA_)
// MmUnmapViewInSessionSpace is internally promoted to
// MmUnmapViewInSystemSpace on non-Hydra systems.
ntStatus = Win32UnmapViewInSessionSpace((PVOID) gFntCache->pTable ); #else
ntStatus = MmUnmapViewInSystemSpace((PVOID)gFntCache->pTable))); #endif
#if DBG
if (!NT_SUCCESS(ntStatus)) RIP(" Font cache file remove Map View failed \n"); #endif
#if DBG && defined(_HYDRA_)
if ((!G_fConsole) && (NT_SUCCESS(ntStatus))) { DebugGreTrackRemoveMapView((PVOID) gFntCache->pTable); } #endif
DEREFERENCE_FONTVIEW_SECTION(gFntCache->pSection);
gFntCache->pSection = NULL; gFntCache->pTable = NULL;
return; }
/*****************************************************************************
* VOID CloseFNTCache() * * Clean font cache after system boot * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
extern "C" VOID CloseFNTCache() { // do paranoid check
HSEMAPHORE hsemTmp = ghsemFntCache;
if (ghsemFntCache == NULL) return;
{ SEMOBJ so(ghsemFntCache);
if (!(gflFntCacheState & FNT_CACHE_MASK)) { gflFntCacheState = 0; return; }
if (gflFntCacheState & FNT_CACHE_CREATE_MODE) { // Close the file, we are done recreating it
if (gFntCache->pTable) { if (gFntCache->bWrite) { gFntCache->pTable->ulTotalLinks = gFntCache->ulCurrentHlink; gFntCache->pTable->cjDataUsed = (ULONG)(gFntCache->pCacheBuf - gFntCache->pCacheBufStart); gFntCache->pTable->CheckSum = FNTCacheFileCheckSum(gFntCache->pTable, gFntCache->pTable->ulFileSize); } } }
if (gFntCache->pTable) { vUnmapFontCacheFile(); }
// now that the file is closed set the registry to indicate that it is ok for remote
// sessions to read from the cache file
if (gflFntCacheState & FNT_CACHE_CREATE_MODE) { if (gFntCache->flPrevBoot != gFntCache->flThisBoot) bSetFntCacheReg(LASTBOOTTIME_FONT_CACHE_STATE, gFntCache->flThisBoot);
// Unlock fnt cache file, say that it is ok to read from it
bSetFntCacheReg(DISABLE_REMOTE_FONT_BOOT_CACHE, 0); } else { if (gFntCache->flThisBoot & (FNT_CACHE_STATE_ERROR | FNT_CACHE_STATE_FULL)) bSetFntCacheReg(LASTBOOTTIME_FONT_CACHE_STATE, gFntCache->flThisBoot); }
VFREEMEM((PVOID) gFntCache); gFntCache = NULL;
gflFntCacheState = 0; ghsemFntCache = NULL; }
// delete the semaphore, no longer needed
GreDeleteSemaphore(hsemTmp); }
/*****************************************************************************
* BOOL bReAllocCacheFile(ULONG ulSize) * * ReAlloc font cache buffer * * History * 10-14-98 modified [YungT] * 8-22-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
BOOL bReAllocCacheFile(ULONG ulSize) { BOOL bOK = FALSE; ULONG ulSizeExtraOrg; ULONG ulFileSizeOrg; ULONG ulSizeExtra; ULONG ulCurrentSize; ULONG ulFileSize; DWORD dpOffsetStart; FILEVIEW FileView;
// OVERFLOW means that we would like to get a bigger cache file but the OS would not give it to us.
// In this case we just close the cache file, update the checksum (bWrite set to true) and
// let remote sessions that are to be started later use the partial cache file
if (gFntCache->flThisBoot & FNT_CACHE_STATE_OVERFLOW) { // we tried this once before and it did not work, so we do not bother to do it again
return bOK; }
ulFileSizeOrg = gFntCache->pTable->ulFileSize; ulCurrentSize = (ULONG) (gFntCache->pCacheBufEnd - gFntCache->pCacheBuf);
// Calculate the extra cache we need
ulSizeExtra = QWORD_ALIGN(ulSize - ulCurrentSize) + FNT_CACHE_EXTRA_SIZE;
ulFileSize = ulFileSizeOrg + ulSizeExtra;
dpOffsetStart = (DWORD) (gFntCache->pCacheBufStart - (PBYTE) gFntCache->pTable);
if (gFntCache->pTable) { vUnmapFontCacheFile(); }
RtlZeroMemory(&FileView, sizeof(FILEVIEW));
if (bMapFile(FNTCACHEPATH, &FileView, ulFileSize, NULL)) { DWORD dpOffset;
gFntCache->pTable = (FNTCACHEHEADER *) FileView.pvKView; gFntCache->pSection = FileView.pSection;
gFntCache->pTable->ulFileSize = ulFileSize; gFntCache->pTable->cjDataExtra += ulSizeExtra;
dpOffset = (ULONG)(gFntCache->pCacheBuf - gFntCache->pCacheBufStart);
// Got a new Table and got to re-calculate the buffer end pointer
gFntCache->pCacheBufStart = (PBYTE) gFntCache->pTable + dpOffsetStart;
gFntCache->pCacheBuf = gFntCache->pCacheBufStart + dpOffset;
gFntCache->pCacheBufEnd = gFntCache->pCacheBufStart + gFntCache->pTable->cjDataAll + gFntCache->pTable->cjDataExtra;
bOK = TRUE; } else { // Something wrong, so we do not change anything
RtlZeroMemory(&FileView, sizeof(FILEVIEW));
if (bMapFile(FNTCACHEPATH, &FileView, ulFileSizeOrg, NULL)) { gFntCache->pTable = (FNTCACHEHEADER *) FileView.pvKView; gFntCache->pSection = FileView.pSection;
// we want the cache properly closed, with check sum recomputed etc.
gFntCache->bWrite = TRUE;
// Force rebuild on the next boot, but for this boot let remote sessions
// use the partial cache file.
gFntCache->flThisBoot |= (FNT_CACHE_STATE_OVERFLOW | FNT_CACHE_STATE_FULL); } else { // Something wrong here. We need to set it to no cache mode.
WARNING("bReAllocCacheFile failed to allocate more buffer \n"); gFntCache->flThisBoot |= FNT_CACHE_STATE_ERROR; } }
return bOK; }
/*****************************************************************************
* ULONG QueryFontReg(PWCHAR pwcRegKeyPath, LARGE_INTEGER *pFontRegLastWriteTime) * * Helper function for query fonts information from TT and T1 fonts registry * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
BOOL QueryFontReg(PWCHAR pwcRegKeyPath, LARGE_INTEGER *pFontRegLastWriteTime, ULONG * pulFonts) { NTSTATUS Status; KEY_FULL_INFORMATION KeyInfo; HANDLE hkey = NULL; DWORD Length;
*pulFonts = 0;
Status = GetGreRegKey(&hkey,KEY_READ, pwcRegKeyPath);
if (NT_SUCCESS(Status)) {
// get the number of entries in the [Fonts] section and get the last write time
Status = ZwQueryKey(hkey, KeyFullInformation, &KeyInfo, sizeof(KeyInfo), &Length);
if (NT_SUCCESS(Status)) {
// for additional fonts that do not load from fonts section of the registry
*pulFonts = KeyInfo.Values; pFontRegLastWriteTime->QuadPart = KeyInfo.LastWriteTime.QuadPart;
FNT_KdBreakPoint(FNTCACHE_DBG_LEVEL_0, (" %d items in Font key \n", *pulFonts));
}
ZwCloseKey(hkey); }
return NT_SUCCESS(Status); }
/*****************************************************************************
* PVOID EngFntCacheAlloc(ULONG ulFastCheckSum, ULONG ulSize) * * Alloc the cached buffer for font driver * * History * 10-5-98 rewrite [YungT] * 8-22-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
extern "C" PVOID EngFntCacheAlloc(ULONG ulFastCheckSum, ULONG ulSize) {
PVOID pvIfi = NULL;
{ if (ghsemFntCache == NULL) return pvIfi;
SEMOBJ so(ghsemFntCache);
if (gflFntCacheState & FNT_CACHE_CREATE_MODE) {
if ( (gFntCache->pCacheBuf + QWORD_ALIGN(ulSize) < gFntCache->pCacheBufEnd) || bReAllocCacheFile(ulSize)) { FNTHLINK *pFntHlink = NULL;
if (pFntHlink = SearchFntCacheNewLink(ulFastCheckSum)) { // If fast check sum is conflict, we can not cache it.
if (pFntHlink->cjData == 0 && pFntHlink->dpData == 0) { pvIfi = (PVOID) gFntCache->pCacheBuf;
// Gaurantee the cache pointer is at 8 byte boundary
gFntCache->pCacheBuf = gFntCache->pCacheBuf + QWORD_ALIGN(ulSize); pFntHlink->cjData = ulSize; pFntHlink->dpData = (DWORD) ((PBYTE) pvIfi - gFntCache->pCacheBufStart); } else { WARNING("Checksum conflict in EngFntCacheAlloc"); pFntHlink->flLink |= FNT_CACHE_CHECKSUM_CONFLICT; }
gFntCache->bWrite = TRUE; } } } else { ASSERTGDI(gflFntCacheState & FNT_CACHE_LOOKUP_MODE, "EngFntCacheAlloc: gflFntCacheState\n");
// During read mode, the remote session still wants to write into fntcache.dat.
// This could happen if RemoteSession1 adds more fonts to both registry and on the disk.
// Then later, the RemoteSession2 may attepmpt during its initialization to add these fonts
// to the font cache, but we will reject this and ask that on the next boot the cache file
// be rebuilt. also, the files could have been overwritten on the disk without
// registry entries being updated, so we just force rebuild next time to be safe.
gFntCache->flThisBoot |= FNT_CACHE_STATE_FULL; } }
if (gFntCache->flThisBoot & FNT_CACHE_STATE_ERROR) { CloseFNTCache(); pvIfi = NULL; }
return pvIfi; }
/*****************************************************************************
* PVOID EngFntCacheLookUp(ULONG FastCheckSum, ULONG *pcjData) * * Lookup font cache * * History * 10-5-98 rewrite [YungT] * 8-22-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
extern "C" PVOID EngFntCacheLookUp(ULONG FastCheckSum, ULONG *pcjData) { FNTHLINK *pFntHlink; PBYTE pCache = NULL;
*pcjData = 0; pFntHlink = NULL;
if (ghsemFntCache == NULL) return (PVOID) pCache;
SEMOBJ so(ghsemFntCache);
if (gflFntCacheState & FNT_CACHE_LOOKUP_MODE) { if (gFntCache->pTable) {
// Search the cache table
SearchFNTCacheHlink( FastCheckSum, &pFntHlink, gFntCache->pTable);
if(pFntHlink && !(pFntHlink->flLink & FNT_CACHE_CHECKSUM_CONFLICT)) {
*pcjData = pFntHlink->cjData;
if (*pcjData) { pCache = gFntCache->pCacheBufStart + pFntHlink->dpData;
} } #if DBG
else { if (pFntHlink && (pFntHlink->flLink & FNT_CACHE_CHECKSUM_CONFLICT)) WARNING("Catch the checksum conflict in EngFntCacheLookUp \n"); } #endif
}
}
return (PVOID) pCache; }
/*****************************************************************************
* VOID InitNewCacheTable() * * Initialize font cache, open the fntcache,dat file and create hash table * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
BOOL bInitCacheTable(ULONG ulTTFonts, ULONG ulT1Fonts, LARGE_INTEGER FntRegLWT, LARGE_INTEGER T1RegLWT, LARGE_INTEGER Win32kLWT, LARGE_INTEGER AtmfdLWT, ULONG CodePage) { ULONG ulSize, ulIfiSize; BOOL bOk = FALSE; ULONG ulMaxFonts; FILEVIEW FileView;
ulMaxFonts = ulTTFonts + ulT1Fonts + RESERVE_LINKS;
ulSize = SZ_FNTCACHE(ulMaxFonts) + SZ_FNTIFICACHE(ulTTFonts, ulT1Fonts);
if (gFntCache->pTable) { vUnmapFontCacheFile(); }
RtlZeroMemory(&FileView, sizeof(FILEVIEW));
if(bMapFile(FNTCACHEPATH, &FileView, ulSize, NULL)) { gFntCache->pTable = (FNTCACHEHEADER *) FileView.pvKView; gFntCache->pSection = FileView.pSection;
RtlFillMemory((PBYTE) gFntCache->pTable->aiBuckets, FNTCACHE_MAX_BUCKETS * sizeof(DWORD), 0xFF); RtlZeroMemory((PBYTE) gFntCache->pTable->ahlnk, ulMaxFonts * sizeof(FNTHLINK));
gFntCache->pTable->ulCodePage = (ULONG) CodePage; gFntCache->pTable->ulMaxFonts = ulMaxFonts; gFntCache->pTable->ulTotalLinks = 0; gFntCache->pTable->CheckSum = 0; gFntCache->pTable->FntRegLWT.QuadPart = FntRegLWT.QuadPart; gFntCache->pTable->T1RegLWT.QuadPart = T1RegLWT.QuadPart; gFntCache->pTable->Win32kLWT.QuadPart = Win32kLWT.QuadPart; gFntCache->pTable->AtmfdLWT.QuadPart = AtmfdLWT.QuadPart; gFntCache->pTable->ulFileSize = ulSize; gFntCache->pTable->cjDataAll = SZ_FNTIFICACHE(ulTTFonts, ulT1Fonts); gFntCache->pTable->cjDataExtra = 0; gFntCache->pTable->cjDataUsed = 0;
bOk = TRUE; }
return bOk; }
/*****************************************************************************
* VOID InitFNTCache() * * Initialize font cache, open the fntcache,dat file and create hash table * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
VOID InitFNTCache() {
LARGE_INTEGER FntRegLWT = { 0, 0}; LARGE_INTEGER T1RegLWT = { 0, 0}; LARGE_INTEGER Win32kLWT = { 0, 0}; LARGE_INTEGER AtmfdLWT = { 0, 0};
ULONG ulTTFonts = 0; ULONG ulT1Fonts; ULONG ulSize = 0; BOOL bQryFntReg = FALSE; USHORT AnsiCodePage, OemCodePage; BOOL bLocked = TRUE;
// Initialize all the global variables
gflFntCacheState = 0;
ghsemFntCache = GreCreateSemaphore();
if (ghsemFntCache == NULL) { goto CleanUp; } // Only for performance evaluation.
if (bFntCacheDisabled()) { goto CleanUp; }
// Initialize and zero out all the memory
gFntCache = (FNTCACHE *) PALLOCMEM(sizeof(FNTCACHE), 'CFTT');
// There is something wrong we can not allocate buf
if (!gFntCache) { goto CleanUp; } if (G_fConsole) bLocked = bSetFntCacheReg(DISABLE_REMOTE_FONT_BOOT_CACHE, 1);
// If we can not lock the font cache file,
// then we can not open it in console
if (!bLocked) { goto CleanUp; }
gFntCache->pTable = NULL; gFntCache->ulCurrentHlink = 0; gFntCache->hDev[0] = 0; gFntCache->hDev[1] = 0; gFntCache->hDev[2] = 0; gFntCache->hDev[3] = 0; gFntCache->hDev[4] = 0; gFntCache->bWrite = FALSE;
RtlGetDefaultCodePage(&AnsiCodePage,&OemCodePage);
// Get the last boot time status
vGetLastBootTimeStatus();
// Get LWT of font driver
vGetFontDriverLWT(&Win32kLWT, &AtmfdLWT);
// now open the TT Fonts key :
if (QueryFontReg(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", &FntRegLWT, &ulTTFonts)) { ulTTFonts += FNTCACHE_EXTRA_LINKS;
// now open the Type 1 Fonts key :
if (QueryFontReg(L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Type 1 Installer\\Type 1 Fonts", &T1RegLWT, &ulT1Fonts)) { bQryFntReg = TRUE; } }
{ FILEVIEW FileView;
RtlZeroMemory(&FileView, sizeof(FILEVIEW));
if (bMapFile(FNTCACHEPATH, &FileView, 0, NULL)) { gFntCache->pTable = (FNTCACHEHEADER *) FileView.pvKView; gFntCache->pSection = (FNTCACHEHEADER *) FileView.pSection; }
if (gFntCache->pTable) { ULONG ulCheckSum; BOOL bCacheRead; BOOL bCheckSum;
bCacheRead = FALSE; bCheckSum = FALSE;
// File did not change from last time boot.
if (gFntCache->pTable->CheckSum && FileView.cjView == gFntCache->pTable->ulFileSize && gFntCache->pTable->CheckSum == FNTCacheFileCheckSum(gFntCache->pTable, FileView.cjView) && gFntCache->pTable->AtmfdLWT.QuadPart == AtmfdLWT.QuadPart && // current signature of atmfd
gFntCache->pTable->ulCodePage == AnsiCodePage && // If locale changed, we need to re-create the cache
!(gFntCache->flPrevBoot & FNT_CACHE_STATE_ERROR) && // No error at last boot time
(!G_fConsole || // for remote session would not care about the registry update
(!(gFntCache->flPrevBoot & FNT_CACHE_STATE_FULL) && gFntCache->pTable->Win32kLWT.QuadPart == Win32kLWT.QuadPart && // check signature of win32k.sys
FntRegLWT.QuadPart == gFntCache->pTable->FntRegLWT.QuadPart && // Check date time of cache file
T1RegLWT.QuadPart == gFntCache->pTable->T1RegLWT.QuadPart ) ) ) { gflFntCacheState = FNT_CACHE_LOOKUP_MODE; } else { if(G_fConsole && bInitCacheTable(ulTTFonts, ulT1Fonts, FntRegLWT, T1RegLWT, Win32kLWT, AtmfdLWT, (ULONG) AnsiCodePage)) {
// If something will not match, then it means we need to create FNTCACHE again
gflFntCacheState = FNT_CACHE_CREATE_MODE; } else { if (G_fConsole) { WARNING(" Boot time Font Cache failed\n"); WARNING(" The pTable is corrupted and font registry is failed to open\n"); } } } } else { // If there is no FNTCACHE.DAT file
// Then we need to create it.
if(G_fConsole && bInitCacheTable(ulTTFonts, ulT1Fonts, FntRegLWT, T1RegLWT, Win32kLWT, AtmfdLWT, (ULONG) AnsiCodePage)) { gflFntCacheState = FNT_CACHE_CREATE_MODE;
} else { if (G_fConsole) { WARNING("Boot time Font Cache failed\n"); WARNING(" If you read this message, please contact YungT or NTFONTS\n"); WARNING(" You can continue without any harm, just hit g\n"); } } }
}
CleanUp:
// Semaphore initialized
if (gflFntCacheState & FNT_CACHE_MASK) {
ASSERTGDI(gFntCache->pTable, "Fnt Cache pTable did not open \n");
// Initialize the start pointer of current Cache table
gFntCache->pCacheBufStart = (PBYTE) gFntCache->pTable + SZ_FNTCACHE(gFntCache->pTable->ulMaxFonts); gFntCache->pCacheBuf = gFntCache->pCacheBufStart + gFntCache->pTable->cjDataUsed; gFntCache->pCacheBufEnd = gFntCache->pCacheBufStart + gFntCache->pTable->cjDataAll + gFntCache->pTable->cjDataExtra;
gFntCache->ulCurrentHlink = gFntCache->pTable->ulTotalLinks;
if (gflFntCacheState & FNT_CACHE_LOOKUP_MODE) { // Unlock the the font cache file to make other session to use it
bSetFntCacheReg(DISABLE_REMOTE_FONT_BOOT_CACHE, 0); } else // FNT_CACHE_CREATE_MODE
{ gFntCache->flThisBoot = 0; } } else { gflFntCacheState = 0;
// Clean up the memory
if (gFntCache) { if (gFntCache->pTable) { vUnmapFontCacheFile(); }
VFREEMEM((PVOID) gFntCache); gFntCache = NULL; }
if (ghsemFntCache) { GreDeleteSemaphore(ghsemFntCache); ghsemFntCache = NULL; }
}
FNT_KdBreakPoint(FNTCACHE_DBG_LEVEL_1, ("FNT Cache Create mode %d\n", gflFntCacheState)); }
/*****************************************************************************
* ULONG ComupteFNTCacheFastCheckSum(ULONG cwc, PWSZ pwsz) * * Helper function to compute fast checksum * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
ULONG ComupteFNTCacheFastCheckSum(ULONG cwc, PWSZ pwsz, PFONTFILEVIEW *ppfv,ULONG cFiles, DESIGNVECTOR *pdv, ULONG cjDV) { ULONG i; ULONG checksum = 0; USHORT *pusCode;
for ( i = 0; i < cFiles; i++) { checksum += (checksum * 256 + ppfv[i]->fv.cjView); checksum += (checksum * 256 + (ULONG) ppfv[i]->fv.LastWriteTime.LowPart); checksum += (checksum * 256 + (ULONG) ppfv[i]->fv.LastWriteTime.HighPart); }
pusCode = (USHORT *) pwsz;
for ( i = 0; i < cwc; i++, pusCode++) { // SUM offset by 1 bit, it will make FastCheckSum unique
checksum += (checksum * 256 + (ULONG) *pusCode); }
if (pdv && cjDV) { PULONG pulCur, pulEnd;
pulCur = (PULONG) pdv;
for (pulEnd = pulCur + cjDV / sizeof(ULONG); pulCur < pulEnd; pulCur ++) { checksum += 256 * checksum + *pulCur; } }
return checksum; }
/*****************************************************************************
* ULONG LookUpFNTCacheTable(ULONG cwc, PWSZ pwszPathname, PULONG pulFastCheckSum) * * Lookup hash table if UFI exist then we return it, otherwise return 0 * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
ULONG LookUpFNTCacheTable(ULONG cwc, PWSZ pwszPathname, PULONG pulFastCheckSum, PFONTFILEVIEW *ppfv, ULONG cFiles, PPDEV * pppDevCache, DESIGNVECTOR *pdv, ULONG cjDV) { ULONG ulUFI = 0; ULONG ulBucket = 0; FNTHLINK *pFntHlink;
*pulFastCheckSum = 0; *pppDevCache = NULL;
if (ghsemFntCache == NULL) return ulUFI;
SEMOBJ so(ghsemFntCache);
if(cwc != 0) { *pulFastCheckSum = ComupteFNTCacheFastCheckSum ( cwc, pwszPathname, ppfv, cFiles, pdv, cjDV);
// If in CREATE mode, then nothing is in the cache
if (gflFntCacheState & FNT_CACHE_LOOKUP_MODE) { pFntHlink = NULL;
SearchFNTCacheHlink( *pulFastCheckSum, &pFntHlink, gFntCache->pTable);
if(pFntHlink && !(pFntHlink->flLink & FNT_CACHE_CHECKSUM_CONFLICT)) { ASSERTGDI( pFntHlink->ulFastCheckSum == *pulFastCheckSum, "ulFastCheckSum != pFntHlink->ulFastCheckSum \n"); ulUFI = pFntHlink->ulUFI; *pppDevCache = gFntCache->hDev[pFntHlink->ulDrvMode]; } } }
return ulUFI; }
/*****************************************************************************
* VOID SearchFNTCacheHlink(ULONG ulFastCheckSum, FNTHLINK **ppFntHlink) * * Hash table search function * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
VOID SearchFNTCacheHlink(ULONG ulFastCheckSum, FNTHLINK **ppFntHlink, FNTCACHEHEADER *pTable) { // If there is a Cache, then ppFntHlink will not be NULL
FNTHLINK *pFntHlink;
*ppFntHlink = NULL;
ULONG ulHashBucket;
DWORD iNext;
// Calculate the hash buckets
ulHashBucket = ulFastCheckSum % FNTCACHE_MAX_BUCKETS;
// Start from the first Offset.
iNext = pTable->aiBuckets[ulHashBucket];
while (iNext != FNTINDEX_INVALID) { pFntHlink = &pTable->ahlnk[iNext];
if (ulFastCheckSum == pFntHlink->ulFastCheckSum) { *ppFntHlink = pFntHlink; break; }
iNext = pFntHlink->iNext; }
return; }
FNTHLINK * SearchFntCacheNewLink(ULONG ulFastCheckSum) { FNTHLINK *pFntHlink = NULL;
// Search the new Link from pNewTable
SearchFNTCacheHlink(ulFastCheckSum, &pFntHlink, gFntCache->pTable);
// new Link dose not exist, we got to create it from pNewTable
if (!pFntHlink) { if (gFntCache->ulCurrentHlink < gFntCache->pTable->ulMaxFonts && bFntCacheCreateHLink(ulFastCheckSum)) { pFntHlink = &gFntCache->pTable->ahlnk[gFntCache->ulCurrentHlink]; pFntHlink->ulFastCheckSum = ulFastCheckSum; pFntHlink->ulUFI = 0; pFntHlink->iNext = FNTINDEX_INVALID; pFntHlink->cjData = 0; pFntHlink->dpData = 0; pFntHlink->flLink = 0;
pFntHlink->ulDrvMode = FNT_DUMMY_DRV; gFntCache->ulCurrentHlink++; } else { gFntCache->flThisBoot |= FNT_CACHE_STATE_FULL; } }
return pFntHlink; }
/*****************************************************************************
* VOID PutFNTCacheCheckSum(ULONG ulFastCheckSum,ULONG ulUFI) * * Hash table write mode, the UFI does not have in hash and then we put it in. * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
VOID PutFNTCacheCheckSum(ULONG ulFastCheckSum,ULONG ulUFI) { FNTHLINK *pFntHlink; if (ghsemFntCache == NULL) return;
SEMOBJ so(ghsemFntCache);
if (gflFntCacheState & FNT_CACHE_CREATE_MODE) {
pFntHlink = NULL;
if (pFntHlink = SearchFntCacheNewLink(ulFastCheckSum)) { // If fast check sum is conflict, we can not cache it.
if(pFntHlink->ulUFI == 0) { pFntHlink->ulUFI = ulUFI; } else { WARNING("Checksum conflict in PutFNTCacheCheckSum"); pFntHlink->flLink |= FNT_CACHE_CHECKSUM_CONFLICT; }
gFntCache->bWrite = TRUE;
} else { WARNING("FNTCACHE is not big enough \n"); FNT_KdBreakPoint(FNTCACHE_DBG_LEVEL_1, ("Put Trace: buckets %d, FastCheckSum %x,Check Sum %x \n", gFntCache->ulCurrentHlink, ulFastCheckSum, ulUFI)); } } else { ASSERTGDI(gflFntCacheState & FNT_CACHE_LOOKUP_MODE, "PutFNTCacheCheckSum: gflFntCacheState\n"); // During read mode, it still wants to write into fntcache.dat
// Then we will rebuild it at next boot time.
gFntCache->flThisBoot |= FNT_CACHE_STATE_FULL; }
}
/*****************************************************************************
* void FntCacheCreateHLink * * Build hash link in hash table * * History * 4-3-98 Yung-Jen Tony Tsai [YungT] * Wrote it. *****************************************************************************/
BOOL bFntCacheCreateHLink(ULONG ulFastCheckSum) { ULONG ulHashBucket; FNTHLINK *pCurHlink; DWORD iNextLink;
ulHashBucket = ulFastCheckSum % FNTCACHE_MAX_BUCKETS;
iNextLink = gFntCache->pTable->aiBuckets[ulHashBucket];
if (iNextLink != FNTINDEX_INVALID) { if (iNextLink > gFntCache->pTable->ulMaxFonts) return FALSE;
pCurHlink = &gFntCache->pTable->ahlnk[iNextLink];
// We put the new link at the end so that the search time is faster
while (pCurHlink->iNext != FNTINDEX_INVALID) { if (pCurHlink->iNext > gFntCache->pTable->ulMaxFonts) { gFntCache->flThisBoot |= FNT_CACHE_STATE_FULL; return FALSE; }
pCurHlink = &gFntCache->pTable->ahlnk[pCurHlink->iNext];
FNT_KdBreakPoint(FNTCACHE_DBG_LEVEL_0, ("Current iNextLink %x\n", pCurHlink->iNext)); }
pCurHlink->iNext = gFntCache->ulCurrentHlink;
} else { // put it at the head of the linked list
gFntCache->pTable->aiBuckets[ulHashBucket] = gFntCache->ulCurrentHlink;
FNT_KdBreakPoint(FNTCACHE_DBG_LEVEL_0, ("Put on HashBuckets %x\n", ulHashBucket)); }
return TRUE; }
|