Leaked source code of windows server 2003
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

#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();
}