Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1401 lines
40 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. dbaccessplus.c
  5. Abstract:
  6. This module implements APIs to access the shim database.
  7. Author:
  8. clupu created sometime in 2001
  9. Revision History:
  10. several people contributed (vadimb, dmunsil, ...)
  11. --*/
  12. #include "sdbp.h"
  13. //
  14. // This file is not included for KERNEL_MODE
  15. //
  16. //
  17. // SdbInitDatabase is not used in Kernel mode. SdbInitDatabaseInMemory is used instead
  18. //
  19. HSDB
  20. SdbInitDatabase(
  21. IN DWORD dwFlags, // flags that tell how the database should be
  22. // initialized.
  23. IN LPCTSTR pszDatabasePath // the OPTIONAL full path to the database to be used.
  24. )
  25. /*++
  26. Return: A handle to the database.
  27. Desc: This is the first API someone needs to call to initiate comunication
  28. with the database. Should be paired with a call to SdbReleaseDatabase
  29. when finished.
  30. HID_DATABASE_FULLPATH indicates that pszDatabasePath points to the full path of the
  31. main database, when this flag is not present and pszDatabasePath
  32. is not NULL we treat it as the directory where sysmain.sdb and
  33. systest.sdb are to be found
  34. HID_DOS_PATHS indicates the format of the pszDatabasePath: when this flag is
  35. present, we treat it as being in dos c:\blah\blah format, when
  36. it's not present - we treat pszDatabasePath as being in nt format
  37. e.g. "\SystemRoot\Apppatch"
  38. HID_NO_DATABASE indicates that no database will be open at this time
  39. (pszDatabasePath is simply ignored, along with all
  40. the other flags)
  41. In addition to the flags above you can specify the type of the database that needs to be
  42. opened via the SDB_DATABASE_MAIN_* flags such as:
  43. SDB_DATABASE_MAIN_SHIM - sysmain.sdb
  44. SDB_DATABASE_MAIN_MSI - msimain.sdb
  45. SDB_DATABASE_MAIN_DRIVERS - drvmain.sdb
  46. This feature is not present on downlevel platforms.
  47. When any of the database type flags are provided, pszDatabasePath should be set to NULL
  48. --*/
  49. {
  50. // check whether the database we're trying to open is msi,
  51. // if so -- set the image type to msi
  52. USHORT uExeType = DEFAULT_IMAGE;
  53. if (dwFlags & HID_DATABASE_TYPE_MASK) {
  54. DWORD dwType = (dwFlags & HID_DATABASE_TYPE_MASK);
  55. //
  56. // check to see whether this database is msi -- if so, set image type accordingly
  57. //
  58. if (dwType == SDB_DATABASE_MAIN_MSI) {
  59. uExeType = (USHORT)IMAGE_FILE_MSI;
  60. }
  61. if (dwFlags & (HID_DATABASE_FULLPATH | HID_DOS_PATHS | HID_NO_DATABASE)) {
  62. //
  63. // there should be no "type" flags
  64. //
  65. dwFlags &= ~HID_DATABASE_TYPE_MASK;
  66. }
  67. }
  68. return SdbInitDatabaseEx(dwFlags, pszDatabasePath, uExeType);
  69. }
  70. HSDB
  71. SdbInitDatabaseEx(
  72. IN DWORD dwFlags, // flags that tell how the database should be
  73. // initialized.
  74. IN LPCTSTR pszDatabasePath,// the OPTIONAL full path to the database to be used.
  75. IN USHORT uExeType // executable's image type
  76. )
  77. /*++
  78. Return: A handle to the database.
  79. Desc: This is the first API someone needs to call to initiate comunication
  80. with the database. Should be paired with a call to SdbReleaseDatabase
  81. when finished.
  82. HID_DATABASE_FULLPATH indicates that pszDatabasePath points to the full path of the
  83. main database, when this flag is not present and pszDatabasePath
  84. is not NULL we treat it as the directory where sysmain.sdb and
  85. systest.sdb are to be found
  86. HID_DOS_PATHS indicates the format of the pszDatabasePath: when this flag is
  87. present, we treat it as being in dos c:\blah\blah format, when
  88. it's not present - we treat pszDatabasePath as being in nt format
  89. e.g. "\SystemRoot\Apppatch"
  90. HID_NO_DATABASE indicates that no database will be open at this time
  91. (pszDatabasePath is simply ignored, along with all
  92. the other flags)
  93. In addition to the flags above you can specify the type of the database that needs to be
  94. opened via the SDB_DATABASE_MAIN_* flags such as:
  95. SDB_DATABASE_MAIN_SHIM - sysmain.sdb
  96. SDB_DATABASE_MAIN_MSI - msimain.sdb
  97. SDB_DATABASE_MAIN_DRIVERS - drvmain.sdb
  98. This feature is not present on downlevel platforms.
  99. When any of the database type flags are provided, pszDatabasePath should be set to NULL
  100. --*/
  101. {
  102. TCHAR wszShimDB[MAX_PATH] = TEXT("");
  103. PSDBCONTEXT pContext;
  104. DWORD dwFlagOpen = 0;
  105. //
  106. // Allocate the HSDB handle.
  107. //
  108. pContext = (PSDBCONTEXT)SdbAlloc(sizeof(SDBCONTEXT));
  109. if (pContext == NULL) {
  110. DBGPRINT((sdlError, "SdbInitDatabaseEx", "Failed to allocate %d bytes for HSDB\n",
  111. sizeof(SDBCONTEXT)));
  112. return NULL;
  113. }
  114. pContext->uExeType = uExeType;
  115. //
  116. // See if we need to open db...
  117. //
  118. if (dwFlags & HID_NO_DATABASE) {
  119. DBGPRINT((sdlInfo, "SdbInitDatabaseEx", "No database is open\n"));
  120. goto InitDone;
  121. }
  122. //
  123. // Determine which flag to use with the OPEN call
  124. //
  125. dwFlagOpen = (dwFlags & HID_DOS_PATHS) ? DOS_PATH : NT_PATH;
  126. //
  127. // Open the main database and do this under a try/except so we don't kill
  128. // our caller if the database is corrupt.
  129. //
  130. __try {
  131. if (dwFlags & HID_DATABASE_FULLPATH) {
  132. // we better have the ptr
  133. if (pszDatabasePath == NULL) {
  134. DBGPRINT((sdlError, "SdbInitDatabaseEx",
  135. "Database not specified with the database path flag\n"));
  136. goto errHandle;
  137. }
  138. StringCchCopy(wszShimDB,
  139. CHARCOUNT(wszShimDB),
  140. pszDatabasePath);
  141. } else {
  142. //
  143. // we do not have a database path
  144. // see if we have a database type to open as a "main" db
  145. //
  146. #ifndef WIN32A_MODE
  147. //
  148. // This code works only on UNICODE
  149. //
  150. if (dwFlags & HID_DATABASE_TYPE_MASK) {
  151. DWORD dwDatabaseType = dwFlags;
  152. DWORD dwLen;
  153. dwLen = SdbpGetStandardDatabasePath((HSDB)pContext,
  154. dwDatabaseType,
  155. dwFlags,
  156. wszShimDB,
  157. CHARCOUNT(wszShimDB));
  158. if (dwLen > CHARCOUNT(wszShimDB)) {
  159. DBGPRINT((sdlError,
  160. "SdbInitDatabaseEx",
  161. "Cannot get standard database path\n"));
  162. goto errHandle;
  163. }
  164. } else
  165. #endif // WIN32A_MODE
  166. {
  167. if (pszDatabasePath != NULL) {
  168. int nLen;
  169. StringCchCopy(wszShimDB,
  170. CHARCOUNT(wszShimDB),
  171. pszDatabasePath);
  172. nLen = (int)_tcslen(wszShimDB);
  173. if (nLen > 0 && TEXT('\\') == wszShimDB[nLen-1]) {
  174. wszShimDB[nLen-1] = TEXT('\0');
  175. }
  176. } else { // standard database path
  177. if (dwFlags & HID_DOS_PATHS) {
  178. SdbpGetAppPatchDir((HSDB)pContext, wszShimDB, CHARCOUNT(wszShimDB));
  179. } else {
  180. if (uExeType == IMAGE_FILE_MACHINE_IA64) {
  181. StringCchCopy(wszShimDB,
  182. CHARCOUNT(wszShimDB),
  183. TEXT("\\SystemRoot\\AppPatch\\IA64"));
  184. } else {
  185. StringCchCopy(wszShimDB,
  186. CHARCOUNT(wszShimDB),
  187. TEXT("\\SystemRoot\\AppPatch"));
  188. }
  189. }
  190. }
  191. StringCchCat(wszShimDB, CHARCOUNT(wszShimDB), TEXT("\\sysmain.sdb"));
  192. }
  193. }
  194. pContext->pdbMain = SdbOpenDatabase(wszShimDB, dwFlagOpen);
  195. } __except(SHIM_EXCEPT_HANDLER) {
  196. pContext->pdbMain = NULL;
  197. }
  198. if (pContext->pdbMain == NULL) {
  199. DBGPRINT((sdlError, "SdbInitDatabaseEx", "Unable to open main database sysmain.sdb.\n"));
  200. goto errHandle;
  201. }
  202. if (dwFlags & HID_DATABASE_FULLPATH) {
  203. // we are done, no test db
  204. goto InitDone;
  205. }
  206. //
  207. // Now try to open the systest.sdb if it exists.
  208. //
  209. __try {
  210. if (NULL != pszDatabasePath) {
  211. int nLen;
  212. StringCchCopy(wszShimDB, CHARCOUNT(wszShimDB), pszDatabasePath);
  213. nLen = (int)_tcslen(wszShimDB);
  214. if (nLen > 0 && TEXT('\\') == wszShimDB[nLen-1]) {
  215. wszShimDB[nLen-1] = TEXT('\0');
  216. }
  217. } else { // standard database path
  218. if (dwFlags & HID_DOS_PATHS) {
  219. SdbpGetAppPatchDir((HSDB)pContext, wszShimDB, CHARCOUNT(wszShimDB));
  220. } else {
  221. if (uExeType == IMAGE_FILE_MACHINE_IA64) {
  222. StringCchCopy(wszShimDB,
  223. CHARCOUNT(wszShimDB),
  224. TEXT("\\SystemRoot\\AppPatch\\IA64"));
  225. } else {
  226. StringCchCopy(wszShimDB,
  227. CHARCOUNT(wszShimDB),
  228. TEXT("\\SystemRoot\\AppPatch"));
  229. }
  230. }
  231. }
  232. StringCchCat(wszShimDB, CHARCOUNT(wszShimDB), TEXT("\\systest.sdb"));
  233. pContext->pdbTest = SdbOpenDatabase(wszShimDB, dwFlagOpen);
  234. } __except(SHIM_EXCEPT_HANDLER) {
  235. pContext->pdbTest = NULL;
  236. }
  237. if (pContext->pdbTest == NULL) {
  238. DBGPRINT((sdlInfo, "SdbInitDatabaseEx", "No systest.sdb found.\n"));
  239. }
  240. InitDone:
  241. //
  242. // Initialize new members (local db support)
  243. //
  244. if (pContext->pdbMain) {
  245. pContext->rgSDB[0].pdb = pContext->pdbMain;
  246. pContext->rgSDB[0].dwFlags = SDBENTRY_VALID_ENTRY|SDBENTRY_VALID_GUID;
  247. RtlCopyMemory(&pContext->rgSDB[0].guidDB, &GUID_SYSMAIN_SDB, sizeof(GUID));
  248. SDBCUSTOM_SET_MASK(pContext, SDB_MASK_TO_INDEX(PDB_MAIN));
  249. }
  250. if (pContext->pdbTest) {
  251. pContext->rgSDB[1].pdb = pContext->pdbTest;
  252. pContext->rgSDB[1].dwFlags = SDBENTRY_VALID_ENTRY|SDBENTRY_VALID_GUID;
  253. RtlCopyMemory(&pContext->rgSDB[1].guidDB, &GUID_SYSTEST_SDB, sizeof(GUID));
  254. SDBCUSTOM_SET_MASK(pContext, SDB_MASK_TO_INDEX(PDB_TEST));
  255. }
  256. //
  257. // Initialize architecture
  258. //
  259. pContext->dwRuntimePlatform = SdbpGetProcessorArchitecture(uExeType);
  260. //
  261. // Initialize OS SKU and SP
  262. //
  263. SdbpGetOSSKU(&pContext->dwOSSKU, &pContext->dwSPMask);
  264. return (HSDB)pContext;
  265. errHandle:
  266. //
  267. // Cleanup on failure.
  268. //
  269. if (pContext != NULL) {
  270. if (pContext->pdbMain != NULL) {
  271. SdbCloseDatabaseRead(pContext->pdbMain);
  272. }
  273. if (pContext->pdbTest != NULL) {
  274. SdbCloseDatabaseRead(pContext->pdbTest);
  275. }
  276. SdbFree(pContext);
  277. }
  278. return NULL;
  279. }
  280. VOID
  281. SdbSetImageType(
  282. IN HSDB hSDB,
  283. IN USHORT uExeType
  284. )
  285. /*++
  286. This function is used to override default image type for the context
  287. Used by msi-related function in apphelp.dll
  288. --*/
  289. {
  290. ((PSDBCONTEXT)hSDB)->uExeType = uExeType;
  291. }
  292. BOOL
  293. SdbpOpenAndMapFile(
  294. IN LPCTSTR szPath, // Filename
  295. OUT PIMAGEFILEDATA pImageData, // pointer to the structure to be filled
  296. IN PATH_TYPE ePathType // path type, only DOS_PATH is supported on win32
  297. )
  298. /*++
  299. Return: TRUE on success, FALSE otherwise.
  300. Desc: Opens a file and maps it into memory.
  301. --*/
  302. {
  303. HANDLE hFile;
  304. DWORD dwFlags = 0;
  305. if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) {
  306. //
  307. // special case, only headers are valid in our assumption
  308. //
  309. return TRUE;
  310. }
  311. if (pImageData->dwFlags & IMAGEFILEDATA_HANDLEVALID) {
  312. hFile = pImageData->hFile;
  313. dwFlags |= IMAGEFILEDATA_NOFILECLOSE;
  314. } else {
  315. hFile = SdbpOpenFile(szPath, ePathType);
  316. }
  317. if (hFile == INVALID_HANDLE_VALUE) {
  318. return FALSE;
  319. }
  320. if (!SdbpMapFile(hFile, pImageData)) {
  321. if (!(dwFlags & IMAGEFILEDATA_NOFILECLOSE)) {
  322. SdbpCloseFile(hFile);
  323. }
  324. return FALSE;
  325. }
  326. pImageData->dwFlags = dwFlags;
  327. return TRUE;
  328. }
  329. BOOL
  330. SdbpUnmapAndCloseFile(
  331. IN PIMAGEFILEDATA pImageData
  332. )
  333. /*++
  334. Return: BUGBUG: ?
  335. Desc: BUGBUG: ?
  336. --*/
  337. {
  338. HANDLE hFile;
  339. BOOL bSuccess;
  340. if (pImageData->dwFlags & IMAGEFILEDATA_PBASEVALID) { // externally supplied pointer
  341. RtlZeroMemory(pImageData, sizeof(*pImageData));
  342. return TRUE;
  343. }
  344. hFile = pImageData->hFile;
  345. bSuccess = SdbpUnmapFile(pImageData);
  346. if (hFile != INVALID_HANDLE_VALUE) {
  347. if (pImageData->dwFlags & IMAGEFILEDATA_NOFILECLOSE) {
  348. pImageData->hFile = INVALID_HANDLE_VALUE;
  349. } else {
  350. SdbpCloseFile(hFile);
  351. }
  352. }
  353. return bSuccess;
  354. }
  355. BOOL
  356. SdbpCleanupLocalDatabaseSupport(
  357. IN HSDB hSDB
  358. )
  359. {
  360. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  361. DWORD dwIndex;
  362. DWORD dwMask;
  363. //
  364. // Ee start with entry 2 -- to include local sdbs
  365. //
  366. if (pSdbContext->dwDatabaseMask & SDB_CUSTOM_MASK) {
  367. for (dwIndex = 3; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
  368. dwMask = 1 << dwIndex;
  369. if (pSdbContext->dwDatabaseMask & dwMask) {
  370. SdbCloseLocalDatabaseEx(hSDB, NULL, dwIndex);
  371. }
  372. }
  373. }
  374. //
  375. // Always check for entry 2 (local sdb)
  376. //
  377. if (pSdbContext->pdbLocal != NULL) {
  378. SdbCloseLocalDatabaseEx(hSDB, NULL, SDB_MASK_TO_INDEX(PDB_LOCAL));
  379. }
  380. return TRUE;
  381. }
  382. BOOL
  383. SdbpIsLocalTempPDB(
  384. IN HSDB hSDB,
  385. IN PDB pdb
  386. )
  387. {
  388. PSDBENTRY pEntry = SDBGETLOCALENTRY(hSDB);
  389. if (pEntry->dwFlags & SDBENTRY_VALID_ENTRY) {
  390. return pdb == pEntry->pdb;
  391. }
  392. return FALSE;
  393. }
  394. BOOL
  395. SdbpIsMainPDB(
  396. IN HSDB hSDB,
  397. IN PDB pdb
  398. )
  399. {
  400. DWORD dwIndex;
  401. if (!SdbpFindLocalDatabaseByPDB(hSDB, pdb, FALSE, &dwIndex)) {
  402. return FALSE;
  403. }
  404. return (dwIndex == SDB_MASK_TO_INDEX(PDB_MAIN) || dwIndex == SDB_MASK_TO_INDEX(PDB_TEST));
  405. }
  406. BOOL
  407. SdbpFindLocalDatabaseByPDB(
  408. IN HSDB hSDB,
  409. IN PDB pdb,
  410. IN BOOL bExcludeLocalDB, // exclude local db entry?
  411. OUT LPDWORD pdwIndex
  412. )
  413. {
  414. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  415. DWORD dwIndex;
  416. PSDBENTRY pEntry;
  417. BOOL bSuccess = FALSE;
  418. for (dwIndex = 0; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
  419. if (bExcludeLocalDB && dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
  420. continue;
  421. }
  422. if (!SDBCUSTOM_CHECK_INDEX(hSDB, dwIndex)) {
  423. continue;
  424. }
  425. pEntry = &pSdbContext->rgSDB[dwIndex];
  426. if ((pEntry->dwFlags & SDBENTRY_VALID_ENTRY) && (pdb == pEntry->pdb)) {
  427. bSuccess = TRUE;
  428. break;
  429. }
  430. }
  431. if (bSuccess && pdwIndex != NULL) {
  432. *pdwIndex = dwIndex;
  433. }
  434. return bSuccess;
  435. }
  436. BOOL
  437. SdbpFindLocalDatabaseByGUID(
  438. IN HSDB hSDB,
  439. IN GUID* pGuidDB,
  440. IN BOOL bExcludeLocalDB,
  441. OUT LPDWORD pdwIndex // this index (if valid) will work as an initial point for comparison
  442. )
  443. {
  444. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  445. PSDBENTRY pEntry;
  446. DWORD dwIndex;
  447. for (dwIndex = 0; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
  448. if (bExcludeLocalDB && dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
  449. continue;
  450. }
  451. if (!SDBCUSTOM_CHECK_INDEX(hSDB, dwIndex)) {
  452. continue;
  453. }
  454. pEntry = SDBGETENTRY(hSDB, dwIndex);
  455. if (!(pEntry->dwFlags & SDBENTRY_VALID_GUID)) {
  456. //
  457. // if this happens to be a valid database -- get it's guid
  458. //
  459. if ((pEntry->dwFlags & SDBENTRY_VALID_ENTRY) && (pEntry->pdb != NULL)) {
  460. //
  461. // retrieve guid
  462. //
  463. GUID guidDB;
  464. if (SdbGetDatabaseGUID(hSDB, pEntry->pdb, &guidDB)) {
  465. pEntry->guidDB = guidDB;
  466. pEntry->dwFlags |= SDBENTRY_VALID_GUID;
  467. goto checkEntry;
  468. }
  469. }
  470. continue;
  471. }
  472. checkEntry:
  473. if (RtlEqualMemory(&pEntry->guidDB, pGuidDB, sizeof(GUID))) {
  474. if (pdwIndex) {
  475. *pdwIndex = dwIndex;
  476. }
  477. return TRUE;
  478. }
  479. }
  480. return FALSE;
  481. }
  482. DWORD
  483. SdbpFindFreeLocalEntry(
  484. IN HSDB hSDB
  485. )
  486. {
  487. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  488. DWORD dwIndex;
  489. for (dwIndex = 3; dwIndex < ARRAYSIZE(pSdbContext->rgSDB); ++dwIndex) {
  490. if (SDBCUSTOM_CHECK_INDEX(hSDB, dwIndex)) {
  491. continue;
  492. }
  493. if (!(pSdbContext->rgSDB[dwIndex].dwFlags & (SDBENTRY_VALID_ENTRY | SDBENTRY_VALID_GUID))) {
  494. return dwIndex;
  495. }
  496. }
  497. //
  498. // We have no entry
  499. //
  500. return SDBENTRY_INVALID_INDEX;
  501. }
  502. /*++
  503. returns SDBENTRY_INVALID_INDEX if none could be found
  504. if success, returns an index where the local db entry was found
  505. --*/
  506. DWORD
  507. SdbpRetainLocalDBEntry(
  508. IN HSDB hSDB,
  509. OUT PDB* ppPDB OPTIONAL // optional pointer to the pdb
  510. )
  511. {
  512. DWORD dwIndex = SDBENTRY_INVALID_INDEX;
  513. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  514. PSDBENTRY pEntry;
  515. PSDBENTRY pEntryLocal = SDBGETLOCALENTRY(hSDB);
  516. GUID guidDB;
  517. if (pEntryLocal->pdb == NULL || !(pEntryLocal->dwFlags & SDBENTRY_VALID_ENTRY)) {
  518. return SDBENTRY_INVALID_INDEX;
  519. }
  520. //
  521. // Recycling could be done here so that we reuse custom db entries which
  522. // may have been opened already (for instance set by __COMPAT_LAYER)
  523. //
  524. if (SdbGetDatabaseGUID(hSDB, pEntryLocal->pdb, &guidDB) &&
  525. SdbpFindLocalDatabaseByGUID(hSDB, &guidDB, TRUE, &dwIndex) &&
  526. dwIndex != SDBENTRY_INVALID_INDEX) {
  527. //
  528. // Close the local db
  529. //
  530. SdbCloseLocalDatabase(hSDB);
  531. pEntry = SDBGETENTRY(hSDB, dwIndex);
  532. pSdbContext->pdbLocal = pEntry->pdb;
  533. if (ppPDB != NULL) {
  534. *ppPDB = pEntry->pdb;
  535. }
  536. return dwIndex;
  537. }
  538. //
  539. // An attempt to recycle has failed -- allocate new entry
  540. //
  541. dwIndex = SdbpFindFreeLocalEntry(hSDB);
  542. if (dwIndex != SDBENTRY_INVALID_INDEX) {
  543. //
  544. // We have found an empty slot, relocate
  545. //
  546. pEntry = SDBGETENTRY(hSDB, dwIndex);
  547. RtlCopyMemory(pEntry, pEntryLocal, sizeof(SDBENTRY));
  548. RtlZeroMemory(pEntryLocal, sizeof(SDBENTRY));
  549. SDBCUSTOM_SET_MASK(hSDB, dwIndex);
  550. if (ppPDB != NULL) {
  551. *ppPDB = pEntry->pdb;
  552. }
  553. //
  554. // Note that pdbLocal is still valid, we never close this handle manually though
  555. //
  556. }
  557. return dwIndex;
  558. }
  559. BOOL
  560. SdbCloseLocalDatabaseEx(
  561. IN HSDB hSDB,
  562. IN PDB pdb,
  563. IN DWORD dwIndex
  564. )
  565. {
  566. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  567. PSDBENTRY pEntry;
  568. DWORD dwMask;
  569. if (pdb != NULL) {
  570. if (!SdbpFindLocalDatabaseByPDB(hSDB, pdb, FALSE, &dwIndex)) {
  571. return FALSE;
  572. }
  573. }
  574. dwMask = 1 << dwIndex;
  575. if (dwIndex >= ARRAYSIZE(pSdbContext->rgSDB) || !(pSdbContext->dwDatabaseMask & dwMask)) {
  576. return FALSE;
  577. }
  578. pEntry = &pSdbContext->rgSDB[dwIndex];
  579. if (pEntry->dwFlags & SDBENTRY_VALID_ENTRY) {
  580. if (pEntry->pdb) {
  581. SdbCloseDatabaseRead(pEntry->pdb);
  582. }
  583. }
  584. RtlZeroMemory(pEntry, sizeof(*pEntry));
  585. SDBCUSTOM_CLEAR_MASK(hSDB, dwIndex);
  586. if (dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
  587. pSdbContext->pdbLocal = NULL;
  588. }
  589. return TRUE;
  590. }
  591. BOOL
  592. SdbOpenLocalDatabaseEx(
  593. IN HSDB hSDB,
  594. IN LPCVOID pDatabaseID,
  595. IN DWORD dwFlags,
  596. OUT PDB* pPDB OPTIONAL,
  597. IN OUT LPDWORD pdwLocalDBMask OPTIONAL // local db mask for tagref
  598. )
  599. {
  600. PSDBCONTEXT pSdbContext = (PSDBCONTEXT)hSDB;
  601. PDB pdb = NULL;
  602. DWORD dwOpenFlags = DOS_PATH;
  603. TCHAR szDatabasePath[MAX_PATH];
  604. LPTSTR pszDatabasePath;
  605. GUID guidDB;
  606. GUID* pGuidDB;
  607. DWORD dwDatabaseType = 0;
  608. DWORD dwCount;
  609. BOOL bSuccess = FALSE;
  610. DWORD dwIndex;
  611. TCHAR* pszIA64;
  612. PSDBENTRY pEntry;
  613. if (!(SDBCUSTOM_FLAGS(dwFlags) & SDBCUSTOM_USE_INDEX)) {
  614. //
  615. // Find free local sdb entry
  616. //
  617. dwIndex = SdbpFindFreeLocalEntry(hSDB);
  618. if (dwIndex == SDBENTRY_INVALID_INDEX) {
  619. DBGPRINT((sdlError,
  620. "SdbOpenLocalDatabaseEx",
  621. "No more free entries in local db table\n"));
  622. goto cleanup;
  623. }
  624. pEntry = &pSdbContext->rgSDB[dwIndex];
  625. } else {
  626. dwIndex = *pdwLocalDBMask;
  627. if (dwIndex & TAGREF_STRIP_PDB) {
  628. dwIndex = SDB_MASK_TO_INDEX(dwIndex);
  629. }
  630. if (dwIndex >= ARRAYSIZE(pSdbContext->rgSDB)) {
  631. DBGPRINT((sdlError,
  632. "SdbOpenLocalDatabaseEx",
  633. "Bad index 0x%lx\n",
  634. dwIndex));
  635. goto cleanup;
  636. }
  637. if (dwIndex < 2) {
  638. DBGPRINT((sdlWarning,
  639. "SdbOpenLocalDatabaseEx",
  640. "Unusual use of SdbOpenLocalDatabaseEx index 0x%lx\n",
  641. dwIndex));
  642. }
  643. pEntry = &pSdbContext->rgSDB[dwIndex];
  644. SdbCloseLocalDatabaseEx(hSDB, NULL, dwIndex);
  645. }
  646. switch (SDBCUSTOM_TYPE(dwFlags)) {
  647. case SDBCUSTOM_PATH:
  648. if (SDBCUSTOM_PATH_NT & SDBCUSTOM_FLAGS(dwFlags)) {
  649. dwOpenFlags = NT_PATH;
  650. }
  651. pszDatabasePath = (LPTSTR)pDatabaseID;
  652. pGuidDB = NULL;
  653. break;
  654. case SDBCUSTOM_GUID:
  655. if (SDBCUSTOM_GUID_STRING & SDBCUSTOM_FLAGS(dwFlags)) {
  656. if (!SdbGUIDFromString((LPCTSTR)pDatabaseID, &guidDB)) {
  657. DBGPRINT((sdlError,
  658. "SdbOpenLocalDatabaseEx",
  659. "Cannot convert \"%s\" to guid\n",
  660. (LPCTSTR)pDatabaseID));
  661. goto cleanup;
  662. }
  663. pGuidDB = &guidDB;
  664. } else {
  665. pGuidDB = (GUID*)pDatabaseID;
  666. }
  667. dwCount = SdbResolveDatabase(hSDB,
  668. pGuidDB,
  669. &dwDatabaseType,
  670. szDatabasePath,
  671. CHARCOUNT(szDatabasePath));
  672. if (dwCount == 0 || dwCount >= CHARCOUNT(szDatabasePath)) {
  673. DBGPRINT((sdlError,
  674. "SdbOpenLocalDatabaseEx",
  675. "Cannot resolve database, the path length is 0x%lx\n",
  676. dwCount));
  677. goto cleanup;
  678. }
  679. //
  680. // Verify the executable's type
  681. //
  682. _tcsupr(szDatabasePath);
  683. //
  684. // when image type is set to IMAGE_FILE_MSI we assume that any kind of database path
  685. // is acceptable since we do search both 32-bit and 64-bit database for shims
  686. //
  687. if (pSdbContext->uExeType != IMAGE_FILE_MSI) {
  688. pszIA64 = _tcsstr(szDatabasePath, _T("\\IA64\\"));
  689. if ((pszIA64 == NULL && pSdbContext->uExeType == IMAGE_FILE_MACHINE_IA64) ||
  690. (pszIA64 != NULL && pSdbContext->uExeType == IMAGE_FILE_MACHINE_I386)) {
  691. DBGPRINT((sdlWarning,
  692. "SdbOpenLocalDatabaseEx",
  693. "Database \"%s\" is not of the same type as the main EXE\n",
  694. szDatabasePath));
  695. goto cleanup;
  696. }
  697. }
  698. pszDatabasePath = szDatabasePath;
  699. break;
  700. default:
  701. DBGPRINT((sdlError, "SdbOpenLocalDatabaseEx", "Bad flags 0x%lx\n", dwFlags));
  702. goto cleanup;
  703. break;
  704. }
  705. pdb = SdbOpenDatabase(pszDatabasePath, dwOpenFlags);
  706. if (pdb == NULL) {
  707. //
  708. // dbgprint not needed here
  709. //
  710. goto cleanup;
  711. }
  712. pSdbContext->rgSDB[dwIndex].pdb = pdb;
  713. pSdbContext->rgSDB[dwIndex].dwFlags = SDBENTRY_VALID_ENTRY;
  714. SDBCUSTOM_SET_MASK(pSdbContext, dwIndex);
  715. if (pGuidDB != NULL) {
  716. RtlCopyMemory(&pSdbContext->rgSDB[dwIndex].guidDB, pGuidDB, sizeof(GUID));
  717. pSdbContext->rgSDB[dwIndex].dwFlags |= SDBENTRY_VALID_GUID;
  718. } else {
  719. RtlZeroMemory(&pSdbContext->rgSDB[dwIndex].guidDB, sizeof(GUID));
  720. }
  721. bSuccess = TRUE;
  722. cleanup:
  723. if (bSuccess) {
  724. if (dwIndex == SDB_MASK_TO_INDEX(PDB_LOCAL)) {
  725. pSdbContext->pdbLocal = pdb;
  726. }
  727. if (pdwLocalDBMask != NULL) {
  728. *pdwLocalDBMask = SDB_INDEX_TO_MASK(dwIndex);
  729. }
  730. if (pPDB != NULL) {
  731. *pPDB = pdb;
  732. }
  733. }
  734. return bSuccess;
  735. }
  736. BOOL
  737. SdbOpenLocalDatabase(
  738. IN HSDB hSDB, // handle to the database channel
  739. IN LPCTSTR pszLocalDatabase // full DOS path to the local database to open.
  740. )
  741. /*++
  742. Return: TRUE on success, FALSE otherwise.
  743. Desc: Opens a local database.
  744. --*/
  745. {
  746. DWORD dwIndex = PDB_LOCAL;
  747. BOOL bSuccess;
  748. bSuccess = SdbOpenLocalDatabaseEx(hSDB,
  749. pszLocalDatabase,
  750. (SDBCUSTOM_PATH_DOS | SDBCUSTOM_USE_INDEX),
  751. NULL,
  752. &dwIndex);
  753. return bSuccess;
  754. }
  755. BOOL
  756. SdbCloseLocalDatabase(
  757. IN HSDB hSDB // handle to the database channel
  758. )
  759. /*++
  760. Return: TRUE on success, FALSE otherwise.
  761. Desc: Closes the local database.
  762. --*/
  763. {
  764. return SdbCloseLocalDatabaseEx(hSDB, NULL, SDB_MASK_TO_INDEX(PDB_LOCAL));
  765. }
  766. TAGREF
  767. SdbGetItemFromItemRef(
  768. IN HSDB hSDB, // handle to the database channel
  769. IN TAGREF trItemRef, // TAGREF of a DLL_REF record
  770. IN TAG tagItemKey, // key that has the name of the item (TAG_NAME)
  771. IN TAG tagItemTAGID, // tag that points to the location of the desired item by it's tagid
  772. IN TAG tagItem // what to look for under Library
  773. )
  774. /*++
  775. Return: TAGREF of a DLL record that matches the DLL_REF.
  776. Desc: Given a TAGREF that points to a *tag*_REF type tag, searches through
  777. the various databases for the matching tag (generally located
  778. under the LIBRARY tag in gpdbMain).
  779. if bAllowNonMain is specified then the library section is looked up
  780. in the same database where trItemRef was found. This is used with
  781. MSI transforms - to locate and extract them from custom databases.
  782. This flag IS NOT used for other components - such as patches and
  783. shim dlls. This is ensured through the macros -
  784. SdbGetShimFromShimRef(hSDB, trShimRef)
  785. and
  786. SdbGetPatchFromPatchRef(hSDB, trPatchRef)
  787. Both of these macros call this function with bAllowNonMain set to FALSE
  788. --*/
  789. {
  790. PSDBCONTEXT pDbContext = (PSDBCONTEXT)hSDB;
  791. TAGID tiItemRef = TAGID_NULL;
  792. PDB pdbItemRef = NULL;
  793. TAGREF trReturn = TAGREF_NULL;
  794. TAGID tiReturn = TAGID_NULL;
  795. TAGID tiDatabase = TAGID_NULL;
  796. TAGID tiLibrary = TAGID_NULL;
  797. TAGID tiItemTagID = TAGID_NULL;
  798. TAGID tiItemName;
  799. LPTSTR szItemName = NULL;
  800. try {
  801. //
  802. // Find first which database contains the reference TAGREF.
  803. //
  804. if (!SdbTagRefToTagID(pDbContext, trItemRef, &pdbItemRef, &tiItemRef)){
  805. DBGPRINT((sdlError, "SdbGetItemFromItemRef", "Can't convert tag ref.\n"));
  806. goto out;
  807. }
  808. //
  809. // First check if there's a TAG_item_TAGID that tells us exactly
  810. // where the item is within the current database.
  811. //
  812. tiItemTagID = SdbFindFirstTag(pdbItemRef, tiItemRef, tagItemTAGID);
  813. if (tiItemTagID != TAGID_NULL) {
  814. tiReturn = (TAGID)SdbReadDWORDTag(pdbItemRef, tiItemTagID, 0);
  815. if (tiReturn != TAGID_NULL) {
  816. goto out;
  817. }
  818. }
  819. if (pdbItemRef == pDbContext->pdbMain) {
  820. goto checkMainDatabase;
  821. }
  822. //
  823. // Then check for the item in the LIBRARY section of the
  824. // current database.
  825. //
  826. tiDatabase = SdbFindFirstTag(pdbItemRef, TAGID_ROOT, TAG_DATABASE);
  827. if (!tiDatabase) {
  828. DBGPRINT((sdlError,
  829. "SdbGetItemFromItemRef",
  830. "Can't find DATABASE tag in db.\n"));
  831. goto checkMainDatabase;
  832. }
  833. tiLibrary = SdbFindFirstTag(pdbItemRef, tiDatabase, TAG_LIBRARY);
  834. if (!tiLibrary) {
  835. //
  836. // This library doesn't have a LIBRARY section. That's ok, go check
  837. // sysmain.sdb.
  838. //
  839. goto checkMainDatabase;
  840. }
  841. //
  842. // We need to search by name.
  843. //
  844. tiItemName = SdbFindFirstTag(pdbItemRef, tiItemRef, tagItemKey);
  845. if (!tiItemName) {
  846. goto out;
  847. }
  848. szItemName = SdbGetStringTagPtr(pdbItemRef, tiItemName);
  849. if (!szItemName) {
  850. goto out;
  851. }
  852. tiReturn = SdbFindFirstNamedTag(pdbItemRef,
  853. tiLibrary,
  854. tagItem,
  855. tagItemKey,
  856. szItemName);
  857. if (tiReturn != TAGID_NULL) {
  858. goto out;
  859. }
  860. checkMainDatabase:
  861. tiDatabase = SdbFindFirstTag(pDbContext->pdbMain, TAGID_ROOT, TAG_DATABASE);
  862. if (!tiDatabase) {
  863. DBGPRINT((sdlError,
  864. "SdbGetItemFromItemRef",
  865. "Can't find DATABASE tag in main db.\n"));
  866. goto out;
  867. }
  868. tiLibrary = SdbFindFirstTag(pDbContext->pdbMain, tiDatabase, TAG_LIBRARY);
  869. if (!tiLibrary) {
  870. DBGPRINT((sdlError,
  871. "SdbGetItemFromItemRef",
  872. "Can't find LIBRARY tag in main db.\n"));
  873. goto out;
  874. }
  875. //
  876. // We need to search by name.
  877. //
  878. if (szItemName == NULL) {
  879. tiItemName = SdbFindFirstTag(pdbItemRef, tiItemRef, tagItemKey);
  880. if (!tiItemName) {
  881. goto out;
  882. }
  883. szItemName = SdbGetStringTagPtr(pdbItemRef, tiItemName);
  884. if (!szItemName) {
  885. goto out;
  886. }
  887. }
  888. tiReturn = SdbFindFirstNamedTag(pDbContext->pdbMain,
  889. tiLibrary,
  890. tagItem,
  891. tagItemKey,
  892. szItemName);
  893. pdbItemRef = pDbContext->pdbMain;
  894. } except (SHIM_EXCEPT_HANDLER) {
  895. tiReturn = TAGID_NULL;
  896. trReturn = TAGREF_NULL;
  897. }
  898. out:
  899. if (tiReturn) {
  900. assert(pdbItemRef != NULL);
  901. if (!SdbTagIDToTagRef(pDbContext, pdbItemRef, tiReturn, &trReturn)) {
  902. trReturn = TAGREF_NULL;
  903. }
  904. }
  905. if (trReturn == TAGREF_NULL) {
  906. DBGPRINT((sdlError,
  907. "SdbGetItemFromItemRef",
  908. "Can't find tag for tag ref 0x%x.\n", trItemRef));
  909. }
  910. return trReturn;
  911. }
  912. TAGID
  913. SdbpGetLibraryFile(
  914. IN PDB pdb, // handle to the database channel
  915. IN LPCTSTR szDllName // the name of the DLL
  916. )
  917. /*++
  918. Return: The TAGID of the DLL used by the specified shim.
  919. Desc: This function gets the TAGID of the DLL with the specified name.
  920. --*/
  921. {
  922. TAGID tiDatabase;
  923. TAGID tiLibrary;
  924. TAGID tiDll = TAG_NULL;
  925. tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
  926. if (!tiDatabase) {
  927. DBGPRINT((sdlError, "SdbpGetLibraryFile", "Can't find DATABASE tag in main db.\n"));
  928. goto out;
  929. }
  930. tiLibrary = SdbFindFirstTag(pdb, tiDatabase, TAG_LIBRARY);
  931. if (!tiLibrary) {
  932. DBGPRINT((sdlError, "SdbpGetLibraryFile", "Can't find LIBRARY tag in main db.\n"));
  933. goto out;
  934. }
  935. tiDll = SdbFindFirstNamedTag(pdb, tiLibrary, TAG_FILE, TAG_NAME, szDllName);
  936. if (!tiDll) {
  937. DBGPRINT((sdlError,
  938. "SdbpGetLibraryFile", "Can't find FILE \"%s\" in main db library.\n",
  939. szDllName));
  940. goto out;
  941. }
  942. out:
  943. return tiDll;
  944. }
  945. BOOL
  946. SdbGetDllPath(
  947. IN HSDB hSDB, // handle to the database channel
  948. IN TAGREF trShimRef, // SHIM_REF to use to search for the DLL
  949. OUT LPTSTR pwszBuffer, // Buffer to fill with the path to the DLL containing
  950. // the specified shim.
  951. IN DWORD cchBufferSize // Size of the buffer (in characters)
  952. )
  953. /*++
  954. Return: TRUE if the DLL was found, FALSE otherwise.
  955. Desc: Hunts for the DLL file on disk, first in the same
  956. directory as the EXE (if there was a local database opened), then
  957. in the %windir%\AppPatch directory.
  958. Always fills in a DOS_PATH type path (UNC or 'x:').
  959. --*/
  960. {
  961. BOOL bReturn = FALSE;
  962. HANDLE hFile = INVALID_HANDLE_VALUE;
  963. PBYTE pBuffer = NULL;
  964. TAGREF trShim;
  965. TAGREF trName;
  966. TCHAR szFile[2 * MAX_PATH];
  967. TCHAR szName[MAX_PATH];
  968. assert(pwszBuffer);
  969. try {
  970. //
  971. // Initialize the return buffer.
  972. //
  973. pwszBuffer[0] = _T('\0');
  974. SdbpGetAppPatchDir(hSDB, szFile, CHARCOUNT(szFile));
  975. StringCchCat(szFile, CHARCOUNT(szFile), _T("\\"));
  976. //
  977. // Look for the SHIM record in the LIBRARY section.
  978. //
  979. trShim = SdbGetShimFromShimRef(hSDB, trShimRef);
  980. if (trShim == TAGREF_NULL) {
  981. //
  982. // No SHIM in LIBRARY. Error out.
  983. //
  984. DBGPRINT((sdlError, "SdbGetDllPath", "No SHIM in LIBRARY.\n"));
  985. goto out;
  986. }
  987. //
  988. // Get the name of the file that contains this shim.
  989. //
  990. trName = SdbFindFirstTagRef(hSDB, trShim, TAG_DLLFILE);
  991. if (trName == TAGREF_NULL) {
  992. //
  993. // Nope, and we need one. Error out.
  994. //
  995. DBGPRINT((sdlError, "SdbGetDllPath", "No DLLFILE for the SHIM in LIBRARY.\n"));
  996. goto out;
  997. }
  998. if (!SdbReadStringTagRef(hSDB, trName, szName, MAX_PATH)) {
  999. DBGPRINT((sdlError, "SdbGetDllPath", "Can't read DLL name.\n"));
  1000. goto out;
  1001. }
  1002. //
  1003. // Check if the file is already on the disk.
  1004. // Look in %windir%\AppPatch directory for the DLL.
  1005. //
  1006. StringCchCat(szFile, CHARCOUNT(szFile), szName);
  1007. StringCchCopy(pwszBuffer, cchBufferSize, szFile);
  1008. DBGPRINT((sdlInfo, "SdbGetDllPath", "Opening file \"%s\".\n", szFile));
  1009. hFile = SdbpOpenFile(szFile, DOS_PATH);
  1010. if (hFile != INVALID_HANDLE_VALUE) {
  1011. bReturn = TRUE;
  1012. goto out;
  1013. }
  1014. out:
  1015. ;
  1016. } except (SHIM_EXCEPT_HANDLER) {
  1017. bReturn = FALSE;
  1018. }
  1019. if (hFile != INVALID_HANDLE_VALUE) {
  1020. SdbpCloseFile(hFile);
  1021. }
  1022. if (pBuffer != NULL) {
  1023. SdbFree(pBuffer);
  1024. }
  1025. if (bReturn) {
  1026. DBGPRINT((sdlInfo, "SdbGetDllPath", "Using DLL \"%s\".\n", szFile));
  1027. }
  1028. return bReturn;
  1029. }
  1030. BOOL
  1031. SdbReadPatchBits(
  1032. IN HSDB hSDB, // handle to the database channel
  1033. IN TAGREF trPatchRef, // PATCH_REF to use to find the PATCH
  1034. OUT PVOID pBuffer, // buffer to fill with bits
  1035. OUT LPDWORD lpdwBufferSize // size of passed-in buffer
  1036. )
  1037. /*++
  1038. Return: Returns TRUE on success, FALSE on failure.
  1039. Desc: Looks for the patch, first on disk, then in the DB, and fills
  1040. pBuffer with the bits. If the size specified in lpdwBufferSize is
  1041. less than the size of the patch this function will return in
  1042. lpdwBufferSize the size required. In that case pBuffer is ignored
  1043. and can be NULL.
  1044. --*/
  1045. {
  1046. BOOL bReturn = FALSE;
  1047. TAGID tiPatchRef = TAGID_NULL;
  1048. PDB pdb = NULL;
  1049. LPTSTR szName = NULL;
  1050. TAGREF trPatch = TAGREF_NULL;
  1051. TAGREF trPatchBits = TAGREF_NULL;
  1052. TAGID tiName = TAGID_NULL;
  1053. DWORD dwSize;
  1054. try {
  1055. if (!SdbTagRefToTagID(hSDB, trPatchRef, &pdb, &tiPatchRef)) {
  1056. DBGPRINT((sdlError, "SdbReadPatchBits", "Can't convert tag ref.\n"));
  1057. goto out;
  1058. }
  1059. tiName = SdbFindFirstTag(pdb, tiPatchRef, TAG_NAME);
  1060. if (!tiName) {
  1061. DBGPRINT((sdlError, "SdbReadPatchBits", "Can't find the name tag.\n"));
  1062. goto out;
  1063. }
  1064. szName = SdbGetStringTagPtr(pdb, tiName);
  1065. if (!szName) {
  1066. DBGPRINT((sdlError, "SdbReadPatchBits", "Can't read the name of the patch.\n"));
  1067. goto out;
  1068. }
  1069. //
  1070. // Look in the main database for the patch bits.
  1071. //
  1072. trPatch = SdbGetPatchFromPatchRef(hSDB, trPatchRef);
  1073. if (!trPatch) {
  1074. DBGPRINT((sdlError, "SdbReadPatchBits", "Can't get the patch tag.\n"));
  1075. goto out;
  1076. }
  1077. trPatchBits = SdbFindFirstTagRef(hSDB, trPatch, TAG_PATCH_BITS);
  1078. if (!trPatchBits) {
  1079. DBGPRINT((sdlError, "SdbReadPatchBits", "Can't get the patch bits tag.\n"));
  1080. goto out;
  1081. }
  1082. dwSize = SdbpGetTagRefDataSize(hSDB, trPatchBits);
  1083. if (dwSize == 0) {
  1084. DBGPRINT((sdlError, "SdbReadPatchBits", "Corrupt database. Zero sized patch.\n"));
  1085. goto out;
  1086. }
  1087. //
  1088. // Check for buffer size.
  1089. //
  1090. if (dwSize > *lpdwBufferSize) {
  1091. *lpdwBufferSize = dwSize;
  1092. goto out;
  1093. }
  1094. //
  1095. // Read the bits if the buffer is big enough.
  1096. //
  1097. *lpdwBufferSize = dwSize;
  1098. if (!SdbpReadBinaryTagRef(hSDB, trPatchBits, pBuffer, dwSize)) {
  1099. DBGPRINT((sdlError, "SdbReadPatchBits", "Cannot get the patch bits.\n"));
  1100. goto out;
  1101. }
  1102. bReturn = TRUE;
  1103. } except (SHIM_EXCEPT_HANDLER) {
  1104. bReturn = FALSE;
  1105. }
  1106. out:
  1107. return bReturn;
  1108. }