2025-04-27 07:49:33 -04:00

1151 lines
29 KiB
C++

/* ------------------------------------------------------------------------
mapfile.cpp
(was bbmpfile.cpp)
A wrapper function to perform the cook book type operations required
to map a file into memory. Maps the whole file, and nothing but the
file, so help me God. Returns a pointer to void; NULL on error.
An error also results in an entry in the event log, unless the error
is "file not found" during CreateFile().
Copyright (C) 1994, 1995 Microsoft Corporation.
All Rights Reserved.
Author
Lindsay Harris - lindsayh
------------------------------------------------------------------------ */
#include <windows.h>
#include "mapfile.h"
#ifndef _ASSERT
#define _ASSERT( f ) if( (f) ) ; else DebugBreak()
#endif
/* ------------------------------------------------------------------------
CMapFile::CMapFile
Constructor for unicode mapping.
Author
Lindsay Harris - lindsayh
History
16:11 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
First version, to support tracking of objects in exception handling.
------------------------------------------------------------------------ */
CMapFile::CMapFile( const WCHAR *pwchFileName, BOOL fWriteEnable, BOOL fTrack )
{
HANDLE hFile; // Ditto.
// Set default values corresponding to no mapping happened.
//
m_pv = NULL;
m_cb = 0;
m_fFlags = 0; // Until later.
hFile = CreateFileW( pwchFileName,
fWriteEnable ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
{
// Only legitimate reason for coming here is non-existent file.
//
if ( GetLastError() != ERROR_FILE_NOT_FOUND
&& GetLastError() != ERROR_PATH_NOT_FOUND )
{
// Error case
//
m_pv = NULL;
}
return; // Default values are failure.
}
wcsncpy( m_rgwchFileName, pwchFileName, MAX_PATH );
MapFromHandle( hFile, fWriteEnable, 0 );
BOOL fClose = CloseHandle( hFile );
_ASSERT( fClose ) ;
return;
}
/* ------------------------------------------------------------------------
CMapFile::CMapFile
Constructor for ascii file name version.
Author
Lindsay Harris - lindsayh
History:
16:13 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
First version to handle tracking of objects for exception handling.
------------------------------------------------------------------------ */
CMapFile::CMapFile( const char *pchFileName, BOOL fWriteEnable, BOOL fTrack, DWORD cbIncrease )
{
HANDLE hFile; // Ditto.
// Set default values corresponding to no mapping happened.
m_pv = NULL;
m_cb = 0;
m_fFlags = 0; // None set yet.
hFile = CreateFile( pchFileName,
fWriteEnable ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
{
// Only legitimate reason for coming here is non-existent file.
//
if ( GetLastError() != ERROR_FILE_NOT_FOUND
&& GetLastError() != ERROR_PATH_NOT_FOUND )
{
// Error case
//
m_pv = NULL;
}
return;
}
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pchFileName, -1,
m_rgwchFileName, MAX_PATH );
MapFromHandle( hFile, fWriteEnable, cbIncrease );
BOOL fClose = CloseHandle( hFile );
_ASSERT( fClose ) ;
return;
}
/* ------------------------------------------------------------------------
CMapFile::CMapFile.
Constructor for ascii file name version.
Note: Creates file handle if necessary. Does not close file handle.
Author
Lindsay Harris - lindsayh
History:
16:13 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
First version to handle tracking of objects for exception handling.
------------------------------------------------------------------------ */
CMapFile::CMapFile( const char *pchFileName, HANDLE & hFile, BOOL fWriteEnable, DWORD cbIncrease )
{
// Set default values corresponding to no mapping happened.
//
m_pv = NULL;
m_cb = 0;
m_fFlags = 0; // None set yet.
if ( INVALID_HANDLE_VALUE == hFile )
{
hFile = CreateFile( pchFileName,
fWriteEnable ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
{
// Only legitimate reason for coming here is non-existent file.
//
if ( GetLastError() != ERROR_FILE_NOT_FOUND
&& GetLastError() != ERROR_PATH_NOT_FOUND )
{
// Error case
//
m_pv = NULL;
}
return;
}
}
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, pchFileName, -1,
m_rgwchFileName, MAX_PATH );
MapFromHandle( hFile, fWriteEnable, cbIncrease );
return;
}
/* ------------------------------------------------------------------------
CMapFile::CMapFile
Constructor when a file handle is available rather than a name.
Note that it does not closes the handle
Author
Lindsay Harris - lindsayh
History
16:14 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
First version to allow object tracking. Based on CarlK's function.
------------------------------------------------------------------------ */
CMapFile::CMapFile( HANDLE hFile, BOOL fWriteEnable, BOOL fTrack, DWORD cbIncrease, BOOL fZero )
{
m_pv = NULL;
m_cb = 0; // Set defaults.
m_fFlags = 0; // None set yet.
wcsncpy( m_rgwchFileName, L"<name unavailable - from handle>", MAX_PATH );
MapFromHandle( hFile, fWriteEnable, cbIncrease, fZero );
return;
}
/* ------------------------------------------------------------------------
CMapFile::~CMapFile
Destructor. Two purposes, being to unmap the file, and optionally
remove it from the track data.
Author
Lindsay Harris - lindsayh
History
16:22 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
Numero Uno.
------------------------------------------------------------------------ */
CMapFile::~CMapFile( void )
{
//
// Unmap the file, if we succeeded in mapping it first!
//
if ( !(m_fFlags & MF_RELINQUISH) )
{
// We're still controlling this file, so stick with it.
//
if ( m_pv )
{
UnmapViewOfFile( m_pv );
}
}
return;
}
/* ------------------------------------------------------------------------
CMapFile::MapFromHandle
Does the real work of mapping. Given a handle to the file, go through
the motions of mapping, and recording what happens. Reports errors
as needed. Also adjusts file size if requested.
Author
Lindsay Harris - lindsayh
Carl Kadie - carlk
History
16:30 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
First version, based on older code with CarlK enhancements.
------------------------------------------------------------------------ */
void
CMapFile::MapFromHandle( HANDLE hFile, BOOL fWriteEnable, DWORD cbIncrease, BOOL fZero )
{
if ( !fWriteEnable && cbIncrease != 0 )
return; // This is non-sensical.
m_cb = GetFileSize( hFile, NULL );
DWORD cbNewSize = 0;
//
// Determine if the file is to grow. Only pass a non-zero size
// to the system if the size is growing - it's probably faster, and
// the most likely common case.
//
if ( cbIncrease )
{
cbNewSize = m_cb += cbIncrease;
}
else
{
if ( m_cb == 0 )
return; // Nothing there.
}
#if 1
if ( cbIncrease )
{
_ASSERT(fWriteEnable);
//
// Make sure the file is the correct size.
//
DWORD fpos;
BOOL fSetEnd;
if ( (DWORD)-1 == ( fpos = SetFilePointer( hFile, cbNewSize, NULL, FILE_BEGIN ))
|| !(fSetEnd = SetEndOfFile( hFile ))
)
{
//
// Error case
//
m_pv = NULL;
return;
}
}
#endif
//
// Create the mapping object.
//
HANDLE hFileMap; // Intermediate step.
hFileMap = CreateFileMapping( hFile, NULL,
fWriteEnable ? PAGE_READWRITE : PAGE_READONLY,
0, cbNewSize, NULL );
if ( !hFileMap )
{
// Error case
//
m_pv = NULL;
return;
}
//
// Get the pointer mapped to the desired file.
//
m_pv = MapViewOfFile( hFileMap,
fWriteEnable ? FILE_MAP_WRITE : FILE_MAP_READ,
0, 0, 0 );
if ( !m_pv )
{
// Error case
//
m_pv = NULL;
m_cb = 0; // Also set to zero, just in case.
}
if( fZero && cbIncrease )
{
// zero out the part grown
DWORD cbOldSize = cbNewSize - cbIncrease;
ZeroMemory( (LPVOID)((LPBYTE)m_pv + cbOldSize), cbNewSize - cbOldSize );
}
//
// Now that we have our pointer, we can close the mapping object.
//
BOOL fClose = CloseHandle( hFileMap );
_ASSERT( fClose );
return;
}
/* -------------------------------------------------------------------------
pvMapFile
Map a file into memory and return the base address, NULL on failure.
Author
Lindsay Harris - lindsayh
History
14:21 on Mon 20 Feb 1995 -by- Lindsay Harris [lindsayh]
Amended to use unicode file name.
10:18 on Tue 29 Nov 1994 -by- Lindsay Harris [lindsayh]
Made a separately compiled module.
10:55 on Mon 10 Oct 1994 -by- Lindsay Harris [lindsayh]
Added FILE_FLAG_SEQUENTIAL_SCAN to speed up directory reading.
17:38 on Wed 06 Jul 1994 -by- Lindsay Harris [lindsayh]
Make write enable code functional; clean up some old ideas.
15:35 on Wed 06 Apr 1994 -by- Lindsay Harris [lindsayh]
Adding this comment, written some time back.
------------------------------------------------------------------------- */
void *
pvMapFile( DWORD *pdwSize, const WCHAR *pwchFileName, BOOL bWriteEnable )
{
//
// Cook book formula.
//
VOID *pvRet; // Returned to caller
HANDLE hFileMap; // Used during operations, closed before return
HANDLE hFile; // Ditto.
hFile = CreateFileW( pwchFileName,
bWriteEnable ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
{
// Only legitimate reason for coming here is non-existent file.
//
if ( GetLastError() != ERROR_FILE_NOT_FOUND
&& GetLastError() != ERROR_PATH_NOT_FOUND )
{
// Error case
}
return NULL;
}
//
// If the caller wants to know the size (usually does) then get it now.
//
if ( pdwSize )
*pdwSize = GetFileSize( hFile, NULL );
//
// Create the mapping object.
//
hFileMap = CreateFileMapping( hFile, NULL,
bWriteEnable ? PAGE_READWRITE : PAGE_READONLY,
0, 0, NULL );
if ( !hFileMap )
{
// Error case
//
BOOL fClose = CloseHandle( hFile ); // No handle leaks.
_ASSERT( fClose ) ;
return NULL;
}
//
// Get the pointer mapped to the desired file.
//
pvRet = MapViewOfFile( hFileMap,
bWriteEnable ? FILE_MAP_WRITE : FILE_MAP_READ,
0, 0, 0 );
if ( !pvRet )
{
// Error case
//
}
//
// Now that we have our pointer, we can close the file and the
// mapping object.
//
BOOL fClose = CloseHandle( hFileMap );
_ASSERT( fClose || hFileMap == 0 ) ;
fClose = CloseHandle( hFile );
_ASSERT( fClose || hFile == INVALID_HANDLE_VALUE ) ;
return pvRet;
}
/* -------------------------------------------------------------------------
pvMapFile
Map a file into memory and return the base address, NULL on failure.
Author
Lindsay Harris - lindsayh
History
10:18 on Tue 29 Nov 1994 -by- Lindsay Harris [lindsayh]
Made a separately compiled module.
10:55 on Mon 10 Oct 1994 -by- Lindsay Harris [lindsayh]
Added FILE_FLAG_SEQUENTIAL_SCAN to speed up directory reading.
17:38 on Wed 06 Jul 1994 -by- Lindsay Harris [lindsayh]
Make write enable code functional; clean up some old ideas.
15:35 on Wed 06 Apr 1994 -by- Lindsay Harris [lindsayh]
Adding this comment, written some time back.
------------------------------------------------------------------------- */
void *
pvMapFile( DWORD *pdwSize, const char *pchFileName, BOOL bWriteEnable )
{
//
// Cook book formula.
//
VOID *pvRet; /* Returned to caller */
HANDLE hFileMap; // Used during operations, closed before return
HANDLE hFile; // Ditto.
hFile = CreateFile( pchFileName,
bWriteEnable ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
{
// Only legitimate reason for coming here is non-existent file.
//
if ( GetLastError() != ERROR_FILE_NOT_FOUND
&& GetLastError() != ERROR_PATH_NOT_FOUND )
{
// Error case
//
}
return NULL;
}
//
// If the caller wants to know the size (usually does) then get it now.
//
if ( pdwSize )
*pdwSize = GetFileSize( hFile, NULL );
//
// Create the mapping object.
//
hFileMap = CreateFileMapping( hFile, NULL,
bWriteEnable ? PAGE_READWRITE : PAGE_READONLY,
0, 0, NULL );
if ( !hFileMap )
{
// Error case
//
BOOL fClose = CloseHandle( hFile ); // No handle leaks.
_ASSERT( fClose ) ;
return NULL;
}
//
// Get the pointer mapped to the desired file.
//
pvRet = MapViewOfFile( hFileMap,
bWriteEnable ? FILE_MAP_WRITE : FILE_MAP_READ,
0, 0, 0 );
if ( !pvRet )
{
// Error case
//
}
//
// Now that we have our pointer, we can close the file and the
// mapping object.
//
BOOL fClose = CloseHandle( hFileMap );
_ASSERT( fClose || hFileMap == 0 ) ;
fClose = CloseHandle( hFile );
_ASSERT( fClose || hFile == INVALID_HANDLE_VALUE ) ;
return pvRet;
}
/* -------------------------------------------------------------------------
pvFromHandle
Creates a mapped file from an file handle. Does not close that handle.
History
21 Dec 1994 -by- Carl Kadie [carlk]
Based on pvMapFile code by Lindsay Harris [lindsayh]
------------------------------------------------------------------------- */
void *
pvFromHandle( HANDLE hFile,
BOOL bWriteEnable, // If the file is to be writeable
DWORD * pdwSizeFinal, // If not Null, returns the final size of the file
DWORD dwSizeIncrease ) // Use 0 if the size is not to increase
{
DWORD dwSize;
VOID *pvRet; /* Returned to caller */
HANDLE hFileMap;
dwSize = GetFileSize( hFile, NULL ) + dwSizeIncrease;
if ( pdwSizeFinal )
{
*pdwSizeFinal = dwSize;
}
// If the ultimate size of the file is 0, then return NULL. The
// calling program may decide that this is OK.
//
if ( !dwSize)
{
return NULL;
}
#if 1
if ( dwSizeIncrease )
{
_ASSERT(bWriteEnable);
//
// Make sure the file is the correct size.
//
DWORD fpos;
BOOL fSetEnd;
if ( (DWORD)-1 == (fpos = SetFilePointer( hFile, dwSize, NULL, FILE_BEGIN ))
|| !(fSetEnd = SetEndOfFile( hFile ))
)
{
//
// Error case
//
BOOL fClose = CloseHandle( hFile ); // No handle leaks.
return NULL;
}
}
#endif
//
// Create the mapping object.
//
hFileMap = CreateFileMapping( hFile, NULL,
bWriteEnable ? PAGE_READWRITE : PAGE_READONLY,
0, dwSize, NULL );
if ( !hFileMap )
{
// Error case
//
BOOL fClose = CloseHandle( hFile ); // No handle leaks.
return NULL;
}
//
// Get the pointer mapped to the desired file.
//
pvRet = MapViewOfFile( hFileMap,
bWriteEnable ? FILE_MAP_WRITE : FILE_MAP_READ,
0, 0, 0 );
if ( !pvRet )
{
// Log the error, but continue, which returns the error.
//
#if 0
char rgchErr[ MAX_PATH + 32 ];
wsprintf( rgchErr, "MapViewOfFile" );
LogErrorEvent( MSG_GEN_FAIL, rgchErr, "pvFromHandle" );
#endif
}
//
// Now that we have our pointer, we can close the file and the
// mapping object.
//
BOOL fClose = CloseHandle( hFileMap );
_ASSERT( fClose ) ;
return pvRet;
}
/* -------------------------------------------------------------------------
pvMapFile
Map a file into memory and return the base address, NULL on failure.
Also, allows the file to be grown.
History
11:08 on Tue 18 Oct 1994 -by- Carl Kadie [carlk]
Generalize pvMapFile to add support for adding to the file
10:55 on Mon 10 Oct 1994 -by- Lindsay Harris [lindsayh]
Added FILE_FLAG_SEQUENTIAL_SCAN to speed up directory reading.
17:38 on Wed 06 Jul 1994 -by- Lindsay Harris [lindsayh]
Make write enable code functional; clean up some old ideas.
15:35 on Wed 06 Apr 1994 -by- Lindsay Harris [lindsayh]
Adding this comment, written some time back.
------------------------------------------------------------------------- */
void *
pvMapFile( const char * pchFileName, // The name of the file
BOOL bWriteEnable, // If the file is to be writeable
DWORD * pdwSizeFinal, // If not Null, returns the final size of the file
DWORD dwSizeIncrease ) // Use 0 if the size is not to increase
{
//
// Cook book formula.
//
HANDLE hFile;
VOID *pvRet; /* Returned to caller */
// If the file is to grow, it only makes sense to open it read/write.
//
if (0 != dwSizeIncrease && !bWriteEnable)
{
return NULL;
}
hFile = CreateFile( pchFileName,
bWriteEnable ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_ALWAYS, //changed from open_existing
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
if ( INVALID_HANDLE_VALUE == hFile )
{
return NULL;
}
//
// If the caller wants to know the size (usually does) then get it now.
//
pvRet = pvFromHandle(hFile, bWriteEnable, pdwSizeFinal, dwSizeIncrease);
BOOL fClose = CloseHandle( hFile );
_ASSERT( fClose ) ;
return pvRet;
}
#ifdef DEBUG
//
// CMapFileEx: version with guard pages to be used only in DEBUG builds
// to catch other threads writing into our memory !
//
/* ------------------------------------------------------------------------
CMapFileEx::CMapFileEx
Constructor when a file handle is available rather than a name.
Note that it does not closes the handle
Author
Lindsay Harris - lindsayh
History
16:14 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
First version to allow object tracking. Based on CarlK's function.
------------------------------------------------------------------------ */
CMapFileEx::CMapFileEx( HANDLE hFile, BOOL fWriteEnable, BOOL fTrack, DWORD cbIncrease )
{
m_pv = NULL;
m_cb = 0; // Set defaults.
m_fFlags = 0; // None set yet.
m_hFile = INVALID_HANDLE_VALUE;
m_pvFrontGuard = NULL;
m_cbFrontGuardSize = 0;
m_pvRearGuard = NULL;
m_cbRearGuardSize = 0;
InitializeCriticalSection(&m_csProtectMap);
wcsncpy( m_rgwchFileName, L"<name unavailable - from handle>", MAX_PATH );
MapFromHandle( hFile, fWriteEnable, cbIncrease );
m_hFile = hFile;
return;
}
/* ------------------------------------------------------------------------
CMapFileEx::~CMapFileEx
Destructor. Two purposes, being to unmap the file, and optionally
remove it from the track data.
Author
Lindsay Harris - lindsayh
History
16:22 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
Numero Uno.
------------------------------------------------------------------------ */
CMapFileEx::~CMapFileEx( void )
{
//
// Unmap the file, if we succeeded in mapping it first!
//
// Lock
EnterCriticalSection(&m_csProtectMap);
if ( !(m_fFlags & MF_RELINQUISH) )
{
// We're still controlling this file, so stick with it.
//
if ( m_pvFrontGuard )
{
// get rid of guard pages
DWORD dwOldProtect = PAGE_READONLY | PAGE_GUARD;
if(!VirtualProtect(
(LPVOID)m_pvFrontGuard,
m_cbFrontGuardSize,
PAGE_READWRITE,
&dwOldProtect
))
{
_ASSERT( 1==0 );
goto CMapFileEx_Exit ;
}
if(!VirtualProtect(
(LPVOID)m_pv,
m_cb,
PAGE_READWRITE,
&dwOldProtect
))
{
_ASSERT( 1==0 );
goto CMapFileEx_Exit ;
}
if(!VirtualProtect(
(LPVOID)m_pvRearGuard,
m_cbRearGuardSize,
PAGE_READWRITE,
&dwOldProtect
))
{
_ASSERT( 1== 0 );
goto CMapFileEx_Exit ;
}
MoveMemory( m_pvFrontGuard, m_pv, m_cb );
FlushViewOfFile( m_pvFrontGuard, m_cb ) ;
UnmapViewOfFile( (LPVOID)m_pvFrontGuard );
if( INVALID_HANDLE_VALUE != m_hFile )
{
if( SetFilePointer( m_hFile, m_cb, NULL, FILE_BEGIN ) == m_cb )
{
SetEndOfFile( m_hFile ) ;
}
}
m_pvFrontGuard = m_pvRearGuard = m_pv = NULL ;
}
}
CMapFileEx_Exit:
LeaveCriticalSection(&m_csProtectMap);
DeleteCriticalSection(&m_csProtectMap);
return;
}
/* ------------------------------------------------------------------------
CMapFileEx::MapFromHandle
Does the real work of mapping. Given a handle to the file, go through
the motions of mapping, and recording what happens. Reports errors
as needed. Also adjusts file size if requested.
Author
Lindsay Harris - lindsayh
Carl Kadie - carlk
History
16:30 on Mon 10 Apr 1995 -by- Lindsay Harris [lindsayh]
First version, based on older code with CarlK enhancements.
------------------------------------------------------------------------ */
void
CMapFileEx::MapFromHandle( HANDLE hFile, BOOL fWriteEnable, DWORD cbIncrease )
{
if ( !fWriteEnable && cbIncrease != 0 )
return; // This is non-sensical.
m_cb = GetFileSize( hFile, NULL );
DWORD cbNewSize = 0;
DWORD cbOldSize = 0;
//
// Determine if the file is to grow. Only pass a non-zero size
// to the system if the size is growing - it's probably faster, and
// the most likely common case.
//
if ( cbIncrease )
{
cbNewSize = m_cb += cbIncrease;
}
else
{
if ( m_cb == 0 )
return; // Nothing there.
}
//
// Add guard page logic
//
SYSTEM_INFO si;
GetSystemInfo(&si);
DWORD dwPageSize = si.dwPageSize ;
DWORD dwGuardPageSize = si.dwAllocationGranularity;
// GuardPageSize should be > cbNewSize
while( cbNewSize > dwGuardPageSize )
{
dwGuardPageSize += si.dwAllocationGranularity;
}
// cbNewSize should be a multiple of dwPageSize, to ensure rear guard page is properly aligned
_ASSERT( (cbNewSize % dwPageSize) == 0 ) ;
DWORD cbAllocSize = (2 * (dwGuardPageSize)) + cbNewSize;
DWORD dwOldProtect = PAGE_READWRITE ;
DWORD dwError;
//
// Grow the file to match the size of memory mapping
//
if ( cbIncrease )
{
_ASSERT(fWriteEnable);
//
// Make sure the file is the correct size.
//
DWORD fpos;
BOOL fSetEnd;
if ( (DWORD)-1 == ( fpos = SetFilePointer( hFile, cbAllocSize, NULL, FILE_BEGIN ))
|| !(fSetEnd = SetEndOfFile( hFile ))
)
{
//
// Error case
//
m_pv = NULL;
return;
}
}
//
// Create the mapping object.
//
HANDLE hFileMap; // Intermediate step.
hFileMap = CreateFileMapping(
hFile,
NULL,
fWriteEnable ? PAGE_READWRITE : PAGE_READONLY,
0,
cbAllocSize, // NOTE: this is greater than cbNewSize by 2*GuardPageSize
NULL
);
if ( !hFileMap )
{
// Error case
//
m_pv = NULL;
m_cb = 0;
return;
}
//
// Get the pointer mapped to the desired file.
//
m_pvFrontGuard = (LPBYTE)MapViewOfFile(
hFileMap,
fWriteEnable ? FILE_MAP_WRITE : FILE_MAP_READ,
0, 0, 0
);
if ( !m_pvFrontGuard )
{
// Error case
//
m_pv = NULL;
m_cb = 0; // Also set to zero, just in case.
goto MapFromHandle_Exit;
}
// zero out the part grown
cbOldSize = cbNewSize - cbIncrease;
ZeroMemory( m_pvFrontGuard + cbOldSize, cbAllocSize - cbOldSize );
// front guard page of size (64KB)
m_cbFrontGuardSize = dwGuardPageSize ;
// actual memory-mapping
m_pv = m_pvFrontGuard + m_cbFrontGuardSize ;
MoveMemory( m_pv, m_pvFrontGuard, cbNewSize );
// rear guard page of size (64KB)
m_pvRearGuard = m_pv + cbNewSize ;
m_cbRearGuardSize = m_cbFrontGuardSize ;
// zero out the front and rear guard pages
ZeroMemory( m_pvFrontGuard, m_cbFrontGuardSize );
ZeroMemory( m_pvRearGuard, m_cbRearGuardSize );
// make front page a guard page
if(!VirtualProtect(
(LPVOID)m_pvFrontGuard,
m_cbFrontGuardSize,
PAGE_READONLY | PAGE_GUARD,
&dwOldProtect
))
{
m_pv = NULL;
m_cb = 0;
goto MapFromHandle_Exit ;
}
// make mapping read-only; users of CMapFileEx will need to use the
// UnprotectMapping() / ProtectMapping() calls to write to this mapping.
if(!VirtualProtect(
(LPVOID)m_pv,
cbNewSize,
PAGE_READONLY,
&dwOldProtect
))
{
m_pv = NULL;
m_cb = 0;
goto MapFromHandle_Exit ;
}
// make rear page a guard page
if(!VirtualProtect(
(LPVOID)m_pvRearGuard,
m_cbRearGuardSize,
PAGE_READONLY | PAGE_GUARD,
&dwOldProtect
))
{
m_pv = NULL;
m_cb = 0;
goto MapFromHandle_Exit ;
}
MapFromHandle_Exit:
dwError = GetLastError();
//
// Now that we have our pointer, we can close the mapping object.
//
BOOL fClose = CloseHandle( hFileMap );
_ASSERT( fClose );
return;
}
/* ------------------------------------------------------------------------
CMapFileEx::UnprotectMapping
Change mapping from READONLY to READWRITE when a write is necessary
**** NOTE: Calls to UnprotectMapping() and ProtectMapping() should be matched ***
eg:
{
UnprotectMapping();
//
// code to write to the mapping
//
ProtectMapping();
}
Returns TRUE on success, FALSE on failure
Lock is held only if returns TRUE
------------------------------------------------------------------------ */
BOOL
CMapFileEx::UnprotectMapping()
{
DWORD dwOldProtect = PAGE_READONLY;
// *** This is released in ProtectMapping() ***
EnterCriticalSection(&m_csProtectMap);
// enable writes
if(!VirtualProtect(
(LPVOID)m_pv,
m_cb,
PAGE_READWRITE,
&dwOldProtect
))
{
LeaveCriticalSection(&m_csProtectMap);
return FALSE;
}
return TRUE;
}
/* ------------------------------------------------------------------------
CMapFileEx::UnprotectMapping
This is called to revert the mapping protection back to READONLY
**** The thread calling this function should have the protect lock *****
Returns TRUE on success, FALSE on failure
Lock is released in either case
------------------------------------------------------------------------ */
BOOL
CMapFileEx::ProtectMapping()
{
DWORD dwOldProtect = PAGE_READWRITE;
BOOL fRet = TRUE;
// disable writes
if(!VirtualProtect(
(LPVOID)m_pv,
m_cb,
PAGE_READONLY,
&dwOldProtect
))
{
fRet = FALSE ;
}
LeaveCriticalSection(&m_csProtectMap);
return fRet;
}
#endif // DEBUG