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.

1462 lines
37 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. index.c
  5. Abstract:
  6. This module implements the APIs and internal functions used to access and build
  7. indexes in the database.
  8. Author:
  9. dmunsil created sometime in 1999
  10. Revision History:
  11. several people contributed (vadimb, clupu, ...)
  12. --*/
  13. #include "sdbp.h"
  14. #if defined(KERNEL_MODE) && defined(ALLOC_DATA_PRAGMA)
  15. #pragma data_seg()
  16. #endif // KERNEL_MODE && ALLOC_DATA_PRAGMA
  17. #if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
  18. #pragma alloc_text(PAGE, SdbFindFirstGUIDIndexedTag)
  19. #pragma alloc_text(PAGE, SdbFindNextGUIDIndexedTag)
  20. #pragma alloc_text(PAGE, SdbFindFirstDWORDIndexedTag)
  21. #pragma alloc_text(PAGE, SdbFindNextDWORDIndexedTag)
  22. #pragma alloc_text(PAGE, SdbFindFirstStringIndexedTag)
  23. #pragma alloc_text(PAGE, SdbFindNextStringIndexedTag)
  24. #pragma alloc_text(PAGE, SdbpBinarySearchUnique)
  25. #pragma alloc_text(PAGE, SdbpBinarySearchFirst)
  26. #pragma alloc_text(PAGE, SdbpGetFirstIndexedRecord)
  27. #pragma alloc_text(PAGE, SdbpGetNextIndexedRecord)
  28. #pragma alloc_text(PAGE, SdbpPatternMatch)
  29. #pragma alloc_text(PAGE, SdbpPatternMatchAnsi)
  30. #pragma alloc_text(PAGE, SdbpKeyToAnsiString)
  31. #pragma alloc_text(PAGE, SdbpFindFirstIndexedWildCardTag)
  32. #pragma alloc_text(PAGE, SdbpFindNextIndexedWildCardTag)
  33. #pragma alloc_text(PAGE, SdbGetIndex)
  34. #pragma alloc_text(PAGE, SdbpScanIndexes)
  35. #pragma alloc_text(PAGE, SdbpGetIndex)
  36. #pragma alloc_text(PAGE, SdbMakeIndexKeyFromString)
  37. #pragma alloc_text(PAGE, SdbpTagToKey)
  38. #endif // KERNEL_MODE && ALLOC_PRAGMA
  39. TAGID
  40. SdbFindFirstGUIDIndexedTag(
  41. IN PDB pdb,
  42. IN TAG tWhich,
  43. IN TAG tKey,
  44. IN GUID* pguidName,
  45. OUT FIND_INFO* pFindInfo
  46. )
  47. /*++
  48. Return: void
  49. Desc: This function locates the first matching entry indexed by GUID id
  50. --*/
  51. {
  52. TAGID tiReturn;
  53. DWORD dwFlags = 0;
  54. pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
  55. if (pFindInfo->tiIndex == TAGID_NULL) {
  56. DBGPRINT((sdlError,
  57. "SdbFindFirstGUIDIndexedTag",
  58. "Failed to find index 0x%lx key 0x%lx\n",
  59. tWhich, tKey));
  60. return TAGID_NULL;
  61. }
  62. pFindInfo->tName = tKey;
  63. pFindInfo->pguidName = pguidName;
  64. pFindInfo->dwFlags = dwFlags;
  65. pFindInfo->ullKey = MAKEKEYFROMGUID(pguidName);
  66. tiReturn = SdbpGetFirstIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo->ullKey, pFindInfo);
  67. if (tiReturn == TAGID_NULL) {
  68. //
  69. // While this is handled properly in FindMatchingGUID we return here since
  70. // the record was not found in the index. It is not an abnormal condition.
  71. // We have just failed to find the match. Likewise, DBGPRINT is not warranted
  72. //
  73. return tiReturn;
  74. }
  75. return SdbpFindMatchingGUID(pdb, tiReturn, pFindInfo);
  76. }
  77. TAGID
  78. SdbFindNextGUIDIndexedTag(
  79. IN PDB pdb,
  80. OUT FIND_INFO* pFindInfo
  81. )
  82. /*++
  83. Return: The TAGID of the next GUID-indexed tag.
  84. Desc: This function finds the next entry matching a guid provided in a
  85. previous call to SdbFindNextGUIDIndexedTag
  86. --*/
  87. {
  88. TAGID tiReturn;
  89. //
  90. // Get a preliminary match from the index.
  91. //
  92. tiReturn = SdbpGetNextIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo);
  93. if (tiReturn == TAGID_NULL) {
  94. //
  95. // This case is handled properly in SdbpFindMatchingGUID
  96. // we return here however for simplicity.
  97. // DBGPRINT is not needed since it's not an abnormal condition
  98. //
  99. return tiReturn;
  100. }
  101. return SdbpFindMatchingGUID(pdb, tiReturn, pFindInfo);
  102. }
  103. TAGID
  104. SdbFindFirstDWORDIndexedTag(
  105. IN PDB pdb,
  106. IN TAG tWhich,
  107. IN TAG tKey,
  108. IN DWORD dwName,
  109. OUT FIND_INFO* pFindInfo
  110. )
  111. /*++
  112. Return: BUGBUG: ?
  113. Desc: BUGBUG: what does this do ?
  114. --*/
  115. {
  116. TAGID tiReturn;
  117. DWORD dwFlags = 0;
  118. pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
  119. if (pFindInfo->tiIndex == TAGID_NULL) {
  120. DBGPRINT((sdlError,
  121. "SdbFindFirstDWORDIndexedTag",
  122. "Failed to find index 0x%lx key 0x%lx\n",
  123. tWhich, tKey));
  124. return TAGID_NULL;
  125. }
  126. pFindInfo->tName = tKey;
  127. pFindInfo->dwName = dwName;
  128. pFindInfo->dwFlags = dwFlags;
  129. pFindInfo->ullKey = MAKEKEYFROMDWORD(dwName);
  130. tiReturn = SdbpGetFirstIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo->ullKey, pFindInfo);
  131. if (tiReturn == TAGID_NULL) {
  132. //
  133. // While this is handled properly in FindMatchingGUID we return here since
  134. // the record was not found in the index. It is not an abnormal condition.
  135. // We have just failed to find the match. Likewise, DBGPRINT is not warranted
  136. //
  137. return tiReturn;
  138. }
  139. return SdbpFindMatchingDWORD(pdb, tiReturn, pFindInfo);
  140. }
  141. TAGID
  142. SdbFindNextDWORDIndexedTag(
  143. IN PDB pdb,
  144. OUT FIND_INFO* pFindInfo
  145. )
  146. /*++
  147. Return: BUGBUG: ?
  148. Desc: BUGBUG: ?
  149. --*/
  150. {
  151. TAGID tiReturn;
  152. //
  153. // Get a preliminary match from the index.
  154. //
  155. tiReturn = SdbpGetNextIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo);
  156. if (tiReturn == TAGID_NULL) {
  157. //
  158. // This case is handled properly in SdbpFindMatchingDWORD
  159. // we return here however for simplicity.
  160. // DBGPRINT is not needed since it's not an abnormal condition
  161. //
  162. return tiReturn;
  163. }
  164. return SdbpFindMatchingDWORD(pdb, tiReturn, pFindInfo);
  165. }
  166. TAGID
  167. SdbFindFirstStringIndexedTag(
  168. IN PDB pdb,
  169. IN TAG tWhich,
  170. IN TAG tKey,
  171. IN LPCTSTR pszName,
  172. OUT FIND_INFO* pFindInfo
  173. )
  174. /*++
  175. Return: BUGBUG: ?
  176. Desc: BUGBUG: ?
  177. --*/
  178. {
  179. TAGID tiReturn;
  180. DWORD dwFlags = 0;
  181. pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
  182. if (pFindInfo->tiIndex == TAGID_NULL) {
  183. DBGPRINT((sdlError,
  184. "SdbFindFirstStringIndexedTag",
  185. "Index not found 0x%lx Key 0x%lx\n",
  186. tWhich,
  187. tKey));
  188. return TAGID_NULL;
  189. }
  190. pFindInfo->tName = tKey;
  191. pFindInfo->szName = (LPTSTR)pszName;
  192. pFindInfo->dwFlags = dwFlags;
  193. pFindInfo->ullKey = SdbMakeIndexKeyFromString(pszName);
  194. //
  195. // Get a preliminary match from the index.
  196. //
  197. tiReturn = SdbpGetFirstIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo->ullKey, pFindInfo);
  198. if (tiReturn == TAGID_NULL) {
  199. //
  200. // This is not a bug, tag was not found
  201. //
  202. return tiReturn;
  203. }
  204. DBGPRINT((sdlInfo, "SdbFindFirstStringIndexedTag", "Found tagid 0x%x\n", tiReturn));
  205. return SdbpFindMatchingName(pdb, tiReturn, pFindInfo);
  206. }
  207. TAGID
  208. SdbFindNextStringIndexedTag(
  209. IN PDB pdb,
  210. OUT FIND_INFO* pFindInfo
  211. )
  212. /*++
  213. Return: BUGBUG: ?
  214. Desc: BUGBUG: ?
  215. --*/
  216. {
  217. TAGID tiReturn;
  218. //
  219. // Get a preliminary match from the index.
  220. //
  221. tiReturn = SdbpGetNextIndexedRecord(pdb, pFindInfo->tiIndex, pFindInfo);
  222. if (tiReturn == TAGID_NULL) {
  223. //
  224. // This is not a bug, this item was not found
  225. //
  226. return tiReturn;
  227. }
  228. return SdbpFindMatchingName(pdb, tiReturn, pFindInfo);
  229. }
  230. BOOL
  231. SdbpBinarySearchUnique(
  232. IN PINDEX_RECORD pRecords, // index record ptr
  233. IN DWORD nRecords, // number of records
  234. IN ULONGLONG ullKey, // key to search for
  235. OUT DWORD* pdwIndex // index to the item
  236. )
  237. /*++
  238. Return: TRUE if the index to the item is found.
  239. Desc: BUGBUG: comment ?
  240. --*/
  241. {
  242. int iLeft = 0;
  243. int iRight = (int)nRecords - 1;
  244. int i = -1;
  245. ULONGLONG ullKeyIndex;
  246. BOOL bFound = FALSE;
  247. if (iRight >= 0) {
  248. do {
  249. i = (iLeft + iRight) / 2; // middle
  250. READ_INDEX_KEY(pRecords, i, &ullKeyIndex);
  251. if (ullKey <= ullKeyIndex) {
  252. iRight = i - 1;
  253. }
  254. if (ullKey >= ullKeyIndex) {
  255. iLeft = i + 1;
  256. }
  257. } while (iRight >= iLeft);
  258. }
  259. bFound = (iLeft - iRight > 1);
  260. if (bFound) {
  261. *pdwIndex = (DWORD)i;
  262. }
  263. return bFound;
  264. }
  265. BOOL
  266. SdbpBinarySearchFirst(
  267. IN PINDEX_RECORD pRecords,
  268. IN DWORD nRecords,
  269. IN ULONGLONG ullKey,
  270. OUT DWORD* pdwIndex
  271. )
  272. {
  273. int iLeft = 0;
  274. int iRight = (int)nRecords - 1;
  275. int i = -1;
  276. ULONGLONG ullKeyIndex = 0;
  277. ULONGLONG ullKeyIndexPrev = 0;
  278. BOOL bFound = FALSE;
  279. if (iRight < 0) {
  280. return FALSE;
  281. }
  282. do {
  283. i= (iLeft + iRight) / 2; // middle
  284. READ_INDEX_KEY(pRecords, i, &ullKeyIndex);
  285. if (ullKey == ullKeyIndex) {
  286. if (i == 0 || READ_INDEX_KEY_VAL(pRecords, i - 1, &ullKeyIndexPrev) != ullKey) {
  287. //
  288. // we are done, thank you
  289. //
  290. bFound = TRUE;
  291. break;
  292. } else {
  293. //
  294. // look in the previous record
  295. //
  296. iRight = i - 1;
  297. }
  298. } else {
  299. if (ullKey < ullKeyIndex) {
  300. iRight = i - 1;
  301. } else {
  302. iLeft = i + 1;
  303. }
  304. }
  305. } while (iRight >= iLeft);
  306. if (bFound) {
  307. *pdwIndex = (DWORD)i;
  308. }
  309. return bFound;
  310. }
  311. TAGID
  312. SdbpGetFirstIndexedRecord(
  313. IN PDB pdb, // the DB to use
  314. IN TAGID tiIndex, // the index to use
  315. IN ULONGLONG ullKey, // the key to search for
  316. OUT FIND_INFO* pFindInfo // search context
  317. )
  318. /*++
  319. Return: the record found, or TAGID_NULL.
  320. Desc: Looks through an index for the first record that matches the key. It
  321. returns the index record position for subsequent calls to SdbpGetNextIndexedRecord.
  322. --*/
  323. {
  324. PINDEX_RECORD pIndexRecords;
  325. DWORD dwRecords;
  326. BOOL bFound;
  327. if (SdbGetTagFromTagID(pdb, tiIndex) != TAG_INDEX_BITS) {
  328. DBGPRINT((sdlError,
  329. "SdbpGetFirstIndexedRecord",
  330. "The tag 0x%lx is not an index tag\n",
  331. tiIndex));
  332. return TAGID_NULL;
  333. }
  334. dwRecords = SdbGetTagDataSize(pdb, tiIndex) / sizeof(INDEX_RECORD);
  335. pIndexRecords = (INDEX_RECORD*)SdbpGetMappedTagData(pdb, tiIndex);
  336. if (pIndexRecords == NULL) {
  337. DBGPRINT((sdlError,
  338. "SdbpGetFirstIndexedRecord",
  339. "Failed to get the pointer to index data, index tagid 0x%lx\n",
  340. tiIndex));
  341. return TAGID_NULL;
  342. }
  343. //
  344. // Check to see whether our index is "unique", if so use our search proc.
  345. //
  346. if (pFindInfo->dwFlags & SHIMDB_INDEX_UNIQUE_KEY) {
  347. bFound = SdbpBinarySearchUnique(pIndexRecords,
  348. dwRecords,
  349. ullKey,
  350. &pFindInfo->dwIndexRec);
  351. if (bFound && pFindInfo->dwIndexRec < (dwRecords - 1)) {
  352. //
  353. // We have the next rec -- retrieve the next tagid.
  354. //
  355. pFindInfo->tiEndIndex = pIndexRecords[pFindInfo->dwIndexRec + 1].tiRef;
  356. } else {
  357. //
  358. // We will have to search until eof.
  359. //
  360. pFindInfo->tiEndIndex = TAGID_NULL;
  361. }
  362. pFindInfo->tiCurrent = TAGID_NULL;
  363. } else {
  364. bFound = SdbpBinarySearchFirst(pIndexRecords,
  365. dwRecords,
  366. ullKey,
  367. &pFindInfo->dwIndexRec);
  368. }
  369. return bFound ? pIndexRecords[pFindInfo->dwIndexRec].tiRef : TAGID_NULL;
  370. }
  371. TAGID
  372. SdbpGetNextIndexedRecord(
  373. IN PDB pdb, // the DB to use
  374. IN TAGID tiIndex, // the index to use
  375. OUT FIND_INFO* pFindInfo // the find context
  376. )
  377. /*++
  378. Return: the record found, or TAGID_NULL.
  379. Desc: Gets the next record that matches the one found by a previous call to
  380. SdbpGetFirstIndexedRecord.
  381. --*/
  382. {
  383. ULONGLONG ullKey;
  384. ULONGLONG ullKeyNext;
  385. PINDEX_RECORD pIndexRecords;
  386. DWORD dwRecords;
  387. TAGID tiRef = TAGID_NULL;
  388. TAGID tiThis;
  389. TAG tag, tagThis;
  390. if (SdbGetTagFromTagID(pdb, tiIndex) != TAG_INDEX_BITS) {
  391. DBGPRINT((sdlError,
  392. "SdbpGetNextIndexedRecord",
  393. "The tag 0x%lx is not an index tag\n",
  394. tiIndex));
  395. return TAGID_NULL;
  396. }
  397. pIndexRecords = (PINDEX_RECORD)SdbpGetMappedTagData(pdb, tiIndex);
  398. if (pIndexRecords == NULL) {
  399. DBGPRINT((sdlError,
  400. "SdbpGetNextIndexedRecord",
  401. "Failed to get pointer to the index data tagid x%lx\n",
  402. tiIndex));
  403. return TAGID_NULL;
  404. }
  405. if (pFindInfo->dwFlags & SHIMDB_INDEX_UNIQUE_KEY) {
  406. //
  407. // There are 2 cases:
  408. // - this is the very first call to SdbpGetNextIndexedrecord
  409. // - this is one of the subsequent calls
  410. //
  411. // In the first case, we will have tiCurrent member of the FIND_INFO
  412. // structure set to TAGID_NULL. We use then the reference to the
  413. // index table contained in pFindInfo->dwIndexRec to obtain the reference
  414. // to the next eligible entry in the database.
  415. // In the second case we use the stored tiCurrent to obtain the current tag
  416. //
  417. if (pFindInfo->tiCurrent == TAGID_NULL) {
  418. tiThis = pIndexRecords[pFindInfo->dwIndexRec].tiRef;
  419. } else {
  420. tiThis = pFindInfo->tiCurrent;
  421. }
  422. //
  423. // The tag tiThis which we just obtained was the one we previously looked at
  424. // we need to step to the next tag, the call below does that. Entries are sorted
  425. // since we're using "unique" index
  426. //
  427. tiRef = SdbpGetNextTagId(pdb, tiThis);
  428. //
  429. // Now check the tag for corruption, eof and other calamities.
  430. //
  431. tagThis = SdbGetTagFromTagID(pdb, tiThis);
  432. tag = SdbGetTagFromTagID(pdb, tiRef);
  433. if (tag == TAG_NULL || GETTAGTYPE(tag) != TAG_TYPE_LIST || tag != tagThis) {
  434. //
  435. // This is NOT a bug, but a special condition when the tag happened to be
  436. // the very last tag in the index, thus we have to walk until we hit either
  437. // the end of the file - or a tag of a different type
  438. return TAGID_NULL;
  439. }
  440. //
  441. // Also check for the endtag. It will be a check for TAGID_NULL if we're
  442. // looking for eof but this condition has already been caught by the code above.
  443. //
  444. if (tiRef == pFindInfo->tiEndIndex) {
  445. //
  446. // This is not an error condition. We have walked all the matching entries until
  447. // we hit the very last entry, as denoted by tiEndIndex
  448. //
  449. return TAGID_NULL;
  450. }
  451. //
  452. // Also here check whether the key still has the same
  453. // value for this entry as it did for the previous entry.
  454. // This would have been easy but keys are not immediately available
  455. // for this entry therefore we just return the tiRef. The caller will
  456. // verify whether the entry is valid and whether the search should continue.
  457. //
  458. pFindInfo->tiCurrent = tiRef;
  459. } else {
  460. dwRecords = SdbGetTagDataSize(pdb, tiIndex) / sizeof(INDEX_RECORD);
  461. //
  462. // Get out if this is the last record.
  463. //
  464. if (pFindInfo->dwIndexRec == dwRecords - 1) {
  465. //
  466. // This is not a bug, record not found
  467. //
  468. return TAGID_NULL;
  469. }
  470. //
  471. // we check the next index record to see if it has the same key
  472. //
  473. READ_INDEX_KEY(pIndexRecords, pFindInfo->dwIndexRec, &ullKey);
  474. READ_INDEX_KEY(pIndexRecords, pFindInfo->dwIndexRec + 1, &ullKeyNext);
  475. if (ullKey != ullKeyNext) {
  476. //
  477. // This is not a bug, record not found
  478. //
  479. return TAGID_NULL;
  480. }
  481. ++pFindInfo->dwIndexRec;
  482. tiRef = pIndexRecords[pFindInfo->dwIndexRec].tiRef;
  483. }
  484. return tiRef;
  485. }
  486. BOOL
  487. SdbpPatternMatch(
  488. IN LPCTSTR pszPattern,
  489. IN LPCTSTR pszTestString)
  490. /*++
  491. Return: TRUE if pszTestString matches pszPattern
  492. FALSE if not
  493. Desc: This function does a case-insensitive comparison of
  494. pszTestString against pszPattern. pszPattern can
  495. include asterisks to do wildcard matches.
  496. Any complaints about this function should be directed
  497. toward MarkDer.
  498. --*/
  499. {
  500. //
  501. // March through pszTestString. Each time through the loop,
  502. // pszTestString is advanced one character.
  503. //
  504. while (TRUE) {
  505. //
  506. // If pszPattern and pszTestString are both sitting on a NULL,
  507. // then they reached the end at the same time and the strings
  508. // must be equal.
  509. //
  510. if (*pszPattern == TEXT('\0') && *pszTestString == TEXT('\0')) {
  511. return TRUE;
  512. }
  513. if (*pszPattern != TEXT('*')) {
  514. //
  515. // Non-asterisk mode. Look for a match on this character.
  516. // If equal, continue traversing. Otherwise, the strings
  517. // cannot be equal so return FALSE.
  518. //
  519. if (UPCASE_CHAR(*pszPattern) == UPCASE_CHAR(*pszTestString)) {
  520. pszPattern++;
  521. } else {
  522. return FALSE;
  523. }
  524. } else {
  525. //
  526. // Asterisk mode. Look for a match on the character directly
  527. // after the asterisk.
  528. //
  529. if (*(pszPattern + 1) == TEXT('*')) {
  530. //
  531. // Asterisks exist side by side. Advance the pattern pointer
  532. // and go through loop again.
  533. //
  534. pszPattern++;
  535. continue;
  536. }
  537. if (*(pszPattern + 1) == TEXT('\0')) {
  538. //
  539. // Asterisk exists at the end of the pattern string. Any
  540. // remaining part of pszTestString matches so we can
  541. // immediately return TRUE.
  542. //
  543. return TRUE;
  544. }
  545. if (UPCASE_CHAR(*(pszPattern + 1)) == UPCASE_CHAR(*pszTestString)) {
  546. //
  547. // Characters match. If the remaining parts of
  548. // pszPattern and pszTestString match, then the entire
  549. // string matches. Otherwise, keep advancing the
  550. // pszTestString pointer.
  551. //
  552. if (SdbpPatternMatch(pszPattern + 1, pszTestString)) {
  553. return TRUE;
  554. }
  555. }
  556. }
  557. //
  558. // No more pszTestString left. Must not be a match.
  559. //
  560. if (!*pszTestString) {
  561. return FALSE;
  562. }
  563. pszTestString++;
  564. }
  565. }
  566. BOOL
  567. SdbpPatternMatchAnsi(
  568. IN LPCSTR pszPattern,
  569. IN LPCSTR pszTestString)
  570. {
  571. //
  572. // March through pszTestString. Each time through the loop,
  573. // pszTestString is advanced one character.
  574. //
  575. while (TRUE) {
  576. //
  577. // If pszPattern and pszTestString are both sitting on a NULL,
  578. // then they reached the end at the same time and the strings
  579. // must be equal.
  580. //
  581. if (*pszPattern == '\0' && *pszTestString == '\0') {
  582. return TRUE;
  583. }
  584. if (*pszPattern != '*') {
  585. //
  586. // Non-asterisk mode. Look for a match on this character.
  587. // If equal, continue traversing. Otherwise, the strings
  588. // cannot be equal so return FALSE.
  589. //
  590. if (toupper(*pszPattern) == toupper(*pszTestString)) {
  591. pszPattern++;
  592. } else {
  593. return FALSE;
  594. }
  595. } else {
  596. //
  597. // Asterisk mode. Look for a match on the character directly
  598. // after the asterisk.
  599. //
  600. if (*(pszPattern + 1) == '*') {
  601. //
  602. // Asterisks exist side by side. Advance the pattern pointer
  603. // and go through loop again.
  604. //
  605. pszPattern++;
  606. continue;
  607. }
  608. if (*(pszPattern + 1) == '\0') {
  609. //
  610. // Asterisk exists at the end of the pattern string. Any
  611. // remaining part of pszTestString matches so we can
  612. // immediately return TRUE.
  613. //
  614. return TRUE;
  615. }
  616. if (toupper(*(pszPattern + 1)) == toupper(*pszTestString)) {
  617. //
  618. // Characters match. If the remaining parts of
  619. // pszPattern and pszTestString match, then the entire
  620. // string matches. Otherwise, keep advancing the
  621. // pszTestString pointer.
  622. //
  623. if (SdbpPatternMatchAnsi(pszPattern + 1, pszTestString)) {
  624. return TRUE;
  625. }
  626. }
  627. }
  628. //
  629. // No more pszTestString left. Must not be a match.
  630. //
  631. if (!*pszTestString) {
  632. return FALSE;
  633. }
  634. pszTestString++;
  635. }
  636. }
  637. char*
  638. SdbpKeyToAnsiString(
  639. ULONGLONG ullKey,
  640. char* szString
  641. )
  642. /*++
  643. Return: ?
  644. Desc: ?
  645. --*/
  646. {
  647. char* szRevString = (char*)&ullKey;
  648. int i;
  649. for (i = 0; i < 8; ++i) {
  650. szString[i] = szRevString[7 - i];
  651. }
  652. szString[8] = 0;
  653. return szString;
  654. }
  655. TAGID
  656. SdbpFindFirstIndexedWildCardTag(
  657. PDB pdb,
  658. TAG tWhich,
  659. TAG tKey,
  660. LPCTSTR szName,
  661. FIND_INFO* pFindInfo
  662. )
  663. /*++
  664. Return: ?
  665. Desc: ?
  666. --*/
  667. {
  668. char szAnsiName[MAX_PATH];
  669. char szAnsiKey[10];
  670. PINDEX_RECORD pIndex = NULL;
  671. DWORD dwRecs;
  672. NTSTATUS status;
  673. DWORD dwFlags = 0;
  674. DWORD i, j;
  675. pFindInfo->tiIndex = SdbGetIndex(pdb, tWhich, tKey, &dwFlags);
  676. if (pFindInfo->tiIndex == TAGID_NULL) {
  677. DBGPRINT((sdlError,
  678. "SdbpFindFirstIndexedWilCardTag",
  679. "Failed to get an index for tag 0x%lx key 0x%lx\n",
  680. (DWORD)tWhich,
  681. (DWORD)tKey));
  682. return TAGID_NULL;
  683. }
  684. pFindInfo->tName = tKey;
  685. pFindInfo->szName = szName;
  686. pFindInfo->dwFlags = dwFlags;
  687. RtlZeroMemory(szAnsiName, MAX_PATH);
  688. RtlZeroMemory(szAnsiKey, 10);
  689. //
  690. // Get the uppercase ANSI version of this search string so
  691. // it will match the keys in the index.
  692. //
  693. status = UPCASE_UNICODETOMULTIBYTEN(szAnsiName,
  694. CHARCOUNT(szAnsiName), // this is size in characters
  695. pFindInfo->szName);
  696. if (!NT_SUCCESS(status)) {
  697. DBGPRINT((sdlError,
  698. "SdbpFindFirstIndexedWildCardTag",
  699. "Failed to convert name to multi-byte\n"));
  700. return TAGID_NULL;
  701. }
  702. //
  703. // Get the index.
  704. //
  705. pIndex = SdbpGetIndex(pdb, pFindInfo->tiIndex, &dwRecs);
  706. if (pIndex == NULL) {
  707. DBGPRINT((sdlError,
  708. "SdbpFindFirstIndexedWildCardTag",
  709. "Failed to get index by tag id 0x%lx\n",
  710. pFindInfo->tiIndex));
  711. return TAGID_NULL;
  712. }
  713. //
  714. // Walk through the whole index sequentially, doing a first pass check of the key
  715. // so we can avoid getting the whole record if the name clearly isn't a match.
  716. //
  717. for (i = 0; i < dwRecs; ++i) {
  718. TAGID tiMatch;
  719. TAGID tiKey;
  720. LPTSTR szDBName;
  721. ULONGLONG ullKey;
  722. READ_INDEX_KEY(pIndex, i, &ullKey);
  723. //
  724. // the call below never fails, so we don't check return value
  725. //
  726. SdbpKeyToAnsiString(pIndex[i].ullKey, szAnsiKey);
  727. //
  728. // If the original pattern match is more than eight characters, we have
  729. // to plant an asterisk at the eighth character so that proper wildcard
  730. // matching occurs.
  731. //
  732. szAnsiKey[8] = '*';
  733. //
  734. // Quick check of the string that's in the key.
  735. //
  736. if (!SdbpPatternMatchAnsi(szAnsiKey, szAnsiName)) {
  737. continue;
  738. }
  739. //
  740. // We found a tentative match, now pull the full record and
  741. // see if it's real.
  742. //
  743. tiMatch = pIndex[i].tiRef;
  744. //
  745. // Get the key field.
  746. //
  747. tiKey = SdbFindFirstTag(pdb, tiMatch, pFindInfo->tName);
  748. if (tiKey == TAGID_NULL) {
  749. //
  750. // This is not a bug, but rather continue searching
  751. //
  752. continue;
  753. }
  754. szDBName = SdbGetStringTagPtr(pdb, tiKey);
  755. if (szDBName == NULL) {
  756. // BUGBUG: what if this fails ?
  757. continue;
  758. }
  759. //
  760. // Is this really a match?
  761. //
  762. if (SdbpPatternMatch(szDBName, pFindInfo->szName)) {
  763. pFindInfo->dwIndexRec = i;
  764. return tiMatch;
  765. }
  766. }
  767. // BUGBUG: DPF
  768. return TAGID_NULL;
  769. }
  770. TAGID
  771. SdbpFindNextIndexedWildCardTag(
  772. PDB pdb,
  773. FIND_INFO* pFindInfo
  774. )
  775. /*++
  776. Return: ?
  777. Desc: ?
  778. --*/
  779. {
  780. char szAnsiName[MAX_PATH];
  781. char szAnsiKey[10];
  782. PINDEX_RECORD pIndex = NULL;
  783. DWORD dwRecs;
  784. NTSTATUS status;
  785. DWORD i, j;
  786. RtlZeroMemory(szAnsiName, MAX_PATH);
  787. RtlZeroMemory(szAnsiKey, 10);
  788. //
  789. // Get the uppercase ANSI version of this search string so
  790. // it will match the keys in the index.
  791. //
  792. status = UPCASE_UNICODETOMULTIBYTEN(szAnsiName,
  793. CHARCOUNT(szAnsiName),
  794. pFindInfo->szName);
  795. if (!NT_SUCCESS(status)) {
  796. // BUGBUG: DPF
  797. return TAGID_NULL;
  798. }
  799. //
  800. // Get the index.
  801. //
  802. pIndex = SdbpGetIndex(pdb, pFindInfo->tiIndex, &dwRecs);
  803. if (pIndex == NULL) {
  804. // BUGBUG: DPF
  805. return TAGID_NULL;
  806. }
  807. //
  808. // Walk through the rest of the index sequentially, doing a first pass
  809. // check of the key so we can avoid getting the whole record if the
  810. // name clearly isn't a match.
  811. //
  812. for (i = pFindInfo->dwIndexRec + 1; i < dwRecs; ++i) {
  813. TAGID tiMatch;
  814. TAGID tiKey;
  815. LPTSTR pszDBName;
  816. ULONGLONG ullKey;
  817. READ_INDEX_KEY(pIndex, i, &ullKey);
  818. SdbpKeyToAnsiString(ullKey, szAnsiKey);
  819. //
  820. // If the original pattern match is more than eight characters, we have
  821. // to plant an asterisk at the eighth character so that proper wildcard
  822. // matching occurs.
  823. //
  824. szAnsiKey[8] = '*';
  825. //
  826. // Quick check of the string that's in the key.
  827. //
  828. if (!SdbpPatternMatchAnsi(szAnsiKey, szAnsiName)) {
  829. // BUGBUG: DPF
  830. continue;
  831. }
  832. //
  833. // We found a tentative match, now pull the full record and
  834. // see if it's real.
  835. //
  836. tiMatch = pIndex[i].tiRef;
  837. //
  838. // Get the key field.
  839. //
  840. tiKey = SdbFindFirstTag(pdb, tiMatch, pFindInfo->tName);
  841. if (tiKey == TAGID_NULL) {
  842. // BUGBUG: DPF
  843. continue;
  844. }
  845. pszDBName = SdbGetStringTagPtr(pdb, tiKey);
  846. if (pszDBName == NULL) {
  847. // BUGBUG: DPF
  848. continue;
  849. }
  850. //
  851. // Is this really a match?
  852. //
  853. if (SdbpPatternMatch(pszDBName, pFindInfo->szName)) {
  854. pFindInfo->dwIndexRec = i;
  855. return tiMatch;
  856. }
  857. }
  858. // BUGBUG: DPF
  859. return TAGID_NULL;
  860. }
  861. //
  862. // Index access functions (for reading) -- better to use tiFindFirstIndexedTag, above
  863. //
  864. TAGID
  865. SdbGetIndex(
  866. IN PDB pdb, // db to use
  867. IN TAG tWhich, // tag we'd like an index for
  868. IN TAG tKey, // the kind of tag used as a key for this index
  869. OUT LPDWORD lpdwFlags // index record flags (e.g. indicator whether the index
  870. // is "unique" style
  871. )
  872. /*++
  873. Return: TAGID of index, or TAGID_NULL.
  874. Desc: Retrieves a TAGID ptr to the index bits for a specific
  875. tag, if one exists.
  876. --*/
  877. {
  878. TAGID tiReturn = TAGID_NULL;
  879. int i;
  880. //
  881. // Scan the indexes if not done already.
  882. //
  883. if (!pdb->bIndexesScanned) {
  884. SdbpScanIndexes(pdb);
  885. }
  886. for (i = 0; i < MAX_INDEXES; ++i) {
  887. if (!pdb->aIndexes[i].tWhich) {
  888. DBGPRINT((sdlInfo,
  889. "SdbGetIndex",
  890. "index 0x%x(0x%x) was not found in the index table\n",
  891. tWhich,
  892. tKey));
  893. return TAGID_NULL;
  894. }
  895. if (pdb->aIndexes[i].tWhich == tWhich && pdb->aIndexes[i].tKey == tKey) {
  896. tiReturn = pdb->aIndexes[i].tiIndex;
  897. if (lpdwFlags != NULL) {
  898. *lpdwFlags = pdb->aIndexes[i].dwFlags;
  899. }
  900. break;
  901. }
  902. }
  903. return tiReturn;
  904. }
  905. void
  906. SdbpScanIndexes(
  907. IN PDB pdb // db to use
  908. )
  909. /*++
  910. Params: described above.
  911. Return: void. No failure case.
  912. Desc: Scans the initial tags in the DB and gets the index pointer info.
  913. --*/
  914. {
  915. TAGID tiFirst;
  916. TAGID tiIndex;
  917. if (pdb->bIndexesScanned && !pdb->bWrite) {
  918. //
  919. // This is not an error condition
  920. //
  921. return;
  922. }
  923. RtlZeroMemory(pdb->aIndexes, sizeof(pdb->aIndexes));
  924. pdb->bIndexesScanned = TRUE;
  925. //
  926. // The indexes must be the first tag.
  927. //
  928. tiFirst = SdbGetFirstChild(pdb, TAGID_ROOT);
  929. if (tiFirst == TAGID_NULL) {
  930. DBGPRINT((sdlError,
  931. "SdbpScanIndexes",
  932. "Failed to get the child index from root\n"));
  933. return;
  934. }
  935. if (SdbGetTagFromTagID(pdb, tiFirst) != TAG_INDEXES) {
  936. DBGPRINT((sdlError,
  937. "SdbpScanIndexes",
  938. "Root child tag is not index tagid 0x%lx\n",
  939. tiFirst));
  940. return;
  941. }
  942. pdb->dwIndexes = 0;
  943. tiIndex = SdbFindFirstTag(pdb, tiFirst, TAG_INDEX);
  944. while (tiIndex != TAGID_NULL) {
  945. TAGID tiIndexTag;
  946. TAGID tiIndexKey;
  947. TAGID tiIndexBits;
  948. TAGID tiIndexFlags;
  949. if (pdb->dwIndexes == MAX_INDEXES) {
  950. DBGPRINT((sdlError,
  951. "SdbpScanIndexes",
  952. "Too many indexes in file. Recompile and increase MAX_INDEXES.\n"));
  953. return;
  954. }
  955. tiIndexTag = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_TAG);
  956. if (tiIndexTag == TAGID_NULL) {
  957. DBGPRINT((sdlError,
  958. "SdbpScanIndexes",
  959. "Index missing TAG_INDEX_TAG.\n"));
  960. return;
  961. }
  962. pdb->aIndexes[pdb->dwIndexes].tWhich = SdbReadWORDTag(pdb, tiIndexTag, TAG_NULL);
  963. tiIndexKey = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_KEY);
  964. if (tiIndexKey == TAGID_NULL) {
  965. DBGPRINT((sdlError, "SdbpScanIndexes", "Index missing TAG_INDEX_KEY.\n"));
  966. return;
  967. }
  968. pdb->aIndexes[pdb->dwIndexes].tKey = SdbReadWORDTag(pdb, tiIndexKey, TAG_NULL);
  969. tiIndexFlags = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_FLAGS);
  970. if (tiIndexFlags != TAGID_NULL) {
  971. pdb->aIndexes[pdb->dwIndexes].dwFlags = SdbReadDWORDTag(pdb, tiIndexFlags, 0);
  972. } else {
  973. pdb->aIndexes[pdb->dwIndexes].dwFlags = 0;
  974. }
  975. tiIndexBits = SdbFindFirstTag(pdb, tiIndex, TAG_INDEX_BITS);
  976. if (tiIndexBits == TAGID_NULL) {
  977. pdb->aIndexes[pdb->dwIndexes].tWhich = TAG_NULL;
  978. DBGPRINT((sdlError, "SdbpScanIndexes", "Index missing TAG_INDEX_BITS.\n"));
  979. return;
  980. }
  981. pdb->aIndexes[pdb->dwIndexes].tiIndex = tiIndexBits;
  982. pdb->dwIndexes++;
  983. tiIndex = SdbFindNextTag(pdb, tiFirst, tiIndex);
  984. }
  985. return;
  986. }
  987. PINDEX_RECORD
  988. SdbpGetIndex(
  989. IN PDB pdb,
  990. IN TAGID tiIndex,
  991. OUT DWORD* pdwNumRecs
  992. )
  993. /*++
  994. Return: ?
  995. Desc: ?
  996. --*/
  997. {
  998. if (SdbGetTagFromTagID(pdb, tiIndex) != TAG_INDEX_BITS) {
  999. DBGPRINT((sdlError,
  1000. "SdbpGetIndex",
  1001. "Index tagid 0x%lx is not referring to the index bits\n",
  1002. tiIndex));
  1003. return NULL;
  1004. }
  1005. *pdwNumRecs = SdbGetTagDataSize(pdb, tiIndex) / sizeof(INDEX_RECORD);
  1006. return (PINDEX_RECORD)SdbpGetMappedTagData(pdb, tiIndex);
  1007. }
  1008. #if defined(_WIN64)
  1009. ULONGLONG
  1010. SdbMakeIndexKeyFromGUID(
  1011. IN GUID* pGuid
  1012. )
  1013. /*
  1014. Return: a 64-bit key to use for searching
  1015. Desc: The standard index key is created for a Guid
  1016. using the xor operation on a first and second half
  1017. of guid
  1018. */
  1019. {
  1020. ULONGLONG ullPart1 = 0,
  1021. ullPart2 = 0;
  1022. RtlMoveMemory(&ullPart1, pGuid, sizeof(ULONGLONG));
  1023. RtlMoveMemory(&ullPart2, (PBYTE)pGuid + sizeof(ULONGLONG), sizeof(ULONGLONG));
  1024. return (ullPart1 ^ ullPart2);
  1025. }
  1026. #endif // _WIN64
  1027. #define SDB_KEY_LENGTH_BYTES 8
  1028. #define SDB_KEY_LENGTH 8
  1029. ULONGLONG
  1030. SdbMakeIndexKeyFromString(
  1031. IN LPCTSTR szKey
  1032. )
  1033. /*++
  1034. Return: a 64-bit key to use for searching.
  1035. Desc: The standard index key for a Unicode string is the
  1036. first 8 characters of the string, converted to uppercase ansi,
  1037. then cast to a ULONGLONG (64 bit unsigned int).
  1038. --*/
  1039. {
  1040. char szFlippedKey[SDB_KEY_LENGTH_BYTES]; // flipped to deal with little-endian issues
  1041. char* pszKey = &szFlippedKey[SDB_KEY_LENGTH_BYTES-1]; // points to the last char
  1042. NTSTATUS status;
  1043. int i;
  1044. WCHAR ch;
  1045. int nLength;
  1046. #ifndef WIN32A_MODE
  1047. UNICODE_STRING ustrKey;
  1048. UNICODE_STRING ustrKeySrc; // truncated string
  1049. UNICODE_STRING ustrKeySrcUpcased;
  1050. WCHAR Buffer[SDB_KEY_LENGTH];
  1051. WCHAR BufferUpcased[SDB_KEY_LENGTH];
  1052. LPCWSTR pKeyBuffer = BufferUpcased;
  1053. NTSTATUS Status;
  1054. RtlInitUnicodeString(&ustrKey, szKey);
  1055. //
  1056. // Call below copies upto maximum length of the destination string
  1057. //
  1058. ustrKeySrc.Buffer = Buffer;
  1059. ustrKeySrc.MaximumLength = sizeof(Buffer);
  1060. RtlCopyUnicodeString(&ustrKeySrc, &ustrKey);
  1061. //
  1062. // Upcase what we have created
  1063. //
  1064. ustrKeySrcUpcased.Buffer = BufferUpcased;
  1065. ustrKeySrcUpcased.MaximumLength = sizeof(BufferUpcased);
  1066. Status = RtlUpcaseUnicodeString(&ustrKeySrcUpcased, &ustrKeySrc, FALSE);
  1067. if (!NT_SUCCESS(Status)) {
  1068. DBGPRINT((sdlError,
  1069. "SdbMakeIndexKeyFromString",
  1070. "Failed to upcase unicode string \"%s\"\n",
  1071. szKey));
  1072. return 0;
  1073. }
  1074. //
  1075. // Now we have an upper-case unicode string which is of max. 8 characters length
  1076. //
  1077. nLength = ustrKeySrcUpcased.Length / sizeof(WCHAR);
  1078. #else // WIN32A_MODE
  1079. WCHAR Buffer[SDB_KEY_LENGTH + 1];
  1080. LPCWSTR pKeyBuffer = Buffer;
  1081. nLength = mbstowcs(Buffer, szKey, CHARCOUNT(Buffer));
  1082. if (nLength < 0) {
  1083. DBGPRINT((sdlError,
  1084. "SdbMakeIndexKeyFromString",
  1085. "Failed to convert string \"%s\" to unicode\n",
  1086. szKey));
  1087. return 0;
  1088. }
  1089. Buffer[nLength] = TEXT('\0'); // zero-terminate
  1090. //
  1091. // Upcase now. Buffer is always 0-terminated.
  1092. //
  1093. _wcsupr(Buffer);
  1094. #endif // WIN32A_MODE
  1095. assert(nLength <= SDB_KEY_LENGTH);
  1096. RtlZeroMemory(szFlippedKey , sizeof(szFlippedKey));
  1097. //
  1098. // To be compatible with the old (ANSI) scheme of making keys, we
  1099. // construct the key using all non-null bytes in the string, up to 8
  1100. //
  1101. for (i = 0; i < nLength; ++i) {
  1102. ch = *pKeyBuffer++;
  1103. *pszKey-- = (unsigned char)ch;
  1104. //
  1105. // ch is a unicode char, whatever it is, see if it has 2 bytes or just one
  1106. //
  1107. if (HIBYTE(ch) && i < (SDB_KEY_LENGTH - 1)) {
  1108. //
  1109. // Two bytes, store both
  1110. //
  1111. *pszKey-- = (unsigned char)HIBYTE(ch);
  1112. ++i;
  1113. }
  1114. }
  1115. return *((ULONGLONG*)szFlippedKey);
  1116. }
  1117. ULONGLONG
  1118. SdbpTagToKey(
  1119. IN PDB pdb,
  1120. IN TAGID tiTag
  1121. )
  1122. /*++
  1123. Return: ?
  1124. Desc: ?
  1125. --*/
  1126. {
  1127. TAG_TYPE ttType;
  1128. ULONGLONG ullReturn = 0;
  1129. DWORD dwSize;
  1130. PVOID pData;
  1131. LPTSTR szTemp = NULL;
  1132. ttType = GETTAGTYPE(SdbGetTagFromTagID(pdb, tiTag));
  1133. switch (ttType) {
  1134. case TAG_TYPE_STRING:
  1135. case TAG_TYPE_STRINGREF:
  1136. szTemp = SdbGetStringTagPtr(pdb, tiTag);
  1137. if (!szTemp) {
  1138. ullReturn = 0;
  1139. } else {
  1140. ullReturn = SdbMakeIndexKeyFromString(szTemp);
  1141. }
  1142. break;
  1143. case TAG_TYPE_NULL:
  1144. ullReturn = 1;
  1145. break;
  1146. case TAG_TYPE_BINARY: // indexing binary data
  1147. // check that the size of the data is sizeof(GUID)
  1148. if (sizeof(GUID) == SdbGetTagDataSize(pdb, tiTag)) {
  1149. //
  1150. // Special case.
  1151. //
  1152. pData = SdbpGetMappedTagData(pdb, tiTag);
  1153. if (pData == NULL) {
  1154. return 0;
  1155. }
  1156. ullReturn = MAKEKEYFROMGUID((GUID*)pData);
  1157. break;
  1158. }
  1159. //
  1160. // Fall through to the general binary data case.
  1161. //
  1162. default:
  1163. dwSize = SdbGetTagDataSize(pdb, tiTag);
  1164. if (dwSize > sizeof(ULONGLONG)) {
  1165. dwSize = sizeof(ULONGLONG);
  1166. }
  1167. pData = SdbpGetMappedTagData(pdb, tiTag);
  1168. if (pData == NULL) {
  1169. return 0;
  1170. }
  1171. memcpy(&ullReturn, pData, dwSize);
  1172. break;
  1173. }
  1174. return ullReturn;
  1175. }