/******************************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); }