#include "config.h" #define HANDLE WINHANDLE #include #undef HANDLE #include #include #include #include #include #include #include #include /* 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(); }