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.

937 lines
23 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. dbaccess.c
  5. Abstract:
  6. This module implements APIs to access the shim database.
  7. Author:
  8. dmunsil created sometime in 1999
  9. Revision History:
  10. several people contributed (vadimb, clupu, ...)
  11. --*/
  12. #include "sdbp.h"
  13. #if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
  14. #pragma alloc_text(PAGE, SdbReleaseDatabase)
  15. #pragma alloc_text(PAGE, SdbGetDatabaseVersion)
  16. #pragma alloc_text(PAGE, SdbGetDatabaseInformation)
  17. #pragma alloc_text(PAGE, SdbGetDatabaseID)
  18. #pragma alloc_text(PAGE, SdbFreeDatabaseInformation)
  19. #pragma alloc_text(PAGE, SdbGetDatabaseInformationByName)
  20. #pragma alloc_text(PAGE, SdbpGetDatabaseDescriptionPtr)
  21. #pragma alloc_text(PAGE, SdbpReadMappedData)
  22. #pragma alloc_text(PAGE, SdbpGetMappedData)
  23. #pragma alloc_text(PAGE, SdbOpenDatabase)
  24. #pragma alloc_text(PAGE, SdbpOpenDatabaseInMemory)
  25. #pragma alloc_text(PAGE, SdbCloseDatabaseRead)
  26. #pragma alloc_text(PAGE, SdbpOpenAndMapDB)
  27. #pragma alloc_text(PAGE, SdbpUnmapAndCloseDB)
  28. #pragma alloc_text(PAGE, SdbGetTagFromTagID)
  29. #pragma alloc_text(PAGE, SdbpGetNextTagId)
  30. #pragma alloc_text(PAGE, SdbGetFirstChild)
  31. #pragma alloc_text(PAGE, SdbGetNextChild)
  32. #pragma alloc_text(PAGE, SdbpCreateSearchPathPartsFromPath)
  33. #endif // KERNEL_MODE && ALLOC_PRAGMA
  34. void
  35. SdbReleaseDatabase(
  36. IN HSDB hSDB // handle to the database channel
  37. )
  38. /*++
  39. Return: void.
  40. Desc: This API should be called in pair with SdbInitDatabase.
  41. --*/
  42. {
  43. PSDBCONTEXT pContext = (PSDBCONTEXT)hSDB;
  44. assert(pContext != NULL);
  45. //
  46. // Do everything under a try/except block so we don't screw the caller
  47. // if the databases are corrupt.
  48. //
  49. __try {
  50. #ifndef KERNEL_MODE
  51. SdbpCleanupLocalDatabaseSupport(hSDB);
  52. if (pContext->rgSDB[2].dwFlags & SDBENTRY_VALID_ENTRY) {
  53. SdbCloseDatabaseRead(pContext->rgSDB[2].pdb);
  54. }
  55. #endif // KERNEL_MODE
  56. if (pContext->pdbTest != NULL) {
  57. SdbCloseDatabaseRead(pContext->pdbTest);
  58. }
  59. if (pContext->pdbMain != NULL) {
  60. SdbCloseDatabaseRead(pContext->pdbMain);
  61. }
  62. //
  63. // Cleanup attributes.
  64. //
  65. SdbpCleanupAttributeMgr(pContext);
  66. #ifndef KERNEL_MODE
  67. //
  68. // Cleanup user sdb cache
  69. //
  70. SdbpCleanupUserSDBCache(pContext);
  71. #endif // KERNEL_MODE
  72. #if defined(NT_MODE) || defined(WIN32U_MODE)
  73. if (SDBCONTEXT_IS_INSTRUMENTED(pContext)) {
  74. SdbpCloseDebugPipe(SDBCONTEXT_GET_PIPE(pContext));
  75. }
  76. #endif
  77. SdbFree(pContext);
  78. } __except (SHIM_EXCEPT_HANDLER) {
  79. ;
  80. }
  81. }
  82. BOOL
  83. SdbGetDatabaseVersion(
  84. IN LPCTSTR pszFileName, // the file name
  85. OUT LPDWORD lpdwMajor, // store the major version of the database
  86. OUT LPDWORD lpdwMinor // store the minor version of the database
  87. )
  88. /*++
  89. Return: void.
  90. Desc: This API should be called in pair with SdbInitDatabase.
  91. --*/
  92. {
  93. PDB pdb;
  94. SDBDATABASEINFO DBInfo;
  95. BOOL bSuccess;
  96. pdb = SdbAlloc(sizeof(DB));
  97. if (pdb == NULL) {
  98. DBGPRINT((sdlError, "SdbGetDatabaseVersion", "Can't allocate DB structure.\n"));
  99. return FALSE;
  100. }
  101. if (!SdbpOpenAndMapDB(pdb, pszFileName, DOS_PATH)) {
  102. DBGPRINT((sdlError,
  103. "SdbGetDatabaseVersion",
  104. "Failed to open the database \"%s\".\n",
  105. pszFileName));
  106. goto err1;
  107. }
  108. pdb->bWrite = FALSE;
  109. pdb->dwSize = SdbpGetFileSize(pdb->hFile);
  110. if (!SdbGetDatabaseInformation(pdb, &DBInfo)) {
  111. DBGPRINT((sdlError, "SdbGetDatabaseVersion", "Can't read database information.\n"));
  112. goto err2;
  113. }
  114. *lpdwMajor = DBInfo.dwVersionMajor;
  115. *lpdwMinor = DBInfo.dwVersionMinor;
  116. err2:
  117. SdbpUnmapAndCloseDB(pdb);
  118. err1:
  119. SdbFree(pdb);
  120. return TRUE;
  121. }
  122. BOOL
  123. SDBAPI
  124. SdbGetDatabaseInformation(
  125. IN PDB pdb,
  126. OUT PSDBDATABASEINFO pSdbInfo
  127. )
  128. {
  129. DB_HEADER DBHeader;
  130. BOOL bReturn = FALSE;
  131. RtlZeroMemory(pSdbInfo, sizeof(*pSdbInfo));
  132. if (!SdbpReadMappedData(pdb, 0, &DBHeader, sizeof(DB_HEADER))) {
  133. DBGPRINT((sdlError, "SdbGetDatabaseInformation", "Can't read database header.\n"));
  134. goto errHandle;
  135. }
  136. if (DBHeader.dwMagic != SHIMDB_MAGIC) {
  137. DBGPRINT((sdlError,
  138. "SdbGetDatabaseInformation",
  139. "Magic doesn't match. Magic: 0x%08X, Expected: 0x%08X.\n",
  140. DBHeader.dwMagic,
  141. (DWORD)SHIMDB_MAGIC));
  142. goto errHandle;
  143. }
  144. pSdbInfo->dwVersionMajor = DBHeader.dwMajorVersion;
  145. pSdbInfo->dwVersionMinor = DBHeader.dwMinorVersion;
  146. //
  147. // Id and description are optional
  148. //
  149. if (SdbGetDatabaseID(pdb, &pSdbInfo->guidDB)) {
  150. pSdbInfo->dwFlags |= DBINFO_GUID_VALID;
  151. }
  152. //
  153. // Now try to get valid description.
  154. //
  155. pSdbInfo->pszDescription = (LPTSTR)SdbpGetDatabaseDescriptionPtr(pdb);
  156. bReturn = TRUE;
  157. errHandle:
  158. return bReturn;
  159. }
  160. BOOL
  161. SDBAPI
  162. SdbGetDatabaseID(
  163. IN PDB pdb,
  164. OUT GUID* pguidDB
  165. )
  166. {
  167. TAGID tiDatabase;
  168. TAGID tiGuidID;
  169. BOOL bReturn = FALSE;
  170. if (!(pdb->dwFlags & DB_GUID_VALID)) {
  171. tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
  172. if (!tiDatabase) {
  173. DBGPRINT((sdlError, "SdbGetDatabaseID", "Failed to get root tag\n"));
  174. goto errHandle;
  175. }
  176. tiGuidID = SdbFindFirstTag(pdb, tiDatabase, TAG_DATABASE_ID);
  177. if (!tiGuidID) {
  178. DBGPRINT((sdlWarning, "SdbGetDatabaseID", "Failed to get the database id\n"));
  179. goto errHandle;
  180. }
  181. if (!SdbReadBinaryTag(pdb, tiGuidID, (PBYTE)&pdb->guidDB, sizeof(GUID))) {
  182. DBGPRINT((sdlError,
  183. "SdbGetDatabaseID",
  184. "Failed to read database id 0x%lx\n",
  185. tiGuidID));
  186. goto errHandle;
  187. }
  188. pdb->dwFlags |= DB_GUID_VALID;
  189. }
  190. //
  191. // If we are here, GUID retrieval was successful.
  192. //
  193. if (pdb->dwFlags & DB_GUID_VALID) {
  194. RtlMoveMemory(pguidDB, &pdb->guidDB, sizeof(GUID));
  195. bReturn = TRUE;
  196. }
  197. errHandle:
  198. return bReturn;
  199. }
  200. VOID
  201. SDBAPI
  202. SdbFreeDatabaseInformation(
  203. IN PSDBDATABASEINFO pDBInfo
  204. )
  205. {
  206. if (pDBInfo != NULL && (pDBInfo->dwFlags & DBINFO_SDBALLOC)) {
  207. SdbFree(pDBInfo);
  208. }
  209. }
  210. BOOL
  211. SDBAPI
  212. SdbGetDatabaseInformationByName(
  213. IN LPCTSTR pszDatabase,
  214. OUT PSDBDATABASEINFO* ppdbInfo
  215. )
  216. /*++
  217. Return: TRUE on success, FALSE otherwise.
  218. Desc: This function retrieves database information given the database name
  219. the pointer to the SDBDATABASEINFO should be freed by the caller using
  220. SdbFreeDatabaseInformation
  221. --*/
  222. {
  223. PDB pdb = NULL;
  224. DWORD dwDescriptionSize = 0;
  225. PSDBDATABASEINFO pDbInfo = NULL;
  226. BOOL bReturn = FALSE;
  227. SDBDATABASEINFO DbInfo;
  228. assert(ppdbInfo != NULL);
  229. pdb = SdbOpenDatabase(pszDatabase, DOS_PATH);
  230. if (pdb == NULL) {
  231. DBGPRINT((sdlError,
  232. "SdbGetDatabaseInformationByName",
  233. "Error opening database file \"%s\"\n",
  234. pszDatabase));
  235. return FALSE;
  236. }
  237. //
  238. // Find the size of the database description
  239. //
  240. if (!SdbGetDatabaseInformation(pdb, &DbInfo)) {
  241. DBGPRINT((sdlError,
  242. "SdbGetDatabaseInformationByName",
  243. "Error Retrieving Database information for \"%s\"\n",
  244. pszDatabase));
  245. goto HandleError;
  246. }
  247. if (DbInfo.pszDescription != NULL) {
  248. dwDescriptionSize = (_tcslen(DbInfo.pszDescription) + 1) * sizeof(TCHAR);
  249. }
  250. pDbInfo = (PSDBDATABASEINFO)SdbAlloc(sizeof(SDBDATABASEINFO) + dwDescriptionSize);
  251. if (pDbInfo == NULL) {
  252. DBGPRINT((sdlError,
  253. "SdbGetDatabaseInformationByName",
  254. "Error allocating 0x%lx bytes for database information \"%s\"\n",
  255. sizeof(SDBDATABASEINFO) + dwDescriptionSize,
  256. pszDatabase));
  257. goto HandleError;
  258. }
  259. RtlMoveMemory(pDbInfo, &DbInfo, sizeof(DbInfo));
  260. pDbInfo->dwFlags |= DBINFO_SDBALLOC;
  261. //
  262. // Make it "self-contained"
  263. //
  264. if (DbInfo.pszDescription != NULL) {
  265. pDbInfo->pszDescription = (LPTSTR)(pDbInfo + 1);
  266. RtlMoveMemory(pDbInfo->pszDescription, DbInfo.pszDescription, dwDescriptionSize);
  267. }
  268. *ppdbInfo = pDbInfo;
  269. bReturn = TRUE;
  270. HandleError:
  271. if (pdb != NULL) {
  272. SdbCloseDatabaseRead(pdb);
  273. }
  274. if (!bReturn) {
  275. if (pDbInfo != NULL) {
  276. SdbFree(pDbInfo);
  277. }
  278. }
  279. return bReturn;
  280. }
  281. LPCTSTR
  282. SdbpGetDatabaseDescriptionPtr(
  283. IN PDB pdb
  284. )
  285. {
  286. TAGID tiDatabase;
  287. TAGID tiName;
  288. LPCTSTR lpszDescription = NULL;
  289. tiDatabase = SdbFindFirstTag(pdb, TAGID_ROOT, TAG_DATABASE);
  290. if (!tiDatabase) {
  291. DBGPRINT((sdlError,
  292. "SdbpGetDatabaseDescriptionPtr",
  293. "Failed to get database tag, db is corrupt\n"));
  294. goto errHandle;
  295. }
  296. tiName = SdbFindFirstTag(pdb, tiDatabase, TAG_NAME);
  297. if (tiName) {
  298. lpszDescription = SdbGetStringTagPtr(pdb, tiName);
  299. }
  300. errHandle:
  301. return lpszDescription;
  302. }
  303. BOOL
  304. SdbpReadMappedData(
  305. IN PDB pdb, // database handle
  306. IN DWORD dwOffset, // offset in the database where the data is to be copied from
  307. OUT PVOID pBuffer, // destination buffer
  308. IN DWORD dwSize // the region size
  309. )
  310. /*++
  311. Return: TRUE if successful, FALSE otherwise.
  312. Desc: This function reads the data (dwSize bytes) from the database
  313. starting at offset dwOffset into the buffer pBuffer provided
  314. by the caller
  315. --*/
  316. {
  317. if (pdb->dwSize < dwOffset + dwSize) {
  318. DBGPRINT((sdlError,
  319. "SdbpReadMappedData",
  320. "Attempt to read past the end of the database offset 0x%lx size 0x%lx (0x%lx)\n",
  321. dwOffset,
  322. dwSize,
  323. pdb->dwSize));
  324. return FALSE;
  325. }
  326. assert(pdb->pBase != NULL);
  327. memcpy(pBuffer, (PBYTE)pdb->pBase + dwOffset, dwSize);
  328. return TRUE;
  329. }
  330. PVOID
  331. SdbpGetMappedData(
  332. IN PDB pdb, // database handle
  333. IN DWORD dwOffset // offset in the database
  334. )
  335. /*++
  336. Return: The pointer to the data.
  337. Desc: This function returns the pointer to data within the database at
  338. offset dwOffset. It will return FALSE if dwOffset is invalid.
  339. --*/
  340. {
  341. assert(pdb);
  342. assert(pdb->pBase != NULL);
  343. if (dwOffset >= pdb->dwSize) {
  344. DBGPRINT((sdlError,
  345. "SdbpGetMappedData",
  346. "Trying to read mapped data past the end of the database offset 0x%x size 0x%x\n",
  347. dwOffset,
  348. pdb->dwSize));
  349. assert(FALSE);
  350. return NULL;
  351. }
  352. return (PBYTE)pdb->pBase + dwOffset;
  353. }
  354. PDB
  355. SdbOpenDatabase(
  356. IN LPCTSTR szPath, // full path to the DB
  357. IN PATH_TYPE eType // DOS_PATH for standard paths,
  358. // NT_PATH for internal NT paths
  359. )
  360. /*++
  361. Return: A pointer to the open DB, or NULL on failure.
  362. Desc: Opens up a shim database file, checks version and magic numbers, and creates
  363. a DB record that is passed back as a PDB. eType can be NT_PATH or DOS_PATH,
  364. and tells whether we are using NTDLL internal paths, or the more familiar
  365. DOS paths.
  366. --*/
  367. {
  368. PDB pdb;
  369. DB_HEADER DBHeader;
  370. BOOL bSuccess;
  371. pdb = SdbAlloc(sizeof(DB));
  372. if (pdb == NULL) {
  373. DBGPRINT((sdlError, "SdbOpenDatabase", "Can't allocate DB structure.\n"));
  374. return NULL;
  375. }
  376. if (!SdbpOpenAndMapDB(pdb, szPath, eType)) {
  377. DBGPRINT((sdlInfo,
  378. "SdbOpenDatabase",
  379. "Failed to open the database \"%s\".\n",
  380. szPath));
  381. goto err1;
  382. }
  383. pdb->bWrite = FALSE;
  384. pdb->dwSize = SdbpGetFileSize(pdb->hFile);
  385. //
  386. // Check version and magic.
  387. //
  388. if (!SdbpReadMappedData(pdb, 0, &DBHeader, sizeof(DB_HEADER))) {
  389. DBGPRINT((sdlError, "SdbOpenDatabase", "Can't read database header.\n"));
  390. goto err2;
  391. }
  392. if (DBHeader.dwMagic != SHIMDB_MAGIC) {
  393. DBGPRINT((sdlError, "SdbOpenDatbase", "Magic does not match 0x%lx\n", DBHeader.dwMagic));
  394. goto err2;
  395. }
  396. if (DBHeader.dwMajorVersion == 1) {
  397. DBGPRINT((sdlWarning, "SdbOpenDatabase", "Reading under hack from older database\n"));
  398. pdb->bUnalignedRead = TRUE;
  399. } else if (DBHeader.dwMajorVersion != SHIMDB_MAJOR_VERSION) {
  400. DBGPRINT((sdlError, "SdbOpenDatabase",
  401. "MajorVersion mismatch, MajorVersion 0x%lx Expected 0x%lx\n",
  402. DBHeader.dwMajorVersion, (DWORD)SHIMDB_MAJOR_VERSION));
  403. goto err2;
  404. }
  405. if (DBHeader.dwMagic != SHIMDB_MAGIC || DBHeader.dwMajorVersion != SHIMDB_MAJOR_VERSION) {
  406. DBGPRINT((sdlError,
  407. "SdbOpenDatabase",
  408. "Magic or MajorVersion doesn't match."
  409. "Magic: %08X, Expected: %08X; MajorVersion: %08X, Expected: %08X.\n",
  410. DBHeader.dwMagic,
  411. (DWORD)SHIMDB_MAGIC,
  412. DBHeader.dwMajorVersion,
  413. (DWORD)SHIMDB_MAJOR_VERSION));
  414. goto err2;
  415. }
  416. return pdb;
  417. err2:
  418. SdbpUnmapAndCloseDB(pdb);
  419. err1:
  420. SdbFree(pdb);
  421. return NULL;
  422. }
  423. PDB
  424. SdbpOpenDatabaseInMemory(
  425. IN LPVOID pImageDatabase, // Pointer to the image of the mapped database
  426. IN DWORD dwSize // the size of the file in bytes
  427. )
  428. /*++
  429. Return: BUGBUG: ?
  430. Desc: BUGBUG: ?
  431. --*/
  432. {
  433. PDB pdb = NULL;
  434. DB_HEADER DBHeader;
  435. pdb = SdbAlloc(sizeof(DB));
  436. if (pdb == NULL) {
  437. DBGPRINT((sdlError,
  438. "SdbpOpenDatabaseInMemory",
  439. "Failed to allocate DB structure\n"));
  440. return NULL;
  441. }
  442. pdb->bWrite = FALSE;
  443. pdb->hFile = INVALID_HANDLE_VALUE;
  444. pdb->pBase = pImageDatabase;
  445. pdb->dwSize = dwSize;
  446. pdb->dwFlags |= DB_IN_MEMORY;
  447. if (!SdbpReadMappedData(pdb, 0, &DBHeader, sizeof(DB_HEADER))) {
  448. DBGPRINT((sdlError,
  449. "SdbpOpenDatabaseInMemory",
  450. "Can't read database header\n"));
  451. goto ErrHandle;
  452. }
  453. if (DBHeader.dwMagic != SHIMDB_MAGIC || DBHeader.dwMajorVersion != SHIMDB_MAJOR_VERSION) {
  454. DBGPRINT((sdlError,
  455. "SdbpOpenDatabaseInMemory",
  456. "Magic or MajorVersion doesn't match."
  457. "Magic: %08X, Expected: %08X; MajorVersion: %08X, Expected: %08X.\n",
  458. DBHeader.dwMagic,
  459. (DWORD)SHIMDB_MAGIC,
  460. DBHeader.dwMajorVersion,
  461. (DWORD)SHIMDB_MAJOR_VERSION));
  462. goto ErrHandle;
  463. }
  464. return pdb;
  465. ErrHandle:
  466. if (pdb != NULL) {
  467. SdbFree(pdb);
  468. }
  469. return NULL;
  470. }
  471. void
  472. SdbCloseDatabaseRead(
  473. IN PDB pdb // handle to the DB to close
  474. )
  475. /*++
  476. Return: void.
  477. Desc: Closes a database that was opened for read access as it is the case
  478. with the majority of our run-time code.
  479. --*/
  480. {
  481. assert(pdb);
  482. assert(!pdb->bWrite);
  483. if (pdb->pBase != NULL) {
  484. SdbpUnmapAndCloseDB(pdb);
  485. CLEANUP_STRING_CACHE_READ(pdb);
  486. SdbFree(pdb);
  487. }
  488. }
  489. BOOL
  490. SdbpOpenAndMapDB(
  491. IN PDB pdb, // pdb to fill in with mapping handles and whatnot
  492. IN LPCTSTR pszPath, // full path of file to open
  493. IN PATH_TYPE eType // DOS_PATH for standard paths, NT_PATH for nt internal paths
  494. )
  495. /*++
  496. Return: TRUE if successful, FALSE otherwise.
  497. Desc: Opens a db file, maps it into memory, and sets up the global vars in the pdb.
  498. --*/
  499. {
  500. NTSTATUS status;
  501. IMAGEFILEDATA ImageData;
  502. ImageData.dwFlags = 0;
  503. if (!SdbpOpenAndMapFile(pszPath, &ImageData, eType)) {
  504. DBGPRINT((sdlInfo, "SdbpOpenAndMapDB", "Failed to open file \"%s\"\n", pszPath));
  505. return FALSE;
  506. }
  507. pdb->hFile = ImageData.hFile;
  508. pdb->hSection = ImageData.hSection;
  509. pdb->pBase = ImageData.pBase;
  510. pdb->dwSize = (DWORD)ImageData.ViewSize;
  511. return TRUE;
  512. }
  513. BOOL
  514. SdbpUnmapAndCloseDB(
  515. IN PDB pdb // pdb to close the files and mapping info
  516. )
  517. /*++
  518. Return: TRUE if successful, FALSE otherwise.
  519. Desc: Cleans up for the specified database.
  520. --*/
  521. {
  522. BOOL bReturn;
  523. IMAGEFILEDATA ImageData;
  524. if (pdb->dwFlags & DB_IN_MEMORY) {
  525. //
  526. // database in memory
  527. //
  528. pdb->pBase = NULL;
  529. pdb->dwSize = 0;
  530. return TRUE;
  531. }
  532. ImageData.dwFlags = 0;
  533. ImageData.hFile = pdb->hFile;
  534. ImageData.hSection = pdb->hSection;
  535. ImageData.pBase = pdb->pBase;
  536. bReturn = SdbpUnmapAndCloseFile(&ImageData);
  537. //
  538. // once we nuke the file -- reset values
  539. //
  540. if (bReturn) {
  541. pdb->hFile = INVALID_HANDLE_VALUE;
  542. pdb->hSection = NULL;
  543. pdb->pBase = NULL;
  544. }
  545. return bReturn;
  546. }
  547. TAG
  548. SdbGetTagFromTagID(
  549. IN PDB pdb, // DB to use
  550. IN TAGID tiWhich // record to get the tag for
  551. )
  552. /*++
  553. Return: Just the TAG (the word-sized header) of the record.
  554. Desc: Returns just the TAG that a TAGID points to.
  555. --*/
  556. {
  557. TAG tWhich = TAG_NULL;
  558. assert(pdb && tiWhich);
  559. if (!SdbpReadMappedData(pdb, (DWORD)tiWhich, &tWhich, sizeof(TAG))) {
  560. DBGPRINT((sdlError, "SdbGetTagFromTagID", "Error reading data.\n"));
  561. return TAG_NULL;
  562. }
  563. return tWhich;
  564. }
  565. TAGID
  566. SdbpGetNextTagId(
  567. IN PDB pdb, // DB to look in
  568. IN TAGID tiWhich // tag to get the next sibling of
  569. )
  570. /*++
  571. Return: The next tag after the one passed in, or one past end of file if no more.
  572. Desc: Gets the TAGID of the next tag in the DB, or a virtual
  573. TAGID that is one past the end of the file, which means
  574. there are no more tags in the DB.
  575. This is an internal function, and shouldn't be called by
  576. external functions, as there's no clean way to tell you've
  577. walked off the end of the file. Use tiGetNextChildTag instead.
  578. --*/
  579. {
  580. //
  581. // If the tag is an unfinished list tag, point to the end of the file.
  582. //
  583. if (GETTAGTYPE(SdbGetTagFromTagID(pdb, tiWhich)) == TAG_TYPE_LIST &&
  584. SdbGetTagDataSize(pdb, tiWhich) == TAG_SIZE_UNFINISHED) {
  585. DBGPRINT((sdlError, "SdbpGetNextTagId", "Reading from unfinished list.\n"));
  586. return pdb->dwSize;
  587. } else {
  588. return (TAGID)(tiWhich + GETTAGDATAOFFSET(pdb, tiWhich));
  589. }
  590. }
  591. TAGID
  592. SdbGetFirstChild(
  593. IN PDB pdb, // DB to use
  594. IN TAGID tiParent // parent to look in
  595. )
  596. /*++
  597. Return: The first child of tiParent, or TAGID_NULL if there are none.
  598. Desc: Returns the first child of tiParent, which must point to a tag
  599. of basic type LIST.
  600. --*/
  601. {
  602. TAGID tiParentEnd;
  603. TAGID tiReturn;
  604. assert(pdb);
  605. if (tiParent != TAGID_ROOT &&
  606. GETTAGTYPE(SdbGetTagFromTagID(pdb, tiParent)) != TAG_TYPE_LIST) {
  607. DBGPRINT((sdlError,
  608. "SdbGetFirstChild",
  609. "Trying to operate on non-list, non-root tag.\n"));
  610. return TAGID_NULL;
  611. }
  612. if (tiParent == TAGID_ROOT) {
  613. tiParentEnd = pdb->dwSize;
  614. //
  615. // Skip past the header.
  616. //
  617. tiReturn = sizeof(DB_HEADER);
  618. } else {
  619. tiParentEnd = SdbpGetNextTagId(pdb, tiParent);
  620. //
  621. // Just skip past the tag and size params.
  622. //
  623. tiReturn = tiParent + sizeof(TAG) + sizeof(DWORD);
  624. }
  625. if (tiReturn >= tiParentEnd) {
  626. tiReturn = TAGID_NULL;
  627. }
  628. return tiReturn;
  629. }
  630. TAGID
  631. SdbGetNextChild(
  632. IN PDB pdb, // DB to use
  633. IN TAGID tiParent, // parent to look in
  634. IN TAGID tiPrev // previously found child
  635. )
  636. /*++
  637. Return: The next child of tiParent, or TAGID_NULL if there are none.
  638. Desc: Returns the next child of tiParent after tiPrev. tiParent must point
  639. to a tag of basic type LIST.
  640. --*/
  641. {
  642. TAGID tiParentEnd;
  643. TAGID tiReturn;
  644. assert(pdb && tiPrev);
  645. if (tiParent != TAGID_ROOT &&
  646. GETTAGTYPE(SdbGetTagFromTagID(pdb, tiParent)) != TAG_TYPE_LIST) {
  647. DBGPRINT((sdlError,
  648. "SdbGetNextChild",
  649. "Trying to operate on non-list, non-root tag.\n"));
  650. return TAGID_NULL;
  651. }
  652. if (tiParent == TAGID_ROOT) {
  653. tiParentEnd = pdb->dwSize;
  654. } else {
  655. tiParentEnd = SdbpGetNextTagId(pdb, tiParent);
  656. }
  657. //
  658. // Get the next tag.
  659. //
  660. tiReturn = SdbpGetNextTagId(pdb, tiPrev);
  661. if (tiReturn >= tiParentEnd) {
  662. tiReturn = TAGID_NULL;
  663. }
  664. return tiReturn;
  665. }
  666. BOOL
  667. SdbpCreateSearchPathPartsFromPath(
  668. IN LPCTSTR pszPath,
  669. OUT PSEARCHPATHPARTS* ppSearchPathParts
  670. )
  671. /*++
  672. Return: Returns TRUE on success, FALSE on failure.
  673. Desc: This function breaks down a search path (PROCESS_HISTORY) into
  674. parts, with each part specifying a directory where the search
  675. for a matching binary to take place. Directories are organized
  676. in such a way that the last executed binary provides the first
  677. search path.
  678. --*/
  679. {
  680. LPCTSTR pszDir = pszPath;
  681. LPCTSTR pszDirEnd = NULL;
  682. ULONG nParts = 0;
  683. ULONG i = 0;
  684. PSEARCHPATHPARTS pSearchPathParts = NULL;
  685. if (pszPath == NULL) {
  686. DBGPRINT((sdlError,
  687. "SdbpCreateSearchPathPartsFromPath",
  688. "Invalid argument.\n"));
  689. return FALSE;
  690. }
  691. //
  692. // We count search path parts by counting semicolons in the path string
  693. // numberOfParts = numberOfSemicolons + 1
  694. //
  695. pszDir = pszPath;
  696. if (*pszDir != 0) {
  697. //
  698. // At least one part there...
  699. //
  700. nParts++;
  701. }
  702. while ((pszDir = _tcschr(pszDir, _T(';'))) != NULL) {
  703. pszDir++;
  704. nParts++;
  705. }
  706. //
  707. // nParts now has the number of parts in a search path.
  708. //
  709. pSearchPathParts = (PSEARCHPATHPARTS)SdbAlloc(sizeof(SEARCHPATHPARTS) +
  710. sizeof(SEARCHPATHPART) * nParts);
  711. if (pSearchPathParts == NULL) {
  712. DBGPRINT((sdlError,
  713. "SdbpCreateSearchPathPartsFromPath",
  714. "Failed to allocate %d bytes.\n",
  715. sizeof(SEARCHPATHPARTS) + sizeof(SEARCHPATHPART) * nParts));
  716. return FALSE;
  717. }
  718. pSearchPathParts->PartCount = nParts;
  719. pszDir = pszPath + _tcslen(pszPath);
  720. while (pszDir >= pszPath) {
  721. if (*pszDir == _T('\\') && pszDirEnd == NULL) {
  722. //
  723. // Points to the backslash
  724. //
  725. pszDirEnd = pszDir;
  726. }
  727. if ((*pszDir == _T(';') || pszPath == pszDir) && pszDirEnd != NULL) {
  728. //
  729. // At this point we should have an end to the string,
  730. // If not that means we are stepping from a recently found path
  731. //
  732. if (*pszDir == _T(';')) {
  733. pszDir++;
  734. }
  735. pSearchPathParts->Parts[i].pszPart = pszDir;
  736. pSearchPathParts->Parts[i].PartLength = (ULONG)(pszDirEnd - pszDir + 1);
  737. i++;
  738. pszDirEnd = NULL;
  739. }
  740. pszDir--;
  741. }
  742. *ppSearchPathParts = pSearchPathParts;
  743. return TRUE;
  744. }