You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2372 lines
69 KiB
2372 lines
69 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: mapfile2.c
|
|
*
|
|
* Copyright (c) 1997-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
#ifdef _HYDRA_
|
|
#include "muclean.hxx"
|
|
#endif
|
|
|
|
extern BOOL G_fConsole;
|
|
extern PW32PROCESS gpidSpool;
|
|
|
|
typedef enum _MAP_MODE {
|
|
ModeKernel,
|
|
ModeFD
|
|
} MAP_MODE;
|
|
|
|
typedef enum _FONT_IMAGE_TYPE {
|
|
RemoteImage = 1,
|
|
MemoryImage = 2
|
|
} FONT_IMAGE_TYPE;
|
|
|
|
BOOL bCreateSection(IN PWSTR, OUT FILEVIEW*, IN INT, BOOL *pbIsFAT);
|
|
VOID vUnmapFileFD(FILEVIEW*);
|
|
BOOL bMapRoutine(FONTFILEVIEW *pffv, FILEVIEW *pfv, MAP_MODE Mode, BOOL bIsFAT);
|
|
extern "C" HFASTMUTEX ghfmMemory;
|
|
|
|
#define SZDLHEADER ALIGN8(offsetof(DOWNLOADFONTHEADER, FileOffsets[1]))
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* Routine Name:
|
|
*
|
|
* cMapRemoteFonts
|
|
*
|
|
* This procedure creates a virtual memory section in which we store
|
|
* a copy of the spooler's data buffer. I shall refer to this copy
|
|
* as the "spooler section". The pointer to the associated section
|
|
* object is saved for later use. A view of the spooler section is
|
|
* mapped into the user-mode address space of the calling procedure
|
|
* (the spooler process). All the information about the spooler
|
|
* section and its mappings is stored in a FONTFILEVIEW
|
|
* strucutue supplied by the caller.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* ppHeader - address of a variable that gives and receives a
|
|
* pointer to a DOWNLOADFONTHEADER structure.
|
|
* Upon entry, this is a pointer to a view of the spooler
|
|
* section that is valid in the context of the calling
|
|
* process (the spooler process).
|
|
*
|
|
* Upon error the value placed at this address is zero.
|
|
*
|
|
* cjBuffer - a 32 bit variable that contains the size of the
|
|
* spooler image. In the case of MemoryImage fonts
|
|
* this size is actually larger than the size of the buffer
|
|
* by SZDLHEADER bytes.
|
|
*
|
|
* pFontFileView - a pointer to a FONTFILEVIEW structure that
|
|
* points to incomming receive the information about
|
|
* the copy of the spooler image.
|
|
*
|
|
* Upon error this structure consists of all zero's.
|
|
*
|
|
* Upon a successful completion of this procedure,
|
|
* pFontFileView->gtfv.pvView will point to the first
|
|
* font in the spooler buffer and
|
|
* pFontFileView->gtfv.cjView will be equal to the
|
|
* size of the spooler buffer starting at pvView.
|
|
* That is, cjView is equal to cjBuffer minus
|
|
* the size of the spooler header.
|
|
*
|
|
* The fields of the FONTFILEVIEW structure that are
|
|
* affected are:
|
|
*
|
|
* SpoolerBase - points to the base of a view of the spooler
|
|
* view of the spooler section. pHeader is
|
|
* valid only in the context of the this process
|
|
* (the spooler process)
|
|
*
|
|
* fv.pvView - points to the first font file in the spooler
|
|
* view of the spooler section. This view of
|
|
* the spooler section is valid only in the
|
|
* context of the calling process.
|
|
*
|
|
* fv.cjView - a 32-bit varaible that contains the size of
|
|
* header information is subtracted off. Another
|
|
* way to say this is: cjView is the offset of
|
|
* the end of the spooler section from the start
|
|
* of the image of the first font file.
|
|
*
|
|
* ulRegionSize - equal to the entire size of the spooler
|
|
* section including the header information.
|
|
*
|
|
* fv.pSection - pointer to the section object controling the
|
|
* spooler section. This is a kernel mode
|
|
* address and thus is accessable by any process
|
|
* in kernel mode.
|
|
*
|
|
* SpoolerPid - the process id of the calling process. This is
|
|
* the id of the process that has valid access
|
|
* to pHeader, and fv.pvView.
|
|
*
|
|
* ImageType - One of RemoteImage or MemoryImage. In
|
|
* the case of a remote font image, the image starts
|
|
* with a variable length DOWNLOADFONTHEADER structure
|
|
* followed by a series of file images at offsets
|
|
* specified in the header. In this case cjBuffer is
|
|
* equal to the size of the spooler image in bytes. This
|
|
* includes the size of the header, the files, and all
|
|
* necessary padding. In the case of a memory font image,
|
|
* the image is of a single font file; no header, no
|
|
* padding. In this case cjBuffer is equal to the size
|
|
* of the image plus SZDLHEADER. Here cjBuffer is equal
|
|
* to the size of the section to be produced which will
|
|
* start with a header, generated here, followed by
|
|
* a single font file image.
|
|
*
|
|
* Called by:
|
|
*
|
|
* NtGdiAddRemoteFontToDC
|
|
*
|
|
\**************************************************************************/
|
|
|
|
extern "C" ULONG cMapRemoteFonts(
|
|
DOWNLOADFONTHEADER **ppHeader, // IN OUT pointer to spooler buffer
|
|
// mapped into CSRSS address sapce
|
|
COUNT cjBuffer, // IN size of spooler buffer in bytes
|
|
FONTFILEVIEW *pFontFileView, // OUT pointer to mapped file information
|
|
FONT_IMAGE_TYPE ImageType // {Remote, Memory}
|
|
)
|
|
|
|
{
|
|
NTSTATUS NtStatus;
|
|
PVOID pSection, pView;
|
|
LARGE_INTEGER MaximumSize;
|
|
LARGE_INTEGER SectionOffset;
|
|
SIZE_T ViewSize;
|
|
ULONG TempSize, NumFiles;
|
|
BOOL bRet;
|
|
BOOL bSpooledType1 = FALSE;
|
|
|
|
DOWNLOADFONTHEADER *pHeader, *pCopy;
|
|
|
|
// Copy the address of the spooler data into pHeader for safe keeping
|
|
|
|
pHeader = *ppHeader;
|
|
|
|
// Set the (return value) of the address of the copy of the spooler
|
|
// data to zero. This indicates error.
|
|
|
|
*ppHeader = 0;
|
|
|
|
#define MAX_FONTFILE 0x10000000
|
|
|
|
// claudebe 6/24/99, the new surrogate enabled MungLui is blowing the previous limit of 0x80000000
|
|
|
|
ASSERTGDI(cjBuffer <= MAX_FONTFILE, "cjBuffer > MAX_FONTFILE");
|
|
|
|
// return 0 if cjBuffer is bogus
|
|
|
|
if ((cjBuffer > MAX_FONTFILE) || (cjBuffer < sizeof(DOWNLOADFONTHEADER)))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Initialize these variables to zero to prevent unintended access
|
|
// in the clean up code at the end of this routine. We also zero
|
|
// out the FONTFILEVIEW structure, not only to indicate error, but
|
|
// this will save us explicitly zeroing fields that we do not touch
|
|
// in this routine.
|
|
|
|
pSection = 0;
|
|
pView = 0;
|
|
|
|
if (pFontFileView == 0)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
RtlZeroMemory(pFontFileView, sizeof(*pFontFileView));
|
|
|
|
if (ImageType == RemoteImage)
|
|
{
|
|
__try
|
|
{
|
|
ProbeForRead(pHeader, sizeof(DOWNLOADFONTHEADER), sizeof(ULONG));
|
|
NumFiles = pHeader->NumFiles;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("cMapRemoteFonts: invalid pointer pHeader\n");
|
|
return (0);
|
|
}
|
|
|
|
// do some checks to ensure that these numbers are not entirely bogus.
|
|
// Eg. in reality we never have more than 3 files per font, the total
|
|
// sum of their sizes should not exceed MAX_FONTFILE (32MB for now);
|
|
// ClaudeBe 6/24/99, limit extended to 256 MB
|
|
|
|
ASSERTGDI(NumFiles <= 3, "NumFiles not reasonable\n");
|
|
|
|
if (NumFiles > 3)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// The upper limit on the size of the spooler section is 256Mb
|
|
|
|
if (0x10000000 < cjBuffer)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
if (!IS_USER_ADDRESS(pHeader))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
// If this a pfm,pfb image spooled from the NT 4.0 client,
|
|
// NumFiles will be set to zero and Type1ID will be set to
|
|
// ufi hash value. In this case we have to set the NumFiles to 2:
|
|
|
|
if (NumFiles == 0)
|
|
{
|
|
bSpooledType1 = TRUE;
|
|
NumFiles = 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// for MemoryImage, NumFiles should be 1
|
|
|
|
NumFiles = 1;
|
|
}
|
|
|
|
// Set TempSize to be equal to the size of the stuff preceeding
|
|
// the first font file. This is the size of the header information
|
|
// if you wish
|
|
|
|
TempSize = ALIGN8(offsetof(DOWNLOADFONTHEADER, FileOffsets[NumFiles]));
|
|
|
|
// return 0 if the TempSize is bigger than cjBuffer
|
|
|
|
if (cjBuffer < TempSize)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// Create a section where we will store a copy of the spooler data
|
|
|
|
MaximumSize.QuadPart = (LONGLONG) cjBuffer;
|
|
|
|
NtStatus =
|
|
Win32CreateSection(
|
|
&pSection , // SectionObject
|
|
SECTION_ALL_ACCESS , // DesiredAccess
|
|
0 , // ObjectAttributes
|
|
&MaximumSize , // MaximumSize
|
|
PAGE_READWRITE , // SectionPageProtection
|
|
SEC_COMMIT , // AllocationAttributes
|
|
0 , // FileHandle
|
|
0 , // FileObject
|
|
TAG_SECTION_REMOTEFONT
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
// Map a view of the spooler section into the user mode address space
|
|
// of the current process (this spooler process)
|
|
|
|
SectionOffset.QuadPart = 0;
|
|
ViewSize = cjBuffer;
|
|
|
|
ASSERTGDI(pView == 0, "pView != 0\n");
|
|
|
|
// Temporarily map a view of the section into the user mode address space
|
|
// of the spooler process. This will allow us to copy the data from
|
|
// the spool file to the section. After we are done we will close
|
|
// this mapping and open a mapping into the user mode address space
|
|
// of the CSRSS process.
|
|
|
|
NtStatus =
|
|
MmMapViewOfSection(
|
|
pSection , // SectionToMap,
|
|
PsGetCurrentProcess(), // spooler process
|
|
&pView , // CapturedBase,
|
|
0 , // ZeroBits,
|
|
ViewSize , // CommitSize,
|
|
&SectionOffset , // SectionOffset,
|
|
&ViewSize , // CapturedViewSize,
|
|
ViewUnmap , // InheritDisposition,
|
|
SEC_NO_CHANGE , // AllocationType,
|
|
PAGE_READWRITE // Allow writing on this view
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
Win32DestroySection(pSection);
|
|
return(0);
|
|
}
|
|
|
|
// this operation is a suspect for copying into 0-th page of csrss:
|
|
|
|
ASSERTGDI(pView, "pView == 0\n");
|
|
|
|
// Change pHeader to point at the copy
|
|
|
|
DOWNLOADFONTHEADER *pTmp = pCopy = (DOWNLOADFONTHEADER*) pView;
|
|
|
|
if (ImageType == MemoryImage)
|
|
{
|
|
// pHeader is a buffer of size cjBuffer - SZDLHEADER
|
|
// advance the pointer to the right position
|
|
|
|
cjBuffer -= SZDLHEADER;
|
|
pView = (PBYTE)pView + SZDLHEADER;
|
|
|
|
// fill out the fields in DOWNLOADFONTHEADER for memory fonts
|
|
|
|
__try
|
|
{
|
|
ProbeAndWriteUlong( &pTmp->Type1ID, 0);
|
|
ProbeAndWriteUlong( &pTmp->NumFiles, NumFiles);
|
|
ProbeAndWriteUlong( &pTmp->FileOffsets[0], cjBuffer);
|
|
bRet = TRUE;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("cMapRemoteFonts: exception occured for memory image\n");
|
|
EngSetLastError(ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
if (bRet == FALSE)
|
|
{
|
|
NtStatus = MmUnmapViewOfSection(PsGetCurrentProcess(), (PVOID)pCopy);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
WARNING("Could not unmap the current process view of the memory font\n");
|
|
}
|
|
Win32DestroySection(pSection);
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
// Copy the spooler data into this view of the spooler section
|
|
|
|
__try
|
|
{
|
|
ProbeForRead(pHeader, cjBuffer, sizeof(BYTE));
|
|
RtlCopyMemory(pView, pHeader, cjBuffer);
|
|
bRet = TRUE;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("cMapRemoteFonts: exception occured\n");
|
|
EngSetLastError(ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
}
|
|
|
|
// fix the spooled (from NT 4.0) Type1 font case:
|
|
|
|
if (bSpooledType1)
|
|
{
|
|
__try
|
|
{
|
|
ProbeAndWriteUlong( &pTmp->Type1ID, 0);
|
|
ProbeAndWriteUlong( &pTmp->NumFiles, NumFiles);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("cMapRemoteFonts: exception occured\n");
|
|
EngSetLastError(ERROR_INVALID_PARAMETER);
|
|
bRet = FALSE;
|
|
}
|
|
}
|
|
|
|
// We have OR have not successfully completed copying the data
|
|
// from the file to the section. In either case we no longer
|
|
// need this view of the section
|
|
// so we will unmap the spooler view at this time
|
|
|
|
NtStatus = MmUnmapViewOfSection(PsGetCurrentProcess(), (PVOID)pCopy);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
WARNING("Could not unmap the current process view of the memory font\n");
|
|
KdPrint(("Could not unmap the current process view of the memory font\n"));
|
|
|
|
Win32DestroySection(pSection);
|
|
return(0);
|
|
}
|
|
|
|
if (bRet == FALSE)
|
|
{
|
|
Win32DestroySection(pSection);
|
|
return(0);
|
|
}
|
|
|
|
// Now we will map a view into the user mode address space
|
|
// of the CSRSS process. Remember that this view cannot
|
|
// be seen by the current process.
|
|
|
|
pView = 0;
|
|
ViewSize = 0;
|
|
SectionOffset.QuadPart = 0;
|
|
|
|
NtStatus =
|
|
MmMapViewOfSection(
|
|
pSection , // SectionToMap,
|
|
gpepCSRSS , // CSRSS process
|
|
&pView , // CapturedBase,
|
|
0 , // ZeroBits,
|
|
ViewSize , // CommitSize,
|
|
&SectionOffset , // SectionOffset,
|
|
&ViewSize , // CapturedViewSize,
|
|
ViewUnmap , // InheritDisposition,
|
|
SEC_NO_CHANGE , // AllocationType,
|
|
PAGE_READONLY // No writing on this view
|
|
);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
Win32DestroySection(pSection);
|
|
return(0);
|
|
}
|
|
|
|
ASSERTGDI((ULONG_PTR)pView > 0x100000,
|
|
"cmap remote fonts: csrss view smaller than 1MB \n");
|
|
|
|
// Reset pCopy to point to a view of the section in the context
|
|
// of the CSRSS process. CAUTION - you cannot access any data
|
|
// off of pCopy or pView after this point.
|
|
|
|
pCopy = (DOWNLOADFONTHEADER*) pView;
|
|
|
|
if (ImageType == MemoryImage)
|
|
{
|
|
// reset the size and pointer
|
|
|
|
cjBuffer += SZDLHEADER;
|
|
pView = pCopy;
|
|
}
|
|
|
|
// Set the FONTFILEVIEW
|
|
//
|
|
// SpoolerBase points at the base of the copy.
|
|
// pvView points to the first font image.
|
|
// cjView is the size of the section with starting
|
|
// at the first font image.
|
|
// ulRegionSize is set to the size of the entire view.
|
|
|
|
pFontFileView->SpoolerBase = pCopy;
|
|
pFontFileView->fv.pvViewFD = (char*) pCopy + TempSize;
|
|
pFontFileView->fv.cjView = cjBuffer - TempSize;
|
|
pFontFileView->ulRegionSize = ViewSize;
|
|
|
|
// We have to set FD ref count to 1, KM ref count to zero [bodind]
|
|
|
|
pFontFileView->cKRefCount = 0;
|
|
pFontFileView->cRefCountFD = 1;
|
|
|
|
pFontFileView->fv.pSection = pSection;
|
|
pFontFileView->SpoolerPid = W32GetCurrentPID(); // this could be the pid of the spooler
|
|
// or the pid of the current process which is loading a memory font
|
|
|
|
*ppHeader = pCopy; // Valid in CSRSS process only.
|
|
|
|
return(NumFiles);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vUnmapRemoteFonts
|
|
*
|
|
* This is a remote font so delete the memory for the view.
|
|
*
|
|
* CAUTION
|
|
*
|
|
* This code is intimately linked with NtGdiAddRemoteFontToDC()
|
|
* so any changes here should be synchronized there.
|
|
*
|
|
* The pool memory starts with a DOWNLOADFONTHEADER followed by the
|
|
* file image pointed to by pvView. We must pass the pointer to the
|
|
* beginning of the pool allocation to the free routine.
|
|
*
|
|
*
|
|
* Spooler data format for Engine fonts
|
|
*
|
|
*
|
|
* DOWNLOADFONTHEADER PADDING
|
|
* | |
|
|
* | |- FILE OFFSETS-| |
|
|
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
* | 0 | 1 | 2 | 3 | N | x | font image #0 | font image #1 |...
|
|
* +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
|
* ^
|
|
* pvView points to first font image
|
|
*
|
|
*
|
|
* Parameters:
|
|
*
|
|
* pFontFileView - a 32-bit variable that contains a pointer to a
|
|
* FONTFILEVIEW structure that describes the very
|
|
* first font file image in the spooler data.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* none
|
|
*
|
|
* Called by:
|
|
*
|
|
* NtGdiAddRemoteFontsToDC
|
|
* FreeFileView
|
|
*
|
|
\**************************************************************************/
|
|
|
|
extern "C" void vUnmapRemoteFonts(FONTFILEVIEW *pFontFileView)
|
|
{
|
|
if (pFontFileView == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ASSERTGDI(pFontFileView->SpoolerPid == W32GetCurrentPID() ||
|
|
gpidSpool == (PW32PROCESS)W32GetCurrentProcess(),
|
|
"vUnmapRemoteFonts: wrong process freeing remote font data\n");
|
|
|
|
// We initialize the cRefCountFD to 1 in cMapRemoteFonts() function
|
|
|
|
if (pFontFileView->cRefCountFD)
|
|
{
|
|
pFontFileView->cRefCountFD -= 1;
|
|
}
|
|
|
|
if (pFontFileView->cRefCountFD == 0)
|
|
{
|
|
if (pFontFileView->fv.pSection)
|
|
{
|
|
if (pFontFileView->SpoolerBase)
|
|
{
|
|
MmUnmapViewOfSection(gpepCSRSS, pFontFileView->SpoolerBase);
|
|
pFontFileView->SpoolerBase = NULL;
|
|
}
|
|
Win32DestroySection(pFontFileView->fv.pSection);
|
|
pFontFileView->fv.pSection = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bCreateFontFileView
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bCreateFontFileView(
|
|
FONTFILEVIEW *pFontFileViewIn, // kernel mode address
|
|
DOWNLOADFONTHEADER *pHeader, // CSRSS address of spool section
|
|
COUNT cjBuffer,
|
|
FONTFILEVIEW ***papfv,
|
|
ULONG NumFiles
|
|
)
|
|
{
|
|
FONTFILEVIEW **apfv, *pFontFileView, FontFileView;
|
|
NTSTATUS NtStatus;
|
|
ULONG offset;
|
|
COUNT cjHeader;
|
|
BOOL bRet = TRUE;
|
|
|
|
//
|
|
// In order to see the data pointed to by pHeader we must attach
|
|
// to the address space of the CSRSS process
|
|
//
|
|
|
|
KeAttachProcess(PsGetProcessPcb(gpepCSRSS));
|
|
|
|
//
|
|
// engine fonts
|
|
//
|
|
|
|
apfv = 0;
|
|
FontFileView = *pFontFileViewIn;
|
|
|
|
cjHeader = ALIGN8(offsetof(DOWNLOADFONTHEADER,FileOffsets[NumFiles]));
|
|
|
|
if (cjBuffer <= cjHeader)
|
|
{
|
|
EngSetLastError(ERROR_INVALID_PARAMETER);
|
|
KeDetachProcess();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// The lowest part of the block of memory pointed to by apfv
|
|
// will be occupied by NumFiles pointers to FONTFILEVIEW structures.
|
|
// The FONTFILEVIEW structures pointed to by these pointers follow
|
|
// at the first 8-byte aligned address after the array of pointers.
|
|
//
|
|
/*********************************************************************************
|
|
* *
|
|
* Structure of data pointed to by `apfv' *
|
|
* *
|
|
* pointer data +----------------------------+ *
|
|
* | V *
|
|
* +---+ +---+---+---+---+---+---+----+---+---+---+----+---+---+---+----+---+ *
|
|
* |apfv ... | p | p | p | |FONTFILEVIEW| |FONTFILEVIEW| |FONTFILEVIEW| | *
|
|
* +---+ +---+---+---+---+---+---+----+---+---+---+----+---+---+---+----+---+ *
|
|
* | ^ | ^ *
|
|
* +-------+ +-------------+ *
|
|
* *
|
|
* | | *
|
|
* |<-- offset --->| *
|
|
* *
|
|
*********************************************************************************/
|
|
|
|
//
|
|
// `offset' is the count of bytes from the beginning of the allocated
|
|
// memory to where the array of FONTFILEVIEW structures starts. An array
|
|
// of FONTFILEVIEW pointers preceeds.
|
|
//
|
|
|
|
offset = ALIGN8(sizeof(FONTFILEVIEW*) * NumFiles);
|
|
|
|
apfv = (FONTFILEVIEW**) PALLOCMEM(sizeof(FONTFILEVIEW) * NumFiles + offset, 'vffG');
|
|
|
|
if (apfv == 0)
|
|
{
|
|
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
KeDetachProcess();
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Only initiaze these values for one file view in the
|
|
// array. This file view will be used to free the entire
|
|
// block of memory containing all the files.
|
|
//
|
|
|
|
FONTFILEVIEW **ppFontFileView = apfv;
|
|
|
|
pFontFileView = (FONTFILEVIEW*) ((char*) apfv + offset);
|
|
|
|
//
|
|
// FileOffset[i] = offset of File[i+1] from begining of first
|
|
// font file view
|
|
//
|
|
// Size[i] = FileOffset[i] - FileOffset[i-1];
|
|
//
|
|
|
|
//
|
|
// copy the FONTFILEVIEW structure initialized by vMapSpoolerFontFiles
|
|
// into the first positon in the array
|
|
//
|
|
|
|
*pFontFileView = FontFileView;
|
|
|
|
//
|
|
// Set pchView to point to the first FONTFILEVIEW structure in the
|
|
// array
|
|
//
|
|
|
|
char *pchView = (char*) FontFileView.fv.pvViewFD;
|
|
|
|
//
|
|
// pchLast points to illegal memory. This step relies on
|
|
// vMapRemotFonts to place in cjView the size of the view as
|
|
// though it were based at the start of the first file.
|
|
//
|
|
|
|
char *pchLast = pchView + FontFileView.fv.cjView;
|
|
|
|
ULONG Offset = 0;
|
|
ULONG *pOffset = &(pHeader->FileOffsets[0]);
|
|
ULONG *pOffsetLast = pOffset + NumFiles;
|
|
|
|
for (; pOffset < pOffsetLast; pOffset++)
|
|
{
|
|
ULONG NextOffset = *pOffset;
|
|
ULONG cjView = NextOffset - Offset;
|
|
Offset = ALIGN4(NextOffset);
|
|
// the offset alignement must correspond to \ntgdi\client\ufi.c WriteFontToSpoolFile()
|
|
// if there is a need for different alignement, then we would need to map each file separately
|
|
ASSERTGDI(Offset == NextOffset, "bCreateFontFileView ALIGN difference between client and server");
|
|
|
|
|
|
if (pchLast < pchView + cjView)
|
|
{
|
|
bRet = FALSE;
|
|
break;
|
|
}
|
|
|
|
pFontFileView->fv.pvViewFD = pchView;
|
|
pFontFileView->fv.cjView = cjView;
|
|
|
|
//
|
|
// move pchView to point at the next font image
|
|
//
|
|
|
|
pchView += cjView;
|
|
|
|
*ppFontFileView = pFontFileView;
|
|
|
|
ppFontFileView++;
|
|
pFontFileView++;
|
|
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
VFREEMEM(apfv);
|
|
}
|
|
else
|
|
{
|
|
*papfv = apfv;
|
|
}
|
|
|
|
KeDetachProcess();
|
|
|
|
return (bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* NtGdiAddRemoteFontToDC
|
|
*
|
|
* This routine is called by the spooler process, at playback time, to
|
|
* add remote fonts to a printer DC. The font files in question are for
|
|
* the use of the associated print job only. No other application can
|
|
* have access. In order to prevent mischevious application on the server
|
|
* from picking up font to which it has not right, we have chosen to not
|
|
* copy the file images contained in the spool file to separate font file
|
|
* on the disk. This means that the spooler process cannot use
|
|
* AddFontResource to allow the DC access to the fonts.
|
|
* Instead, we have introduced this private entry point for the spooler.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* hdc - handle to DC to which remote font is to be added
|
|
*
|
|
* pvBuffer - pointer to a DOWNLOADFONTHEADER that details
|
|
* the location of the font files contained
|
|
* withing this buffer.
|
|
*
|
|
* cjBuffer - is the size of the buffe, in bytes, pointed
|
|
* to by pvBuffer
|
|
*
|
|
* Return Value:
|
|
*
|
|
* TRUE if successful, FALSE if not.
|
|
*
|
|
* Remarks:
|
|
*
|
|
* In the process of loading the fonts to the spooler DC, we create
|
|
* an array of FONTFILEVIEW structures. The lowest part of the block
|
|
* of memory pointed to by apfv will be occupied by NumFiles pointers
|
|
* to FONTFILEVIEW structures. The FONTFILEVIEW structures pointed to
|
|
* by these pointers follow at the first 8-byte aligned address after
|
|
* the array of pointers.
|
|
*
|
|
* Structure of data pointed to by `apfv'
|
|
*
|
|
* pointer data +----------------------------+
|
|
* | V
|
|
* +---+ +---+---+---+---+---+---+----+---+---+---+----+---+---+---+----+---+
|
|
* |apfv ... | p | p | p | |FONTFILEVIEW| |FONTFILEVIEW| |FONTFILEVIEW| |
|
|
* +---+ +---+---+---+---+---+---+----+---+---+---+----+---+---+---+----+---+
|
|
* | ^ | ^
|
|
* +-------+ +-------------+
|
|
*
|
|
* | |
|
|
* |<-- offset --->|
|
|
*
|
|
\**************************************************************************/
|
|
|
|
extern "C" BOOL APIENTRY NtGdiAddRemoteFontToDC(
|
|
HDC hdc , // handle to DC to which remote font is to be added
|
|
PVOID pvBuffer , // pointer to spool font file image
|
|
COUNT cjBuffer , // size of spool font file image
|
|
PUNIVERSAL_FONT_ID pufi //orignal ufi for subsetted font, used for remote printing only
|
|
)
|
|
{
|
|
FONTFILEVIEW FontFileView, **apfv, *pFontFileView;
|
|
DOWNLOADFONTHEADER *pHeader;
|
|
NTSTATUS NtStatus;
|
|
ULONG offset;
|
|
ULONG NumFiles;
|
|
BOOL bRet;
|
|
BOOL bMappedSpoolerFont;
|
|
UNIVERSAL_FONT_ID ufiTmp;
|
|
UNIVERSAL_FONT_ID *pufiTmp = pufi;
|
|
|
|
__try
|
|
{
|
|
if (pufiTmp)
|
|
{
|
|
ufiTmp = ProbeAndReadStructure(pufiTmp, UNIVERSAL_FONT_ID);
|
|
pufiTmp = &ufiTmp;
|
|
}
|
|
bRet = TRUE;
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
|
|
if (!bRet)
|
|
return bRet;
|
|
|
|
bRet = FALSE;
|
|
XDCOBJ dco(hdc);
|
|
|
|
if (!dco.bValid())
|
|
{
|
|
return bRet;
|
|
}
|
|
|
|
apfv = 0;
|
|
pFontFileView = NULL;
|
|
|
|
pHeader = (DOWNLOADFONTHEADER*) pvBuffer;
|
|
|
|
NumFiles = cMapRemoteFonts(&pHeader, cjBuffer, &FontFileView, RemoteImage);
|
|
|
|
if (pHeader == 0)
|
|
{
|
|
goto exit_point;
|
|
}
|
|
bRet = TRUE;
|
|
pFontFileView = &FontFileView;
|
|
|
|
if (NumFiles)
|
|
{
|
|
// engine fonts
|
|
|
|
if (bRet = bCreateFontFileView(&FontFileView, pHeader, cjBuffer, &apfv, NumFiles))
|
|
{
|
|
PUBLIC_PFTOBJ pfto;
|
|
|
|
bRet = pfto.bLoadRemoteFonts(dco, apfv, NumFiles, 0, pufiTmp);
|
|
}
|
|
}
|
|
|
|
exit_point:
|
|
|
|
if (!bRet)
|
|
{
|
|
if (pFontFileView)
|
|
{
|
|
vUnmapRemoteFonts(pFontFileView);
|
|
}
|
|
if (apfv)
|
|
{
|
|
VFREEMEM(apfv);
|
|
}
|
|
}
|
|
dco.vUnlockFast();
|
|
|
|
return (bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GreAddFontMemResourceEx
|
|
*
|
|
* This function uses same routines that NtGdiAddRemoteToDC()
|
|
* uses to create the file view structrues before it can load
|
|
* the font into the system. Memory fonts are always added as
|
|
* private to the private font tale.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HANDLE GreAddFontMemResourceEx(
|
|
PVOID pvBuffer,
|
|
ULONG cjBuffer,
|
|
DESIGNVECTOR *pdv,
|
|
DWORD cjDV,
|
|
DWORD *pNumFonts
|
|
)
|
|
{
|
|
FONTFILEVIEW **apfv, FontFileView;
|
|
DOWNLOADFONTHEADER *pHeader;
|
|
ULONG NumFiles;
|
|
|
|
HANDLE hMMFont = 0;
|
|
BOOL bOK = FALSE;
|
|
|
|
apfv = 0;
|
|
pHeader = (DOWNLOADFONTHEADER*) pvBuffer;
|
|
|
|
// in order to use the same routines used by remote fonts, we need to
|
|
// attach a DOWNLOADFONTHEADER structure in fron of the font image
|
|
|
|
cjBuffer += SZDLHEADER;
|
|
|
|
NumFiles = cMapRemoteFonts(&pHeader, cjBuffer, &FontFileView, MemoryImage);
|
|
|
|
if (pHeader != 0)
|
|
{
|
|
ASSERTGDI(NumFiles == 1, "GreAddFontMemResourceEx() NumFiles != 1\n");
|
|
|
|
if (bCreateFontFileView(&FontFileView, pHeader, cjBuffer, &apfv, 1))
|
|
{
|
|
if (gpPFTPrivate || bInitPrivatePFT())
|
|
{
|
|
PUBLIC_PFTOBJ pfto(gpPFTPrivate);
|
|
ULONG cFonts;
|
|
|
|
bOK = TRUE;
|
|
// if hLoadMemFonts fail to load a bad font, apfv is already released
|
|
// inside hLoadMemFonts at FreeFileView and doesn't need to be freed
|
|
// below, see Windows bug 770114
|
|
if (hMMFont = pfto.hLoadMemFonts(apfv, pdv, cjDV, &cFonts))
|
|
{
|
|
*pNumFonts = cFonts;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vUnmapRemoteFonts(&FontFileView);
|
|
}
|
|
}
|
|
|
|
if (!bOK && apfv)
|
|
{
|
|
VFREEMEM(apfv);
|
|
}
|
|
|
|
return hMMFont;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* FreeFileView
|
|
*
|
|
* This routine is called to free the copy of the spooler data,
|
|
* if it exists.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* apfv - pointer to an array of FONTFILEVIEW pointers.
|
|
* The number of pointers in the array is given by cFiles.
|
|
*
|
|
* cFiles - a 32-bit variable containing the number of pointers in
|
|
* the array pointed to by apfv.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None.
|
|
*
|
|
* Called by:
|
|
*
|
|
* PFFOBJ::pPFFC_Delete
|
|
*
|
|
\**************************************************************************/
|
|
|
|
extern "C" void FreeFileView(PFONTFILEVIEW apfv[], ULONG cFiles)
|
|
{
|
|
FONTFILEVIEW *pfv, **ppfv;
|
|
|
|
for (ppfv = apfv; ppfv < apfv + cFiles; ppfv++)
|
|
{
|
|
pfv = *ppfv;
|
|
|
|
if (pfv->ulRegionSize)
|
|
{
|
|
vUnmapRemoteFonts(pfv);
|
|
}
|
|
}
|
|
VFREEMEM(apfv);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* BOOL EngMapFontFileInternal
|
|
*
|
|
* This is called by font drivers to return a buffer containing the
|
|
* raw bytes for a font file, given a handle passed to DrvLoadFontFile.
|
|
* The handle is really a pointer to the PFF for this file.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* iFile - Supplies a 32-bit identifier of the font file. This is
|
|
* the value supplied in DrvLoadFontFile.
|
|
*
|
|
* ppjBuf - Supplies a pointer to a variable that will receive the
|
|
* address of the base of the view of the file.
|
|
*
|
|
* pcjBuf - Supplies a pointer to a variable that will receive the
|
|
* size of the view of the file.
|
|
* bFontDrv - if this is called by font driver.
|
|
*
|
|
* Return Values:
|
|
*
|
|
* TRUE if successufl, FALSE if not.
|
|
*
|
|
* Called by:
|
|
*
|
|
* PUBLIC_PFTOBJ::bLoadFonts
|
|
* NtGdiAddRemoteFontToDC
|
|
* GreMakeFontDir
|
|
*
|
|
* History:
|
|
* 20-Jan-1995 -by- Gerrit van Wingerden
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL EngMapFontFileInternal(
|
|
ULONG_PTR iFile ,
|
|
PULONG *ppjBuf,
|
|
ULONG *pcjBuf,
|
|
BOOL bFontDrv
|
|
)
|
|
{
|
|
PFONTFILEVIEW pffv = (PFONTFILEVIEW) iFile;
|
|
BOOL bMapIt,bRet;
|
|
FILEVIEW fv;
|
|
|
|
RtlZeroMemory(&fv, sizeof(fv));
|
|
|
|
bRet = TRUE;
|
|
bMapIt = TRUE;
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
if (pffv->fv.pvKView)
|
|
{
|
|
bMapIt = FALSE;
|
|
pffv->cKRefCount += 1;
|
|
}
|
|
else if (!pffv->pwszPath)
|
|
{
|
|
RIP("fv.pvKView==0 && pwszPath==0\n");
|
|
}
|
|
else if (pffv->fv.pSection)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
SIZE_T ViewSize;
|
|
LARGE_INTEGER SectionOffset;
|
|
|
|
SectionOffset.QuadPart = 0;
|
|
ViewSize = 0;
|
|
|
|
#if defined(_GDIPLUS_)
|
|
|
|
NtStatus = MapViewInProcessSpace(
|
|
pffv->fv.pSection,
|
|
&pffv->fv.pvKView,
|
|
&ViewSize);
|
|
|
|
#elif defined(_HYDRA_)
|
|
// MmMapViewInSessionSpace is internally promoted to
|
|
// MmMapViewInSystemSpace on non-Hydra systems.
|
|
|
|
NtStatus= Win32MapViewInSessionSpace(
|
|
pffv->fv.pSection,
|
|
&pffv->fv.pvKView,
|
|
&ViewSize);
|
|
#else
|
|
NtStatus = MmMapViewInSystemSpace(
|
|
pffv->fv.pSection,
|
|
&pffv->fv.pvKView,
|
|
&ViewSize);
|
|
#endif
|
|
|
|
|
|
if (bRet = NT_SUCCESS(NtStatus))
|
|
{
|
|
#ifdef _HYDRA_
|
|
#if DBG
|
|
if (!G_fConsole)
|
|
{
|
|
DebugGreTrackAddMapView(pffv->fv.pvKView);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
pffv->cKRefCount = 1;
|
|
}
|
|
bMapIt = FALSE;
|
|
}
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
if (bMapIt)
|
|
{
|
|
BOOL bMapOK, bIsFAT;
|
|
|
|
// If the call is from the font driver, the current thread
|
|
// is attached to the CSRSS process. By attaching it to the
|
|
// CSRSS, the thread loses its user security context which
|
|
// prevents the thread to open a network font file.
|
|
|
|
if (bFontDrv)
|
|
KeDetachProcess();
|
|
|
|
bMapOK = bMapFile(pffv->pwszPath, &fv, 0, &bIsFAT);
|
|
|
|
if (bFontDrv)
|
|
KeAttachProcess(PsGetProcessPcb(gpepCSRSS));
|
|
|
|
if (!bMapOK)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
BOOL bKeepIt;
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
pffv->cKRefCount += 1;
|
|
if (pffv->fv.pvKView)
|
|
{
|
|
bKeepIt = FALSE; // file mapped by another thread
|
|
}
|
|
else
|
|
{
|
|
bRet = bKeepIt = bMapRoutine(pffv, &fv, ModeKernel, bIsFAT);
|
|
}
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
if (!bKeepIt)
|
|
{
|
|
vUnmapFile(&fv);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
//
|
|
// it's okay to access these without grabbing the MUTEX since we've
|
|
// incremented the reference count;
|
|
//
|
|
|
|
if (ppjBuf)
|
|
{
|
|
*ppjBuf = (ULONG*) pffv->fv.pvKView;
|
|
}
|
|
if (pcjBuf)
|
|
{
|
|
*pcjBuf = pffv->fv.cjView;
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
|
|
}
|
|
|
|
/***********************Public*Routine*********************\
|
|
*
|
|
* BOOL EngMapFontFile
|
|
*
|
|
* History:
|
|
* 20-Jan-1995 -by- Gerrit van Wingerden
|
|
*
|
|
\**********************************************************/
|
|
|
|
BOOL EngMapFontFile(
|
|
ULONG_PTR iFile ,
|
|
PULONG *ppjBuf,
|
|
ULONG *pcjBuf
|
|
)
|
|
{
|
|
return (EngMapFontFileInternal(iFile, ppjBuf, pcjBuf, FALSE));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* EngUnmapFontFile
|
|
*
|
|
* This is called by font drivers to unmap a file mapped by a previous
|
|
* call to EngMapFontFile.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* iFile - is the font identifier as returned by EngMapFontFile.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* None.
|
|
*
|
|
* Called by:
|
|
*
|
|
* PUBLIC_PFTOBJ::bLoadFonts
|
|
* GreMakeFontDir
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void EngUnmapFontFile(ULONG_PTR iFile)
|
|
{
|
|
FILEVIEW fv;
|
|
PFONTFILEVIEW pffv = (PFONTFILEVIEW) iFile;
|
|
|
|
fv.pvKView = NULL;
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
|
|
if (pffv->cKRefCount)
|
|
{
|
|
pffv->cKRefCount -= 1;
|
|
|
|
if (pffv->cKRefCount == 0)
|
|
{
|
|
if (pffv->pwszPath)
|
|
{
|
|
fv = pffv->fv; // copy pvKView, pvViewFD and pSection;
|
|
|
|
pffv->fv.pvKView = 0;
|
|
|
|
if (pffv->fv.pvViewFD == 0)
|
|
{
|
|
pffv->fv.pSection = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
if (fv.pvKView)
|
|
{
|
|
vUnmapFile(&fv);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bMapFile
|
|
*
|
|
* Similar to PosMapFile except that it takes unicode file name
|
|
*
|
|
* If iFileSize is -1 then the file is module is mapped for read/write. If
|
|
* iFileSize is > 0 then the file is extended or truncated to be iFileSize
|
|
* bytes in size and is mapped for read/write.
|
|
*
|
|
* History:
|
|
* 21-May-1991 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bMapFile(PWSTR pwszFileName, FILEVIEW *pfvw, INT iFileSize, BOOL *pbIsFAT)
|
|
{
|
|
FILEVIEW fv;
|
|
NTSTATUS NtStatus;
|
|
BOOL ReturnValue;
|
|
SIZE_T ViewSize;
|
|
|
|
ReturnValue = FALSE;
|
|
|
|
if (bCreateSection(pwszFileName, &fv, iFileSize, pbIsFAT))
|
|
{
|
|
ViewSize = 0;
|
|
|
|
#if defined(_GDIPLUS_)
|
|
|
|
NtStatus = MapViewInProcessSpace(fv.pSection, &fv.pvKView, &ViewSize);
|
|
|
|
#elif defined(_HYDRA_)
|
|
// MmMapViewInSessionSpace is internally promoted to
|
|
// MmMapViewInSystemSpace on non-Hydra systems.
|
|
|
|
NtStatus = Win32MapViewInSessionSpace(fv.pSection, &fv.pvKView, &ViewSize);
|
|
#else
|
|
NtStatus = MmMapViewInSystemSpace(fv.pSection, &fv.pvKView, &ViewSize);
|
|
#endif
|
|
if (NT_SUCCESS(NtStatus))
|
|
{
|
|
|
|
#ifdef _HYDRA_
|
|
#if DBG
|
|
if (!G_fConsole)
|
|
{
|
|
DebugGreTrackAddMapView (fv.pvKView);
|
|
}
|
|
#endif
|
|
#endif
|
|
*pfvw = fv;
|
|
ReturnValue = TRUE;
|
|
}
|
|
else
|
|
{
|
|
DEREFERENCE_FONTVIEW_SECTION(fv.pSection);
|
|
}
|
|
}
|
|
|
|
return(ReturnValue);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vCopyDESIGNVECTOR
|
|
*
|
|
\**************************************************************************/
|
|
|
|
extern "C" VOID vCopyDESIGNVECTOR(DESIGNVECTOR *pDst, DESIGNVECTOR *pSrc)
|
|
{
|
|
RtlCopyMemory(pDst, pSrc, SIZEOFDV(pSrc->dvNumAxes));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* EngMapFontFileFDInternal
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL EngMapFontFileFDInternal(
|
|
ULONG_PTR iFile ,
|
|
PULONG *ppjBuf,
|
|
ULONG *pcjBuf,
|
|
BOOL bFontDrv
|
|
)
|
|
{
|
|
PFONTFILEVIEW pffv = (PFONTFILEVIEW) iFile;
|
|
BOOL bMapIt,bRet;
|
|
FILEVIEW fv;
|
|
|
|
RtlZeroMemory(&fv, sizeof(fv));
|
|
|
|
bRet = TRUE;
|
|
bMapIt = TRUE;
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
if (pffv->fv.pvViewFD)
|
|
{
|
|
bMapIt = FALSE;
|
|
pffv->cRefCountFD += 1;
|
|
}
|
|
else if (!pffv->pwszPath)
|
|
{
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
return(FALSE);
|
|
}
|
|
else if (pffv->fv.pSection)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
SIZE_T ViewSize;
|
|
LARGE_INTEGER SectionOffset;
|
|
|
|
SectionOffset.QuadPart = 0;
|
|
ViewSize = 0;
|
|
|
|
#if defined(_GDIPLUS_)
|
|
|
|
NtStatus = MapViewInProcessSpace(pffv->fv.pSection, &pffv->fv.pvViewFD, &ViewSize);
|
|
#else
|
|
|
|
NtStatus = MmMapViewOfSection(
|
|
pffv->fv.pSection , // SectionToMap,
|
|
gpepCSRSS , // spooler process
|
|
&pffv->fv.pvViewFD, // CapturedBase,
|
|
0 , // ZeroBits,
|
|
ViewSize , // CommitSize,
|
|
&SectionOffset , // SectionOffset,
|
|
&ViewSize , // CapturedViewSize,
|
|
ViewUnmap , // InheritDisposition,
|
|
SEC_NO_CHANGE , // AllocationType,
|
|
PAGE_READONLY // Protect
|
|
);
|
|
#endif
|
|
|
|
if (bRet = NT_SUCCESS(NtStatus))
|
|
{
|
|
pffv->cRefCountFD = 1;
|
|
}
|
|
bMapIt = FALSE;
|
|
}
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
if (bMapIt)
|
|
{
|
|
// If the call is from the font driver, the current thread
|
|
// is attached to the CSRSS process. By attaching it to the
|
|
// CSRSS, the thread loses its user security context which
|
|
// prevents the thread to open a network font file.
|
|
|
|
BOOL bCreateOK, bIsFAT;
|
|
|
|
if (bFontDrv)
|
|
KeDetachProcess();
|
|
|
|
bCreateOK = bCreateSection(pffv->pwszPath, &fv, 0, &bIsFAT);
|
|
|
|
if (bFontDrv)
|
|
KeAttachProcess(PsGetProcessPcb(gpepCSRSS));
|
|
|
|
if (!bCreateOK)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
BOOL bKeepIt;
|
|
NTSTATUS NtStatus;
|
|
SIZE_T ViewSize = 0;
|
|
PVOID pvView, pSection;
|
|
LARGE_INTEGER SectionOffset = {0,0};
|
|
|
|
#if defined(_GDIPLUS_)
|
|
|
|
NtStatus = MapViewInProcessSpace(fv.pSection, &fv.pvViewFD, &ViewSize);
|
|
|
|
#else
|
|
|
|
NtStatus = MmMapViewOfSection(
|
|
fv.pSection , // SectionToMap,
|
|
gpepCSRSS , // spooler process
|
|
&fv.pvViewFD , // CapturedBase,
|
|
0 , // ZeroBits,
|
|
ViewSize , // CommitSize,
|
|
&SectionOffset, // SectionOffset,
|
|
&ViewSize , // CapturedViewSize,
|
|
ViewUnmap , // InheritDisposition,
|
|
SEC_NO_CHANGE , // AllocationType,
|
|
PAGE_READONLY // Protect
|
|
);
|
|
#endif
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
DEREFERENCE_FONTVIEW_SECTION(fv.pSection);
|
|
return(FALSE);
|
|
}
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
pffv->cRefCountFD += 1;
|
|
if (pffv->fv.pvViewFD)
|
|
{
|
|
bKeepIt = FALSE;
|
|
}
|
|
else
|
|
{
|
|
bRet = bKeepIt = bMapRoutine(pffv, &fv, ModeFD, bIsFAT);
|
|
}
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
if (!bKeepIt)
|
|
{
|
|
vUnmapFileFD(&fv);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
|
|
ASSERTGDI((ULONG_PTR)pffv->fv.pvViewFD > 0x100000,
|
|
"csrss view smaller than 1MB \n");
|
|
|
|
if (ppjBuf)
|
|
{
|
|
*ppjBuf = (ULONG*) pffv->fv.pvViewFD;
|
|
}
|
|
if (pcjBuf)
|
|
{
|
|
*pcjBuf = pffv->fv.cjView;
|
|
}
|
|
}
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
|
|
/************************Public*Routine**********************\
|
|
*
|
|
* EngMapFontFileFD
|
|
*
|
|
\************************************************************/
|
|
|
|
BOOL EngMapFontFileFD(
|
|
ULONG_PTR iFile,
|
|
PULONG *ppjBuf,
|
|
ULONG *pcjBuf
|
|
)
|
|
{
|
|
return (EngMapFontFileFDInternal(iFile, ppjBuf, pcjBuf, TRUE));
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* vUnmapFileFD
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vUnmapFileFD(FILEVIEW *pFileView)
|
|
{
|
|
#if defined(_GDIPLUS_)
|
|
UnmapViewInProcessSpace(pFileView->pvViewFD);
|
|
#else
|
|
MmUnmapViewOfSection(gpepCSRSS, pFileView->pvViewFD);
|
|
#endif
|
|
|
|
if (pFileView->pvKView == 0)
|
|
{
|
|
DEREFERENCE_FONTVIEW_SECTION(pFileView->pSection);
|
|
}
|
|
|
|
pFileView->bLastUpdated = FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* EngUnmapFontFileFD
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void EngUnmapFontFileFD(ULONG_PTR iFile)
|
|
{
|
|
FILEVIEW fv;
|
|
PFONTFILEVIEW pffv = (PFONTFILEVIEW) iFile;
|
|
|
|
fv.pvViewFD = NULL;
|
|
|
|
GreAcquireFastMutex(ghfmMemory);
|
|
|
|
if (pffv->cRefCountFD)
|
|
{
|
|
pffv->cRefCountFD -= 1;
|
|
|
|
if (pffv->cRefCountFD == 0)
|
|
{
|
|
if (pffv->pwszPath)
|
|
{
|
|
// This path is never taken for remote fonts
|
|
// so this routine does not unmap remote fonts
|
|
|
|
fv = pffv->fv; // copy pvKView, pvViewFD and pSection;
|
|
|
|
if (pffv->fv.pvViewFD)
|
|
{
|
|
pffv->fv.pvViewFD = 0;
|
|
|
|
if (pffv->fv.pvKView == 0)
|
|
{
|
|
pffv->fv.pSection = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GreReleaseFastMutex(ghfmMemory);
|
|
|
|
if (fv.pvViewFD)
|
|
{
|
|
vUnmapFileFD(&fv);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bCreateSection
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bCreateSection(PWSTR pwszFileName, FILEVIEW *pFileView, INT iFileSize, BOOL *pbIsFAT)
|
|
{
|
|
#if defined(_GDIPLUS_)
|
|
|
|
return CreateMemoryMappedSection(pwszFileName, pFileView, iFileSize);
|
|
|
|
#else // !_GDIPLUS_
|
|
|
|
UNICODE_STRING UnicodeString;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS NtStatus;
|
|
HANDLE FileHandle = 0;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
FILE_STANDARD_INFORMATION FileStandardInfo;
|
|
FILE_BASIC_INFORMATION FileBasicInfo;
|
|
LARGE_INTEGER DesiredSize;
|
|
FILEVIEW FileView;
|
|
|
|
RtlZeroMemory(pFileView, sizeof(FILEVIEW));
|
|
RtlZeroMemory(&FileView, sizeof(FILEVIEW));
|
|
|
|
RtlInitUnicodeString(&UnicodeString, pwszFileName);
|
|
|
|
BOOLEAN oldErrorState = IoSetThreadHardErrorMode(FALSE);
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
|
0,
|
|
0);
|
|
|
|
if (iFileSize)
|
|
{
|
|
NtStatus = IoCreateFile(
|
|
&FileHandle,
|
|
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
0,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ
|
|
| FILE_SHARE_WRITE
|
|
| FILE_SHARE_DELETE,
|
|
FILE_OPEN_IF,
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
// Here is the code for reference NtOpenFile
|
|
// File locates it at ..\ntos\io\open.c
|
|
//
|
|
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);
|
|
|
|
}
|
|
|
|
IoSetThreadHardErrorMode(oldErrorState);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
NtStatus = ZwQueryInformationFile(
|
|
FileHandle,
|
|
&IoStatusBlock,
|
|
&FileStandardInfo,
|
|
sizeof(FILE_STANDARD_INFORMATION),
|
|
FileStandardInformation);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
ZwClose(FileHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Get the time stamp
|
|
|
|
NtStatus = ZwQueryInformationFile(
|
|
FileHandle,
|
|
&IoStatusBlock,
|
|
&FileBasicInfo,
|
|
sizeof(FileBasicInfo),
|
|
FileBasicInformation);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
ZwClose(FileHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
FileView.LastWriteTime = FileBasicInfo.LastWriteTime;
|
|
FileView.bLastUpdated = TRUE;
|
|
|
|
if (pbIsFAT)
|
|
{
|
|
struct
|
|
{
|
|
FILE_FS_ATTRIBUTE_INFORMATION Info;
|
|
WCHAR Buffer[MAX_PATH];
|
|
} FileFsAttrInfoBuffer;
|
|
|
|
*pbIsFAT = FALSE;
|
|
|
|
NtStatus = ZwQueryVolumeInformationFile(
|
|
FileHandle,
|
|
&IoStatusBlock,
|
|
&FileFsAttrInfoBuffer.Info,
|
|
sizeof(FileFsAttrInfoBuffer),
|
|
FileFsAttributeInformation);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
ZwClose(FileHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (!_wcsnicmp((LPWSTR)FileFsAttrInfoBuffer.Info.FileSystemName, L"FAT", 3))
|
|
{
|
|
*pbIsFAT = TRUE;
|
|
}
|
|
}
|
|
|
|
// Note that we must call ZwSetInformation even in the case where iFileSize
|
|
// is -1. By doing so we force the file time to change. It turns out that
|
|
// just mapping a file for write (and writing to the section) is not enough
|
|
// to cause the file time to change.
|
|
|
|
if (iFileSize)
|
|
{
|
|
if (iFileSize > 0)
|
|
{
|
|
DesiredSize.LowPart = (ULONG) iFileSize;
|
|
}
|
|
else
|
|
{
|
|
DesiredSize.LowPart = FileStandardInfo.EndOfFile.LowPart;
|
|
}
|
|
|
|
DesiredSize.HighPart = 0;
|
|
|
|
//
|
|
// set the file length to the requested size
|
|
//
|
|
|
|
NtStatus = ZwSetInformationFile(
|
|
FileHandle,
|
|
&IoStatusBlock,
|
|
&DesiredSize,
|
|
sizeof(DesiredSize),
|
|
FileEndOfFileInformation);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
ZwClose(FileHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// set FileStandardInfo and fall through to the case where we called
|
|
// ZwQueryInfo to get the file size
|
|
//
|
|
|
|
FileStandardInfo.EndOfFile.LowPart = (ULONG) DesiredSize.LowPart;
|
|
FileStandardInfo.EndOfFile.HighPart = 0;
|
|
}
|
|
|
|
if (FileStandardInfo.EndOfFile.HighPart)
|
|
{
|
|
ZwClose(FileHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
FileView.cjView = FileStandardInfo.EndOfFile.LowPart;
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
0,
|
|
OBJ_KERNEL_HANDLE,
|
|
0,
|
|
0);
|
|
|
|
NtStatus = ZwWin32CreateSection(
|
|
&FileView.pSection,
|
|
SECTION_ALL_ACCESS,
|
|
&ObjectAttributes,
|
|
&FileStandardInfo.EndOfFile,
|
|
(iFileSize) ? PAGE_READWRITE : PAGE_EXECUTE_READ,
|
|
SEC_COMMIT,
|
|
FileHandle,
|
|
0,
|
|
TAG_SECTION_CREATESECTION);
|
|
|
|
ZwClose(FileHandle);
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
RtlCopyMemory(pFileView, &FileView, sizeof(FileView));
|
|
|
|
return(TRUE);
|
|
|
|
#endif // !_GDIPLUS_
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vUnmapFile
|
|
*
|
|
* Unmaps file whose view is based at pv
|
|
*
|
|
* Called by:
|
|
*
|
|
* EngMapFontFile
|
|
* EngUnmapFontFile
|
|
* GetTypeOneFontList
|
|
*
|
|
* 14-Dec-1990 -by- Bodin Dresevic [BodinD]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID vUnmapFile(PFILEVIEW pfv)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
|
|
#if defined(_GDIPLUS_)
|
|
|
|
NtStatus = UnmapViewInProcessSpace(pfv->pvKView);
|
|
|
|
#elif defined(_HYDRA_)
|
|
// MmUnmapViewInSessionSpace is internally promoted to
|
|
// MmUnmapViewInSystemSpace on non-Hydra systems.
|
|
|
|
NtStatus = Win32UnmapViewInSessionSpace(pfv->pvKView);
|
|
#else
|
|
MmUnmapViewInSystemSpace(pfv->pvKView);
|
|
#endif
|
|
|
|
#if DBG && defined(_HYDRA_)
|
|
if ((!G_fConsole) && (NT_SUCCESS(NtStatus)))
|
|
{
|
|
DebugGreTrackRemoveMapView(pfv->pvKView);
|
|
}
|
|
#endif
|
|
|
|
if (pfv->pvViewFD == 0)
|
|
{
|
|
DEREFERENCE_FONTVIEW_SECTION(pfv->pSection);
|
|
}
|
|
|
|
pfv->bLastUpdated = FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetModuleHandleAndIncrementRefcount
|
|
*
|
|
* This function searches through the GreEngLoadModuleAllocList to see
|
|
* if a module has been loaded already, and if so it returns a handle
|
|
* to that module (and increments the reference count).
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pwsz -- The name of the module
|
|
*
|
|
* Return Value:
|
|
*
|
|
* a FILEVIEW pointer if the module has been loaded already, NULL
|
|
* otherwise.
|
|
*
|
|
* History:
|
|
*
|
|
* 21-Apr-1998 -by- Ori Gershony [orig]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
GetModuleHandleAndIncrementRefcount(
|
|
PWSZ pwsz
|
|
)
|
|
{
|
|
HANDLE hRet=NULL;
|
|
|
|
if (GreEngLoadModuleAllocListLock) GreAcquireSemaphore(GreEngLoadModuleAllocListLock);
|
|
|
|
PLIST_ENTRY pNextEntry = GreEngLoadModuleAllocList.Flink;
|
|
|
|
//
|
|
// Loop through the loaded modules looking for pwsz
|
|
//
|
|
|
|
while ((pNextEntry != &GreEngLoadModuleAllocList) && !(hRet))
|
|
{
|
|
PWSZ pwszModuleName = (PWSZ) (((PBYTE) pNextEntry) + sizeof(ENGLOADMODULEHDR) -
|
|
((PENGLOADMODULEHDR)pNextEntry)->cjSize);
|
|
|
|
if (_wcsicmp(pwsz, pwszModuleName) == 0)
|
|
{
|
|
((PENGLOADMODULEHDR)pNextEntry)->cRef++;
|
|
hRet = (HANDLE) (((PBYTE) pNextEntry) + sizeof(ENGLOADMODULEHDR));
|
|
}
|
|
|
|
pNextEntry = pNextEntry->Flink;
|
|
}
|
|
|
|
if (GreEngLoadModuleAllocListLock) GreReleaseSemaphore(GreEngLoadModuleAllocListLock);
|
|
|
|
return hRet;
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* LoadModuleWorkHorse
|
|
*
|
|
* Note that all allocations are tracked through a linked list maintained
|
|
* via the ENGLOADMODULEHDR fields. This enables us to do just one allocation
|
|
* per file even if called multiple times. The diagram below shows the layout
|
|
* of the data structures in memory.
|
|
*
|
|
*
|
|
*
|
|
* Buffer
|
|
* pBaseAlloc --> +------------------+<-|
|
|
* | Module name | |
|
|
* pelmNew --> +------------------+ |-cjSize (length of module name
|
|
* | ENGLOADMODULEHDR | | plus ENGLOADMODULE header)
|
|
* pfv --> +------------------+<-|
|
|
* | FILEVIEW |
|
|
* | |
|
|
* +------------------+
|
|
*
|
|
*
|
|
* Note that it is theoretically possible for two modules with the same name
|
|
* to be mapped twice (to two different virtual addresses), because we don't
|
|
* grab the GreEngLoadModuleAllocListLock until late in the code (so if two
|
|
* threads enter this function and both pass the search stage before either
|
|
* grabs the lock, both would independently get different entries for this
|
|
* module). There are two possible ways to remedy this:
|
|
* 1) Grab the lock before the search -- the problem is that this will force
|
|
* us to keep the lock during the call to bMapFile which can take a while
|
|
* 2) Search twice, the second time being after the call to bMapFile (and after
|
|
* we obtain the lock). This is quite ugly, and would force us to free the
|
|
* memory allocated by bMapFile in the scenario described above.
|
|
*
|
|
* So because neither solution is particularly attractive, we allow the same
|
|
* module to be placed multiple times in the list. In practice this should
|
|
* happen very rarely, and shouldn't lead to any major problems (except
|
|
* for a minor waste of resources).
|
|
*
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HANDLE LoadModuleWorkHorse(PWSZ pwsz, INT iSize)
|
|
{
|
|
UNICODE_STRING usPath;
|
|
BYTE *pBaseAlloc;
|
|
FILEVIEW *pfv;
|
|
HANDLE hRet = 0;
|
|
ULONGSIZE_T cj = sizeof(FILEVIEW);
|
|
ULONG cjStringLength;
|
|
|
|
//
|
|
// NULL names are bad.
|
|
//
|
|
|
|
if (wcslen(pwsz) == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// First check if this is mapped into kernel memory already
|
|
//
|
|
|
|
if (iSize == 0) // Only share on EngLoadModule calls because iSize may not be the same
|
|
{
|
|
if ((hRet = GetModuleHandleAndIncrementRefcount(pwsz)) != NULL)
|
|
{
|
|
return hRet;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the name of the module length string. Round up to a multiple of
|
|
// 8 bytes so that the buffer we return will be 8-byte aligned (ENGLOADMODULEHDR is
|
|
// already 8-byte aligned).
|
|
//
|
|
|
|
cjStringLength = (wcslen(pwsz) + 1) * sizeof(WCHAR);
|
|
cjStringLength = ((cjStringLength + 7) & (~7));
|
|
|
|
//
|
|
// Increase the size of the allocation by the size of the ENGLOADMODULEHDR header
|
|
// plus the length of the string.
|
|
//
|
|
|
|
cj += sizeof(ENGLOADMODULEHDR) + cjStringLength;
|
|
|
|
if (MakeSystemRelativePath(pwsz, &usPath, FALSE))
|
|
{
|
|
if (pBaseAlloc = (BYTE *) PALLOCMEM(cj, 'lifG'))
|
|
{
|
|
ENGLOADMODULEHDR *pelmNew = (ENGLOADMODULEHDR *) (pBaseAlloc + cjStringLength);
|
|
pfv = (FILEVIEW *) (pelmNew + 1);
|
|
|
|
if (bMapFile(usPath.Buffer, pfv, iSize, NULL))
|
|
{
|
|
hRet = pfv;
|
|
|
|
//
|
|
// Copy the filename into the buffer
|
|
//
|
|
|
|
if (iSize==0)
|
|
{
|
|
//
|
|
// EngLoadModule -- share with other calls
|
|
//
|
|
|
|
wcscpy((PWSZ)pBaseAlloc, pwsz);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// EngLoadModuleForWrite -- don't share because of possible buffer size mismatches
|
|
// It is possible to code this so that writeable modules would be shared
|
|
// as well (store size in the ENGLOADMODULEHDR), but I don't think this case
|
|
// will happen very frequently so the benefit of doing this is very small.
|
|
//
|
|
|
|
wcscpy((PWSZ)pBaseAlloc, L"");
|
|
}
|
|
|
|
|
|
//
|
|
// Setup the ENGLOADMODULEHDR
|
|
//
|
|
|
|
pelmNew->cRef = 1;
|
|
pelmNew->cjSize = sizeof(ENGLOADMODULEHDR) + cjStringLength;
|
|
|
|
//
|
|
// Now add to the tracking list
|
|
//
|
|
|
|
if (GreEngLoadModuleAllocListLock) GreAcquireSemaphore(GreEngLoadModuleAllocListLock);
|
|
|
|
InsertTailList(&GreEngLoadModuleAllocList, &(pelmNew->list));
|
|
|
|
if (GreEngLoadModuleAllocListLock) GreReleaseSemaphore(GreEngLoadModuleAllocListLock);
|
|
}
|
|
else
|
|
{
|
|
VFREEMEM(pBaseAlloc);
|
|
}
|
|
}
|
|
VFREEMEM(usPath.Buffer);
|
|
}
|
|
|
|
return(hRet);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* EngLoadModuleForWrite
|
|
*
|
|
* History:
|
|
* 4/24/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*******************************************************************************/
|
|
|
|
HANDLE EngLoadModuleForWrite(PWSZ pwsz, ULONG cjSizeOfModule)
|
|
{
|
|
return(LoadModuleWorkHorse(pwsz, cjSizeOfModule ? cjSizeOfModule : -1));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* EngLoadModule
|
|
*
|
|
* History:
|
|
* 4/24/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*******************************************************************************/
|
|
|
|
HANDLE EngLoadModule(PWSZ pwsz)
|
|
{
|
|
return(LoadModuleWorkHorse(pwsz, 0));
|
|
}
|
|
|
|
/****************************************************************************
|
|
* EngFreeModule()
|
|
*
|
|
* History:
|
|
* 4/27/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
VOID EngFreeModule(HANDLE h)
|
|
{
|
|
ULONG cRef;
|
|
|
|
if (h)
|
|
{
|
|
ENGLOADMODULEHDR *pelmVictim = (ENGLOADMODULEHDR *) h;
|
|
pelmVictim--; // Now it points to the real ENGLOADMODULEHDR
|
|
|
|
//
|
|
// Enforce synchronization on the linked list
|
|
//
|
|
|
|
if (GreEngLoadModuleAllocListLock) GreAcquireSemaphore(GreEngLoadModuleAllocListLock);
|
|
|
|
pelmVictim->cRef--; // Decrement reference count
|
|
|
|
//
|
|
// Remove resource if necessary. Cache cRef in a local variable in case it gets
|
|
// modified by another thread after we exit the critical section.
|
|
//
|
|
|
|
if ((cRef=pelmVictim->cRef) == 0)
|
|
{
|
|
RemoveEntryList(&(pelmVictim->list));
|
|
}
|
|
|
|
//
|
|
// Restore IRQL level as soon as possible
|
|
//
|
|
|
|
if (GreEngLoadModuleAllocListLock) GreReleaseSemaphore(GreEngLoadModuleAllocListLock);
|
|
|
|
//
|
|
// If removing resource still need to unmap file and free headers memory
|
|
//
|
|
|
|
if (cRef == 0)
|
|
{
|
|
//
|
|
// Dereference section and unmap the file
|
|
//
|
|
vUnmapFile((FILEVIEW *)h);
|
|
//
|
|
// Free allocated memory
|
|
//
|
|
|
|
VFREEMEM (((PBYTE) h) - pelmVictim->cjSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* PVOID EngMapModule( HANDLE, PULONG )
|
|
*
|
|
* History:
|
|
* 5/25/1995 by Gerrit van Wingerden [gerritv]
|
|
* Wrote it.
|
|
*****************************************************************************/
|
|
|
|
PVOID EngMapModule(HANDLE h, PULONG pSize)
|
|
{
|
|
*pSize=((PFILEVIEW)h)->cjView;
|
|
return(((PFILEVIEW)h)->pvKView);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL EngMapFile
|
|
*
|
|
* Create or Open a file and map it into system space. The file is extended or
|
|
* truncated according to the cjSize passed in. If cjSize == 0, the file size
|
|
* is unchanged. The view is always mapped on the entire file.
|
|
*
|
|
* Parameters
|
|
* IN pwsz - Name of the file to be mapped.
|
|
* Filename has to be fully qualified. ex. L"\\??\\c:\\test.dat"
|
|
* IN cjSize - Size of the file.
|
|
* OUT iFile - identifier of the mapped file
|
|
*
|
|
* Return Value
|
|
* Pointer to the memory view.
|
|
*
|
|
* History:
|
|
* 4-Nov-1996 -by- Lingyun Wang [LingyunW]
|
|
* 19-Nov-1998 -by- Lingyun Wang [lingyunw] changed interface
|
|
*
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
PVOID EngMapFile(PWSZ pwsz, ULONG cjSize, ULONG_PTR *piFile)
|
|
{
|
|
FILEVIEW *pfv;
|
|
PVOID ReturnValue = 0;
|
|
|
|
if (pfv = (FILEVIEW*) PALLOCMEM(sizeof(FILEVIEW), 'lifG'))
|
|
{
|
|
if (bMapFile(pwsz, pfv, cjSize ? cjSize : -1, NULL))
|
|
{
|
|
*piFile = (ULONG_PTR)pfv;
|
|
ReturnValue = pfv->pvKView;
|
|
}
|
|
else
|
|
{
|
|
*piFile = 0;
|
|
VFREEMEM(pfv);
|
|
}
|
|
}
|
|
return(ReturnValue);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL EngUnmapFile
|
|
*
|
|
* Unmap a view of file in system space
|
|
**
|
|
* Return Value
|
|
* TRUE
|
|
* FALSE
|
|
*
|
|
* History:
|
|
* 4-Nov-1996 -by- Lingyun Wang [LingyunW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL EngUnmapFile(ULONG_PTR iFile)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
FILEVIEW *pfv = (FILEVIEW *)iFile;
|
|
|
|
if (iFile)
|
|
{
|
|
#if defined(_GDIPLUS_)
|
|
|
|
NtStatus = UnmapViewInProcessSpace(pfv->pvKView);
|
|
|
|
#elif defined(_HYDRA_)
|
|
// MmUnmapViewInSessionSpace is internally promoted to
|
|
// MmUnmapViewInSystemSpace on non-Hydra systems.
|
|
|
|
NtStatus = Win32UnmapViewInSessionSpace(pfv->pvKView);
|
|
#else
|
|
MmUnmapViewInSystemSpace(pfv->pvKView);
|
|
#endif
|
|
|
|
#if DBG && defined(_HYDRA_)
|
|
if ((!G_fConsole) && (NT_SUCCESS(NtStatus)))
|
|
{
|
|
DebugGreTrackRemoveMapView(pfv->pvKView);
|
|
}
|
|
#endif
|
|
|
|
DEREFERENCE_FONTVIEW_SECTION(pfv->pSection);
|
|
|
|
VFREEMEM(pfv);
|
|
|
|
return(NT_SUCCESS(NtStatus));
|
|
|
|
}
|
|
else
|
|
{
|
|
return (FALSE);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bIsOneHourDifference()
|
|
*
|
|
*
|
|
* History:
|
|
* 15-April-1999 -by- Xudong Wu [TessieW]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
// one tick is 100ns, us = 10 tick, s = 10*1000*1000 tick
|
|
// 1hr = 10*1000*1000*60*60
|
|
|
|
#define ONEHOUR (10i64*1000i64*1000i64*60i64*60i64)
|
|
|
|
BOOL bIsOneHourDifference(FILEVIEW *pNew, FILEVIEW *pOld)
|
|
{
|
|
LONGLONG llDifference = pNew->LastWriteTime.QuadPart - pOld->LastWriteTime.QuadPart;
|
|
|
|
if(llDifference < 0) llDifference = -llDifference;
|
|
|
|
return (llDifference == ONEHOUR ? TRUE : FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bShouldMap // the font file
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bShouldMap(FILEVIEW *pNew, FILEVIEW *pOld, BOOL bIsFAT)
|
|
{
|
|
|
|
BOOL bMapRet = FALSE;
|
|
|
|
if (pOld->LastWriteTime.QuadPart != 0) // file had been mapped in the past
|
|
{
|
|
if (pOld->cjView == pNew->cjView)
|
|
{
|
|
// we consider the new and the old times the "same" if they
|
|
// are literally the same or if on the FAT system they differ by
|
|
// 1 hour which we think is likely the result of the daylight
|
|
// time saving change:
|
|
|
|
if
|
|
(
|
|
(pOld->LastWriteTime.QuadPart == pNew->LastWriteTime.QuadPart) ||
|
|
(bIsFAT && bIsOneHourDifference(pNew, pOld))
|
|
|| gbGUISetup
|
|
)
|
|
{
|
|
bMapRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else // first time we are attempting to map this file
|
|
{
|
|
bMapRet = TRUE;
|
|
}
|
|
|
|
return(bMapRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* bMapRoutine
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bMapRoutine(FONTFILEVIEW *pffv, FILEVIEW *pfv, MAP_MODE Mode, BOOL bIsFAT)
|
|
{
|
|
BOOL bKeepIt = bShouldMap(pfv, &pffv->fv, bIsFAT);
|
|
|
|
if (bKeepIt)
|
|
{
|
|
//
|
|
// This is the first time that this file has been mapped
|
|
// OR the file has not really changed since it was mapped
|
|
// last time, however, because the time zone changed and
|
|
// because of the bug in the
|
|
// FAT file system, LastWriteTime is now reported different.
|
|
|
|
if (Mode == ModeFD)
|
|
{
|
|
pffv->fv.pvViewFD = pfv->pvViewFD;
|
|
}
|
|
else
|
|
{
|
|
pffv->fv.pvKView = pfv->pvKView;
|
|
}
|
|
|
|
pffv->fv.cjView = pfv->cjView;
|
|
pffv->fv.LastWriteTime = pfv->LastWriteTime;
|
|
pffv->fv.pSection = pfv->pSection;
|
|
pffv->fv.bLastUpdated = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// if the size or the time of the last write has changed
|
|
// then someone has switched the file or tampered with it
|
|
// while we had it unlocked. We will fail the call.
|
|
|
|
if (Mode == ModeFD)
|
|
{
|
|
pffv->cRefCountFD -= 1;
|
|
pffv->fv.pvViewFD = 0;
|
|
}
|
|
else
|
|
{
|
|
pffv->cKRefCount -= 1; // Restore FONTFILEVIEW
|
|
pffv->fv.pvKView = 0; // to original state
|
|
}
|
|
|
|
pffv->fv.bLastUpdated = FALSE;
|
|
}
|
|
return(bKeepIt);
|
|
}
|
|
|