Source code of Windows XP (NT5)
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.

1499 lines
31 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: cBFile.cpp
  8. //
  9. // Contents: Microsoft Internet Security
  10. //
  11. // History: 24-Oct-1997 pberkman created
  12. //
  13. //--------------------------------------------------------------------------
  14. #include "global.hxx"
  15. #include "stack.hxx"
  16. #include "cbfile.hxx"
  17. cBFile_::cBFile_(CRITICAL_SECTION *pCriticalSection, WCHAR *pwszBFilePath, WCHAR *pwszBFileBaseName,
  18. DWORD cbKey, DWORD cbData, SHORT sVersion, BOOL *pfCreatedOK)
  19. {
  20. SECURITY_ATTRIBUTES sa;
  21. SECURITY_ATTRIBUTES* psa = NULL;
  22. SECURITY_DESCRIPTOR sd;
  23. SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  24. PSID psidEveryone = NULL;
  25. DWORD dwAclSize;
  26. PACL pDacl = NULL;
  27. DWORD dwErr = 0;
  28. pCritical = pCriticalSection;
  29. fDirty = FALSE;
  30. fReadOnly = FALSE;
  31. hKFile = INVALID_HANDLE_VALUE;
  32. hDFile = INVALID_HANDLE_VALUE;
  33. pbKMap = NULL;
  34. pbDMap = NULL;
  35. cbDMap = 0;
  36. hDMutex = NULL;
  37. fUseRecNumAsKey = FALSE;
  38. *pfCreatedOK = TRUE; // will be set to FALSE in case of ANY failure
  39. pwszPath = NULL;
  40. pwszBaseName = NULL;
  41. __try {
  42. pwszPath = (LPWSTR) new WCHAR[wcslen(pwszBFilePath) + 1];
  43. if (pwszPath == NULL)
  44. {
  45. goto MemoryError;
  46. }
  47. wcscpy(pwszPath, pwszBFilePath);
  48. pwszBaseName = (LPWSTR) new WCHAR[wcslen(pwszBFileBaseName) + 1];
  49. if (pwszBaseName == NULL)
  50. {
  51. goto MemoryError;
  52. }
  53. wcscpy(pwszBaseName, pwszBFileBaseName);
  54. memset(&sHeader, 0x00, sizeof(BFILE_HEADER));
  55. memset(&sRecord, 0x00, sizeof(BFILE_RECORD));
  56. sHeader.sIntVersion = BFILE_VERSION_1;
  57. sHeader.sVersion = (DWORD)sVersion;
  58. sHeader.cbKey = cbKey;
  59. sHeader.cbData = cbData;
  60. if ( FIsWinNT() == TRUE )
  61. {
  62. if (!AllocateAndInitializeSid(
  63. &siaWorldSidAuthority,
  64. 1,
  65. SECURITY_WORLD_RID,
  66. 0, 0, 0, 0, 0, 0, 0,
  67. &psidEveryone))
  68. {
  69. goto ErrorReturn;
  70. }
  71. //
  72. // compute size of ACL
  73. //
  74. dwAclSize =
  75. sizeof(ACL) +
  76. ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
  77. GetLengthSid(psidEveryone);
  78. //
  79. // allocate storage for Acl
  80. //
  81. if (NULL == (pDacl = (PACL) new BYTE[dwAclSize]))
  82. {
  83. goto MemoryError;
  84. }
  85. if (!InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
  86. {
  87. goto ErrorReturn;
  88. }
  89. if (!AddAccessAllowedAce(
  90. pDacl,
  91. ACL_REVISION,
  92. SYNCHRONIZE,// | MUTEX_MODIFY_STATE,
  93. psidEveryone))
  94. {
  95. goto ErrorReturn;
  96. }
  97. if ( InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION ) == FALSE )
  98. {
  99. goto ErrorReturn;
  100. }
  101. if ( SetSecurityDescriptorDacl( &sd, TRUE, pDacl, FALSE ) == FALSE )
  102. {
  103. goto ErrorReturn;
  104. }
  105. sa.nLength = sizeof( SECURITY_ATTRIBUTES );
  106. sa.lpSecurityDescriptor = &sd;
  107. sa.bInheritHandle = FALSE;
  108. psa = &sa;
  109. }
  110. hDMutex = CreateMutexU( psa, FALSE, pwszBFileBaseName );
  111. if ( hDMutex == NULL )
  112. {
  113. hDMutex = OpenMutexU( SYNCHRONIZE, FALSE, pwszBFileBaseName );
  114. if ( hDMutex == NULL )
  115. {
  116. dwErr = GetLastError();
  117. goto ErrorReturn;
  118. }
  119. }
  120. fInitialized = TRUE; // set it now becuase OpenFiles uses "Lock".
  121. if (!(this->OpenFiles()))
  122. {
  123. goto FileError;
  124. }
  125. } // __try
  126. __except(EXCEPTION_EXECUTE_HANDLER)
  127. {
  128. if (pbKMap != NULL)
  129. {
  130. UnmapViewOfFile(pbKMap);
  131. pbKMap = NULL;
  132. }
  133. if (pbDMap != NULL)
  134. {
  135. UnmapViewOfFile(pbDMap);
  136. pbDMap = NULL;
  137. }
  138. if (hDFile != INVALID_HANDLE_VALUE)
  139. {
  140. CloseHandle(hDFile);
  141. hDFile = INVALID_HANDLE_VALUE;
  142. }
  143. if (hKFile != INVALID_HANDLE_VALUE)
  144. {
  145. CloseHandle(hKFile);
  146. hKFile = INVALID_HANDLE_VALUE;
  147. }
  148. if (hDMutex != NULL)
  149. {
  150. CloseHandle(hDMutex);
  151. hDMutex = NULL;
  152. }
  153. if (pwszPath != NULL)
  154. {
  155. delete[](pwszPath);
  156. pwszPath = NULL;
  157. }
  158. if (pwszBaseName != NULL)
  159. {
  160. delete[](pwszBaseName);
  161. pwszBaseName = NULL;
  162. }
  163. goto ErrorReturn;
  164. }
  165. sRecord.cbKey = sHeader.cbKey;
  166. sRecord.cbData = sHeader.cbData;
  167. if (!(sRecord.pvKey = (void *)new BYTE[cbKey + sizeof(DWORD)]) ||
  168. !(sRecord.pvData = (void *)new BYTE[cbData + sizeof(DWORD)]))
  169. {
  170. goto MemoryError;
  171. }
  172. sRecord.pvData = (BYTE *)sRecord.pvData + sizeof(DWORD); // we use the first dword for rec # (see addrec)
  173. memset(sRecord.pvKey, 0x00, cbKey);
  174. memset(sRecord.pvData, 0x00, cbData);
  175. CommonReturn:
  176. if (pDacl != NULL)
  177. {
  178. delete[] pDacl;
  179. }
  180. if (psidEveryone)
  181. {
  182. FreeSid(psidEveryone);
  183. }
  184. return;
  185. ErrorReturn:
  186. fInitialized = FALSE;
  187. *pfCreatedOK = FALSE;
  188. goto CommonReturn;
  189. SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  190. SET_ERROR_VAR_EX(DBG_SS, FileError, ERROR_FILE_NOT_FOUND);
  191. }
  192. cBFile_::~cBFile_(void)
  193. {
  194. if (fDirty)
  195. {
  196. this->Sort();
  197. }
  198. if (pbKMap != NULL)
  199. {
  200. UnmapViewOfFile(pbKMap);
  201. }
  202. if (pbDMap != NULL)
  203. {
  204. UnmapViewOfFile(pbDMap);
  205. }
  206. if (hDFile != INVALID_HANDLE_VALUE)
  207. {
  208. CloseHandle(hDFile);
  209. }
  210. if (hKFile != INVALID_HANDLE_VALUE)
  211. {
  212. CloseHandle(hKFile);
  213. }
  214. if (hDMutex != NULL)
  215. {
  216. CloseHandle(hDMutex);
  217. }
  218. if (pwszPath != NULL)
  219. {
  220. delete[](pwszPath);
  221. }
  222. if (pwszBaseName != NULL)
  223. {
  224. delete[](pwszBaseName);
  225. }
  226. DELETE_OBJECT(sRecord.pvKey);
  227. if (sRecord.pvData)
  228. {
  229. sRecord.pvData = (BYTE *)sRecord.pvData - sizeof(DWORD); // we bumped the pointer in the constructer, put it back..
  230. delete sRecord.pvData;
  231. }
  232. }
  233. BOOL cBFile_::Initialize(void)
  234. {
  235. return(fInitialized);
  236. }
  237. DWORD cBFile_::GetNumKeys(void)
  238. {
  239. DWORD dwRet;
  240. dwRet = GetFileSize(this->hKFile, NULL);
  241. if (dwRet > 0)
  242. {
  243. dwRet /= BFILE_KEYSIZE;
  244. return(dwRet);
  245. }
  246. return(0);
  247. }
  248. void cBFile_::setKey(void *pvInKey)
  249. {
  250. memcpy(sRecord.pvKey, pvInKey, sRecord.cbKey);
  251. }
  252. void cBFile_::setData(void *pvInData)
  253. {
  254. memcpy(sRecord.pvData, pvInData, sRecord.cbData);
  255. }
  256. BOOL cBFile_::Find(void)
  257. {
  258. DWORD cbDOff;
  259. DWORD dwLastGood;
  260. void *pvKey;
  261. BOOL fRet;
  262. pvKey = new BYTE[sRecord.cbKey];
  263. if (!(pvKey))
  264. {
  265. goto MemoryError;
  266. }
  267. memcpy(pvKey, sRecord.pvKey, sRecord.cbKey);
  268. if (this->BinaryFind(&cbDOff))
  269. {
  270. dwLastGood = this->dwFirstNextRecNum;
  271. while (this->GetPrev(dwLastGood))
  272. {
  273. if (memcmp(pvKey, sRecord.pvKey, sRecord.cbKey) != 0)
  274. {
  275. break;
  276. }
  277. dwLastGood = this->dwFirstNextRecNum;
  278. }
  279. if (dwLastGood > 0)
  280. {
  281. dwLastGood--;
  282. delete pvKey;
  283. return(this->GetNext(dwLastGood));
  284. }
  285. delete pvKey;
  286. __try {
  287. return(this->GetDataRecord(cbDOff));
  288. }
  289. __except(EXCEPTION_EXECUTE_HANDLER) {
  290. this->UnmapAll();
  291. SetLastError(GetExceptionCode());
  292. }
  293. return(FALSE);
  294. }
  295. fRet = FALSE;
  296. CommonReturn:
  297. if (pvKey)
  298. {
  299. delete pvKey;
  300. }
  301. return(fRet);
  302. ErrorReturn:
  303. fRet = FALSE;
  304. goto CommonReturn;
  305. SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  306. }
  307. BOOL cBFile_::GetFirst(void)
  308. {
  309. BOOL fRet;
  310. this->dwFirstNextRecNum = 0;
  311. if (!(this->pbKMap))
  312. {
  313. return(FALSE);
  314. }
  315. __try {
  316. if (!this->ReadHeader())
  317. {
  318. goto ErrorReturn;
  319. }
  320. DWORD cbOff;
  321. memcpy(sRecord.pvKey, &this->pbKMap[0], sRecord.cbKey);
  322. memcpy(&cbOff, &this->pbKMap[sRecord.cbKey], sizeof(DWORD));
  323. if (!(this->GetDataRecord(cbOff)))
  324. {
  325. goto cBFileCorrupt;
  326. }
  327. fRet = TRUE;
  328. }
  329. __except(EXCEPTION_EXECUTE_HANDLER) {
  330. this->UnmapAll();
  331. SetLastError(GetExceptionCode());
  332. goto cBFileCorrupt;
  333. }
  334. CommonReturn:
  335. return(fRet);
  336. ErrorReturn:
  337. fRet = FALSE;
  338. goto CommonReturn;
  339. TRACE_ERROR_EX(DBG_SS, cBFileCorrupt);
  340. }
  341. BOOL cBFile_::GetNext(DWORD dwCurRec)
  342. {
  343. BOOL fRet;
  344. if (!(this->pbKMap))
  345. {
  346. return(FALSE);
  347. }
  348. if (dwCurRec == 0xffffffff)
  349. {
  350. dwCurRec = this->dwFirstNextRecNum;
  351. }
  352. DWORD cbOff;
  353. dwCurRec++;
  354. if (((dwCurRec + 1) * BFILE_KEYSIZE) > sHeader.cbSortedEOF)
  355. {
  356. goto cBFileNoNext;
  357. }
  358. __try {
  359. memcpy(sRecord.pvKey, &this->pbKMap[dwCurRec * BFILE_KEYSIZE], sRecord.cbKey);
  360. memcpy(&cbOff, &this->pbKMap[(dwCurRec * BFILE_KEYSIZE) + sRecord.cbKey], sizeof(DWORD));
  361. if (!(this->GetDataRecord(cbOff)))
  362. {
  363. goto cBFileCorrupt;
  364. }
  365. this->dwFirstNextRecNum = dwCurRec;
  366. fRet = TRUE;
  367. }
  368. __except(EXCEPTION_EXECUTE_HANDLER) {
  369. this->UnmapAll();
  370. SetLastError(GetExceptionCode());
  371. goto cBFileCorrupt;
  372. }
  373. CommonReturn:
  374. return(fRet);
  375. ErrorReturn:
  376. fRet = FALSE;
  377. this->dwFirstNextRecNum = 0;
  378. goto CommonReturn;
  379. TRACE_ERROR_EX(DBG_SS, cBFileNoNext);
  380. TRACE_ERROR_EX(DBG_SS, cBFileCorrupt);
  381. }
  382. BOOL cBFile_::GetPrev(DWORD dwCurRec)
  383. {
  384. BOOL fRet;
  385. if (!(this->pbKMap) || (sHeader.cbSortedEOF == 0))
  386. {
  387. goto cBFileNoPrev;
  388. }
  389. if (dwCurRec == 0xffffffff)
  390. {
  391. dwCurRec = this->dwFirstNextRecNum;
  392. }
  393. DWORD cb;
  394. DWORD cbOff;
  395. if (dwCurRec < 1)
  396. {
  397. goto cBFileNoPrev;
  398. }
  399. dwCurRec--;
  400. if (((dwCurRec + 1) * BFILE_KEYSIZE) >= sHeader.cbSortedEOF)
  401. {
  402. goto cBFileNoPrev;
  403. }
  404. __try {
  405. memcpy(sRecord.pvKey, &this->pbKMap[dwCurRec * BFILE_KEYSIZE], sRecord.cbKey);
  406. memcpy(&cbOff, &this->pbKMap[(dwCurRec * BFILE_KEYSIZE) + sRecord.cbKey], sizeof(DWORD));
  407. if (!(this->GetDataRecord(cbOff)))
  408. {
  409. goto cBFileCorrupt;
  410. }
  411. this->dwFirstNextRecNum = dwCurRec;
  412. fRet = TRUE;
  413. }
  414. __except(EXCEPTION_EXECUTE_HANDLER) {
  415. this->UnmapAll();
  416. SetLastError(GetExceptionCode());
  417. goto cBFileCorrupt;
  418. }
  419. CommonReturn:
  420. return(fRet);
  421. ErrorReturn:
  422. fRet = FALSE;
  423. this->dwFirstNextRecNum = 0;
  424. goto CommonReturn;
  425. TRACE_ERROR_EX(DBG_SS, cBFileNoPrev);
  426. TRACE_ERROR_EX(DBG_SS, cBFileCorrupt);
  427. }
  428. BOOL cBFile_::Update(void)
  429. {
  430. DWORD cbDOff;
  431. if ( fReadOnly == TRUE )
  432. {
  433. SetLastError( ERROR_ACCESS_DENIED );
  434. return( FALSE );
  435. }
  436. if (this->BinaryFind(&cbDOff))
  437. {
  438. this->UpdateDataRecord(cbDOff);
  439. return(TRUE);
  440. }
  441. return(FALSE);
  442. }
  443. BOOL cBFile_::Add(void)
  444. {
  445. if ( fReadOnly == TRUE )
  446. {
  447. SetLastError( ERROR_ACCESS_DENIED );
  448. return( FALSE );
  449. }
  450. if (!this->AddDirtyKey())
  451. {
  452. return(FALSE);
  453. }
  454. return(TRUE);
  455. }
  456. BOOL cBFile_::Lock(void)
  457. {
  458. WaitForSingleObject( this->hDMutex, INFINITE );
  459. return(TRUE);
  460. }
  461. BOOL cBFile_::Unlock(void)
  462. {
  463. ReleaseMutex( this->hDMutex );
  464. return( TRUE );
  465. }
  466. void cBFile_::SpeedSort(void)
  467. {
  468. Stack_ *pcStack;
  469. if ( fReadOnly == TRUE )
  470. {
  471. assert( FALSE && "A sort should not be forced in read-only mode." );
  472. return;
  473. }
  474. pcStack = NULL;
  475. if (!(this->pbKMap))
  476. {
  477. goto RemapError;
  478. }
  479. if (!(this->Lock()))
  480. {
  481. goto LockFileError;
  482. }
  483. //
  484. // load dirty in memory and sort it
  485. //
  486. DWORD cbCurKey;
  487. DWORD cbTotal;
  488. if (!(pcStack = new Stack_(pCritical)))
  489. {
  490. goto MemoryError;
  491. }
  492. cbTotal = GetFileSize(this->hKFile, NULL);
  493. cbCurKey = sHeader.cbSortedEOF;
  494. __try {
  495. while (cbCurKey < cbTotal)
  496. {
  497. pcStack->Add(BFILE_KEYSIZE, &this->pbKMap[cbCurKey]);
  498. cbCurKey += BFILE_KEYSIZE;
  499. }
  500. pcStack->Sort(0, sRecord.cbKey, STACK_SORTTYPE_BINARY);
  501. //
  502. // shuffle into sorted
  503. //
  504. DWORD dwIdx;
  505. DWORD dwInsertion;
  506. DWORD cbFreeSpace;
  507. BYTE *pbKey;
  508. BYTE *pbCurrentKey;
  509. BYTE *pbStartFreeSpace;
  510. pbStartFreeSpace = &this->pbKMap[sHeader.cbSortedEOF];
  511. cbFreeSpace = pcStack->Count() * BFILE_KEYSIZE;
  512. dwIdx = (long)pcStack->Count() - 1;
  513. while (pbKey = (BYTE *)pcStack->Get(dwIdx))
  514. {
  515. //
  516. // get the starting point of our "window"
  517. //
  518. dwInsertion = this->GetInsertionPoint(pbKey);
  519. //
  520. // move the old data to the current free space "window"
  521. //
  522. memmove(&this->pbKMap[dwInsertion + cbFreeSpace], &this->pbKMap[dwInsertion],
  523. sHeader.cbSortedEOF - dwInsertion);
  524. //
  525. // after this, the insersion point has free space the size of the "window" - key size
  526. //
  527. cbFreeSpace -= BFILE_KEYSIZE;
  528. //
  529. // add the new key to the end of the "free space" window.
  530. //
  531. memcpy(&this->pbKMap[dwInsertion + cbFreeSpace], pbKey, BFILE_KEYSIZE);
  532. //
  533. // keep the end of the search up to date for these insertions....
  534. //
  535. sHeader.cbSortedEOF = dwInsertion;
  536. if (dwIdx == 0)
  537. {
  538. break;
  539. }
  540. dwIdx--;
  541. }
  542. sHeader.cbSortedEOF = cbTotal;
  543. sHeader.fDirty = FALSE;
  544. fDirty = FALSE;
  545. this->UpdateHeader();
  546. }
  547. __except( EXCEPTION_EXECUTE_HANDLER ) {
  548. this->UnmapAll();
  549. SetLastError( GetExceptionCode() );
  550. goto RemapError;
  551. }
  552. ErrorReturn:
  553. this->Unlock();
  554. DELETE_OBJECT(pcStack);
  555. return;
  556. TRACE_ERROR_EX(DBG_SS, LockFileError);
  557. TRACE_ERROR_EX(DBG_SS, RemapError);
  558. SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  559. }
  560. DWORD cBFile_::GetInsertionPoint(void *pvIn)
  561. {
  562. DWORD dwEnd;
  563. DWORD dwMiddle;
  564. DWORD dwStart;
  565. DWORD dwHalf;
  566. DWORD dwCur;
  567. DWORD dwRet;
  568. BYTE *pb;
  569. int cmp;
  570. dwStart = 0;
  571. dwEnd = sHeader.cbSortedEOF / BFILE_KEYSIZE;
  572. dwMiddle = dwEnd / 2L;
  573. dwHalf = dwMiddle;
  574. dwCur = 0;
  575. if (sHeader.cbSortedEOF >= BFILE_KEYSIZE)
  576. {
  577. dwRet = sHeader.cbSortedEOF - BFILE_KEYSIZE;
  578. }
  579. else
  580. {
  581. dwRet = 0;
  582. }
  583. for EVER
  584. {
  585. pb = this->pbKMap + (dwMiddle * BFILE_KEYSIZE);
  586. cmp = memcmp(pvIn, pb, sRecord.cbKey);
  587. if (cmp == 0)
  588. {
  589. dwRet = (DWORD)(pb - this->pbKMap);
  590. break;
  591. }
  592. if ( (dwMiddle == 0) ||
  593. (dwMiddle == (sHeader.cbSortedEOF / BFILE_KEYSIZE)) ||
  594. ((dwHalf == 0) && (dwMiddle == dwStart)) )
  595. {
  596. DWORD dwFind;
  597. dwFind = dwRet;
  598. cmp = (-1);
  599. while ((cmp < 0) && ((dwFind + BFILE_KEYSIZE) <= sHeader.cbSortedEOF))
  600. {
  601. cmp = memcmp(pvIn, &this->pbKMap[dwFind], sRecord.cbKey);
  602. dwRet = dwFind;
  603. dwFind += BFILE_KEYSIZE;
  604. }
  605. break;
  606. }
  607. if (cmp < 0)
  608. {
  609. dwEnd = dwMiddle;
  610. dwRet = (dwMiddle * BFILE_KEYSIZE);
  611. }
  612. else
  613. {
  614. dwStart = dwMiddle;
  615. }
  616. dwHalf = (dwEnd - dwStart) / 2L;
  617. dwMiddle = dwStart + dwHalf;
  618. }
  619. return(dwRet);
  620. }
  621. void *cBFile_::GetDumpKey(DWORD dwIdx, void *pvRetKey, DWORD *pdwRecOffset)
  622. {
  623. DWORD dwOffset;
  624. dwOffset = dwIdx * BFILE_KEYSIZE;
  625. if (dwOffset >= GetFileSize(this->hKFile, NULL))
  626. {
  627. return(NULL);
  628. }
  629. __try {
  630. memcpy(pvRetKey, &this->pbKMap[dwOffset], sRecord.cbKey);
  631. memcpy(pdwRecOffset, &this->pbKMap[dwOffset + sRecord.cbKey], sizeof(DWORD));
  632. return(pvRetKey);
  633. }
  634. __except(EXCEPTION_EXECUTE_HANDLER) {
  635. this->UnmapAll();
  636. SetLastError(GetExceptionCode());
  637. }
  638. return(NULL);
  639. }
  640. BOOL cBFile_::GetHeader(BFILE_HEADER *psHeader)
  641. {
  642. __try {
  643. if (!this->ReadHeader())
  644. {
  645. return(FALSE);
  646. }
  647. memcpy(psHeader, &sHeader, sizeof(BFILE_HEADER));
  648. return(TRUE);
  649. }
  650. __except(EXCEPTION_EXECUTE_HANDLER) {
  651. this->UnmapAll();
  652. SetLastError(GetExceptionCode());
  653. }
  654. return(FALSE);
  655. }
  656. void cBFile_::Sort(void)
  657. {
  658. if ( fReadOnly == TRUE )
  659. {
  660. assert( FALSE && "A sort should not be forced in read-only mode." );
  661. return;
  662. }
  663. EnterCriticalSection(pCritical);
  664. if (!FIsWinNT())
  665. {
  666. //
  667. // The only reason this is here is to work around some underlying
  668. // bug in the OS. If we just call RemapKey() and RemapData() then
  669. // we end up with some bogus state on the key and data files which will
  670. // ultimately result in a sharing violation when trying to open the files
  671. // at a later time.
  672. //
  673. if (this->pbKMap != NULL)
  674. {
  675. UnmapViewOfFile(this->pbKMap);
  676. this->pbKMap = NULL;
  677. }
  678. if (this->pbDMap != NULL)
  679. {
  680. UnmapViewOfFile(this->pbDMap);
  681. this->pbDMap = NULL;
  682. }
  683. if (hDFile != INVALID_HANDLE_VALUE)
  684. {
  685. CloseHandle(hDFile);
  686. hDFile = INVALID_HANDLE_VALUE;
  687. }
  688. if (hKFile != INVALID_HANDLE_VALUE)
  689. {
  690. CloseHandle(hKFile);
  691. hKFile = INVALID_HANDLE_VALUE;
  692. }
  693. this->OpenFiles();
  694. }
  695. else
  696. {
  697. this->RemapKey();
  698. this->RemapData();
  699. }
  700. #if 0
  701. if (sHeader.cbSortedEOF > 0)
  702. {
  703. this->SpeedSort();
  704. LeaveCriticalSection(pCritical);
  705. return;
  706. }
  707. #endif
  708. BYTE *pb;
  709. Stack_ *pcStack;
  710. pcStack = NULL;
  711. pb = NULL;
  712. if (!(this->Lock()))
  713. {
  714. goto LockFileError;
  715. }
  716. DWORD dwLen;
  717. DWORD cbFile;
  718. DWORD dwIdx;
  719. DWORD i;
  720. BYTE *pbStack;
  721. if (!(pcStack = new Stack_(pCritical)))
  722. {
  723. goto MemoryError;
  724. }
  725. dwLen = BFILE_KEYSIZE;
  726. if (!(pb = new BYTE[dwLen]))
  727. {
  728. goto MemoryError;
  729. }
  730. cbFile = GetFileSize(this->hKFile, NULL);
  731. __try {
  732. for (i = 0; i < cbFile; i += dwLen)
  733. {
  734. pcStack->Add(dwLen, &this->pbKMap[i]);
  735. }
  736. pcStack->Sort(0, sRecord.cbKey, STACK_SORTTYPE_BINARY);
  737. dwIdx = 0;
  738. i = 0;
  739. while (pbStack = (BYTE *)pcStack->Get(dwIdx))
  740. {
  741. if ((i + dwLen) > cbFile)
  742. {
  743. goto FileSizeError;
  744. }
  745. memcpy(&this->pbKMap[i], pbStack, dwLen);
  746. dwIdx++;
  747. i += dwLen;
  748. }
  749. sHeader.cbSortedEOF = cbFile;
  750. sHeader.fDirty = FALSE;
  751. fDirty = FALSE;
  752. this->UpdateHeader();
  753. }
  754. __except( EXCEPTION_EXECUTE_HANDLER ) {
  755. this->UnmapAll();
  756. SetLastError( GetExceptionCode() );
  757. }
  758. ErrorReturn:
  759. this->Unlock();
  760. DELETE_OBJECT(pcStack);
  761. DELETE_OBJECT(pb);
  762. LeaveCriticalSection(pCritical);
  763. return;
  764. TRACE_ERROR_EX(DBG_SS, FileSizeError);
  765. TRACE_ERROR_EX(DBG_SS, LockFileError);
  766. SET_ERROR_VAR_EX(DBG_SS, MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  767. }
  768. BOOL cBFile_::AddDirtyKey(void)
  769. {
  770. DWORD cbOff;
  771. DWORD cb;
  772. if ( fReadOnly == TRUE )
  773. {
  774. assert( FALSE && "Add dirty key should not occur in read-only mode." );
  775. return(FALSE);
  776. }
  777. this->Lock();
  778. __try {
  779. if (!this->ReadHeader())
  780. {
  781. return(FALSE);
  782. }
  783. sHeader.dwLastRecNum++;
  784. sRecord.dwRecNum = sHeader.dwLastRecNum;
  785. if ((cbOff = this->AddDataRecord()) != 0xffffffff)
  786. {
  787. if (fUseRecNumAsKey)
  788. {
  789. memcpy(sRecord.pvKey, &sRecord.dwRecNum, sizeof(DWORD));
  790. }
  791. memcpy((BYTE *)sRecord.pvKey + sRecord.cbKey, &cbOff, sizeof(DWORD)); // speed...
  792. SetFilePointer(this->hKFile, 0, NULL, FILE_END);
  793. if (FIsWinNT())
  794. {
  795. WriteFile(this->hKFile, sRecord.pvKey, sRecord.cbKey + sizeof(DWORD), &cb, NULL);
  796. // WriteFile(this->hKFile, &cbOff, sizeof(DWORD), &cb, NULL);
  797. }
  798. else
  799. {
  800. if (this->pbKMap != NULL)
  801. {
  802. UnmapViewOfFile(this->pbKMap);
  803. this->pbKMap = NULL;
  804. WriteFile(this->hKFile, sRecord.pvKey, sRecord.cbKey + sizeof(DWORD), &cb, NULL);
  805. this->RemapKey();
  806. }
  807. else
  808. {
  809. WriteFile(this->hKFile, sRecord.pvKey, sRecord.cbKey + sizeof(DWORD), &cb, NULL);
  810. }
  811. }
  812. sHeader.fDirty = TRUE;
  813. this->fDirty = TRUE;
  814. this->UpdateHeader();
  815. }
  816. }
  817. __except( EXCEPTION_EXECUTE_HANDLER ) {
  818. this->UnmapAll();
  819. SetLastError( GetExceptionCode() );
  820. }
  821. this->Unlock();
  822. return(TRUE);
  823. }
  824. BOOL cBFile_::GetDataRecord(DWORD cbDataOffset)
  825. {
  826. DWORD cb;
  827. memset(sRecord.pvData, 0x00, sRecord.cbData);
  828. if (this->cbDMap < (cbDataOffset + sizeof(DWORD) + sRecord.cbData))
  829. {
  830. return(FALSE);
  831. }
  832. memcpy(&sRecord.dwRecNum, &this->pbDMap[cbDataOffset], sizeof(DWORD));
  833. memcpy(sRecord.pvData, &this->pbDMap[cbDataOffset + sizeof(DWORD)], sRecord.cbData);
  834. return(TRUE);
  835. }
  836. void cBFile_::UpdateDataRecord(DWORD cbDataOffset)
  837. {
  838. DWORD cb;
  839. if ( fReadOnly == TRUE )
  840. {
  841. assert( FALSE && "Update data record should not occur in read-only mode." );
  842. return;
  843. }
  844. this->Lock();
  845. if (this->cbDMap < (cbDataOffset + sizeof(DWORD) + sRecord.cbData))
  846. {
  847. this->Unlock();
  848. return;
  849. }
  850. __try {
  851. memcpy(&this->pbDMap[cbDataOffset + sizeof(DWORD)], sRecord.pvData, sRecord.cbData);
  852. }
  853. __except( EXCEPTION_EXECUTE_HANDLER ) {
  854. this->UnmapAll();
  855. SetLastError( GetExceptionCode() );
  856. }
  857. this->Unlock();
  858. }
  859. DWORD cBFile_::AddDataRecord(void)
  860. {
  861. DWORD cbRet;
  862. if ( fReadOnly == TRUE )
  863. {
  864. SetLastError( ERROR_ACCESS_DENIED );
  865. return( 0xFFFFFFFF );
  866. }
  867. //
  868. // no lock here because it is called from add key which
  869. // does a lock
  870. //
  871. if ((cbRet = SetFilePointer(this->hDFile, 0, NULL, FILE_END)) != 0xffffffff)
  872. {
  873. DWORD cb;
  874. BYTE *pv;
  875. pv = (BYTE *)sRecord.pvData - sizeof(DWORD);
  876. memcpy(pv, &sRecord.dwRecNum, sizeof(DWORD));
  877. if (FIsWinNT())
  878. {
  879. WriteFile(this->hDFile, pv, sizeof(DWORD) + sRecord.cbData, &cb, NULL);
  880. // WriteFile(this->hDFile, sRecord.pvData, sRecord.cbData, &cb, NULL);
  881. }
  882. else
  883. {
  884. if (this->pbDMap != NULL)
  885. {
  886. UnmapViewOfFile(this->pbDMap);
  887. this->pbDMap = NULL;
  888. WriteFile(this->hDFile, pv, sizeof(DWORD) + sRecord.cbData, &cb, NULL);
  889. this->RemapData();
  890. }
  891. else
  892. {
  893. WriteFile(this->hDFile, pv, sizeof(DWORD) + sRecord.cbData, &cb, NULL);
  894. }
  895. }
  896. }
  897. return(cbRet);
  898. }
  899. BOOL cBFile_::BinaryFind(DWORD *pcbDataOffset)
  900. {
  901. if (sHeader.fDirty)
  902. {
  903. this->Sort();
  904. }
  905. if (sHeader.cbSortedEOF == 0)
  906. {
  907. return(FALSE);
  908. }
  909. if (!(this->pbKMap))
  910. {
  911. return(FALSE);
  912. }
  913. DWORD dwEnd;
  914. DWORD dwMiddle;
  915. DWORD dwStart;
  916. DWORD dwHalf;
  917. DWORD dwCur;
  918. void *pv;
  919. int cmp;
  920. dwStart = 0;
  921. dwEnd = sHeader.cbSortedEOF / BFILE_KEYSIZE;
  922. dwHalf = dwMiddle = dwEnd / 2L;
  923. dwCur = 0;
  924. __try {
  925. for EVER
  926. {
  927. pv = (void *)(this->pbKMap + (dwMiddle * BFILE_KEYSIZE));
  928. cmp = memcmp(sRecord.pvKey, pv, sRecord.cbKey);
  929. if (cmp == 0)
  930. {
  931. memcpy(pcbDataOffset, (char *)pv + sRecord.cbKey, sizeof(DWORD));
  932. this->dwFirstNextRecNum = (DWORD)((BYTE *)pv - this->pbKMap) / BFILE_KEYSIZE;
  933. return(TRUE);
  934. }
  935. if ((dwMiddle == 0) || (dwMiddle == (sHeader.cbSortedEOF / BFILE_KEYSIZE)) ||
  936. ((dwHalf == 0) && (dwMiddle == dwStart)))
  937. {
  938. break;
  939. }
  940. if (cmp < 0)
  941. {
  942. dwEnd = dwMiddle;
  943. }
  944. else
  945. {
  946. dwStart = dwMiddle;
  947. }
  948. dwHalf = (dwEnd - dwStart) / 2L;
  949. dwMiddle = dwStart + dwHalf;
  950. }
  951. }
  952. __except( EXCEPTION_EXECUTE_HANDLER ) {
  953. this->UnmapAll();
  954. SetLastError( GetExceptionCode() );
  955. }
  956. return(FALSE);
  957. }
  958. BOOL cBFile_::ReadHeader(void)
  959. {
  960. if ((this->pbDMap) && (this->cbDMap >= (sizeof(BFILE_HEADER) + BFILE_SIZEOFSIG)))
  961. {
  962. memcpy(&this->sHeader, &this->pbDMap[BFILE_SIZEOFSIG], sizeof(BFILE_HEADER));
  963. }
  964. else if (SetFilePointer(this->hDFile, BFILE_SIZEOFSIG, NULL, FILE_BEGIN) != 0xffffffff)
  965. {
  966. DWORD cb;
  967. if (!ReadFile(this->hDFile, &this->sHeader, sizeof(BFILE_HEADER), &cb, NULL))
  968. {
  969. return(FALSE);
  970. }
  971. }
  972. else
  973. {
  974. memset(&this->sHeader, 0x00, sizeof(BFILE_HEADER));
  975. }
  976. return(TRUE);
  977. }
  978. BOOL cBFile_::UpdateHeader(void)
  979. {
  980. if ( fReadOnly == TRUE )
  981. {
  982. SetLastError( ERROR_ACCESS_DENIED );
  983. return( FALSE );
  984. }
  985. if ((this->pbDMap) && (this->cbDMap >= (sizeof(BFILE_HEADER) + BFILE_SIZEOFSIG)))
  986. {
  987. memcpy(&this->pbDMap[BFILE_SIZEOFSIG], &this->sHeader, sizeof(BFILE_HEADER));
  988. return(TRUE);
  989. }
  990. if (SetFilePointer(this->hDFile, BFILE_SIZEOFSIG, NULL, FILE_BEGIN) != 0xffffffff)
  991. {
  992. DWORD cbWritten;
  993. WriteFile(this->hDFile, &this->sHeader, sizeof(BFILE_HEADER), &cbWritten, NULL);
  994. return(TRUE);
  995. }
  996. return(FALSE);
  997. }
  998. BOOL cBFile_::OpenFiles(void)
  999. {
  1000. BOOL fRet = TRUE;
  1001. WCHAR wszFile[MAX_PATH];
  1002. DWORD cbWritten;
  1003. int iBaseEnd;
  1004. wcscpy(&wszFile[0], pwszPath);
  1005. if (wszFile[wcslen(pwszPath) - 1] != L'\\')
  1006. {
  1007. wcscat(&wszFile[0], L"\\");
  1008. }
  1009. wcscat(&wszFile[0], pwszBaseName);
  1010. iBaseEnd = wcslen(&wszFile[0]);
  1011. wcscpy(&wszFile[iBaseEnd], BFILE_DATAEXT);
  1012. hDFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1013. NULL, OPEN_EXISTING, 0, NULL);
  1014. if (hDFile == INVALID_HANDLE_VALUE)
  1015. {
  1016. if ( GetLastError() == ERROR_ACCESS_DENIED )
  1017. {
  1018. hDFile = CreateFileU(&wszFile[0], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1019. NULL, OPEN_EXISTING, 0, NULL);
  1020. fReadOnly = TRUE;
  1021. }
  1022. else
  1023. {
  1024. hDFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1025. NULL, CREATE_NEW, 0, NULL);
  1026. }
  1027. if (hDFile == INVALID_HANDLE_VALUE)
  1028. {
  1029. return(FALSE);
  1030. }
  1031. if ( fReadOnly == FALSE )
  1032. {
  1033. WriteFile(this->hDFile, BFILE_SIG, BFILE_SIZEOFSIG, &cbWritten, NULL);
  1034. this->Lock();
  1035. __try {
  1036. fRet = this->UpdateHeader();
  1037. }
  1038. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1039. fRet = FALSE;
  1040. }
  1041. this->Unlock();
  1042. if ( fRet == FALSE )
  1043. {
  1044. return( FALSE );
  1045. }
  1046. wcscpy(&wszFile[iBaseEnd], BFILE_KEYEXT);
  1047. hKFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1048. NULL, OPEN_ALWAYS, 0, NULL);
  1049. }
  1050. else
  1051. {
  1052. wcscpy(&wszFile[iBaseEnd], BFILE_KEYEXT);
  1053. hKFile = CreateFileU(&wszFile[0], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1054. NULL, OPEN_EXISTING, 0, NULL);
  1055. }
  1056. }
  1057. else
  1058. {
  1059. wcscpy(&wszFile[iBaseEnd], BFILE_KEYEXT);
  1060. hKFile = CreateFileU(&wszFile[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1061. NULL, OPEN_ALWAYS, 0, NULL);
  1062. }
  1063. if ((hDFile == INVALID_HANDLE_VALUE) || (hKFile == INVALID_HANDLE_VALUE))
  1064. {
  1065. return(FALSE);
  1066. }
  1067. fRet &= this->RemapKey();
  1068. fRet &= this->RemapData();
  1069. if ( fRet == FALSE )
  1070. {
  1071. return( FALSE );
  1072. }
  1073. __try {
  1074. if (!this->ReadHeader())
  1075. {
  1076. return FALSE;
  1077. }
  1078. }
  1079. __except( EXCEPTION_EXECUTE_HANDLER ) {
  1080. fRet = FALSE;
  1081. }
  1082. return(fRet);
  1083. }
  1084. BOOL cBFile_::RemapKey(void)
  1085. {
  1086. LPBYTE pbOldMap;
  1087. HANDLE hMappedFile;
  1088. DWORD PageAccess = PAGE_READWRITE;
  1089. DWORD FileMapAccess = FILE_MAP_WRITE;
  1090. pbOldMap = this->pbKMap;
  1091. if ( fReadOnly == TRUE )
  1092. {
  1093. PageAccess = PAGE_READONLY;
  1094. FileMapAccess = FILE_MAP_READ;
  1095. }
  1096. hMappedFile = CreateFileMapping(this->hKFile, NULL, PageAccess, 0, 0, NULL);
  1097. if (!(hMappedFile) || (hMappedFile == INVALID_HANDLE_VALUE))
  1098. {
  1099. return(TRUE); // could be the first call!
  1100. }
  1101. this->pbKMap = (BYTE *)MapViewOfFile(hMappedFile, FileMapAccess, 0, 0, 0);
  1102. if ( this->pbKMap != NULL )
  1103. {
  1104. if ( pbOldMap != NULL )
  1105. {
  1106. UnmapViewOfFile( pbOldMap );
  1107. }
  1108. this->cbKMap = GetFileSize(this->hKFile, NULL);
  1109. }
  1110. else
  1111. {
  1112. this->pbKMap = pbOldMap;
  1113. }
  1114. CloseHandle(hMappedFile);
  1115. if ( ( pbOldMap == NULL ) && ( this->pbKMap == NULL ) )
  1116. {
  1117. return(FALSE);
  1118. }
  1119. return(TRUE);
  1120. }
  1121. BOOL cBFile_::RemapData(void)
  1122. {
  1123. LPBYTE pbOldMap;
  1124. HANDLE hMappedFile;
  1125. DWORD PageAccess = PAGE_READWRITE;
  1126. DWORD FileMapAccess = FILE_MAP_WRITE;
  1127. pbOldMap = this->pbDMap;
  1128. if ( fReadOnly == TRUE )
  1129. {
  1130. PageAccess = PAGE_READONLY;
  1131. FileMapAccess = FILE_MAP_READ;
  1132. }
  1133. hMappedFile = CreateFileMapping(this->hDFile, NULL, PageAccess, 0, 0, NULL);
  1134. if (!(hMappedFile) || (hMappedFile == INVALID_HANDLE_VALUE))
  1135. {
  1136. return(TRUE); // could be the first call!
  1137. }
  1138. this->pbDMap = (BYTE *)MapViewOfFile(hMappedFile, FileMapAccess, 0, 0, 0);
  1139. if ( this->pbDMap != NULL )
  1140. {
  1141. if ( pbOldMap != NULL )
  1142. {
  1143. UnmapViewOfFile( pbOldMap );
  1144. }
  1145. this->cbDMap = GetFileSize(this->hDFile, NULL);
  1146. }
  1147. else
  1148. {
  1149. this->pbDMap = pbOldMap;
  1150. }
  1151. CloseHandle(hMappedFile);
  1152. if ( ( pbOldMap == NULL ) && ( this->pbDMap == NULL ) )
  1153. {
  1154. return(FALSE);
  1155. }
  1156. return(TRUE);
  1157. }
  1158. void cBFile_::UnmapAll(void)
  1159. {
  1160. if (this->pbKMap != NULL)
  1161. {
  1162. UnmapViewOfFile(this->pbKMap);
  1163. this->pbKMap = NULL;
  1164. }
  1165. if (this->pbDMap != NULL)
  1166. {
  1167. UnmapViewOfFile(this->pbDMap);
  1168. this->pbDMap = NULL;
  1169. }
  1170. }