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.
1584 lines
34 KiB
1584 lines
34 KiB
#include "config.h"
|
|
|
|
#define HANDLE WINHANDLE
|
|
#include <windows.h>
|
|
#undef HANDLE
|
|
#include <dos.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <ctype.h>
|
|
#include <io.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
|
|
/* this build is for DAYTONA
|
|
/**/
|
|
#define DAYTONA 1
|
|
|
|
/* make sure the definition between os.h/_jet.h is the same as in windows.h */
|
|
#undef FAR
|
|
#undef NEAR
|
|
#undef PASCAL
|
|
#undef far
|
|
#undef near
|
|
#undef cdecl
|
|
#undef pascal
|
|
#undef MAKELONG
|
|
#undef HIWORD
|
|
|
|
#include "daedef.h"
|
|
#include "util.h"
|
|
#include "b71iseng.h"
|
|
|
|
DeclAssertFile; /* Declare file name for assert macros */
|
|
|
|
|
|
VOID SysGetDriveGeometry( HANDLE handle );
|
|
|
|
|
|
DWORD DwSYSGetLastError( VOID )
|
|
{
|
|
DWORD dw = GetLastError();
|
|
|
|
return dw;
|
|
}
|
|
|
|
|
|
LOCAL ERR ErrCheckError( VOID );
|
|
|
|
LOCAL ERR ErrSYSIGetLastError( ERR errDefault )
|
|
{
|
|
ERR err = errDefault;
|
|
DWORD dw = GetLastError();
|
|
|
|
/* maps system error to JET error, or sets err to given
|
|
/* default error.
|
|
/**/
|
|
switch ( dw )
|
|
{
|
|
case ERROR_TOO_MANY_OPEN_FILES:
|
|
err = JET_errNoMoreFiles;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
ERR ErrSysCheckLangid( LANGID langid )
|
|
{
|
|
ERR err;
|
|
WCHAR rgwA[1];
|
|
WCHAR rgwB[1];
|
|
|
|
//NOTE: Julie Bennett said that starting with DAYTONA, the best call to use
|
|
// is IsValidLocale(). I don't have libraries to link to for that yet.
|
|
// She said that the best thing (for performance reasons) to do in NT
|
|
// (pre-daytona) is call CompareStringW with counts of -1. This will
|
|
// determine if the langid is currently configured on the machine.
|
|
// (not just a valid langid somewhere in the universe).
|
|
|
|
rgwA[0] = 0;
|
|
rgwB[0] = 0;
|
|
|
|
if ( CompareStringW( MAKELCID( langid, 0 ), NORM_IGNORECASE, rgwA, -1, rgwB, -1 ) == 0 )
|
|
{
|
|
Assert( GetLastError() == ERROR_INVALID_PARAMETER );
|
|
err = JET_errInvalidLanguageId;
|
|
}
|
|
else
|
|
{
|
|
err = JET_errSuccess;
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
ERR ErrSysMapString(
|
|
LANGID langid,
|
|
BYTE *pbColumn,
|
|
INT cbColumn,
|
|
BYTE *rgbSeg,
|
|
INT cbMax,
|
|
INT *pcbSeg )
|
|
{
|
|
ERR err = JET_errSuccess;
|
|
|
|
// UNDONE: refine this constant based on unicode key format
|
|
/* 3 * number of unicode character bytes + 7 overhead bytes + 10 fudge
|
|
/**/
|
|
#define JET_cbUnicodeKeyMost ( 3 * JET_cbColumnMost + 7 + 10 )
|
|
BYTE rgbKey[JET_cbUnicodeKeyMost];
|
|
INT cwKey;
|
|
INT cbKey;
|
|
#ifndef DATABASE_FORMAT_CHANGE
|
|
WORD rgwUpper[ JET_cbColumnMost / sizeof(WORD) ];
|
|
#endif
|
|
|
|
#ifndef _X86_
|
|
/* convert pbColumn to aligned pointer for MIPS/Alpha builds
|
|
/**/
|
|
BYTE rgbColumn[JET_cbColumnMost];
|
|
|
|
memcpy( rgbColumn, pbColumn, cbColumn );
|
|
pbColumn = (BYTE *)&rgbColumn[0];
|
|
#endif
|
|
|
|
#ifdef DATABASE_FORMAT_CHANGE
|
|
/* assert non-zero length unicode string
|
|
/**/
|
|
Assert( cbColumn =< JET_cbColumnMost );
|
|
Assert( cbColumn > 0 );
|
|
Assert( cbColumn % 2 == 0 );
|
|
|
|
// UNDONE: after shipping with Daytona, remove this ifdef and
|
|
// document database format change.
|
|
cbKey = LCMapStringW(
|
|
MAKELCID( langid, 0 ),
|
|
#ifdef DAYTONA
|
|
LCMAP_SORTKEY | NORM_IGNORECASE,
|
|
#else
|
|
LCMAP_SORTKEY | NORM_IGNORECASE | SORT_STRINGSORT,
|
|
#endif
|
|
(const unsigned short *)pbColumn,
|
|
(int) cbColumn / sizeof(WORD),
|
|
(unsigned short *)rgbKey,
|
|
JET_cbUnicodeKeyMost );
|
|
Assert( cbKey > 0 );
|
|
|
|
if ( cbKey > cbMax )
|
|
{
|
|
err = wrnFLDKeyTooBig;
|
|
*pcbSeg = cbMax;
|
|
}
|
|
else
|
|
{
|
|
Assert( err == JET_errSuccess );
|
|
*pcbSeg = cbKey;
|
|
}
|
|
memcpy( rgbSeg, rgbKey, *pcbSeg );
|
|
|
|
return err;
|
|
#else
|
|
/* assert non-zero length unicode string
|
|
/**/
|
|
Assert( cbColumn <= JET_cbColumnMost );
|
|
Assert( cbColumn > 0 );
|
|
Assert( cbColumn % 2 == 0 );
|
|
|
|
cwKey = LCMapStringW(
|
|
MAKELCID( langid, 0 ),
|
|
LCMAP_UPPERCASE,
|
|
(const unsigned short *) pbColumn,
|
|
(INT) cbColumn / sizeof(WORD),
|
|
rgwUpper,
|
|
JET_cbColumnMost / sizeof(WORD) );
|
|
Assert( cwKey == (INT)(cbColumn / sizeof(WORD)) );
|
|
|
|
cbKey = LCMapStringW(
|
|
MAKELCID( langid, 0 ),
|
|
#ifdef DAYTONA
|
|
LCMAP_SORTKEY,
|
|
#else
|
|
LCMAP_SORTKEY | SORT_STRINGSORT,
|
|
#endif
|
|
(const unsigned short *)rgwUpper,
|
|
cbColumn / sizeof(WORD),
|
|
(unsigned short *) rgbKey,
|
|
JET_cbUnicodeKeyMost );
|
|
|
|
Assert( cbKey > 0 );
|
|
|
|
if ( cbKey > cbMax )
|
|
{
|
|
err = wrnFLDKeyTooBig;
|
|
*pcbSeg = cbMax;
|
|
}
|
|
else
|
|
{
|
|
Assert( err == JET_errSuccess );
|
|
*pcbSeg = cbKey;
|
|
}
|
|
memcpy( rgbSeg, rgbKey, *pcbSeg );
|
|
|
|
return err;
|
|
#endif
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysCreateThread( ULONG (*pulfn)(), ULONG cbStack, LONG lThreadPriority );
|
|
// ========================================================
|
|
//
|
|
// ErrSysCreateThread( ULONG (*pulfn)(), TID *ptid, ULONG cbStack );
|
|
//
|
|
// Creates a thread with the given stack size.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysCreateThread( ULONG (*pulfn)(), ULONG cbStackSize, LONG lThreadPriority, HANDLE *phandle )
|
|
{
|
|
HANDLE handle;
|
|
TID tid;
|
|
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
handle = (HANDLE) CreateThread( NULL,
|
|
cbStackSize,
|
|
(LPTHREAD_START_ROUTINE) pulfn,
|
|
NULL,
|
|
(DWORD) 0,
|
|
(LPDWORD) &tid );
|
|
if ( handle == 0 )
|
|
return JET_errNoMoreThreads;
|
|
|
|
if ( lThreadPriority == lThreadPriorityNormal )
|
|
SetThreadPriority( handle, THREAD_PRIORITY_NORMAL );
|
|
if ( lThreadPriority == lThreadPriorityEnhanced )
|
|
SetThreadPriority( handle, THREAD_PRIORITY_ABOVE_NORMAL );
|
|
if ( lThreadPriority == lThreadPriorityCritical )
|
|
SetThreadPriority( handle, THREAD_PRIORITY_HIGHEST);
|
|
|
|
/* return handle to thread.
|
|
/**/
|
|
*phandle = handle;
|
|
return JET_errSuccess;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// SysExitThread( ULONG ulExitCode );
|
|
// ========================================================
|
|
//
|
|
// SysExitThread( ULONG ulExitCode );
|
|
//
|
|
// Exits thread.
|
|
//
|
|
//----------------------------------------------------------
|
|
VOID SysExitThread( ULONG ulExitCode )
|
|
{
|
|
(VOID)ExitThread( ulExitCode );
|
|
return;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// FSysExitThread
|
|
// ========================================================
|
|
//
|
|
// FSysExitThread( HANDLE handle );
|
|
//
|
|
// Returns fTrue if thread has exited.
|
|
//
|
|
//----------------------------------------------------------
|
|
BOOL FSysExitThread( HANDLE handle )
|
|
{
|
|
BOOL f;
|
|
DWORD dwExitCode;
|
|
DWORD dw;
|
|
|
|
f = GetExitCodeThread( handle, &dwExitCode );
|
|
if ( !f )
|
|
{
|
|
dw = GetLastError();
|
|
// UNDONE: handle error here
|
|
Assert( fFalse );
|
|
}
|
|
|
|
return !(dwExitCode == STILL_ACTIVE);
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ULONG UlSysThreadId( VOID )
|
|
// ========================================================
|
|
//
|
|
// PARAMETERS
|
|
//
|
|
//----------------------------------------------------------
|
|
ULONG UlSysThreadId( VOID )
|
|
{
|
|
return GetCurrentThreadId();
|
|
}
|
|
|
|
|
|
/* open a file that was opened as for write but shared to read.
|
|
/**/
|
|
ERR ErrSysOpenReadFile( CHAR *szFileName, HANDLE *phf )
|
|
{
|
|
*phf = CreateFile( szFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
0,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING |
|
|
FILE_FLAG_RANDOM_ACCESS,
|
|
0 );
|
|
|
|
if ( *phf == handleNil )
|
|
{
|
|
ERR err;
|
|
|
|
err = ErrSYSIGetLastError( JET_errFileNotFound );
|
|
return err;
|
|
}
|
|
|
|
return JET_errSuccess;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysOpenFile
|
|
// ========================================================
|
|
//
|
|
// Open given file.
|
|
//
|
|
//----------------------------------------------------------
|
|
|
|
ERR ErrSysOpenFile(
|
|
CHAR *szFileName,
|
|
HANDLE *phf,
|
|
ULONG ulFileSize,
|
|
BOOL fReadOnly,
|
|
BOOL fOverlapped)
|
|
{
|
|
ERR err = JET_errSuccess;
|
|
DWORD fdwAccess;
|
|
DWORD fdwShare;
|
|
DWORD fdwAttrsAndFlags;
|
|
BOOL f;
|
|
|
|
Assert( !ulFileSize || ulFileSize && !fReadOnly );
|
|
*phf = handleNil;
|
|
|
|
/* set access to read or read-write
|
|
/**/
|
|
if ( fReadOnly )
|
|
fdwAccess = GENERIC_READ;
|
|
else
|
|
fdwAccess = GENERIC_READ | GENERIC_WRITE;
|
|
|
|
/* do not allow sharing on database file
|
|
/**/
|
|
#ifdef JETSER
|
|
fdwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
#else
|
|
fdwShare = FILE_SHARE_READ;
|
|
#endif
|
|
|
|
if ( fOverlapped )
|
|
{
|
|
fdwAttrsAndFlags = FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING |
|
|
FILE_FLAG_WRITE_THROUGH |
|
|
FILE_FLAG_RANDOM_ACCESS |
|
|
FILE_FLAG_OVERLAPPED;
|
|
}
|
|
else
|
|
{
|
|
fdwAttrsAndFlags = FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING |
|
|
FILE_FLAG_WRITE_THROUGH |
|
|
FILE_FLAG_RANDOM_ACCESS;
|
|
}
|
|
|
|
if ( ulFileSize != 0L )
|
|
{
|
|
/* create a new file
|
|
/**/
|
|
fdwAttrsAndFlags = FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_WRITE_THROUGH |
|
|
FILE_FLAG_RANDOM_ACCESS;
|
|
|
|
*phf = CreateFile( szFileName,
|
|
fdwAccess,
|
|
fdwShare,
|
|
0,
|
|
CREATE_NEW,
|
|
fdwAttrsAndFlags,
|
|
0 );
|
|
|
|
if ( *phf == handleNil )
|
|
{
|
|
err = ErrSYSIGetLastError( JET_errFileNotFound );
|
|
return err;
|
|
}
|
|
|
|
/* no overlapped, it does not work!
|
|
/**/
|
|
Call( ErrSysNewSize( *phf, ulFileSize, 0, fFalse ) );
|
|
|
|
/* force log file pre-allocation to be effective
|
|
/**/
|
|
Assert(sizeof(HANDLE) == sizeof(HFILE));
|
|
f = CloseHandle( (HANDLE) *phf );
|
|
Assert( f );
|
|
|
|
// UNDONE: is this still necessary in Daytona
|
|
/* this bogus code works around an NT bug which
|
|
/* causes network files not to have file usage
|
|
/* restrictions reset until a GENERIC_READ file
|
|
/* handle is closed.
|
|
/**/
|
|
if ( fOverlapped )
|
|
{
|
|
fdwAttrsAndFlags = FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING |
|
|
FILE_FLAG_WRITE_THROUGH |
|
|
FILE_FLAG_RANDOM_ACCESS |
|
|
FILE_FLAG_OVERLAPPED;
|
|
}
|
|
else
|
|
{
|
|
fdwAttrsAndFlags = FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING |
|
|
FILE_FLAG_WRITE_THROUGH |
|
|
FILE_FLAG_RANDOM_ACCESS;
|
|
}
|
|
|
|
*phf = CreateFile( szFileName,
|
|
GENERIC_READ,
|
|
fdwShare,
|
|
0,
|
|
OPEN_EXISTING,
|
|
fdwAttrsAndFlags,
|
|
0 );
|
|
|
|
if ( *phf == handleNil )
|
|
{
|
|
err = ErrSYSIGetLastError( JET_errFileNotFound );
|
|
return err;
|
|
}
|
|
|
|
f = CloseHandle( (HANDLE) *phf );
|
|
Assert( f );
|
|
}
|
|
|
|
if ( fOverlapped )
|
|
{
|
|
fdwAttrsAndFlags = FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING |
|
|
FILE_FLAG_WRITE_THROUGH |
|
|
FILE_FLAG_RANDOM_ACCESS |
|
|
FILE_FLAG_OVERLAPPED;
|
|
}
|
|
else
|
|
{
|
|
fdwAttrsAndFlags = FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING |
|
|
FILE_FLAG_WRITE_THROUGH |
|
|
FILE_FLAG_RANDOM_ACCESS;
|
|
}
|
|
|
|
*phf = CreateFile( szFileName,
|
|
fdwAccess,
|
|
fdwShare,
|
|
0,
|
|
OPEN_EXISTING,
|
|
fdwAttrsAndFlags,
|
|
0 );
|
|
|
|
/* open in read_only mode if open in read_write mode failed
|
|
/**/
|
|
if ( *phf == handleNil && !fReadOnly && !ulFileSize )
|
|
{
|
|
/* try to open file read only
|
|
/**/
|
|
fdwAccess = GENERIC_READ;
|
|
|
|
*phf = CreateFile( szFileName,
|
|
fdwAccess,
|
|
fdwShare,
|
|
0,
|
|
OPEN_EXISTING,
|
|
fdwAttrsAndFlags,
|
|
0 );
|
|
|
|
err = JET_wrnFileOpenReadOnly;
|
|
}
|
|
|
|
/* if file could not be opened, return NULL file handle.
|
|
/**/
|
|
if ( *phf == handleNil )
|
|
{
|
|
err = ErrSYSIGetLastError( JET_errFileNotFound );
|
|
return err;
|
|
}
|
|
#if 0
|
|
#ifdef DEBUG
|
|
else
|
|
{
|
|
SysGetDriveGeometry( *phf );
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
HandleError:
|
|
if ( err < 0 && *phf != handleNil )
|
|
{
|
|
f = CloseHandle( (HANDLE) *phf );
|
|
Assert(f);
|
|
*phf = handleNil;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysDeleteFile
|
|
// ========================================================
|
|
//
|
|
// ERR ErrSysDeleteFile( const CHAR *szFileName )
|
|
//
|
|
// Delete given file.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysDeleteFile( const CHAR *szFileName )
|
|
{
|
|
if ( DeleteFile( szFileName ) )
|
|
return JET_errSuccess;
|
|
return JET_errFileNotFound;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ERR ErrSysNewSize( HANDLE hf, ULONG ulSize, ULONG ulSizeHigh, BOOL fOverlapped )
|
|
// ========================================================
|
|
//
|
|
// Resize database file. Not semaphore protected as new size
|
|
// operation will not conflict with chgfileptr, read or write.
|
|
//
|
|
// PARAMETERS
|
|
// hf file handle
|
|
// cpg new size of database file in pages
|
|
//
|
|
//----------------------------------------------------------
|
|
|
|
|
|
#if 0
|
|
// UNDONE: this scheme of write 1024 bytes before the end of file will not work
|
|
// UNDONE: for shrinking files.
|
|
ERR ErrSysNewSize( HANDLE hf, ULONG ulFileSize, ULONG ulFileSizeHigh, BOOL fOverlapped )
|
|
{
|
|
#if 0
|
|
ERR err = JET_errSuccess;
|
|
INT cbT;
|
|
ULONG ul;
|
|
#define cbSec 1024
|
|
/* memory must be 16-byte aligned and mulitple of 1024 bytes
|
|
/**/
|
|
BYTE *pb = (BYTE *) PvSysAllocAndCommit( cbSec + 15 );
|
|
BYTE *pbAligned = (BYTE *)( (ULONG)(pb + 15) & ~0x0f );
|
|
|
|
if ( pb == NULL )
|
|
return JET_errOutOfMemory;
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
if ( ulFileSize >= cbSec )
|
|
{
|
|
ulFileSize -= cbSec;
|
|
}
|
|
else
|
|
{
|
|
Assert( ulFileSize == 0 );
|
|
ulFileSizeHigh--;
|
|
ulFileSize = (ULONG) ~cbSec + 1;
|
|
}
|
|
ul = SetFilePointer( (HANDLE) hf, ulFileSize, &ulFileSizeHigh, FILE_BEGIN );
|
|
if ( ul != ulFileSize )
|
|
{
|
|
// UNDONE: check for other errors
|
|
return JET_errDiskFull;
|
|
}
|
|
|
|
/* the mask bits are to satisfy the 16-byte boundary alignment in MIPS
|
|
/**/
|
|
(VOID)ErrSysWriteBlock( hf, pbAligned, cbSec, &cbT );
|
|
if ( GetLastError() == ERROR_DISK_FULL )
|
|
err = JET_errDiskFull;
|
|
|
|
if ( pb != NULL )
|
|
SysFree( pb );
|
|
|
|
return err;
|
|
#else
|
|
int cb;
|
|
ULONG ul;
|
|
|
|
/* the extra 15 bytes are for the sake of 16-byte
|
|
/* boundary alignment in MIPS
|
|
/**/
|
|
#define cbSec 1024 // must be same as in page.h
|
|
STATIC BYTE rgb[cbSec + 15];
|
|
|
|
Assert(sizeof(HANDLE) == sizeof(HFILE));
|
|
if ( ulFileSize >= cbSec )
|
|
ulFileSize -= cbSec;
|
|
else
|
|
{
|
|
Assert( ulFileSize == 0 );
|
|
ulFileSizeHigh--;
|
|
ulFileSize = (ULONG) ~cbSec + 1;
|
|
}
|
|
ul = SetFilePointer(
|
|
(HANDLE) hf, ulFileSize, &ulFileSizeHigh, FILE_BEGIN );
|
|
if ( ul != ulFileSize )
|
|
goto CheckError;
|
|
|
|
/* the mask bits are to satisfy the 16-byte boundary alignment in MIPS
|
|
/**/
|
|
(void) ErrSysWriteBlock( hf,(BYTE *) ( (ULONG)(rgb+15) & ~0x0f ), cbSec, &cb );
|
|
if ( GetLastError() == ERROR_DISK_FULL )
|
|
return JET_errDiskFull;
|
|
|
|
return JET_errSuccess;
|
|
|
|
CheckError:
|
|
if ( GetLastError() == ERROR_DISK_FULL )
|
|
return JET_errDiskFull;
|
|
|
|
return JET_errDiskIO;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
/* the following function should work -- if FAT FS bug fixed
|
|
/**/
|
|
ERR ErrSysNewSize( HANDLE hf, ULONG ulSize, ULONG ulSizeHigh, BOOL fOverlapped )
|
|
{
|
|
ULONG ul;
|
|
BOOL f;
|
|
|
|
ul = SetFilePointer( hf, ulSize, &ulSizeHigh, FILE_BEGIN );
|
|
if ( ul != ulSize )
|
|
goto HandleError;
|
|
|
|
f = SetEndOfFile( hf );
|
|
if ( !( f ) )
|
|
goto HandleError;
|
|
|
|
return JET_errSuccess;
|
|
|
|
HandleError:
|
|
if ( GetLastError() == ERROR_DISK_FULL )
|
|
return JET_errDiskFull;
|
|
|
|
return JET_errDiskIO;
|
|
}
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysCloseFile
|
|
// =========================================================
|
|
//
|
|
// ERR ErrSysCloseFile( HANDLE hf )
|
|
//
|
|
// Close file.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysCloseHandle( HANDLE hf )
|
|
{
|
|
BOOL f;
|
|
|
|
Assert(sizeof(HANDLE) == sizeof(HFILE));
|
|
f = CloseHandle( (HANDLE) hf );
|
|
if ( !f )
|
|
return JET_errFileClose;
|
|
return JET_errSuccess;
|
|
}
|
|
|
|
|
|
LOCAL ERR ErrCheckError( VOID )
|
|
{
|
|
DWORD dw = GetLastError();
|
|
|
|
if ( dw == ERROR_IO_PENDING )
|
|
return JET_errSuccess;
|
|
|
|
if ( dw == ERROR_INVALID_USER_BUFFER ||
|
|
dw == ERROR_NOT_ENOUGH_MEMORY )
|
|
return JET_errTooManyIO;
|
|
|
|
if ( dw == ERROR_DISK_FULL )
|
|
return JET_errDiskFull;
|
|
|
|
if ( dw == ERROR_HANDLE_EOF )
|
|
return JET_errDiskIO;
|
|
|
|
/* if this assert is hit, then we need another error code
|
|
/**/
|
|
Assert( fFalse );
|
|
return JET_errDiskIO;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysReadBlock( hf, pvBuf, cbBuf, pcbRead )
|
|
// ========================================================
|
|
//
|
|
// ERR ErrSysReadBlock( hf, pvBuf, cbBuf, pcbRead )
|
|
//
|
|
// Reads cbBuf bytes of data into pvBuf. Returns error if DOS error
|
|
// or if less than expected number of bytes retured.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysReadBlock( HANDLE hf, VOID *pvBuf, UINT cbBuf, UINT *pcbRead )
|
|
{
|
|
BOOL f;
|
|
INT msec = 1;
|
|
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
IssueRead:
|
|
f = ReadFile( (HANDLE) hf, pvBuf, cbBuf, pcbRead, NULL );
|
|
if ( f )
|
|
{
|
|
if ( cbBuf != *pcbRead )
|
|
return JET_errDiskIO;
|
|
else
|
|
return JET_errSuccess;
|
|
}
|
|
else
|
|
{
|
|
ERR err = ErrCheckError();
|
|
|
|
if ( err == JET_errTooManyIO )
|
|
{
|
|
msec <<= 1;
|
|
Sleep( msec - 1 );
|
|
goto IssueRead;
|
|
}
|
|
else
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ERR ErrSysWriteBlock( hf, pvBuf, cbBuf, pcbWritten )
|
|
// =========================================================
|
|
//
|
|
// ERR ErrSysWriteBlock( hf, pvBuf, cbBuf, pcbWritten )
|
|
//
|
|
// Writes cbBuf bytes from pbBuf to file hf.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysWriteBlock( HANDLE hf, VOID *pvBuf, UINT cbBuf, UINT *pcbWritten )
|
|
{
|
|
BOOL f;
|
|
INT msec = 1;
|
|
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
IssueWrite:
|
|
f = WriteFile( (HANDLE) hf, pvBuf, cbBuf, pcbWritten, NULL );
|
|
if ( f )
|
|
{
|
|
if ( cbBuf != *pcbWritten )
|
|
{
|
|
if ( GetLastError() == ERROR_DISK_FULL )
|
|
return JET_errDiskFull;
|
|
else
|
|
return JET_errDiskIO;
|
|
}
|
|
else
|
|
return JET_errSuccess;
|
|
}
|
|
else
|
|
{
|
|
ERR err = ErrCheckError();
|
|
|
|
if ( err == JET_errTooManyIO )
|
|
{
|
|
msec <<= 1;
|
|
Sleep(msec - 1);
|
|
goto IssueWrite;
|
|
}
|
|
else
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysReadBlockOverlapped( hf, pvBuf, cbBuf, pcbRead )
|
|
// =========================================================
|
|
//
|
|
// ERR ErrSysReadBlock( hf, pvBuf, cbBuf, pcbRead )
|
|
//
|
|
// Reads cbBuf bytes of data into pvBuf. Returns error if DOS error
|
|
// or if less than expected number of bytes retured.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysReadBlockOverlapped(
|
|
HANDLE hf,
|
|
VOID *pvBuf,
|
|
UINT cbBuf,
|
|
DWORD *pcbRead,
|
|
OLP *polp)
|
|
{
|
|
BOOL f;
|
|
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
Assert( sizeof(OLP) == sizeof(OVERLAPPED) );
|
|
f = ReadFile( (HANDLE) hf, pvBuf, cbBuf, pcbRead, (OVERLAPPED *) polp );
|
|
if ( f )
|
|
return JET_errSuccess;
|
|
else
|
|
return ErrCheckError();
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// Err ErrSysWriteBlockOverlapped( hf, pvBuf, cbBuf, pcbWritten )
|
|
// =========================================================
|
|
//
|
|
// ERR ErrSysWriteBlock( hf, pvBuf, cbBuf, pcbWritten )
|
|
//
|
|
// Writes cbBuf bytes from pbBuf to file hf.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysWriteBlockOverlapped(
|
|
HANDLE hf,
|
|
VOID *pvBuf,
|
|
UINT cbBuf,
|
|
DWORD *pcbWritten,
|
|
OLP *polp)
|
|
{
|
|
BOOL f;
|
|
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
Assert( sizeof(OLP) == sizeof(OVERLAPPED) );
|
|
|
|
f = WriteFile( (HANDLE) hf, pvBuf, cbBuf, pcbWritten, (OVERLAPPED *)polp );
|
|
if ( f )
|
|
{
|
|
return JET_errSuccess;
|
|
}
|
|
else
|
|
{
|
|
return ErrCheckError();
|
|
}
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysReadBlockEx( hf, pvBuf, cbBuf, pcbRead )
|
|
// ========================================================
|
|
//
|
|
// ERR ErrSysReadBlock( hf, pvBuf, cbBuf, pcbRead )
|
|
//
|
|
// Reads cbBuf bytes of data into pvBuf. Returns error if DOS error
|
|
// or if less than expected number of bytes retured.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysReadBlockEx(
|
|
HANDLE hf,
|
|
VOID *pvBuf,
|
|
UINT cbBuf,
|
|
OLP *polp,
|
|
VOID *pfnCompletion)
|
|
{
|
|
BOOL f;
|
|
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
Assert( sizeof(OLP) == sizeof(OVERLAPPED) );
|
|
|
|
f = ReadFileEx( (HANDLE) hf,
|
|
pvBuf,
|
|
cbBuf,
|
|
(OVERLAPPED *) polp,
|
|
(LPOVERLAPPED_COMPLETION_ROUTINE) pfnCompletion );
|
|
|
|
if ( f )
|
|
return JET_errSuccess;
|
|
else
|
|
return ErrCheckError();
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ERR ErrSysWriteBlockEx( hf, pvBuf, cbBuf, pcbWritten )
|
|
// ========================================================
|
|
//
|
|
// ERR ErrSysWriteBlock( hf, pvBuf, cbBuf, pcbWritten )
|
|
//
|
|
// Writes cbBuf bytes from pbBuf to file hf.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysWriteBlockEx(
|
|
HANDLE hf,
|
|
VOID *pvBuf,
|
|
UINT cbBuf,
|
|
OLP *polp,
|
|
VOID *pfnCompletion )
|
|
{
|
|
BOOL f;
|
|
ERR err;
|
|
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
Assert( sizeof(OLP) == sizeof(OVERLAPPED) );
|
|
|
|
f = WriteFileEx( (HANDLE) hf,
|
|
pvBuf,
|
|
cbBuf,
|
|
(OVERLAPPED *)polp,
|
|
(LPOVERLAPPED_COMPLETION_ROUTINE)pfnCompletion );
|
|
|
|
if ( f )
|
|
err = JET_errSuccess;
|
|
else
|
|
err = ErrCheckError();
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
ERR ErrSysGetOverlappedResult(
|
|
HANDLE hf,
|
|
OLP *polp,
|
|
UINT *pcb,
|
|
BOOL fWait)
|
|
{
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
Assert( sizeof(OLP) == sizeof(OVERLAPPED) );
|
|
|
|
if ( GetOverlappedResult( (HANDLE) hf, (OVERLAPPED *)polp, pcb, fWait ) )
|
|
return JET_errSuccess;
|
|
|
|
if ( GetLastError() == ERROR_DISK_FULL )
|
|
return JET_errDiskFull;
|
|
|
|
return JET_errDiskIO;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// VOID SysChgFilePtr( HANDLE hf, LONG lRel, LONG *plRelHigh, ULONG ulRef, ULONG *pul )
|
|
// =========================================================
|
|
//
|
|
// Changes file hf pointer to position lRef relative to position :
|
|
//
|
|
// wRef FILE_BEGIN file beginnging
|
|
//
|
|
//----------------------------------------------------------
|
|
VOID SysChgFilePtr( HANDLE hf, LONG lRel, LONG *plRelHigh, ULONG ulRef, ULONG *pul )
|
|
{
|
|
Assert( sizeof(HANDLE) == sizeof(HFILE) );
|
|
*pul = SetFilePointer( (HANDLE)hf, lRel, plRelHigh, ulRef );
|
|
Assert( ulRef != FILE_BEGIN || *pul == (ULONG)lRel );
|
|
return;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ErrSysMove( CHAR *szFrom, CHAR *szTo )
|
|
// =========================================================
|
|
//
|
|
// ERR ErrSysMove( CHAR *szFrom, CHAR *szTo )
|
|
//
|
|
// Renames file szFrom to file name szTo.
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysMove( CHAR *szFrom, CHAR *szTo )
|
|
{
|
|
if ( MoveFile( szFrom, szTo ) )
|
|
return JET_errSuccess;
|
|
else
|
|
return JET_errFileAccessDenied;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ERR ErrSysCopy( CHAR *szFrom, CHAR *szTo, BOOL fFailIfExists )
|
|
// ========================================================
|
|
//
|
|
// Copies file szFrom to file name szTo.
|
|
// If szTo already exists, the function either fails or overwrites
|
|
// the existing file, depending on the flag fFailIfExists
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysCopy( CHAR *szFrom, CHAR *szTo, BOOL fFailIfExists )
|
|
{
|
|
if ( CopyFile( szFrom, szTo, fFailIfExists ) )
|
|
return JET_errSuccess;
|
|
else
|
|
return JET_errFileAccessDenied;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// ERR ErrSysGetComputerName( CHAR *sz, INT *pcb )
|
|
// =========================================================
|
|
//
|
|
//----------------------------------------------------------
|
|
ERR ErrSysGetComputerName( CHAR *sz, INT *pcb)
|
|
{
|
|
if ( GetComputerName( sz, pcb ) )
|
|
return JET_errSuccess;
|
|
else
|
|
return JET_errNoComputerName;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// SysSleep( ULONG ulTime )
|
|
// =========================================================
|
|
//
|
|
// ERR ErrSysSleep( ULONG ulTime )
|
|
//
|
|
// Waits ulTime milliseconds.
|
|
//
|
|
//----------------------------------------------------------
|
|
VOID SysSleep( ULONG ulTime )
|
|
{
|
|
Sleep( ulTime );
|
|
return;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// VOID SysSleepEx( ULONG ulTime )
|
|
// ========================================================
|
|
//
|
|
// Waits ulTime milliseconds.
|
|
//
|
|
//----------------------------------------------------------
|
|
VOID SysSleepEx( ULONG ulTime, BOOL fAlert )
|
|
{
|
|
SleepEx( ulTime, fAlert );
|
|
return;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// HANDLE SysGetCurrentTask( VOID )
|
|
// ========================================================
|
|
//
|
|
// Gets curren task handle for Windows.
|
|
//
|
|
//----------------------------------------------------------
|
|
HANDLE SysGetCurrentTask( VOID )
|
|
{
|
|
return LongToHandle(GetCurrentProcessId());
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// SysNormText( CHAR *rgchText, INT cchText, CHAR *rgchNorm, INT cchNorm, INT *pchNorm )
|
|
// =========================================================
|
|
//
|
|
// VOID SysNormText( CHAR *rgchText, INT cchText, CHAR *rgchNorm, INT cchNorm, INT *pchNorm )
|
|
//
|
|
// Normalizes text string.
|
|
//
|
|
//----------------------------------------------------------
|
|
VOID SysNormText( CHAR *rgchText, INT cchText, BYTE *rgbNorm, INT cbNorm, INT *pbNorm )
|
|
{
|
|
ERR err;
|
|
|
|
Assert( cbNorm <= JET_cbKeyMost );
|
|
err = ErrSysNormText( rgchText, cchText, cbNorm, rgbNorm, pbNorm );
|
|
Assert( err == JET_errSuccess || err == wrnFLDKeyTooBig );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
//+api------------------------------------------------------
|
|
//
|
|
// VOID SysCmpText( const CHAR *sz1, const CHAR sz2 )
|
|
// ========================================================
|
|
//
|
|
// Compares two unnormalized text strings by first normalizing them
|
|
// and then comparing them.
|
|
//
|
|
// Returns: > 0 if sz1 > sz2
|
|
// == 0 if sz1 == sz2
|
|
// < 0 if sz1 < sz2
|
|
//
|
|
//----------------------------------------------------------
|
|
INT SysCmpText( const CHAR *sz1, const CHAR *sz2 )
|
|
{
|
|
ERR err;
|
|
INT cch1;
|
|
INT cch2;
|
|
CHAR rgch1Norm[ JET_cbKeyMost ];
|
|
INT cch1Norm;
|
|
CHAR rgch2Norm[ JET_cbKeyMost ];
|
|
INT cch2Norm;
|
|
INT cchDiff;
|
|
INT iCmp;
|
|
|
|
/* get text string lengths
|
|
/**/
|
|
cch1 = strlen( sz1 );
|
|
Assert( cch1 <= JET_cbKeyMost );
|
|
cch2 = strlen( sz2 );
|
|
Assert( cch2 <= JET_cbKeyMost );
|
|
|
|
err = ErrSysNormText( sz1, cch1, JET_cbKeyMost, rgch1Norm, &cch1Norm );
|
|
Assert( err == JET_errSuccess || err == wrnFLDKeyTooBig );
|
|
|
|
err = ErrSysNormText( sz2, cch2, JET_cbKeyMost, rgch2Norm, &cch2Norm );
|
|
Assert( err == JET_errSuccess || err == wrnFLDKeyTooBig );
|
|
|
|
cchDiff = cch1Norm - cch2Norm;
|
|
iCmp = memcmp( rgch1Norm, rgch2Norm, cchDiff < 0 ? cch1Norm : cch2Norm );
|
|
return iCmp ? iCmp : cchDiff;
|
|
}
|
|
|
|
|
|
VOID SysStringCompare( char __far *pb1,
|
|
unsigned long cb1,
|
|
char __far *pb2,
|
|
unsigned long cb2,
|
|
unsigned long sort,
|
|
long __far *plResult )
|
|
{
|
|
CHAR rgb1[JET_cbColumnMost + 1];
|
|
CHAR rgb2[JET_cbColumnMost + 1];
|
|
|
|
/* ensure NULL terminated
|
|
/**/
|
|
memcpy( rgb1, pb1, min( JET_cbColumnMost, cb1 ) );
|
|
rgb1[ min( JET_cbColumnMost, cb1 ) ] = '\0';
|
|
memcpy( rgb2, pb2, min( JET_cbColumnMost, cb2 ) );
|
|
rgb2[ min( JET_cbColumnMost, cb2 ) ] = '\0';
|
|
|
|
*plResult = SysCmpText( (const char *)rgb1, (const char *)rgb2 );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ERR ErrSysNormText(
|
|
const BYTE *pbText,
|
|
INT cbText,
|
|
INT cbKeyBufLeft,
|
|
BYTE *pbNorm,
|
|
INT *pcbNorm )
|
|
{
|
|
#ifdef DBCS
|
|
INT iLoop;
|
|
#endif
|
|
|
|
BYTE *pbNormBegin = pbNorm;
|
|
BYTE rgbAccent[ (JET_cbKeyMost + 1) / 2 + 1 ];
|
|
BYTE *pbAccent = rgbAccent;
|
|
BYTE *pbBeyondKeyBufLeft = pbNorm + cbKeyBufLeft;
|
|
const BYTE *pbBeyondText;
|
|
const BYTE *pbTextLastChar = pbText + cbText - 1;
|
|
BYTE bAccentTmp = 0;
|
|
|
|
if (cbKeyBufLeft > 0)
|
|
*pbNorm = '\0';
|
|
|
|
while ( *pbTextLastChar-- == ' ' )
|
|
cbText--;
|
|
|
|
/* add one back to the pointer
|
|
/**/
|
|
pbTextLastChar++;
|
|
|
|
Assert( pbTextLastChar == pbText + cbText - 1 );
|
|
pbBeyondText = pbTextLastChar + 1;
|
|
|
|
while ( pbText < pbBeyondText && pbNorm < pbBeyondKeyBufLeft )
|
|
{
|
|
#ifdef DBCS
|
|
if ( pbText < pbTextLastChar )
|
|
{
|
|
/* two or more char remaining
|
|
/* check for double char to single char
|
|
/* for translation tables of some languages
|
|
/**/
|
|
for ( iLoop = 0; iLoop < cchDouble; iLoop++ )
|
|
{
|
|
BYTE bFirst = *pbText;
|
|
|
|
if ( bFirst == BFirstByteOfDouble(iLoop)
|
|
&& *(pbText + 1) == BSecondByteOfDouble(iLoop) )
|
|
{
|
|
/* don't do a "pbText++" above
|
|
/* do a double to single conversion
|
|
/**/
|
|
*pbNorm++ = BThirdByteOfDouble(iLoop);
|
|
|
|
/* pointing at char for accent map
|
|
/**/
|
|
pbText++;
|
|
|
|
/* no need to loop any more
|
|
/**/
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
BYTE bTmp;
|
|
|
|
/* do a single to single char conversion
|
|
/**/
|
|
*pbNorm = bTmp = BGetTranslation(*pbText);
|
|
|
|
if ( bTmp >= 250 )
|
|
{
|
|
/* do a single to double char conversion
|
|
/**/
|
|
*pbNorm++ = BFirstByteForSingle(bTmp);
|
|
if ( pbNorm < pbBeyondKeyBufLeft )
|
|
*pbNorm = BSecondByteForSingle(bTmp);
|
|
else
|
|
break;
|
|
|
|
/* no need to do accent any more,
|
|
/* so break out of while loop
|
|
/**/
|
|
}
|
|
|
|
pbNorm++;
|
|
}
|
|
|
|
/* at this point, pbText should point to the char for accent mapping
|
|
/**/
|
|
|
|
/* do accent now
|
|
/* the side effect is to increment pbText
|
|
/**/
|
|
if ( bAccentTmp == 0 )
|
|
{
|
|
/* first nibble of accent
|
|
/**/
|
|
bAccentTmp = (BYTE)( BGetAccent( *pbText++ ) << 4 );
|
|
Assert( bAccentTmp > 0 );
|
|
}
|
|
else
|
|
{
|
|
/* already has first nibble
|
|
/**/
|
|
*pbAccent++ = BGetAccent(*pbText++) | bAccentTmp;
|
|
bAccentTmp = 0;
|
|
/* reseting the accents
|
|
/**/
|
|
}
|
|
}
|
|
|
|
if ( pbNorm < pbBeyondKeyBufLeft )
|
|
{
|
|
/* need to do accent
|
|
/**/
|
|
*pbNorm++ = 0;
|
|
|
|
/* key-accent separator
|
|
/**/
|
|
if ( bAccentTmp != 0 && bAccentTmp != 0x10 )
|
|
{
|
|
/* an trailing accent which is not 0x10 should be kept
|
|
/**/
|
|
*pbAccent++ = bAccentTmp;
|
|
}
|
|
|
|
/* at this point, pbAccent is pointing at one char
|
|
/* beyond the accent bytes. clear up trailing 0x11's
|
|
/**/
|
|
while (--pbAccent >= rgbAccent && *pbAccent == 0x11)
|
|
;
|
|
*( pbAccent + 1 ) = 0;
|
|
|
|
/* append accent to text.
|
|
/* copy bytes up to and including '\0'.
|
|
/* case checked for rgbAccent being empty.
|
|
/**/
|
|
pbAccent = rgbAccent;
|
|
Assert( pbNorm <= pbBeyondKeyBufLeft );
|
|
while ( pbNorm < pbBeyondKeyBufLeft && (*pbNorm++ = *pbAccent++ ) )
|
|
;
|
|
}
|
|
|
|
/* compute the length of the normalized key and return
|
|
/**/
|
|
*pcbNorm = (INT)(pbNorm - pbNormBegin);
|
|
|
|
if ( pbNorm < pbBeyondKeyBufLeft )
|
|
return JET_errSuccess;
|
|
else
|
|
return wrnFLDKeyTooBig;
|
|
/* UNDONE: even if >=, maybe
|
|
/* just fit, but not "too big"
|
|
/* Do we want KeyBufFull or TooBig?
|
|
/**/
|
|
}
|
|
|
|
|
|
#if 0
|
|
VOID SysGetDriveGeometry( HANDLE handle )
|
|
{
|
|
BOOL f;
|
|
DISK_GEOMETRY disk_geometry;
|
|
DWORD cb;
|
|
|
|
f = DeviceIoControl( handle,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
&disk_geometry,
|
|
sizeof(disk_geometry),
|
|
&cb,
|
|
NULL );
|
|
Assert( f == fTrue );
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
//==========================================================
|
|
// Memory Routines
|
|
//==========================================================
|
|
|
|
#ifdef DEBUG
|
|
|
|
#ifdef MEM_CHECK
|
|
#define icalMax 10000
|
|
|
|
typedef struct {
|
|
VOID *pv;
|
|
ULONG cbAlloc;
|
|
} CAL;
|
|
|
|
STATIC CAL rgcal[icalMax];
|
|
STATIC ULONG cbAllocTotal = 0;
|
|
STATIC ULONG cblockAlloc = 0;
|
|
STATIC ULONG cblockFree = 0;
|
|
STATIC BOOL fInit = fFalse;
|
|
|
|
|
|
LOCAL VOID UtilIInsertAlloc( VOID *pv, ULONG cbAlloc )
|
|
{
|
|
INT ical;
|
|
|
|
/* do not track failed allocations
|
|
/**/
|
|
if ( pv == NULL )
|
|
return;
|
|
|
|
/* initialize array of allocations if not yet initialized.
|
|
/**/
|
|
if ( fInit == fFalse )
|
|
{
|
|
memset( rgcal, '\0', sizeof(rgcal) );
|
|
fInit = fTrue;
|
|
}
|
|
|
|
for ( ical = 0; ical < icalMax; ical++ )
|
|
{
|
|
if ( rgcal[ical].pv == NULL )
|
|
{
|
|
rgcal[ical].pv = pv;
|
|
rgcal[ical].cbAlloc = cbAlloc;
|
|
cbAllocTotal += cbAlloc;
|
|
cblockAlloc++;
|
|
return;
|
|
}
|
|
}
|
|
Assert( fFalse );
|
|
}
|
|
|
|
|
|
LOCAL VOID UtilIDeleteAlloc( VOID *pv )
|
|
{
|
|
INT ical;
|
|
|
|
Assert( pv != NULL );
|
|
Assert( fInit == fTrue );
|
|
|
|
for ( ical = 0; ical < icalMax; ical++ )
|
|
{
|
|
if ( rgcal[ical].pv == pv )
|
|
{
|
|
cblockFree++;
|
|
cbAllocTotal -= rgcal[ical].cbAlloc;
|
|
rgcal[ical].pv = NULL;
|
|
rgcal[ical].cbAlloc = 0;
|
|
return;
|
|
}
|
|
}
|
|
AssertSz( fFalse, "Attempt to Free a bad pointer" );
|
|
}
|
|
#else
|
|
#define UtilIInsertAlloc( pv, cb )
|
|
#define UtilIDeleteAlloc( pv )
|
|
#endif
|
|
|
|
VOID *SAlloc( ULONG cbBlock )
|
|
{
|
|
VOID *pv;
|
|
|
|
#ifdef RFS2
|
|
if ( !RFSAlloc( SAllocMemory ) )
|
|
return NULL;
|
|
#endif
|
|
|
|
pv = malloc(cbBlock);
|
|
UtilIInsertAlloc( pv, cbBlock );
|
|
return pv;
|
|
}
|
|
|
|
|
|
VOID OSSFree( void *pv )
|
|
{
|
|
UtilIDeleteAlloc( pv );
|
|
free(pv);
|
|
}
|
|
|
|
|
|
VOID *LAlloc( ULONG cBlock, USHORT cbBlock )
|
|
{
|
|
VOID *pv;
|
|
|
|
#ifdef RFS2
|
|
if ( !RFSAlloc( LAllocMemory ) )
|
|
return NULL;
|
|
#endif
|
|
|
|
pv = malloc(cBlock * cbBlock);
|
|
UtilIInsertAlloc( pv, cBlock * cbBlock );
|
|
return pv;
|
|
}
|
|
|
|
|
|
VOID OSLFree( void *pv )
|
|
{
|
|
UtilIDeleteAlloc( pv );
|
|
free(pv);
|
|
}
|
|
|
|
VOID *PvSysAlloc( ULONG dwSize )
|
|
{
|
|
VOID *pv;
|
|
|
|
#ifdef RFS2
|
|
if ( !RFSAlloc( PvSysAllocMemory ) )
|
|
return NULL;
|
|
#endif
|
|
|
|
pv = VirtualAlloc( NULL, dwSize, MEM_RESERVE, PAGE_READWRITE );
|
|
UtilIInsertAlloc( pv, dwSize );
|
|
return pv;
|
|
}
|
|
|
|
|
|
VOID *PvSysCommit( VOID *pv, ULONG ulSize )
|
|
{
|
|
VOID *pvCommit;
|
|
|
|
pvCommit = VirtualAlloc( pv, ulSize, MEM_COMMIT, PAGE_READWRITE );
|
|
|
|
return pvCommit;
|
|
}
|
|
|
|
|
|
VOID SysFree( VOID *pv )
|
|
{
|
|
UtilIDeleteAlloc( pv );
|
|
VirtualFree( pv, 0, MEM_RELEASE );
|
|
return;
|
|
}
|
|
|
|
#else
|
|
|
|
VOID *PvSysAlloc( ULONG dwSize )
|
|
{
|
|
return VirtualAlloc( NULL, dwSize, MEM_RESERVE, PAGE_READWRITE );
|
|
}
|
|
|
|
|
|
VOID *PvSysCommit( VOID *pv, ULONG ulSize )
|
|
{
|
|
return VirtualAlloc( pv, ulSize, MEM_COMMIT, PAGE_READWRITE );
|
|
}
|
|
|
|
|
|
VOID SysFree( VOID *pv )
|
|
{
|
|
VirtualFree( pv, 0, MEM_RELEASE );
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
VOID *PvSysAllocAndCommit( ULONG ulSize )
|
|
{
|
|
VOID *pv;
|
|
|
|
if ( ( pv = PvSysAlloc( ulSize ) ) == NULL )
|
|
return pv;
|
|
if ( PvSysCommit( pv, ulSize ) == NULL )
|
|
{
|
|
SysFree( pv );
|
|
return NULL;
|
|
}
|
|
return pv;
|
|
}
|
|
|
|
|
|
VOID SysTerm( VOID )
|
|
{
|
|
#ifdef MEM_CHECK
|
|
ULONG cbTrueAllocTotal = cbAllocTotal; /* Alloc total not counting critJet */
|
|
INT ical;
|
|
|
|
Assert( critJet != NULL );
|
|
|
|
/* find critJet in store and delete size from true alloc total */
|
|
|
|
for ( ical = 0; ical < icalMax; ical++ )
|
|
{
|
|
if ( rgcal[ical].pv == critJet )
|
|
{
|
|
cbTrueAllocTotal -= rgcal[ical].cbAlloc;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cbTrueAllocTotal != 0)
|
|
{
|
|
char szAllocTotal[256];
|
|
sprintf( szAllocTotal, "%ld bytes unfreed memory on termination.", cbTrueAllocTotal );
|
|
AssertFail((const char *)szAllocTotal, szAssertFilename, __LINE__ );
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
VOID SysDebugBreak( VOID )
|
|
{
|
|
DebugBreak();
|
|
}
|