//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: cBFile.cpp // // Contents: Microsoft Internet Security // // History: 24-Oct-1997 pberkman created // //-------------------------------------------------------------------------- #include "global.hxx" #include "stack.hxx" #include "cbfile.hxx" cBFile_::cBFile_(CRITICAL_SECTION *pCriticalSection, WCHAR *pwszBFilePath, WCHAR *pwszBFileBaseName, DWORD cbKey, DWORD cbData, SHORT sVersion, BOOL *pfCreatedOK) { SECURITY_ATTRIBUTES sa; SECURITY_ATTRIBUTES* psa = NULL; SECURITY_DESCRIPTOR sd; SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; PSID psidEveryone = NULL; DWORD dwAclSize; PACL pDacl = NULL; DWORD dwErr = 0; pCritical = pCriticalSection; fDirty = FALSE; fReadOnly = FALSE; hKFile = INVALID_HANDLE_VALUE; hDFile = INVALID_HANDLE_VALUE; pbKMap = NULL; pbDMap = NULL; cbDMap = 0; hDMutex = NULL; fUseRecNumAsKey = FALSE; *pfCreatedOK = TRUE; // will be set to FALSE in case of ANY failure pwszPath = NULL; pwszBaseName = NULL; __try { pwszPath = (LPWSTR) new WCHAR[wcslen(pwszBFilePath) + 1]; if (pwszPath == NULL) { goto MemoryError; } wcscpy(pwszPath, pwszBFilePath); pwszBaseName = (LPWSTR) new WCHAR[wcslen(pwszBFileBaseName) + 1]; if (pwszBaseName == NULL) { goto MemoryError; } wcscpy(pwszBaseName, pwszBFileBaseName); memset(&sHeader, 0x00, sizeof(BFILE_HEADER)); memset(&sRecord, 0x00, sizeof(BFILE_RECORD)); sHeader.sIntVersion = BFILE_VERSION_1; sHeader.sVersion = (DWORD)sVersion; sHeader.cbKey = cbKey; sHeader.cbData = cbData; if ( FIsWinNT() == TRUE ) { if (!AllocateAndInitializeSid( &siaWorldSidAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &psidEveryone)) { goto ErrorReturn; } // // compute size of ACL // dwAclSize = sizeof(ACL) + ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) + GetLengthSid(psidEveryone); // // allocate storage for Acl // if (NULL == (pDacl = (PACL) new BYTE[dwAclSize])) { goto MemoryError; } if (!InitializeAcl(pDacl, dwAclSize, ACL_REVISION)) { goto ErrorReturn; } if (!AddAccessAllowedAce( pDacl, ACL_REVISION, SYNCHRONIZE,// | MUTEX_MODIFY_STATE, psidEveryone)) { goto ErrorReturn; } if ( InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ) == FALSE ) { goto ErrorReturn; } if ( SetSecurityDescriptorDacl( &sd, TRUE, pDacl, FALSE ) == FALSE ) { goto ErrorReturn; } sa.nLength = sizeof( SECURITY_ATTRIBUTES ); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; psa = &sa; } hDMutex = CreateMutexU( psa, FALSE, pwszBFileBaseName ); if ( hDMutex == NULL ) { hDMutex = OpenMutexU( SYNCHRONIZE, FALSE, pwszBFileBaseName ); if ( hDMutex == NULL ) { dwErr = GetLastError(); goto ErrorReturn; } } fInitialized = TRUE; // set it now becuase OpenFiles uses "Lock". if (!(this->OpenFiles())) { goto FileError; } } // __try __except(EXCEPTION_EXECUTE_HANDLER) { if (pbKMap != NULL) { UnmapViewOfFile(pbKMap); pbKMap = NULL; } if (pbDMap != NULL) { UnmapViewOfFile(pbDMap); pbDMap = NULL; } if (hDFile != INVALID_HANDLE_VALUE) { CloseHandle(hDFile); hDFile = INVALID_HANDLE_VALUE; } if (hKFile != INVALID_HANDLE_VALUE) { CloseHandle(hKFile); hKFile = INVALID_HANDLE_VALUE; } if (hDMutex != NULL) { CloseHandle(hDMutex); hDMutex = NULL; } if (pwszPath != NULL) { delete[](pwszPath); pwszPath = NULL; } if (pwszBaseName != NULL) { delete[](pwszBaseName); pwszBaseName = NULL; } goto ErrorReturn; } sRecord.cbKey = sHeader.cbKey; sRecord.cbData = sHeader.cbData; if (!(sRecord.pvKey = (void *)new BYTE[cbKey + sizeof(DWORD)]) || !(sRecord.pvData = (void *)new BYTE[cbData + sizeof(DWORD)])) { goto MemoryError; } sRecord.pvData = (BYTE *)sRecord.pvData + sizeof(DWORD); // we use the first dword for rec # (see addrec) memset(sRecord.pvKey, 0x00, cbKey); memset(sRecord.pvData, 0x00, cbData); CommonReturn: if (pDacl != NULL) { delete[] pDacl; } if (psidEveryone) { FreeSid(psidEveryone); } return; ErrorReturn: fInitialized = FALSE; *pfCreatedOK = FALSE; goto CommonReturn; SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY); SET_ERROR_VAR_EX(DBG_SS, FileError, ERROR_FILE_NOT_FOUND); } cBFile_::~cBFile_(void) { if (fDirty) { this->Sort(); } if (pbKMap != NULL) { UnmapViewOfFile(pbKMap); } if (pbDMap != NULL) { UnmapViewOfFile(pbDMap); } if (hDFile != INVALID_HANDLE_VALUE) { CloseHandle(hDFile); } if (hKFile != INVALID_HANDLE_VALUE) { CloseHandle(hKFile); } if (hDMutex != NULL) { CloseHandle(hDMutex); } if (pwszPath != NULL) { delete[](pwszPath); } if (pwszBaseName != NULL) { delete[](pwszBaseName); } DELETE_OBJECT(sRecord.pvKey); if (sRecord.pvData) { sRecord.pvData = (BYTE *)sRecord.pvData - sizeof(DWORD); // we bumped the pointer in the constructer, put it back.. delete sRecord.pvData; } } BOOL cBFile_::Initialize(void) { return(fInitialized); } DWORD cBFile_::GetNumKeys(void) { DWORD dwRet; dwRet = GetFileSize(this->hKFile, NULL); if (dwRet > 0) { dwRet /= BFILE_KEYSIZE; return(dwRet); } return(0); } void cBFile_::setKey(void *pvInKey) { memcpy(sRecord.pvKey, pvInKey, sRecord.cbKey); } void cBFile_::setData(void *pvInData) { memcpy(sRecord.pvData, pvInData, sRecord.cbData); } BOOL cBFile_::Find(void) { DWORD cbDOff; DWORD dwLastGood; void *pvKey; BOOL fRet; pvKey = new BYTE[sRecord.cbKey]; if (!(pvKey)) { goto MemoryError; } memcpy(pvKey, sRecord.pvKey, sRecord.cbKey); if (this->BinaryFind(&cbDOff)) { dwLastGood = this->dwFirstNextRecNum; while (this->GetPrev(dwLastGood)) { if (memcmp(pvKey, sRecord.pvKey, sRecord.cbKey) != 0) { break; } dwLastGood = this->dwFirstNextRecNum; } if (dwLastGood > 0) { dwLastGood--; delete pvKey; return(this->GetNext(dwLastGood)); } delete pvKey; __try { return(this->GetDataRecord(cbDOff)); } __except(EXCEPTION_EXECUTE_HANDLER) { this->UnmapAll(); SetLastError(GetExceptionCode()); } return(FALSE); } fRet = FALSE; CommonReturn: if (pvKey) { delete pvKey; } return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY); } BOOL cBFile_::GetFirst(void) { BOOL fRet; this->dwFirstNextRecNum = 0; if (!(this->pbKMap)) { return(FALSE); } __try { if (!this->ReadHeader()) { goto ErrorReturn; } DWORD cbOff; memcpy(sRecord.pvKey, &this->pbKMap[0], sRecord.cbKey); memcpy(&cbOff, &this->pbKMap[sRecord.cbKey], sizeof(DWORD)); if (!(this->GetDataRecord(cbOff))) { goto cBFileCorrupt; } fRet = TRUE; } __except(EXCEPTION_EXECUTE_HANDLER) { this->UnmapAll(); SetLastError(GetExceptionCode()); goto cBFileCorrupt; } CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; goto CommonReturn; TRACE_ERROR_EX(DBG_SS, cBFileCorrupt); } BOOL cBFile_::GetNext(DWORD dwCurRec) { BOOL fRet; if (!(this->pbKMap)) { return(FALSE); } if (dwCurRec == 0xffffffff) { dwCurRec = this->dwFirstNextRecNum; } DWORD cbOff; dwCurRec++; if (((dwCurRec + 1) * BFILE_KEYSIZE) > sHeader.cbSortedEOF) { goto cBFileNoNext; } __try { memcpy(sRecord.pvKey, &this->pbKMap[dwCurRec * BFILE_KEYSIZE], sRecord.cbKey); memcpy(&cbOff, &this->pbKMap[(dwCurRec * BFILE_KEYSIZE) + sRecord.cbKey], sizeof(DWORD)); if (!(this->GetDataRecord(cbOff))) { goto cBFileCorrupt; } this->dwFirstNextRecNum = dwCurRec; fRet = TRUE; } __except(EXCEPTION_EXECUTE_HANDLER) { this->UnmapAll(); SetLastError(GetExceptionCode()); goto cBFileCorrupt; } CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; this->dwFirstNextRecNum = 0; goto CommonReturn; TRACE_ERROR_EX(DBG_SS, cBFileNoNext); TRACE_ERROR_EX(DBG_SS, cBFileCorrupt); } BOOL cBFile_::GetPrev(DWORD dwCurRec) { BOOL fRet; if (!(this->pbKMap) || (sHeader.cbSortedEOF == 0)) { goto cBFileNoPrev; } if (dwCurRec == 0xffffffff) { dwCurRec = this->dwFirstNextRecNum; } DWORD cb; DWORD cbOff; if (dwCurRec < 1) { goto cBFileNoPrev; } dwCurRec--; if (((dwCurRec + 1) * BFILE_KEYSIZE) >= sHeader.cbSortedEOF) { goto cBFileNoPrev; } __try { memcpy(sRecord.pvKey, &this->pbKMap[dwCurRec * BFILE_KEYSIZE], sRecord.cbKey); memcpy(&cbOff, &this->pbKMap[(dwCurRec * BFILE_KEYSIZE) + sRecord.cbKey], sizeof(DWORD)); if (!(this->GetDataRecord(cbOff))) { goto cBFileCorrupt; } this->dwFirstNextRecNum = dwCurRec; fRet = TRUE; } __except(EXCEPTION_EXECUTE_HANDLER) { this->UnmapAll(); SetLastError(GetExceptionCode()); goto cBFileCorrupt; } CommonReturn: return(fRet); ErrorReturn: fRet = FALSE; this->dwFirstNextRecNum = 0; goto CommonReturn; TRACE_ERROR_EX(DBG_SS, cBFileNoPrev); TRACE_ERROR_EX(DBG_SS, cBFileCorrupt); } BOOL cBFile_::Update(void) { DWORD cbDOff; if ( fReadOnly == TRUE ) { SetLastError( ERROR_ACCESS_DENIED ); return( FALSE ); } if (this->BinaryFind(&cbDOff)) { this->UpdateDataRecord(cbDOff); return(TRUE); } return(FALSE); } BOOL cBFile_::Add(void) { if ( fReadOnly == TRUE ) { SetLastError( ERROR_ACCESS_DENIED ); return( FALSE ); } if (!this->AddDirtyKey()) { return(FALSE); } return(TRUE); } BOOL cBFile_::Lock(void) { WaitForSingleObject( this->hDMutex, INFINITE ); return(TRUE); } BOOL cBFile_::Unlock(void) { ReleaseMutex( this->hDMutex ); return( TRUE ); } void cBFile_::SpeedSort(void) { Stack_ *pcStack; if ( fReadOnly == TRUE ) { assert( FALSE && "A sort should not be forced in read-only mode." ); return; } pcStack = NULL; if (!(this->pbKMap)) { goto RemapError; } if (!(this->Lock())) { goto LockFileError; } // // load dirty in memory and sort it // DWORD cbCurKey; DWORD cbTotal; if (!(pcStack = new Stack_(pCritical))) { goto MemoryError; } cbTotal = GetFileSize(this->hKFile, NULL); cbCurKey = sHeader.cbSortedEOF; __try { while (cbCurKey < cbTotal) { pcStack->Add(BFILE_KEYSIZE, &this->pbKMap[cbCurKey]); cbCurKey += BFILE_KEYSIZE; } pcStack->Sort(0, sRecord.cbKey, STACK_SORTTYPE_BINARY); // // shuffle into sorted // DWORD dwIdx; DWORD dwInsertion; DWORD cbFreeSpace; BYTE *pbKey; BYTE *pbCurrentKey; BYTE *pbStartFreeSpace; pbStartFreeSpace = &this->pbKMap[sHeader.cbSortedEOF]; cbFreeSpace = pcStack->Count() * BFILE_KEYSIZE; dwIdx = (long)pcStack->Count() - 1; while (pbKey = (BYTE *)pcStack->Get(dwIdx)) { // // get the starting point of our "window" // dwInsertion = this->GetInsertionPoint(pbKey); // // move the old data to the current free space "window" // memmove(&this->pbKMap[dwInsertion + cbFreeSpace], &this->pbKMap[dwInsertion], sHeader.cbSortedEOF - dwInsertion); // // after this, the insersion point has free space the size of the "window" - key size // cbFreeSpace -= BFILE_KEYSIZE; // // add the new key to the end of the "free space" window. // memcpy(&this->pbKMap[dwInsertion + cbFreeSpace], pbKey, BFILE_KEYSIZE); // // keep the end of the search up to date for these insertions.... // sHeader.cbSortedEOF = dwInsertion; if (dwIdx == 0) { break; } dwIdx--; } sHeader.cbSortedEOF = cbTotal; sHeader.fDirty = FALSE; fDirty = FALSE; this->UpdateHeader(); } __except( EXCEPTION_EXECUTE_HANDLER ) { this->UnmapAll(); SetLastError( GetExceptionCode() ); goto RemapError; } ErrorReturn: this->Unlock(); DELETE_OBJECT(pcStack); return; TRACE_ERROR_EX(DBG_SS, LockFileError); TRACE_ERROR_EX(DBG_SS, RemapError); SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY); } DWORD cBFile_::GetInsertionPoint(void *pvIn) { DWORD dwEnd; DWORD dwMiddle; DWORD dwStart; DWORD dwHalf; DWORD dwCur; DWORD dwRet; BYTE *pb; int cmp; dwStart = 0; dwEnd = sHeader.cbSortedEOF / BFILE_KEYSIZE; dwMiddle = dwEnd / 2L; dwHalf = dwMiddle; dwCur = 0; if (sHeader.cbSortedEOF >= BFILE_KEYSIZE) { dwRet = sHeader.cbSortedEOF - BFILE_KEYSIZE; } else { dwRet = 0; } for EVER { pb = this->pbKMap + (dwMiddle * BFILE_KEYSIZE); cmp = memcmp(pvIn, pb, sRecord.cbKey); if (cmp == 0) { dwRet = (DWORD)(pb - this->pbKMap); break; } if ( (dwMiddle == 0) || (dwMiddle == (sHeader.cbSortedEOF / BFILE_KEYSIZE)) || ((dwHalf == 0) && (dwMiddle == dwStart)) ) { DWORD dwFind; dwFind = dwRet; cmp = (-1); while ((cmp < 0) && ((dwFind + BFILE_KEYSIZE) <= sHeader.cbSortedEOF)) { cmp = memcmp(pvIn, &this->pbKMap[dwFind], sRecord.cbKey); dwRet = dwFind; dwFind += BFILE_KEYSIZE; } break; } if (cmp < 0) { dwEnd = dwMiddle; dwRet = (dwMiddle * BFILE_KEYSIZE); } else { dwStart = dwMiddle; } dwHalf = (dwEnd - dwStart) / 2L; dwMiddle = dwStart + dwHalf; } return(dwRet); } void *cBFile_::GetDumpKey(DWORD dwIdx, void *pvRetKey, DWORD *pdwRecOffset) { DWORD dwOffset; dwOffset = dwIdx * BFILE_KEYSIZE; if (dwOffset >= GetFileSize(this->hKFile, NULL)) { return(NULL); } __try { memcpy(pvRetKey, &this->pbKMap[dwOffset], sRecord.cbKey); memcpy(pdwRecOffset, &this->pbKMap[dwOffset + sRecord.cbKey], sizeof(DWORD)); return(pvRetKey); } __except(EXCEPTION_EXECUTE_HANDLER) { this->UnmapAll(); SetLastError(GetExceptionCode()); } return(NULL); } BOOL cBFile_::GetHeader(BFILE_HEADER *psHeader) { __try { if (!this->ReadHeader()) { return(FALSE); } memcpy(psHeader, &sHeader, sizeof(BFILE_HEADER)); return(TRUE); } __except(EXCEPTION_EXECUTE_HANDLER) { this->UnmapAll(); SetLastError(GetExceptionCode()); } return(FALSE); } void cBFile_::Sort(void) { if ( fReadOnly == TRUE ) { assert( FALSE && "A sort should not be forced in read-only mode." ); return; } EnterCriticalSection(pCritical); if (!FIsWinNT()) { // // The only reason this is here is to work around some underlying // bug in the OS. If we just call RemapKey() and RemapData() then // we end up with some bogus state on the key and data files which will // ultimately result in a sharing violation when trying to open the files // at a later time. // if (this->pbKMap != NULL) { UnmapViewOfFile(this->pbKMap); this->pbKMap = NULL; } if (this->pbDMap != NULL) { UnmapViewOfFile(this->pbDMap); this->pbDMap = NULL; } if (hDFile != INVALID_HANDLE_VALUE) { CloseHandle(hDFile); hDFile = INVALID_HANDLE_VALUE; } if (hKFile != INVALID_HANDLE_VALUE) { CloseHandle(hKFile); hKFile = INVALID_HANDLE_VALUE; } this->OpenFiles(); } else { this->RemapKey(); this->RemapData(); } #if 0 if (sHeader.cbSortedEOF > 0) { this->SpeedSort(); LeaveCriticalSection(pCritical); return; } #endif BYTE *pb; Stack_ *pcStack; pcStack = NULL; pb = NULL; if (!(this->Lock())) { goto LockFileError; } DWORD dwLen; DWORD cbFile; DWORD dwIdx; DWORD i; BYTE *pbStack; if (!(pcStack = new Stack_(pCritical))) { goto MemoryError; } dwLen = BFILE_KEYSIZE; if (!(pb = new BYTE[dwLen])) { goto MemoryError; } cbFile = GetFileSize(this->hKFile, NULL); __try { for (i = 0; i < cbFile; i += dwLen) { pcStack->Add(dwLen, &this->pbKMap[i]); } pcStack->Sort(0, sRecord.cbKey, STACK_SORTTYPE_BINARY); dwIdx = 0; i = 0; while (pbStack = (BYTE *)pcStack->Get(dwIdx)) { if ((i + dwLen) > cbFile) { goto FileSizeError; } memcpy(&this->pbKMap[i], pbStack, dwLen); dwIdx++; i += dwLen; } sHeader.cbSortedEOF = cbFile; sHeader.fDirty = FALSE; fDirty = FALSE; this->UpdateHeader(); } __except( EXCEPTION_EXECUTE_HANDLER ) { this->UnmapAll(); SetLastError( GetExceptionCode() ); } ErrorReturn: this->Unlock(); DELETE_OBJECT(pcStack); DELETE_OBJECT(pb); LeaveCriticalSection(pCritical); return; TRACE_ERROR_EX(DBG_SS, FileSizeError); TRACE_ERROR_EX(DBG_SS, LockFileError); SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY); } BOOL cBFile_::AddDirtyKey(void) { DWORD cbOff; DWORD cb; if ( fReadOnly == TRUE ) { assert( FALSE && "Add dirty key should not occur in read-only mode." ); return(FALSE); } this->Lock(); __try { if (!this->ReadHeader()) { return(FALSE); } sHeader.dwLastRecNum++; sRecord.dwRecNum = sHeader.dwLastRecNum; if ((cbOff = this->AddDataRecord()) != 0xffffffff) { if (fUseRecNumAsKey) { memcpy(sRecord.pvKey, &sRecord.dwRecNum, sizeof(DWORD)); } memcpy((BYTE *)sRecord.pvKey + sRecord.cbKey, &cbOff, sizeof(DWORD)); // speed... SetFilePointer(this->hKFile, 0, NULL, FILE_END); if (FIsWinNT()) { WriteFile(this->hKFile, sRecord.pvKey, sRecord.cbKey + sizeof(DWORD), &cb, NULL); // WriteFile(this->hKFile, &cbOff, sizeof(DWORD), &cb, NULL); } else { if (this->pbKMap != NULL) { UnmapViewOfFile(this->pbKMap); this->pbKMap = NULL; WriteFile(this->hKFile, sRecord.pvKey, sRecord.cbKey + sizeof(DWORD), &cb, NULL); this->RemapKey(); } else { WriteFile(this->hKFile, sRecord.pvKey, sRecord.cbKey + sizeof(DWORD), &cb, NULL); } } sHeader.fDirty = TRUE; this->fDirty = TRUE; this->UpdateHeader(); } } __except( EXCEPTION_EXECUTE_HANDLER ) { this->UnmapAll(); SetLastError( GetExceptionCode() ); } this->Unlock(); return(TRUE); } BOOL cBFile_::GetDataRecord(DWORD cbDataOffset) { DWORD cb; memset(sRecord.pvData, 0x00, sRecord.cbData); if (this->cbDMap < (cbDataOffset + sizeof(DWORD) + sRecord.cbData)) { return(FALSE); } memcpy(&sRecord.dwRecNum, &this->pbDMap[cbDataOffset], sizeof(DWORD)); memcpy(sRecord.pvData, &this->pbDMap[cbDataOffset + sizeof(DWORD)], sRecord.cbData); return(TRUE); } void cBFile_::UpdateDataRecord(DWORD cbDataOffset) { DWORD cb; if ( fReadOnly == TRUE ) { assert( FALSE && "Update data record should not occur in read-only mode." ); return; } this->Lock(); if (this->cbDMap < (cbDataOffset + sizeof(DWORD) + sRecord.cbData)) { this->Unlock(); return; } __try { memcpy(&this->pbDMap[cbDataOffset + sizeof(DWORD)], sRecord.pvData, sRecord.cbData); } __except( EXCEPTION_EXECUTE_HANDLER ) { this->UnmapAll(); SetLastError( GetExceptionCode() ); } this->Unlock(); } DWORD cBFile_::AddDataRecord(void) { DWORD cbRet; if ( fReadOnly == TRUE ) { SetLastError( ERROR_ACCESS_DENIED ); return( 0xFFFFFFFF ); } // // no lock here because it is called from add key which // does a lock // if ((cbRet = SetFilePointer(this->hDFile, 0, NULL, FILE_END)) != 0xffffffff) { DWORD cb; BYTE *pv; pv = (BYTE *)sRecord.pvData - sizeof(DWORD); memcpy(pv, &sRecord.dwRecNum, sizeof(DWORD)); if (FIsWinNT()) { WriteFile(this->hDFile, pv, sizeof(DWORD) + sRecord.cbData, &cb, NULL); // WriteFile(this->hDFile, sRecord.pvData, sRecord.cbData, &cb, NULL); } else { if (this->pbDMap != NULL) { UnmapViewOfFile(this->pbDMap); this->pbDMap = NULL; WriteFile(this->hDFile, pv, sizeof(DWORD) + sRecord.cbData, &cb, NULL); this->RemapData(); } else { WriteFile(this->hDFile, pv, sizeof(DWORD) + sRecord.cbData, &cb, NULL); } } } return(cbRet); } BOOL cBFile_::BinaryFind(DWORD *pcbDataOffset) { if (sHeader.fDirty) { this->Sort(); } if (sHeader.cbSortedEOF == 0) { return(FALSE); } if (!(this->pbKMap)) { return(FALSE); } DWORD dwEnd; DWORD dwMiddle; DWORD dwStart; DWORD dwHalf; DWORD dwCur; void *pv; int cmp; dwStart = 0; dwEnd = sHeader.cbSortedEOF / BFILE_KEYSIZE; dwHalf = dwMiddle = dwEnd / 2L; dwCur = 0; __try { for EVER { pv = (void *)(this->pbKMap + (dwMiddle * BFILE_KEYSIZE)); cmp = memcmp(sRecord.pvKey, pv, sRecord.cbKey); if (cmp == 0) { memcpy(pcbDataOffset, (char *)pv + sRecord.cbKey, sizeof(DWORD)); this->dwFirstNextRecNum = (DWORD)((BYTE *)pv - this->pbKMap) / BFILE_KEYSIZE; return(TRUE); } if ((dwMiddle == 0) || (dwMiddle == (sHeader.cbSortedEOF / BFILE_KEYSIZE)) || ((dwHalf == 0) && (dwMiddle == dwStart))) { break; } if (cmp < 0) { dwEnd = dwMiddle; } else { dwStart = dwMiddle; } dwHalf = (dwEnd - dwStart) / 2L; dwMiddle = dwStart + dwHalf; } } __except( EXCEPTION_EXECUTE_HANDLER ) { this->UnmapAll(); SetLastError( GetExceptionCode() ); } return(FALSE); } BOOL cBFile_::ReadHeader(void) { if ((this->pbDMap) && (this->cbDMap >= (sizeof(BFILE_HEADER) + BFILE_SIZEOFSIG))) { memcpy(&this->sHeader, &this->pbDMap[BFILE_SIZEOFSIG], sizeof(BFILE_HEADER)); } else if (SetFilePointer(this->hDFile, BFILE_SIZEOFSIG, NULL, FILE_BEGIN) != 0xffffffff) { DWORD cb; if (!ReadFile(this->hDFile, &this->sHeader, sizeof(BFILE_HEADER), &cb, NULL)) { return(FALSE); } } else { memset(&this->sHeader, 0x00, sizeof(BFILE_HEADER)); } return(TRUE); } BOOL cBFile_::UpdateHeader(void) { if ( fReadOnly == TRUE ) { SetLastError( ERROR_ACCESS_DENIED ); return( FALSE ); } if ((this->pbDMap) && (this->cbDMap >= (sizeof(BFILE_HEADER) + BFILE_SIZEOFSIG))) { memcpy(&this->pbDMap[BFILE_SIZEOFSIG], &this->sHeader, sizeof(BFILE_HEADER)); return(TRUE); } if (SetFilePointer(this->hDFile, BFILE_SIZEOFSIG, NULL, FILE_BEGIN) != 0xffffffff) { DWORD cbWritten; WriteFile(this->hDFile, &this->sHeader, sizeof(BFILE_HEADER), &cbWritten, NULL); return(TRUE); } return(FALSE); } BOOL cBFile_::OpenFiles(void) { BOOL fRet = TRUE; WCHAR wszFile[MAX_PATH]; DWORD cbWritten; int iBaseEnd; wcscpy(&wszFile[0], pwszPath); if (wszFile[wcslen(pwszPath) - 1] != L'\\') { wcscat(&wszFile[0], L"\\"); } wcscat(&wszFile[0], pwszBaseName); iBaseEnd = wcslen(&wszFile[0]); wcscpy(&wszFile[iBaseEnd], BFILE_DATAEXT); hDFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (hDFile == INVALID_HANDLE_VALUE) { if ( GetLastError() == ERROR_ACCESS_DENIED ) { hDFile = CreateFileU(&wszFile[0], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); fReadOnly = TRUE; } else { hDFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, 0, NULL); } if (hDFile == INVALID_HANDLE_VALUE) { return(FALSE); } if ( fReadOnly == FALSE ) { WriteFile(this->hDFile, BFILE_SIG, BFILE_SIZEOFSIG, &cbWritten, NULL); this->Lock(); __try { fRet = this->UpdateHeader(); } __except( EXCEPTION_EXECUTE_HANDLER ) { fRet = FALSE; } this->Unlock(); if ( fRet == FALSE ) { return( FALSE ); } wcscpy(&wszFile[iBaseEnd], BFILE_KEYEXT); hKFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); } else { wcscpy(&wszFile[iBaseEnd], BFILE_KEYEXT); hKFile = CreateFileU(&wszFile[0], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); } } else { wcscpy(&wszFile[iBaseEnd], BFILE_KEYEXT); hKFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); } if ((hDFile == INVALID_HANDLE_VALUE) || (hKFile == INVALID_HANDLE_VALUE)) { return(FALSE); } fRet &= this->RemapKey(); fRet &= this->RemapData(); if ( fRet == FALSE ) { return( FALSE ); } __try { if (!this->ReadHeader()) { return FALSE; } } __except( EXCEPTION_EXECUTE_HANDLER ) { fRet = FALSE; } return(fRet); } BOOL cBFile_::RemapKey(void) { LPBYTE pbOldMap; HANDLE hMappedFile; DWORD PageAccess = PAGE_READWRITE; DWORD FileMapAccess = FILE_MAP_WRITE; pbOldMap = this->pbKMap; if ( fReadOnly == TRUE ) { PageAccess = PAGE_READONLY; FileMapAccess = FILE_MAP_READ; } hMappedFile = CreateFileMapping(this->hKFile, NULL, PageAccess, 0, 0, NULL); if (!(hMappedFile) || (hMappedFile == INVALID_HANDLE_VALUE)) { return(TRUE); // could be the first call! } this->pbKMap = (BYTE *)MapViewOfFile(hMappedFile, FileMapAccess, 0, 0, 0); if ( this->pbKMap != NULL ) { if ( pbOldMap != NULL ) { UnmapViewOfFile( pbOldMap ); } this->cbKMap = GetFileSize(this->hKFile, NULL); } else { this->pbKMap = pbOldMap; } CloseHandle(hMappedFile); if ( ( pbOldMap == NULL ) && ( this->pbKMap == NULL ) ) { return(FALSE); } return(TRUE); } BOOL cBFile_::RemapData(void) { LPBYTE pbOldMap; HANDLE hMappedFile; DWORD PageAccess = PAGE_READWRITE; DWORD FileMapAccess = FILE_MAP_WRITE; pbOldMap = this->pbDMap; if ( fReadOnly == TRUE ) { PageAccess = PAGE_READONLY; FileMapAccess = FILE_MAP_READ; } hMappedFile = CreateFileMapping(this->hDFile, NULL, PageAccess, 0, 0, NULL); if (!(hMappedFile) || (hMappedFile == INVALID_HANDLE_VALUE)) { return(TRUE); // could be the first call! } this->pbDMap = (BYTE *)MapViewOfFile(hMappedFile, FileMapAccess, 0, 0, 0); if ( this->pbDMap != NULL ) { if ( pbOldMap != NULL ) { UnmapViewOfFile( pbOldMap ); } this->cbDMap = GetFileSize(this->hDFile, NULL); } else { this->pbDMap = pbOldMap; } CloseHandle(hMappedFile); if ( ( pbOldMap == NULL ) && ( this->pbDMap == NULL ) ) { return(FALSE); } return(TRUE); } void cBFile_::UnmapAll(void) { if (this->pbKMap != NULL) { UnmapViewOfFile(this->pbKMap); this->pbKMap = NULL; } if (this->pbDMap != NULL) { UnmapViewOfFile(this->pbDMap); this->pbDMap = NULL; } }