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.

2176 lines
61 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. attributes.c
  5. Abstract:
  6. This file contains complete implementation of attribute retrieval and
  7. caching.
  8. Author:
  9. vadimb created sometime in 2000
  10. Revision History:
  11. several people contributed (clupu, dmunsil...)
  12. --*/
  13. //
  14. // Obtain tag information
  15. //
  16. #define _WANT_TAG_INFO
  17. #include "sdbp.h"
  18. #include <stddef.h>
  19. #include <time.h>
  20. #if defined(KERNEL_MODE) && defined(ALLOC_DATA_PRAGMA)
  21. #pragma data_seg()
  22. #endif // KERNEL_MODE && ALLOC_DATA_PRAGMA
  23. //
  24. // Attribute tags
  25. // The attributes are checked in the order they are listed below.
  26. //
  27. TAG g_rgAttributeTags[] = {
  28. TAG_SIZE,
  29. TAG_CHECKSUM,
  30. TAG_BIN_FILE_VERSION,
  31. TAG_BIN_PRODUCT_VERSION,
  32. TAG_PRODUCT_VERSION,
  33. TAG_FILE_DESCRIPTION,
  34. TAG_COMPANY_NAME,
  35. TAG_PRODUCT_NAME,
  36. TAG_FILE_VERSION,
  37. TAG_ORIGINAL_FILENAME,
  38. TAG_INTERNAL_NAME,
  39. TAG_LEGAL_COPYRIGHT,
  40. TAG_VERDATEHI,
  41. TAG_VERDATELO,
  42. TAG_VERFILEOS,
  43. TAG_VERFILETYPE,
  44. TAG_MODULE_TYPE,
  45. TAG_PE_CHECKSUM,
  46. TAG_LINKER_VERSION,
  47. #ifndef KERNEL_MODE
  48. TAG_16BIT_DESCRIPTION,
  49. TAG_16BIT_MODULE_NAME,
  50. #endif
  51. TAG_UPTO_BIN_FILE_VERSION,
  52. TAG_UPTO_BIN_PRODUCT_VERSION,
  53. TAG_LINK_DATE,
  54. TAG_UPTO_LINK_DATE,
  55. TAG_VER_LANGUAGE
  56. };
  57. #define ATTRIBUTE_COUNT ARRAYSIZE(g_rgAttributeTags)
  58. static TAG_INFO gaTagInfo[] = {
  59. {TAG_DATABASE ,TEXT("DATABASE")},
  60. {TAG_LIBRARY ,TEXT("LIBRARY")},
  61. {TAG_INEXCLUDE ,TEXT("INEXCLUDE")},
  62. {TAG_SHIM ,TEXT("SHIM")},
  63. {TAG_PATCH ,TEXT("PATCH")},
  64. {TAG_FLAG ,TEXT("FLAG")},
  65. {TAG_APP ,TEXT("APP")},
  66. {TAG_EXE ,TEXT("EXE")},
  67. {TAG_MATCHING_FILE ,TEXT("MATCHING_FILE")},
  68. {TAG_SHIM_REF ,TEXT("SHIM_REF")},
  69. {TAG_PATCH_REF ,TEXT("PATCH_REF")},
  70. {TAG_FLAG_REF ,TEXT("FLAG_REF")},
  71. {TAG_LAYER ,TEXT("LAYER")},
  72. {TAG_FILE ,TEXT("FILE")},
  73. {TAG_APPHELP ,TEXT("APPHELP")},
  74. {TAG_LINK ,TEXT("LINK")},
  75. {TAG_DATA ,TEXT("DATA")},
  76. {TAG_ACTION ,TEXT("ACTION")},
  77. {TAG_MSI_TRANSFORM ,TEXT("MSI TRANSFORM")},
  78. {TAG_MSI_TRANSFORM_REF ,TEXT("MSI TRANSFORM REF")},
  79. {TAG_MSI_PACKAGE ,TEXT("MSI PACKAGE")},
  80. {TAG_MSI_CUSTOM_ACTION ,TEXT("MSI CUSTOM ACTION")},
  81. {TAG_NAME ,TEXT("NAME")},
  82. {TAG_DESCRIPTION ,TEXT("DESCRIPTION")},
  83. {TAG_MODULE ,TEXT("MODULE")},
  84. {TAG_API ,TEXT("API")},
  85. {TAG_VENDOR ,TEXT("VENDOR")},
  86. {TAG_APP_NAME ,TEXT("APP_NAME")},
  87. {TAG_DLLFILE ,TEXT("DLLFILE")},
  88. {TAG_COMMAND_LINE ,TEXT("COMMAND_LINE")},
  89. {TAG_ACTION_TYPE ,TEXT("ACTION_TYPE")},
  90. {TAG_COMPANY_NAME ,TEXT("COMPANY_NAME")},
  91. {TAG_WILDCARD_NAME ,TEXT("WILDCARD_NAME")},
  92. {TAG_PRODUCT_NAME ,TEXT("PRODUCT_NAME")},
  93. {TAG_PRODUCT_VERSION ,TEXT("PRODUCT_VERSION")},
  94. {TAG_FILE_DESCRIPTION ,TEXT("FILE_DESCRIPTION")},
  95. {TAG_FILE_VERSION ,TEXT("FILE_VERSION")},
  96. {TAG_ORIGINAL_FILENAME ,TEXT("ORIGINAL_FILENAME")},
  97. {TAG_INTERNAL_NAME ,TEXT("INTERNAL_NAME")},
  98. {TAG_LEGAL_COPYRIGHT ,TEXT("LEGAL_COPYRIGHT")},
  99. {TAG_16BIT_DESCRIPTION ,TEXT("S16BIT_DESCRIPTION")},
  100. {TAG_APPHELP_DETAILS ,TEXT("PROBLEM_DETAILS")},
  101. {TAG_LINK_URL ,TEXT("LINK_URL")},
  102. {TAG_LINK_TEXT ,TEXT("LINK_TEXT")},
  103. {TAG_APPHELP_TITLE ,TEXT("APPHELP_TITLE")},
  104. {TAG_APPHELP_CONTACT ,TEXT("APPHELP_CONTACT")},
  105. {TAG_SXS_MANIFEST ,TEXT("SXS_MANIFEST")},
  106. {TAG_DATA_STRING ,TEXT("DATA_STRING")},
  107. {TAG_MSI_TRANSFORM_FILE ,TEXT("MSI_TRANSFORM_FILE")},
  108. {TAG_16BIT_MODULE_NAME ,TEXT("S16BIT_MODULE_NAME")},
  109. {TAG_LAYER_DISPLAYNAME ,TEXT("LAYER_DISPLAYNAME")},
  110. {TAG_COMPILER_VERSION ,TEXT("COMPILER_VERSION")},
  111. {TAG_SIZE ,TEXT("SIZE")},
  112. {TAG_OFFSET ,TEXT("OFFSET")},
  113. {TAG_CHECKSUM ,TEXT("CHECKSUM")},
  114. {TAG_SHIM_TAGID ,TEXT("SHIM_TAGID")},
  115. {TAG_PATCH_TAGID ,TEXT("PATCH_TAGID")},
  116. {TAG_LAYER_TAGID ,TEXT("LAYER_TAGID")},
  117. {TAG_FLAG_TAGID ,TEXT("FLAG_TAGID")},
  118. {TAG_MODULE_TYPE ,TEXT("MODULE_TYPE")},
  119. {TAG_VERDATEHI ,TEXT("VERFILEDATEHI")},
  120. {TAG_VERDATELO ,TEXT("VERFILEDATELO")},
  121. {TAG_VERFILEOS ,TEXT("VERFILEOS")},
  122. {TAG_VERFILETYPE ,TEXT("VERFILETYPE")},
  123. {TAG_PE_CHECKSUM ,TEXT("PE_CHECKSUM")},
  124. {TAG_LINKER_VERSION ,TEXT("LINKER_VERSION")},
  125. {TAG_LINK_DATE ,TEXT("LINK_DATE")},
  126. {TAG_UPTO_LINK_DATE ,TEXT("UPTO_LINK_DATE")},
  127. {TAG_OS_SERVICE_PACK ,TEXT("OS_SERVICE_PACK")},
  128. {TAG_VER_LANGUAGE ,TEXT("VER_LANGUAGE")},
  129. {TAG_PREVOSMAJORVER ,TEXT("PREVOSMAJORVERSION")},
  130. {TAG_PREVOSMINORVER ,TEXT("PREVOSMINORVERSION")},
  131. {TAG_PREVOSPLATFORMID ,TEXT("PREVOSPLATFORMID")},
  132. {TAG_PREVOSBUILDNO ,TEXT("PREVOSBUILDNO")},
  133. {TAG_PROBLEMSEVERITY ,TEXT("PROBLEM_SEVERITY")},
  134. {TAG_HTMLHELPID ,TEXT("HTMLHELPID")},
  135. {TAG_INDEX_FLAGS ,TEXT("INDEXFLAGS")},
  136. {TAG_LANGID ,TEXT("APPHELP_LANGID")},
  137. {TAG_ENGINE ,TEXT("ENGINE")},
  138. {TAG_FLAGS ,TEXT("FLAGS") },
  139. {TAG_DATA_VALUETYPE ,TEXT("VALUETYPE")},
  140. {TAG_DATA_DWORD ,TEXT("DATA_DWORD")},
  141. {TAG_MSI_TRANSFORM_TAGID,TEXT("MSI_TRANSFORM_TAGID")},
  142. {TAG_RUNTIME_PLATFORM, TEXT("RUNTIME_PLATFORM")},
  143. {TAG_OS_SKU, TEXT("OS_SKU")},
  144. {TAG_INCLUDE ,TEXT("INCLUDE")},
  145. {TAG_GENERAL ,TEXT("GENERAL")},
  146. {TAG_MATCH_LOGIC_NOT ,TEXT("MATCH_LOGIC_NOT")},
  147. {TAG_APPLY_ALL_SHIMS ,TEXT("APPLY_ALL_SHIMS")},
  148. {TAG_USE_SERVICE_PACK_FILES
  149. ,TEXT("USE_SERVICE_PACK_FILES")},
  150. {TAG_TIME ,TEXT("TIME")},
  151. {TAG_BIN_FILE_VERSION ,TEXT("BIN_FILE_VERSION")},
  152. {TAG_BIN_PRODUCT_VERSION,TEXT("BIN_PRODUCT_VERSION")},
  153. {TAG_MODTIME ,TEXT("MODTIME")},
  154. {TAG_FLAG_MASK_KERNEL ,TEXT("FLAG_MASK_KERNEL")},
  155. {TAG_FLAG_MASK_USER ,TEXT("FLAG_MASK_USER")},
  156. {TAG_FLAG_MASK_SHELL ,TEXT("FLAG_MASK_SHELL")},
  157. {TAG_UPTO_BIN_PRODUCT_VERSION, TEXT("UPTO_BIN_PRODUCT_VERSION")},
  158. {TAG_UPTO_BIN_FILE_VERSION, TEXT("UPTO_BIN_FILE_VERSION")},
  159. {TAG_DATA_QWORD ,TEXT("DATA_QWORD")},
  160. {TAG_FLAGS_NTVDM1 ,TEXT("FLAGS_NTVDM1")},
  161. {TAG_FLAGS_NTVDM2 ,TEXT("FLAGS_NTVDM2")},
  162. {TAG_FLAGS_NTVDM3 ,TEXT("FLAGS_NTVDM3")},
  163. {TAG_PATCH_BITS ,TEXT("PATCH_BITS")},
  164. {TAG_FILE_BITS ,TEXT("FILE_BITS")},
  165. {TAG_EXE_ID ,TEXT("EXE_ID(GUID)")},
  166. {TAG_DATA_BITS ,TEXT("DATA_BITS")},
  167. {TAG_MSI_PACKAGE_ID ,TEXT("MSI_PACKAGE_ID(GUID)")},
  168. {TAG_DATABASE_ID ,TEXT("DATABASE_ID(GUID)")},
  169. {TAG_MATCH_MODE ,TEXT("MATCH_MODE")},
  170. //
  171. // Internal types defined in shimdb.h
  172. //
  173. {TAG_STRINGTABLE ,TEXT("STRINGTABLE")},
  174. {TAG_INDEXES ,TEXT("INDEXES")},
  175. {TAG_INDEX ,TEXT("INDEX")},
  176. {TAG_INDEX_TAG ,TEXT("INDEX_TAG")},
  177. {TAG_INDEX_KEY ,TEXT("INDEX_KEY")},
  178. {TAG_INDEX_BITS ,TEXT("INDEX_BITS")},
  179. {TAG_STRINGTABLE_ITEM ,TEXT("STRTAB_ITEM")},
  180. {TAG_TAG ,TEXT("TAG")},
  181. {TAG_TAGID ,TEXT("TAGID")},
  182. {TAG_NULL ,TEXT("")} // always needs to be last item
  183. };
  184. static MOD_TYPE_STRINGS g_rgModTypeStrings[] = {
  185. {MT_UNKNOWN_MODULE, TEXT("NONE")},
  186. {MT_W16_MODULE, TEXT("WIN16")},
  187. {MT_W32_MODULE, TEXT("WIN32")},
  188. {MT_DOS_MODULE, TEXT("DOS")}
  189. };
  190. //
  191. // Version Strings for stringref attributes
  192. //
  193. typedef struct _VER_STRINGS {
  194. TAG tTag;
  195. LPTSTR szName;
  196. } VER_STRINGS;
  197. static VER_STRINGS g_rgVerStrings[] = {
  198. {TAG_PRODUCT_VERSION, TEXT("ProductVersion") },
  199. {TAG_FILE_DESCRIPTION, TEXT("FileDescription") },
  200. {TAG_COMPANY_NAME, TEXT("CompanyName") },
  201. {TAG_PRODUCT_NAME, TEXT("ProductName") },
  202. {TAG_FILE_VERSION, TEXT("FileVersion") },
  203. {TAG_ORIGINAL_FILENAME, TEXT("OriginalFilename") },
  204. {TAG_INTERNAL_NAME, TEXT("InternalName") },
  205. {TAG_LEGAL_COPYRIGHT, TEXT("LegalCopyright") }
  206. };
  207. //
  208. // Binary version tags (DWORDs and QWORDs)
  209. //
  210. //
  211. static TAG g_rgBinVerTags[] = {
  212. TAG_VERDATEHI,
  213. TAG_VERDATELO,
  214. TAG_VERFILEOS,
  215. TAG_VERFILETYPE,
  216. TAG_BIN_PRODUCT_VERSION,
  217. TAG_BIN_FILE_VERSION,
  218. TAG_UPTO_BIN_PRODUCT_VERSION,
  219. TAG_UPTO_BIN_FILE_VERSION
  220. };
  221. //
  222. // Binary header tags (retrieval requires opening a file).
  223. //
  224. static TAG g_rgHeaderTags[] = {
  225. TAG_MODULE_TYPE,
  226. TAG_PE_CHECKSUM,
  227. TAG_LINKER_VERSION,
  228. TAG_CHECKSUM,
  229. TAG_16BIT_DESCRIPTION,
  230. TAG_16BIT_MODULE_NAME,
  231. TAG_LINK_DATE,
  232. TAG_UPTO_LINK_DATE
  233. };
  234. //
  235. // Basic information tags (size).
  236. //
  237. TAG g_rgDirectoryTags[] = {
  238. TAG_SIZE,
  239. 0
  240. };
  241. //
  242. // Invalid tag token
  243. //
  244. static TCHAR s_szInvalidTag[] = _T("InvalidTag");
  245. #if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
  246. #pragma alloc_text(PAGE, TagToIndex)
  247. #pragma alloc_text(PAGE, SdbTagToString)
  248. #pragma alloc_text(PAGE, SdbpModuleTypeToString)
  249. #pragma alloc_text(PAGE, SdbpSetAttribute)
  250. #pragma alloc_text(PAGE, SdbpQueryStringVersionInformation)
  251. #pragma alloc_text(PAGE, SdbpQueryBinVersionInformation)
  252. #pragma alloc_text(PAGE, SdbpGetVersionAttributesNT)
  253. #pragma alloc_text(PAGE, SdbpGetHeaderAttributes)
  254. #pragma alloc_text(PAGE, SdbpGetAttribute)
  255. #pragma alloc_text(PAGE, SdbpCheckAttribute)
  256. #pragma alloc_text(PAGE, FindFileInfo)
  257. #pragma alloc_text(PAGE, CreateFileInfo)
  258. #pragma alloc_text(PAGE, SdbFreeFileInfo)
  259. #pragma alloc_text(PAGE, SdbpCleanupAttributeMgr)
  260. #pragma alloc_text(PAGE, SdbpCheckAllAttributes)
  261. #pragma alloc_text(PAGE, SdbpQueryVersionString)
  262. #pragma alloc_text(PAGE, SdbpGetModuleType)
  263. #pragma alloc_text(PAGE, SdbpGetModulePECheckSum)
  264. #pragma alloc_text(PAGE, SdbpGetImageNTHeader)
  265. #pragma alloc_text(PAGE, SdbpGetFileChecksum)
  266. #pragma alloc_text(PAGE, SdbpCheckVersion)
  267. #pragma alloc_text(PAGE, SdbpCheckUptoVersion)
  268. #endif // KERNEL_MODE && ALLOC_PRAGMA
  269. int
  270. TagToIndex(
  271. IN TAG tag // the tag
  272. )
  273. /*++
  274. Return: The index in the attribute info array (g_rgAttributeTags).
  275. Desc: Self explanatory.
  276. --*/
  277. {
  278. int i;
  279. for (i = 0; i < ATTRIBUTE_COUNT; i++) {
  280. if (tag == g_rgAttributeTags[i]) {
  281. return i;
  282. }
  283. }
  284. DBGPRINT((sdlError, "TagToIndex", "Invalid attribute 0x%x.\n", tag));
  285. return -1;
  286. }
  287. LPCTSTR
  288. SdbTagToString(
  289. TAG tag
  290. )
  291. /*++
  292. Return: The pointer to the string name for the specified tag.
  293. Desc: Self explanatory.
  294. --*/
  295. {
  296. int i;
  297. for (i = 0; i < ARRAYSIZE(gaTagInfo); ++i) {
  298. if (gaTagInfo[i].tWhich == tag) {
  299. return gaTagInfo[i].szName;
  300. }
  301. }
  302. return s_szInvalidTag;
  303. }
  304. LPCTSTR
  305. SdbpModuleTypeToString(
  306. DWORD dwModuleType
  307. )
  308. {
  309. int i;
  310. for (i = 0; i < ARRAYSIZE(g_rgModTypeStrings); ++i) {
  311. if (g_rgModTypeStrings[i].dwModuleType == dwModuleType) {
  312. return g_rgModTypeStrings[i].szModuleType;
  313. }
  314. }
  315. //
  316. // The first element is the "UNKNOWN" type -- NONE
  317. //
  318. return g_rgModTypeStrings[0].szModuleType;
  319. }
  320. BOOL
  321. SdbpSetAttribute(
  322. OUT PFILEINFO pFileInfo, // pointer to the FILEINFO structure.
  323. IN TAG AttrID, // Attribute ID (tag, as in TAG_SIZE
  324. IN PVOID pValue // value
  325. )
  326. /*++
  327. Return: TRUE on success, FALSE otherwise.
  328. Desc: This function sets the value for the specified attribute.
  329. If pValue is NULL it means that the specified attribute is not
  330. available for the file.
  331. --*/
  332. {
  333. int nAttrInd;
  334. PATTRINFO pAttrInfo;
  335. nAttrInd = TagToIndex(AttrID);
  336. if (nAttrInd < 0) {
  337. DBGPRINT((sdlError, "SdbpSetAttribute", "Invalid attribute %d.\n", nAttrInd));
  338. return FALSE;
  339. }
  340. pAttrInfo = &pFileInfo->Attributes[nAttrInd];
  341. if (pValue == NULL) {
  342. //
  343. // No value. Mark and exit.
  344. //
  345. pAttrInfo->dwFlags = (pAttrInfo->dwFlags & ~ATTRIBUTE_AVAILABLE) |
  346. ATTRIBUTE_FAILED;
  347. return TRUE;
  348. }
  349. switch (GETTAGTYPE(AttrID)) {
  350. case TAG_TYPE_DWORD:
  351. pAttrInfo->dwAttr = *(DWORD*)pValue;
  352. break;
  353. case TAG_TYPE_QWORD:
  354. pAttrInfo->ullAttr = *(ULONGLONG*)pValue;
  355. break;
  356. case TAG_TYPE_STRINGREF:
  357. pAttrInfo->lpAttr = (LPTSTR)pValue;
  358. break;
  359. }
  360. pAttrInfo->tAttrID = AttrID;
  361. pAttrInfo->dwFlags |= ATTRIBUTE_AVAILABLE;
  362. return TRUE;
  363. }
  364. //
  365. // This is a guard against bad code in version.dll that stomps over the
  366. // buffer size for Unicode apis on 16-bit exes.
  367. //
  368. #define VERSIONINFO_BUFFER_PAD 16
  369. void
  370. SdbpQueryStringVersionInformation(
  371. IN PSDBCONTEXT pContext,
  372. IN PFILEINFO pFileInfo,
  373. OUT LPVOID pVersionInfo
  374. )
  375. /*++
  376. Return: void.
  377. Desc: Sets all the version string info available for the specified file.
  378. --*/
  379. {
  380. int i;
  381. LPTSTR szVerString;
  382. PLANGANDCODEPAGE pLangCodePage = NULL;
  383. DWORD cbLangCP = 0;
  384. int nTranslations = 0;
  385. if (!pContext->pfnVerQueryValue(pVersionInfo,
  386. TEXT("\\VarFileInfo\\Translation"),
  387. (LPVOID)&pLangCodePage,
  388. &cbLangCP)) {
  389. DBGPRINT((sdlError,
  390. "SdbpQueryStringVersionInformation",
  391. "VerQueryValue failed for translation\n"));
  392. pLangCodePage = NULL;
  393. }
  394. nTranslations = cbLangCP / sizeof(*pLangCodePage);
  395. for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) {
  396. szVerString = SdbpQueryVersionString(pContext,
  397. pVersionInfo,
  398. pLangCodePage,
  399. nTranslations,
  400. g_rgVerStrings[i].szName);
  401. SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, szVerString);
  402. }
  403. #ifndef KERNEL_MODE
  404. //
  405. // Set the attribute for Language
  406. //
  407. if (pLangCodePage != NULL && nTranslations == 1) {
  408. DWORD dwLanguage = (DWORD)pLangCodePage->wLanguage;
  409. SdbpSetAttribute(pFileInfo, TAG_VER_LANGUAGE, &dwLanguage);
  410. } else {
  411. SdbpSetAttribute(pFileInfo, TAG_VER_LANGUAGE, NULL);
  412. }
  413. #endif // KERNEL_MODE
  414. }
  415. VOID
  416. SdbpQueryBinVersionInformation(
  417. IN PSDBCONTEXT pContext,
  418. IN PFILEINFO pFileInfo,
  419. OUT VS_FIXEDFILEINFO* pFixedInfo
  420. )
  421. /*++
  422. Return: void.
  423. Desc: Sets all the version string info available for the specified file
  424. from the fixed size resources.
  425. --*/
  426. {
  427. LARGE_INTEGER liVerData;
  428. SdbpSetAttribute(pFileInfo, TAG_VERDATEHI, &pFixedInfo->dwFileDateMS);
  429. SdbpSetAttribute(pFileInfo, TAG_VERDATELO, &pFixedInfo->dwFileDateLS);
  430. SdbpSetAttribute(pFileInfo, TAG_VERFILEOS, &pFixedInfo->dwFileOS);
  431. SdbpSetAttribute(pFileInfo, TAG_VERFILETYPE, &pFixedInfo->dwFileType);
  432. liVerData.LowPart = pFixedInfo->dwProductVersionLS;
  433. liVerData.HighPart = pFixedInfo->dwProductVersionMS;
  434. SdbpSetAttribute(pFileInfo, TAG_BIN_PRODUCT_VERSION, &liVerData.QuadPart);
  435. SdbpSetAttribute(pFileInfo, TAG_UPTO_BIN_PRODUCT_VERSION, &liVerData.QuadPart);
  436. liVerData.LowPart = pFixedInfo->dwFileVersionLS;
  437. liVerData.HighPart = pFixedInfo->dwFileVersionMS;
  438. SdbpSetAttribute(pFileInfo, TAG_BIN_FILE_VERSION, &liVerData.QuadPart);
  439. SdbpSetAttribute(pFileInfo, TAG_UPTO_BIN_FILE_VERSION, &liVerData.QuadPart);
  440. }
  441. #if defined(NT_MODE) || defined(KERNEL_MODE)
  442. BOOL
  443. SdbpGetVersionAttributesNT(
  444. IN PSDBCONTEXT pContext,
  445. OUT PFILEINFO pFileInfo,
  446. IN PIMAGEFILEDATA pImageData
  447. )
  448. /*++
  449. Return: TRUE on success, FALSE otherwise.
  450. Desc: This function retrieves all of the Version-related attributes
  451. Imports apis from version.dll if called for the first time
  452. --*/
  453. {
  454. BOOL bSuccess;
  455. LPVOID pVersionInfo = NULL;
  456. VS_FIXEDFILEINFO* pFixedInfo = NULL;
  457. int i;
  458. //
  459. // First retrieve the version info.
  460. //
  461. bSuccess = SdbpGetFileVersionInformation(pImageData, &pVersionInfo, &pFixedInfo);
  462. if (!bSuccess) {
  463. DBGPRINT((sdlInfo, "SdbpGetVersionAttributesNT", "No version info.\n"));
  464. goto ErrHandle;
  465. }
  466. //
  467. // Version information available.
  468. //
  469. //
  470. // Set the pointer to our internal function.
  471. //
  472. pContext->pfnVerQueryValue = SdbpVerQueryValue;
  473. for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) {
  474. SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL);
  475. }
  476. SdbpSetAttribute(pFileInfo, TAG_VER_LANGUAGE, NULL);
  477. //
  478. // Query binary stuff
  479. //
  480. SdbpQueryBinVersionInformation(pContext, pFileInfo, pFixedInfo);
  481. pFileInfo->pVersionInfo = pVersionInfo;
  482. return TRUE;
  483. ErrHandle:
  484. //
  485. // Reset all the string info.
  486. //
  487. for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) {
  488. SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL);
  489. }
  490. for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) {
  491. SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL);
  492. }
  493. return FALSE;
  494. }
  495. #endif // NT_MODE || KERNEL_MODE
  496. BOOL
  497. SdbpGetHeaderAttributes(
  498. IN PSDBCONTEXT pContext,
  499. OUT PFILEINFO pFileInfo
  500. )
  501. /*++
  502. Return: TRUE on success, FALSE otherwise.
  503. Desc: This function retrieves the header attributes for the
  504. specified file.
  505. --*/
  506. {
  507. IMAGEFILEDATA ImageData;
  508. HANDLE hFile;
  509. ULONG ulPEChecksum = 0;
  510. ULONG ulChecksum = 0;
  511. DWORD dwModuleType = 0;
  512. UNICODE_STRING ModuleDescription;
  513. DWORD dwLinkerVer;
  514. DWORD dwLinkDate;
  515. BOOL bReturn = FALSE;
  516. BOOL bSuccess;
  517. int i;
  518. ImageData.dwFlags = 0;
  519. if (pFileInfo->hFile != INVALID_HANDLE_VALUE) {
  520. ImageData.hFile = pFileInfo->hFile;
  521. ImageData.dwFlags |= IMAGEFILEDATA_HANDLEVALID;
  522. }
  523. if (pFileInfo->pImageBase != NULL) {
  524. ImageData.pBase = pFileInfo->pImageBase;
  525. ImageData.ViewSize = (SIZE_T) pFileInfo->dwImageSize;
  526. ImageData.FileSize = (ULONGLONG)pFileInfo->dwImageSize;
  527. ImageData.dwFlags |= IMAGEFILEDATA_PBASEVALID;
  528. }
  529. //
  530. // SdbpOpenAndMapFile uses DOS_PATH type as an argument
  531. // In kernel mode this parameter is ignored.
  532. //
  533. if (SdbpOpenAndMapFile(pFileInfo->FilePath, &ImageData, DOS_PATH)) {
  534. bSuccess = SdbpGetModuleType(&dwModuleType, &ImageData);
  535. SdbpSetAttribute(pFileInfo, TAG_MODULE_TYPE, bSuccess ? (PVOID)&dwModuleType : NULL);
  536. bSuccess = SdbpGetModulePECheckSum(&ulPEChecksum, &dwLinkerVer, &dwLinkDate, &ImageData);
  537. SdbpSetAttribute(pFileInfo, TAG_PE_CHECKSUM, bSuccess ? (PVOID)&ulPEChecksum : NULL);
  538. SdbpSetAttribute(pFileInfo, TAG_LINKER_VERSION, bSuccess ? (PVOID)&dwLinkerVer : NULL);
  539. SdbpSetAttribute(pFileInfo, TAG_LINK_DATE, bSuccess ? (PVOID)&dwLinkDate : NULL);
  540. SdbpSetAttribute(pFileInfo, TAG_UPTO_LINK_DATE, bSuccess ? (PVOID)&dwLinkDate : NULL);
  541. bSuccess = SdbpGetFileChecksum(&ulChecksum, &ImageData);
  542. SdbpSetAttribute(pFileInfo, TAG_CHECKSUM, bSuccess ? (PVOID)&ulChecksum : NULL);
  543. #ifndef KERNEL_MODE
  544. //
  545. // Now retrieve 16-bit description string, it's max size is 256 bytes.
  546. //
  547. // This attribute is not available in kernel mode.
  548. //
  549. bSuccess = SdbpGet16BitDescription(&pFileInfo->pDescription16, &ImageData);
  550. SdbpSetAttribute(pFileInfo, TAG_16BIT_DESCRIPTION, pFileInfo->pDescription16);
  551. bSuccess = SdbpGet16BitModuleName(&pFileInfo->pModuleName16, &ImageData);
  552. SdbpSetAttribute(pFileInfo, TAG_16BIT_MODULE_NAME, pFileInfo->pModuleName16);
  553. #if defined(NT_MODE)
  554. //
  555. // Hit this case only on current platform
  556. //
  557. if (pFileInfo->hFile != INVALID_HANDLE_VALUE || pFileInfo->pImageBase != NULL) {
  558. SdbpGetVersionAttributesNT(pContext, pFileInfo, &ImageData);
  559. }
  560. #endif // NT_MODE
  561. #else // KERNEL_MODE
  562. //
  563. // When we are running in kernel mode retrieve version-related
  564. // data now as well.
  565. //
  566. SdbpGetVersionAttributesNT(pContext, pFileInfo, &ImageData);
  567. //
  568. // Retrieve file directory attributes.
  569. //
  570. SdbpGetFileDirectoryAttributesNT(pFileInfo, &ImageData);
  571. #endif // KERNEL_MODE
  572. SdbpUnmapAndCloseFile(&ImageData);
  573. return TRUE;
  574. }
  575. for (i = 0; i < ARRAYSIZE(g_rgHeaderTags); ++i) {
  576. SdbpSetAttribute(pFileInfo, g_rgHeaderTags[i], NULL);
  577. }
  578. #ifdef KERNEL_MODE
  579. //
  580. // Reset all the version attributes here as well.
  581. //
  582. for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) {
  583. SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL);
  584. }
  585. for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) {
  586. SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL);
  587. }
  588. #endif // KERNEL_MODE
  589. return FALSE;
  590. }
  591. BOOL
  592. SdbpGetAttribute(
  593. IN PSDBCONTEXT pContext,
  594. OUT PFILEINFO pFileInfo,
  595. IN TAG AttrID
  596. )
  597. /*++
  598. Return: TRUE on success, FALSE otherwise.
  599. Desc: Retrieve an attribute for a given file. We retrieve all the
  600. attributes of the same class.
  601. --*/
  602. {
  603. BOOL bReturn = FALSE;
  604. switch (AttrID) {
  605. //
  606. // The tags below require checking the file and making a directory query.
  607. //
  608. case TAG_SIZE:
  609. #ifndef KERNEL_MODE // in kernel mode we fall through to header attributes
  610. bReturn = SdbpGetFileDirectoryAttributes(pFileInfo);
  611. break;
  612. #endif // KERNEL_MODE
  613. //
  614. // The tags below require retrieving version resources.
  615. //
  616. case TAG_VERDATEHI:
  617. case TAG_VERDATELO:
  618. case TAG_VERFILEOS:
  619. case TAG_VERFILETYPE:
  620. case TAG_UPTO_BIN_PRODUCT_VERSION:
  621. case TAG_UPTO_BIN_FILE_VERSION:
  622. case TAG_BIN_FILE_VERSION:
  623. case TAG_BIN_PRODUCT_VERSION:
  624. case TAG_PRODUCT_VERSION:
  625. case TAG_FILE_DESCRIPTION:
  626. case TAG_COMPANY_NAME:
  627. case TAG_PRODUCT_NAME:
  628. case TAG_FILE_VERSION:
  629. case TAG_ORIGINAL_FILENAME:
  630. case TAG_INTERNAL_NAME:
  631. case TAG_LEGAL_COPYRIGHT:
  632. case TAG_VER_LANGUAGE:
  633. //
  634. // In KERNEL_MODE we fall through and do the attributes using the
  635. // header attributes.
  636. //
  637. #ifndef KERNEL_MODE
  638. //
  639. // Version attributes are retrieved through the header attributes if
  640. // caller provided a handle/image base
  641. //
  642. if (pFileInfo->hFile == INVALID_HANDLE_VALUE && pFileInfo->pImageBase == NULL) {
  643. bReturn = SdbpGetVersionAttributes(pContext, pFileInfo);
  644. break;
  645. }
  646. #endif // KERNEL_MODE
  647. //
  648. // The tags below require opening a file and mapping it into memory.
  649. //
  650. case TAG_CHECKSUM:
  651. case TAG_PE_CHECKSUM:
  652. case TAG_LINKER_VERSION:
  653. case TAG_16BIT_DESCRIPTION:
  654. case TAG_16BIT_MODULE_NAME:
  655. case TAG_MODULE_TYPE:
  656. case TAG_UPTO_LINK_DATE:
  657. case TAG_LINK_DATE:
  658. bReturn = SdbpGetHeaderAttributes(pContext, pFileInfo);
  659. break;
  660. }
  661. return bReturn;
  662. }
  663. BOOL
  664. SdbpCheckAttribute(
  665. IN PSDBCONTEXT pContext, // Database Context pointer
  666. IN PVOID pFileData, // pointer returned from CheckFile
  667. IN TAG AttrID, // Attribute ID
  668. IN PVOID pAttribute // attribute value ptr (see above for description)
  669. )
  670. /*++
  671. Return: TRUE if the value for given attribute matches
  672. the file's attribute, FALSE otherwise.
  673. Desc: Check an attribute against a given value. This function
  674. retrieves attributes as necessary.
  675. --*/
  676. {
  677. int nAttrIndex;
  678. PATTRINFO pAttrInfo;
  679. BOOL bReturn = FALSE;
  680. PFILEINFO pFileInfo = (PFILEINFO)pFileData;
  681. if (pAttribute == NULL) {
  682. DBGPRINT((sdlError, "SdbpCheckAttribute", "Invalid parameter.\n"));
  683. return FALSE;
  684. }
  685. nAttrIndex = TagToIndex(AttrID);
  686. if (nAttrIndex < 0) {
  687. DBGPRINT((sdlError, "SdbpCheckAttribute", "Bad Attribute ID 0x%x\n", AttrID));
  688. return FALSE;
  689. }
  690. //
  691. // Now see if this attribute is any good.
  692. //
  693. pAttrInfo = &pFileInfo->Attributes[nAttrIndex];
  694. if (!(pAttrInfo->dwFlags & ATTRIBUTE_AVAILABLE)) {
  695. //
  696. // See if we have tried already
  697. //
  698. if (pAttrInfo->dwFlags & ATTRIBUTE_FAILED) {
  699. DBGPRINT((sdlInfo,
  700. "SdbpCheckAttribute",
  701. "Already tried to get attr ID 0x%x.\n",
  702. AttrID));
  703. return FALSE;
  704. }
  705. //
  706. // The attribute has not been retrieved yet, do it now then.
  707. //
  708. // Try to obtain this attribute from the file.
  709. //
  710. if (!SdbpGetAttribute(pContext, pFileInfo, AttrID)) {
  711. DBGPRINT((sdlWarning,
  712. "SdbpCheckAttribute",
  713. "Failed to get attribute \"%s\" for \"%s\"\n",
  714. SdbTagToString(AttrID),
  715. pFileInfo->FilePath));
  716. //
  717. // ATTRIBUTE_FAILED is set by the SdbpGetAttribute
  718. //
  719. return FALSE;
  720. }
  721. }
  722. //
  723. // Check again here in case we had to retrieve the attribute.
  724. //
  725. if (!(pAttrInfo->dwFlags & ATTRIBUTE_AVAILABLE)) {
  726. return FALSE;
  727. }
  728. switch (AttrID) {
  729. case TAG_BIN_PRODUCT_VERSION:
  730. case TAG_BIN_FILE_VERSION:
  731. bReturn = SdbpCheckVersion(*(ULONGLONG*)pAttribute, pAttrInfo->ullAttr);
  732. if (!bReturn) {
  733. ULONGLONG qwDBFileVer = *(ULONGLONG*)pAttribute;
  734. ULONGLONG qwBinFileVer = pAttrInfo->ullAttr;
  735. DBGPRINT((sdlInfo,
  736. "SdbpCheckAttribute",
  737. "\"%s\" mismatch file: \"%s\". Expected %d.%d.%d.%d, Found %d.%d.%d.%d\n",
  738. SdbTagToString(AttrID),
  739. pFileInfo->FilePath,
  740. (WORD)(qwDBFileVer >> 48),
  741. (WORD)(qwDBFileVer >> 32),
  742. (WORD)(qwDBFileVer >> 16),
  743. (WORD)(qwDBFileVer),
  744. (WORD)(qwBinFileVer >> 48),
  745. (WORD)(qwBinFileVer >> 32),
  746. (WORD)(qwBinFileVer >> 16),
  747. (WORD)(qwBinFileVer)));
  748. }
  749. break;
  750. case TAG_UPTO_BIN_PRODUCT_VERSION:
  751. case TAG_UPTO_BIN_FILE_VERSION:
  752. bReturn = SdbpCheckUptoVersion(*(ULONGLONG*)pAttribute, pAttrInfo->ullAttr);
  753. if (!bReturn) {
  754. ULONGLONG qwDBFileVer = *(ULONGLONG*)pAttribute;
  755. ULONGLONG qwBinFileVer = pAttrInfo->ullAttr;
  756. DBGPRINT((sdlInfo,
  757. "SdbpCheckAttribute",
  758. "\"%s\" mismatch file: \"%s\". Expected %d.%d.%d.%d, Found %d.%d.%d.%d\n",
  759. SdbTagToString(AttrID),
  760. pFileInfo->FilePath,
  761. (WORD)(qwDBFileVer >> 48),
  762. (WORD)(qwDBFileVer >> 32),
  763. (WORD)(qwDBFileVer >> 16),
  764. (WORD)(qwDBFileVer),
  765. (WORD)(qwBinFileVer >> 48),
  766. (WORD)(qwBinFileVer >> 32),
  767. (WORD)(qwBinFileVer >> 16),
  768. (WORD)(qwBinFileVer)));
  769. }
  770. break;
  771. case TAG_UPTO_LINK_DATE:
  772. bReturn = (*(DWORD*)pAttribute >= pAttrInfo->dwAttr);
  773. if (!bReturn) {
  774. DBGPRINT((sdlInfo,
  775. "SdbpCheckAttribute",
  776. "\"%s\" mismatch file \"%s\". Expected less than 0x%x Found 0x%x\n",
  777. SdbTagToString(AttrID),
  778. pFileInfo->FilePath,
  779. *(DWORD*)pAttribute,
  780. pAttrInfo->dwAttr));
  781. }
  782. break;
  783. default:
  784. switch (GETTAGTYPE(AttrID)) {
  785. case TAG_TYPE_DWORD:
  786. //
  787. // This is likely to be hit first.
  788. //
  789. bReturn = (*(DWORD*)pAttribute == pAttrInfo->dwAttr);
  790. if (!bReturn) {
  791. DBGPRINT((sdlInfo,
  792. "SdbpCheckAttribute",
  793. "\"%s\" mismatch file \"%s\". Expected 0x%x Found 0x%x\n",
  794. SdbTagToString(AttrID),
  795. pFileInfo->FilePath,
  796. *(DWORD*)pAttribute,
  797. pAttrInfo->dwAttr));
  798. }
  799. break;
  800. case TAG_TYPE_STRINGREF:
  801. bReturn = SdbpPatternMatch((LPCTSTR)pAttribute, (LPCTSTR)pAttrInfo->lpAttr);
  802. if (!bReturn) {
  803. DBGPRINT((sdlInfo,
  804. "SdbpCheckAttribute",
  805. "\"%s\" mismatch file \"%s\". Expected \"%s\" Found \"%s\"\n",
  806. SdbTagToString(AttrID),
  807. pFileInfo->FilePath,
  808. pAttribute,
  809. pAttrInfo->lpAttr));
  810. }
  811. break;
  812. case TAG_TYPE_QWORD:
  813. bReturn = (*(ULONGLONG*)pAttribute == pAttrInfo->ullAttr);
  814. if (!bReturn) {
  815. DBGPRINT((sdlInfo,
  816. "SdbpCheckAttribute",
  817. "\"%s\" mismatch file \"%s\". Expected 0x%I64x Found 0x%I64x\n",
  818. SdbTagToString(AttrID),
  819. pFileInfo->FilePath,
  820. *(ULONGLONG*)pAttribute,
  821. pAttrInfo->ullAttr));
  822. }
  823. break;
  824. }
  825. break;
  826. }
  827. return bReturn;
  828. }
  829. PFILEINFO
  830. FindFileInfo(
  831. IN PSDBCONTEXT pContext,
  832. IN LPCTSTR FilePath
  833. )
  834. /*++
  835. Return: A pointer to the cached FILEINFO structure if one is found
  836. or NULL otherwise.
  837. Desc: This function performs a search in the file cache to determine whether
  838. a given file has already been touched.
  839. --*/
  840. {
  841. PFILEINFO pFileInfo = (PFILEINFO)pContext->pFileAttributeCache; // global cache
  842. while (pFileInfo != NULL) {
  843. if (ISEQUALSTRING(pFileInfo->FilePath, FilePath)) {
  844. DBGPRINT((sdlInfo,
  845. "FindFileInfo",
  846. "FILEINFO for \"%s\" found in the cache.\n",
  847. FilePath));
  848. return pFileInfo;
  849. }
  850. pFileInfo = pFileInfo->pNext;
  851. }
  852. return NULL;
  853. }
  854. PFILEINFO
  855. CreateFileInfo(
  856. IN PSDBCONTEXT pContext,
  857. IN LPCTSTR FullPath,
  858. IN DWORD dwLength OPTIONAL, // length (in characters) of FullPath string
  859. IN HANDLE hFile OPTIONAL, // file handle
  860. IN LPVOID pImageBase OPTIONAL,
  861. IN DWORD dwImageSize OPTIONAL,
  862. IN BOOL bNoCache
  863. )
  864. /*++
  865. Return: A pointer to the allocated FILEINFO structure.
  866. Desc: Allocates the FILEINFO structure for the specified file.
  867. --*/
  868. {
  869. PFILEINFO pFileInfo;
  870. SIZE_T sizeBase;
  871. SIZE_T size;
  872. DWORD nPathLen;
  873. nPathLen = dwLength ? dwLength : (DWORD)_tcslen(FullPath);
  874. sizeBase = sizeof(*pFileInfo) + ATTRIBUTE_COUNT * sizeof(ATTRINFO);
  875. size = sizeBase + (nPathLen + 1) * sizeof(*FullPath);
  876. pFileInfo = (PFILEINFO)SdbAlloc(size);
  877. if (pFileInfo == NULL) {
  878. DBGPRINT((sdlError,
  879. "CreateFileInfo",
  880. "Failed to allocate %d bytes for FILEINFO structure.\n",
  881. size));
  882. return NULL;
  883. }
  884. RtlZeroMemory(pFileInfo, size);
  885. pFileInfo->FilePath = (LPTSTR)((PBYTE)pFileInfo + sizeBase);
  886. RtlCopyMemory(pFileInfo->FilePath, FullPath, nPathLen * sizeof(*FullPath));
  887. pFileInfo->FilePath[nPathLen] = TEXT('\0');
  888. pFileInfo->hFile = hFile;
  889. pFileInfo->pImageBase = pImageBase;
  890. pFileInfo->dwImageSize = dwImageSize;
  891. //
  892. // Now link it in if we use the cache.
  893. //
  894. if (!bNoCache) {
  895. pFileInfo->pNext = (PFILEINFO)pContext->pFileAttributeCache;
  896. pContext->pFileAttributeCache = (PVOID)pFileInfo;
  897. }
  898. return pFileInfo;
  899. }
  900. void
  901. SdbFreeFileInfo(
  902. IN PVOID pFileData // pointer returned from SdbpGetFileAttributes
  903. )
  904. /*++
  905. Return: void.
  906. Desc: Self explanatory. Use this only after calling GetFileInfo
  907. with bNoCache set to TRUE.
  908. --*/
  909. {
  910. PFILEINFO pFileInfo = (PFILEINFO)pFileData;
  911. if (pFileInfo == NULL) {
  912. DBGPRINT((sdlError, "SdbFreeFileInfo", "Invalid parameter.\n"));
  913. return;
  914. }
  915. if (pFileInfo->pVersionInfo != NULL) {
  916. SdbFree(pFileInfo->pVersionInfo);
  917. }
  918. if (pFileInfo->pDescription16 != NULL) {
  919. SdbFree(pFileInfo->pDescription16);
  920. }
  921. if (pFileInfo->pModuleName16 != NULL) {
  922. SdbFree(pFileInfo->pModuleName16);
  923. }
  924. SdbFree(pFileInfo);
  925. }
  926. void
  927. SdbpCleanupAttributeMgr(
  928. IN PSDBCONTEXT pContext // database context
  929. )
  930. /*++
  931. Return: void.
  932. Desc: This function should be called afer we are done checking a given exe
  933. it performs cleanup tasks, such as:
  934. . unload dynamically linked dll (version.dll)
  935. . cleanup file cache
  936. --*/
  937. {
  938. PFILEINFO pFileInfo = (PFILEINFO)pContext->pFileAttributeCache;
  939. PFILEINFO pNext;
  940. while (pFileInfo != NULL) {
  941. pNext = pFileInfo->pNext;
  942. SdbFreeFileInfo(pFileInfo);
  943. pFileInfo = pNext;
  944. }
  945. //
  946. // Reset the cache pointer.
  947. //
  948. pContext->pFileAttributeCache = NULL;
  949. }
  950. BOOL
  951. SdbpCheckAllAttributes(
  952. IN PSDBCONTEXT pContext, // pointer to the database channel
  953. IN PDB pdb, // pointer to the Shim Database that we're checking against
  954. IN TAGID tiMatch, // TAGID for a given file(exe) to be checked
  955. IN PVOID pFileData // pointer returned from CheckFile
  956. )
  957. /*++
  958. Return: TRUE if all the file's attributes match the ones described in the
  959. database for this file, FALSE otherwise.
  960. Desc: TBD
  961. --*/
  962. {
  963. int i;
  964. TAG tAttrID;
  965. PVOID pAttribute;
  966. TAGID tiTemp;
  967. DWORD dwAttribute;
  968. ULONGLONG ullAttribute;
  969. BOOL bReturn = TRUE; // match by default
  970. assert(tiMatch != TAGID_NULL);
  971. if (pFileData == NULL) {
  972. //
  973. // No file was passed in. This can happen if LOGIC="NOT" is used.
  974. //
  975. return FALSE;
  976. }
  977. for (i = 0; i < ATTRIBUTE_COUNT && bReturn; ++i) {
  978. tAttrID = g_rgAttributeTags[i];
  979. tiTemp = SdbFindFirstTag(pdb, tiMatch, tAttrID);
  980. if (tiTemp != TAGID_NULL) {
  981. pAttribute = NULL;
  982. switch (GETTAGTYPE(tAttrID)) {
  983. case TAG_TYPE_DWORD:
  984. dwAttribute = SdbReadDWORDTag(pdb, tiTemp, 0);
  985. pAttribute = &dwAttribute;
  986. break;
  987. case TAG_TYPE_QWORD:
  988. ullAttribute = SdbReadQWORDTag(pdb, tiTemp, 0);
  989. pAttribute = &ullAttribute;
  990. break;
  991. case TAG_TYPE_STRINGREF:
  992. pAttribute = SdbGetStringTagPtr(pdb, tiTemp);
  993. break;
  994. }
  995. //
  996. // Now check the attribute.
  997. //
  998. bReturn = SdbpCheckAttribute(pContext, pFileData, tAttrID, pAttribute);
  999. //
  1000. // we bail out if !bReturn via the condition in FOR loop above
  1001. //
  1002. }
  1003. }
  1004. return bReturn;
  1005. }
  1006. //
  1007. // VERSION DATA
  1008. //
  1009. /*--
  1010. Search order is:
  1011. - Language neutral, Unicode (0x000004B0)
  1012. - Language neutral, Windows-multilingual (0x000004e4)
  1013. - US English, Unicode (0x040904B0)
  1014. - US English, Windows-multilingual (0x040904E4)
  1015. If none of those exist, it's not likely we're going to get good
  1016. matching info from what does exist.
  1017. --*/
  1018. LPTSTR
  1019. SdbpQueryVersionString(
  1020. IN PSDBCONTEXT pContext, // the database channel
  1021. IN PVOID pVersionData, // Version data buffer
  1022. IN PLANGANDCODEPAGE pTranslations,
  1023. IN DWORD TranslationCount,
  1024. IN LPCTSTR szString // String to search for; see VerQueryValue in MSDN
  1025. )
  1026. /*++
  1027. Return: The pointer to the string if found, NULL if not.
  1028. Desc: Gets a pointer to a particular string in the StringFileInfo section
  1029. of a version resource.
  1030. Lookup is performed for known english-language resources followed up
  1031. by a lookup in the available translations section (if such was found)
  1032. --*/
  1033. {
  1034. TCHAR szTemp[128];
  1035. LPTSTR szReturn = NULL;
  1036. int i;
  1037. static DWORD adwLangs[] = {0x000004B0, 0x000004E4, 0x040904B0, 0x040904E4};
  1038. assert(pVersionData && szString);
  1039. for (i = 0; i < ARRAYSIZE(adwLangs); ++i) {
  1040. UINT unLen;
  1041. _stprintf(szTemp, _T("\\StringFileInfo\\%08X\\%s"), adwLangs[i], szString);
  1042. if (pContext->pfnVerQueryValue(pVersionData, szTemp, (PVOID*)&szReturn, &unLen)) {
  1043. return szReturn;
  1044. }
  1045. }
  1046. if (pTranslations != NULL) {
  1047. for (i = 0; i < (int)TranslationCount; ++i, ++pTranslations) {
  1048. UINT unLen;
  1049. _stprintf(szTemp, _T("\\StringFileInfo\\%04X%04X\\%s"),
  1050. (DWORD)pTranslations->wLanguage,
  1051. (DWORD)pTranslations->wCodePage,
  1052. szString);
  1053. if (pContext->pfnVerQueryValue(pVersionData, szTemp, (PVOID*)&szReturn, &unLen)) {
  1054. return szReturn;
  1055. }
  1056. }
  1057. }
  1058. return NULL; // none found
  1059. }
  1060. BOOL
  1061. SdbpGetModuleType(
  1062. OUT LPDWORD lpdwModuleType,
  1063. IN PIMAGEFILEDATA pImageData
  1064. )
  1065. /*++
  1066. Return: TRUE on success, FALSE otherwise.
  1067. Desc: Gets a pointer to a particular string in the StringFileInfo section
  1068. of a version resource.
  1069. --*/
  1070. {
  1071. PIMAGE_DOS_HEADER pDosHeader;
  1072. DWORD dwModuleType = MT_UNKNOWN_MODULE;
  1073. LPBYTE lpSignature;
  1074. DWORD OffsetNew;
  1075. pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase;
  1076. if (pDosHeader == NULL || pDosHeader == (PIMAGE_DOS_HEADER)-1) {
  1077. return FALSE;
  1078. }
  1079. //
  1080. // Check size and read signature.
  1081. //
  1082. if (pImageData->ViewSize < sizeof(*pDosHeader) || pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
  1083. return FALSE;
  1084. }
  1085. //
  1086. // Assume DOS module.
  1087. //
  1088. dwModuleType = MT_DOS_MODULE;
  1089. OffsetNew = (DWORD)pDosHeader->e_lfanew;
  1090. //
  1091. // New header signature. Check offset.
  1092. //
  1093. if (pImageData->ViewSize < OffsetNew + sizeof(DWORD)) {
  1094. return FALSE;
  1095. }
  1096. lpSignature = ((LPBYTE)pImageData->pBase + OffsetNew);
  1097. if (IMAGE_NT_SIGNATURE == *(LPDWORD)lpSignature) {
  1098. dwModuleType = MT_W32_MODULE;
  1099. } else if (IMAGE_OS2_SIGNATURE == *(PWORD)lpSignature) {
  1100. dwModuleType = MT_W16_MODULE;
  1101. }
  1102. if (lpdwModuleType != NULL) {
  1103. *lpdwModuleType = dwModuleType;
  1104. }
  1105. return TRUE;
  1106. }
  1107. BOOL
  1108. SdbpGetImageNTHeader(
  1109. OUT PIMAGE_NT_HEADERS* ppHeader,
  1110. IN PIMAGEFILEDATA pImageData
  1111. )
  1112. /*++
  1113. Return: TRUE on success, FALSE otherwise.
  1114. Desc: Gets a pointer to the IMAGE_NT_HEADERS.
  1115. --*/
  1116. {
  1117. PIMAGE_DOS_HEADER pDosHeader;
  1118. PIMAGE_NT_HEADERS pNtHeaders = NULL;
  1119. DWORD ModuleType;
  1120. if (!SdbpGetModuleType(&ModuleType, pImageData)) {
  1121. return FALSE;
  1122. }
  1123. if (ModuleType != MT_W32_MODULE) {
  1124. return FALSE;
  1125. }
  1126. //
  1127. // Header is valid.
  1128. //
  1129. pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase;
  1130. pNtHeaders = (PIMAGE_NT_HEADERS)((LPBYTE)pImageData->pBase + pDosHeader->e_lfanew);
  1131. if (pImageData->ViewSize >= pDosHeader->e_lfanew + sizeof(*pNtHeaders)) { // not too short?
  1132. *ppHeader = pNtHeaders;
  1133. return TRUE;
  1134. }
  1135. return FALSE;
  1136. }
  1137. BOOL
  1138. SdbpGetModulePECheckSum(
  1139. OUT PULONG pChecksum,
  1140. OUT LPDWORD pdwLinkerVersion,
  1141. OUT LPDWORD pdwLinkDate,
  1142. IN PIMAGEFILEDATA pImageData
  1143. )
  1144. /*++
  1145. Return: TRUE on success, FALSE otherwise.
  1146. Desc: Gets the checksum from the PE headers.
  1147. --*/
  1148. {
  1149. PIMAGE_NT_HEADERS pNtHeader;
  1150. PIMAGE_DOS_HEADER pDosHeader;
  1151. ULONG ulChecksum = 0;
  1152. if (!SdbpGetImageNTHeader(&pNtHeader, pImageData)) {
  1153. DBGPRINT((sdlError, "SdbpGetModulePECheckSum", "Failed to get Image NT header.\n"));
  1154. return FALSE;
  1155. }
  1156. pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase;
  1157. //
  1158. // Fill in the linker version (as it used to calculated in ntuser).
  1159. //
  1160. *pdwLinkerVersion = (pNtHeader->OptionalHeader.MinorImageVersion & 0xFF) +
  1161. ((pNtHeader->OptionalHeader.MajorImageVersion & 0xFF) << 16);
  1162. *pdwLinkDate = pNtHeader->FileHeader.TimeDateStamp;
  1163. switch (pNtHeader->OptionalHeader.Magic) {
  1164. case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
  1165. if (pImageData->ViewSize >= pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS32)) {
  1166. ulChecksum = ((PIMAGE_NT_HEADERS32)pNtHeader)->OptionalHeader.CheckSum;
  1167. *pChecksum = ulChecksum;
  1168. return TRUE;
  1169. }
  1170. break;
  1171. case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
  1172. //
  1173. // Do an additional check.
  1174. //
  1175. if (pImageData->ViewSize >= pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS64)) {
  1176. ulChecksum = ((PIMAGE_NT_HEADERS64)pNtHeader)->OptionalHeader.CheckSum;
  1177. *pChecksum = ulChecksum;
  1178. return TRUE;
  1179. }
  1180. break;
  1181. default:
  1182. //
  1183. // Unknown image type ?
  1184. //
  1185. DBGPRINT((sdlError,
  1186. "SdbpGetModulePECheckSum",
  1187. "Bad image type 0x%x\n",
  1188. pNtHeader->OptionalHeader.Magic));
  1189. *pChecksum = 0;
  1190. break;
  1191. }
  1192. return FALSE;
  1193. }
  1194. #define CHECKSUM_SIZE 4096
  1195. #define CHECKSUM_START 512
  1196. BOOL
  1197. SdbpGetFileChecksum(
  1198. OUT PULONG pChecksum,
  1199. IN PIMAGEFILEDATA pImageData
  1200. )
  1201. /*++
  1202. Return: TRUE on success, FALSE otherwise.
  1203. Desc: Calculates a checksum for the file.
  1204. --*/
  1205. {
  1206. ULONG size = CHECKSUM_SIZE;
  1207. ULONG StartAddress = CHECKSUM_START;
  1208. ULONG ulChecksum = 0;
  1209. LPDWORD lpdw;
  1210. int i;
  1211. if ((SIZE_T)pImageData->FileSize < (SIZE_T)size) {
  1212. StartAddress = 0;
  1213. size = (ULONG)pImageData->FileSize; // this is safe (size is rather small)
  1214. } else if ((SIZE_T)(size + StartAddress) > (SIZE_T)pImageData->FileSize) {
  1215. //
  1216. // The cast here is safe (FileSize is small)
  1217. //
  1218. StartAddress = (ULONG)(pImageData->FileSize - size);
  1219. }
  1220. if (size >= sizeof(DWORD)) {
  1221. ULONG ulCarry;
  1222. lpdw = (LPDWORD)((LPBYTE)pImageData->pBase + StartAddress);
  1223. for (i = 0; i < (INT)(size/sizeof(DWORD)); ++i) {
  1224. if (PtrToUlong(lpdw) & 0x3) { // alignment fault fixup
  1225. ulChecksum += *((DWORD UNALIGNED*)lpdw);
  1226. lpdw++;
  1227. } else {
  1228. ulChecksum += *lpdw++;
  1229. }
  1230. ulCarry = ulChecksum & 1;
  1231. ulChecksum >>= 1;
  1232. if (ulCarry) {
  1233. ulChecksum |= 0x80000000;
  1234. }
  1235. }
  1236. }
  1237. *pChecksum = ulChecksum;
  1238. return TRUE;
  1239. }
  1240. BOOL
  1241. SdbpCheckVersion(
  1242. IN ULONGLONG qwDBFileVer,
  1243. IN ULONGLONG qwBinFileVer
  1244. )
  1245. /*++
  1246. Return: TRUE if the versions match, FALSE if they don't.
  1247. Desc: Checks a binary version from the db against the version from
  1248. the file, including allowing for wildcards, which are represented
  1249. in the DB by using FFFF for that word-sized portion of the version.
  1250. --*/
  1251. {
  1252. WORD wDBSegment, wFileSegment;
  1253. int i;
  1254. for (i = 3; i >= 0; --i) {
  1255. //
  1256. // Get the appropriate word out of the QWORD
  1257. //
  1258. wDBSegment = (WORD)(qwDBFileVer >> (16 * i));
  1259. wFileSegment = (WORD)(qwBinFileVer >> (16 * i));
  1260. //
  1261. // The DB segment may be 0xFFFF, in which case it matches on
  1262. // everything.
  1263. //
  1264. if (wDBSegment != wFileSegment && wDBSegment != 0xFFFF) {
  1265. return FALSE;
  1266. }
  1267. }
  1268. return TRUE;
  1269. }
  1270. BOOL
  1271. SdbpCheckUptoVersion(
  1272. IN ULONGLONG qwDBFileVer,
  1273. IN ULONGLONG qwBinFileVer
  1274. )
  1275. /*++
  1276. Return: TRUE if the versions match, FALSE if they don't.
  1277. Desc: Checks a binary version from the db against the version from
  1278. the file, including allowing for wildcards, which are represented
  1279. in the DB by using FFFF for that word-sized portion of the version.
  1280. --*/
  1281. {
  1282. WORD wDBSegment, wFileSegment;
  1283. BOOL bReturn = TRUE;
  1284. int i;
  1285. for (i = 3; i >= 0; --i) {
  1286. //
  1287. // Get the appropriate word out of the QWORD
  1288. //
  1289. wDBSegment = (WORD)(qwDBFileVer >> (16 * i));
  1290. wFileSegment = (WORD)(qwBinFileVer >> (16 * i));
  1291. if (wDBSegment == wFileSegment || wDBSegment == 0xFFFF) {
  1292. continue;
  1293. }
  1294. //
  1295. // At this point we know that the two values don't match
  1296. // the wFileSegment has to be less than wDBSegment to satisfy this
  1297. // test - so set bReturn and exit
  1298. //
  1299. bReturn = (wDBSegment > wFileSegment);
  1300. break;
  1301. }
  1302. return bReturn;
  1303. }
  1304. #ifndef KERNEL_MODE
  1305. BOOL
  1306. SdbFormatAttribute(
  1307. IN PATTRINFO pAttrInfo, // pointer to the attribute information
  1308. OUT LPTSTR pchBuffer, // receives XML corresponding to the given attribute
  1309. IN DWORD dwBufferSize // size in wide characters of the buffer pchBuffer
  1310. )
  1311. /*++
  1312. Return: FALSE if the buffer is too small or attribute not available.
  1313. Desc: TBD.
  1314. --*/
  1315. {
  1316. int nchBuffer = (int)dwBufferSize;
  1317. int nch;
  1318. TCHAR lpszAttr[MAX_PATH];
  1319. #if defined(WIN32A_MODE) || defined(WIN32U_MODE)
  1320. struct tm* ptm;
  1321. time_t tt;
  1322. #else
  1323. LARGE_INTEGER liTime;
  1324. TIME_FIELDS TimeFields;
  1325. #endif
  1326. if (!(pAttrInfo->dwFlags & ATTRIBUTE_AVAILABLE)) {
  1327. return FALSE;
  1328. }
  1329. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("%s="), SdbTagToString(pAttrInfo->tAttrID));
  1330. if (nch < 0) {
  1331. DBGPRINT((sdlError,
  1332. "SdbFormatAttribute",
  1333. "Buffer is too small to accomodate \"%s\"\n",
  1334. SdbTagToString(pAttrInfo->tAttrID)));
  1335. return FALSE;
  1336. }
  1337. nchBuffer -= nch; // we advance the pointer past the "name="
  1338. pchBuffer += nch;
  1339. nch = -1;
  1340. switch (pAttrInfo->tAttrID) {
  1341. case TAG_BIN_PRODUCT_VERSION:
  1342. case TAG_BIN_FILE_VERSION:
  1343. case TAG_UPTO_BIN_PRODUCT_VERSION:
  1344. case TAG_UPTO_BIN_FILE_VERSION:
  1345. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%d.%d.%d.%d\""),
  1346. (WORD)(pAttrInfo->ullAttr >> 48),
  1347. (WORD)(pAttrInfo->ullAttr >> 32),
  1348. (WORD)(pAttrInfo->ullAttr >> 16),
  1349. (WORD)(pAttrInfo->ullAttr));
  1350. break;
  1351. case TAG_MODULE_TYPE:
  1352. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%s\""),
  1353. SdbpModuleTypeToString(pAttrInfo->dwAttr));
  1354. break;
  1355. case TAG_VER_LANGUAGE:
  1356. //
  1357. // language is a dword attribute that we shall make a string out of
  1358. //
  1359. {
  1360. TCHAR szLanguageName[MAX_PATH];
  1361. DWORD dwLength;
  1362. szLanguageName[0] = TEXT('\0');
  1363. dwLength = VerLanguageName((LANGID)pAttrInfo->dwAttr,
  1364. szLanguageName,
  1365. CHARCOUNT(szLanguageName));
  1366. if (dwLength) {
  1367. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%s [0x%x]\""),
  1368. szLanguageName, pAttrInfo->dwAttr);
  1369. } else {
  1370. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"0x%x\""),
  1371. pAttrInfo->dwAttr);
  1372. }
  1373. }
  1374. break;
  1375. case TAG_LINK_DATE:
  1376. case TAG_UPTO_LINK_DATE:
  1377. #if defined(WIN32A_MODE) || defined(WIN32U_MODE)
  1378. tt = (time_t) pAttrInfo->dwAttr;
  1379. ptm = gmtime(&tt);
  1380. if (ptm) {
  1381. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%02d/%02d/%02d %02d:%02d:%02d\""),
  1382. ptm->tm_mon+1,
  1383. ptm->tm_mday,
  1384. ptm->tm_year+1900,
  1385. ptm->tm_hour,
  1386. ptm->tm_min,
  1387. ptm->tm_sec);
  1388. }
  1389. #else
  1390. RtlSecondsSince1970ToTime((ULONG)pAttrInfo->dwAttr, &liTime);
  1391. RtlTimeToTimeFields(&liTime, &TimeFields);
  1392. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%02d/%02d/%02d %02d:%02d:%02d\""),
  1393. TimeFields.Month,
  1394. TimeFields.Day,
  1395. TimeFields.Year,
  1396. TimeFields.Hour,
  1397. TimeFields.Minute,
  1398. TimeFields.Second);
  1399. #endif
  1400. break;
  1401. case TAG_SIZE:
  1402. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"%ld\""), pAttrInfo->dwAttr);
  1403. break;
  1404. default:
  1405. switch (GETTAGTYPE(pAttrInfo->tAttrID)) {
  1406. case TAG_TYPE_DWORD:
  1407. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"0x%lX\""),
  1408. pAttrInfo->dwAttr);
  1409. break;
  1410. case TAG_TYPE_QWORD:
  1411. //
  1412. // This is an unidentified QWORD attribute
  1413. //
  1414. DBGPRINT((sdlError, "SdbFormatAttribute", "Unexpected qword attribute found\n"));
  1415. nch = _sntprintf(pchBuffer, nchBuffer, TEXT("\"0x%I64X\""), pAttrInfo->ullAttr);
  1416. break;
  1417. case TAG_TYPE_STRINGREF:
  1418. if (nchBuffer < 3) {
  1419. return FALSE; // not enough room even for " ?
  1420. }
  1421. *pchBuffer++ = TEXT('\"');
  1422. nchBuffer--;
  1423. if (!SdbpSanitizeXML(pchBuffer, nchBuffer, pAttrInfo->lpAttr)) {
  1424. // handle error please
  1425. return FALSE;
  1426. }
  1427. //
  1428. // Once done with this, sanitize further
  1429. //
  1430. if (!SafeNCat(pchBuffer, nchBuffer, TEXT("\""), -1)) {
  1431. return FALSE;
  1432. }
  1433. nch = 0;
  1434. break;
  1435. }
  1436. }
  1437. return (nch >= 0); // evaluates to TRUE when we successfully printed the value into the buffer
  1438. }
  1439. BOOL
  1440. SdbpGetVersionAttributes(
  1441. IN PSDBCONTEXT pContext,
  1442. OUT PFILEINFO pFileInfo
  1443. )
  1444. /*++
  1445. Return: TRUE on success, FALSE otherwise.
  1446. Desc: This function retrieves all of the Version-related attributes
  1447. Imports apis from version.dll if called for the first time
  1448. --*/
  1449. {
  1450. BOOL bSuccess;
  1451. DWORD dwNull = 0;
  1452. VS_FIXEDFILEINFO* pFixedInfo = NULL; // fixed info ptr
  1453. UINT FixedInfoSize = 0;
  1454. PVOID pBuffer = NULL; // version data buffer
  1455. DWORD dwBufferSize; // version data buffer size
  1456. int i;
  1457. #ifdef NT_MODE
  1458. //
  1459. // check to see whether we need to run NT routine
  1460. //
  1461. if (pFileInfo->hFile != INVALID_HANDLE_VALUE || pFileInfo->pImageBase != NULL) {
  1462. //
  1463. // not an error -- this case is handled in header attributes
  1464. //
  1465. goto err;
  1466. }
  1467. #endif // NT_MODE
  1468. if (pContext == NULL) {
  1469. //
  1470. // Special case when it's called with null context.
  1471. // In this case we use an internal structure allocated from the stack.
  1472. //
  1473. STACK_ALLOC(pContext, sizeof(SDBCONTEXT));
  1474. if (pContext == NULL) {
  1475. DBGPRINT((sdlError,
  1476. "SdbpGetVersionAttributes",
  1477. "Failed to allocate %d bytes from stack\n",
  1478. sizeof(SDBCONTEXT)));
  1479. goto err;
  1480. }
  1481. RtlZeroMemory(pContext, sizeof(SDBCONTEXT));
  1482. }
  1483. #ifdef WIN32A_MODE
  1484. pContext->pfnGetFileVersionInfoSize = GetFileVersionInfoSizeA;
  1485. pContext->pfnGetFileVersionInfo = GetFileVersionInfoA;
  1486. pContext->pfnVerQueryValue = VerQueryValueA;
  1487. #else
  1488. pContext->pfnGetFileVersionInfoSize = GetFileVersionInfoSizeW;
  1489. pContext->pfnGetFileVersionInfo = GetFileVersionInfoW;
  1490. pContext->pfnVerQueryValue = VerQueryValueW;
  1491. #endif
  1492. dwBufferSize = pContext->pfnGetFileVersionInfoSize(pFileInfo->FilePath, &dwNull);
  1493. if (dwBufferSize == 0) {
  1494. DBGPRINT((sdlInfo, "SdbpGetVersionAttributes", "No version info.\n"));
  1495. //
  1496. // We have failed to obtain version attributes
  1497. //
  1498. goto err;
  1499. }
  1500. pBuffer = SdbAlloc(dwBufferSize + VERSIONINFO_BUFFER_PAD);
  1501. if (pBuffer == NULL) {
  1502. DBGPRINT((sdlError,
  1503. "SdbpGetVersionAttributes",
  1504. "Failed to allocate %d bytes for version info buffer.\n",
  1505. dwBufferSize + VERSIONINFO_BUFFER_PAD));
  1506. goto err;
  1507. }
  1508. if (!pContext->pfnGetFileVersionInfo(pFileInfo->FilePath, 0, dwBufferSize, pBuffer)) {
  1509. DBGPRINT((sdlError,
  1510. "SdbpGetVersionAttributes",
  1511. "Failed to retrieve version info for file \"%s\"",
  1512. pFileInfo->FilePath));
  1513. goto err;
  1514. }
  1515. if (!pContext->pfnVerQueryValue(pBuffer,
  1516. TEXT("\\"),
  1517. (PVOID*)&pFixedInfo,
  1518. &FixedInfoSize)) {
  1519. DBGPRINT((sdlError,
  1520. "SdbpGetVersionAttributes",
  1521. "Failed to query for fixed version info size for \"%s\"\n",
  1522. pFileInfo->FilePath));
  1523. goto err;
  1524. }
  1525. //
  1526. // Retrieve string attributes.
  1527. //
  1528. SdbpQueryStringVersionInformation(pContext, pFileInfo, pBuffer);
  1529. //
  1530. // Now retrieve other attributes.
  1531. //
  1532. if (FixedInfoSize >= sizeof(VS_FIXEDFILEINFO)) {
  1533. SdbpQueryBinVersionInformation(pContext, pFileInfo, pFixedInfo);
  1534. } else {
  1535. //
  1536. // No other version attributes are available. Set the rest of the
  1537. // attributes as being not available.
  1538. //
  1539. for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) {
  1540. SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL);
  1541. }
  1542. }
  1543. //
  1544. // Store the pointer to the version info buffer.
  1545. //
  1546. pFileInfo->pVersionInfo = pBuffer;
  1547. return TRUE;
  1548. err:
  1549. //
  1550. // We are here ONLY when we failed to obtain version info
  1551. // through apis -- regardless of the state of other value we might have
  1552. // obtained
  1553. if (pBuffer != NULL) {
  1554. SdbFree(pBuffer);
  1555. }
  1556. for (i = 0; i < ARRAYSIZE(g_rgBinVerTags); ++i) {
  1557. SdbpSetAttribute(pFileInfo, g_rgBinVerTags[i], NULL);
  1558. }
  1559. for (i = 0; i < ARRAYSIZE(g_rgVerStrings); ++i) {
  1560. SdbpSetAttribute(pFileInfo, g_rgVerStrings[i].tTag, NULL);
  1561. }
  1562. return FALSE;
  1563. }
  1564. BOOL
  1565. SdbpGetFileDirectoryAttributes(
  1566. OUT PFILEINFO pFileInfo
  1567. )
  1568. /*++
  1569. Return: TRUE on success, FALSE otherwise.
  1570. Desc: This function retrieves the file directory attributes for the
  1571. specified file.
  1572. --*/
  1573. {
  1574. BOOL bSuccess = FALSE;
  1575. FILEDIRECTORYATTRIBUTES fda;
  1576. int i;
  1577. bSuccess = SdbpQueryFileDirectoryAttributes(pFileInfo->FilePath, &fda);
  1578. if (!bSuccess) {
  1579. DBGPRINT((sdlInfo,
  1580. "SdbpGetFileDirectoryAttributes",
  1581. "No file directory attributes available.\n"));
  1582. goto Done;
  1583. }
  1584. if (fda.dwFlags & FDA_FILESIZE) {
  1585. assert(fda.dwFileSizeHigh == 0);
  1586. SdbpSetAttribute(pFileInfo, TAG_SIZE, &fda.dwFileSizeLow);
  1587. }
  1588. Done:
  1589. if (!bSuccess) {
  1590. for (i = 0; g_rgDirectoryTags[i] != 0; ++i) {
  1591. SdbpSetAttribute(pFileInfo, g_rgDirectoryTags[i], NULL);
  1592. }
  1593. }
  1594. return bSuccess;
  1595. }
  1596. BOOL
  1597. SdbGetFileAttributes(
  1598. IN LPCTSTR lpwszFileName, // the file for which attributes are requested
  1599. OUT PATTRINFO* ppAttrInfo, // receives allocated pointer to the attribute array
  1600. OUT LPDWORD lpdwAttrCount // receives the number of entries in an attributes table
  1601. )
  1602. /*++
  1603. Return: FALSE if the file does not exist or some other severe error had occured.
  1604. Note that each attribute has it's own flag ATTRIBUTE_AVAILABLE that allows
  1605. for checking whether an attribute has been retrieved successfully
  1606. Not all attributes might be present for all files.
  1607. Desc: TBD
  1608. --*/
  1609. {
  1610. PFILEINFO pFileInfo;
  1611. BOOL bReturn;
  1612. //
  1613. // The call below allocates the structure, context is not used
  1614. //
  1615. pFileInfo = SdbGetFileInfo(NULL, lpwszFileName, INVALID_HANDLE_VALUE, NULL, 0, TRUE);
  1616. if (pFileInfo == NULL) {
  1617. DBGPRINT((sdlError, "SdbGetFileAttributes", "Error retrieving FILEINFO structure\n"));
  1618. return FALSE;
  1619. }
  1620. //
  1621. // The three calls below, even when fail do not produce a fatal condition
  1622. // as the exe may not have all the attributes available.
  1623. //
  1624. bReturn = SdbpGetFileDirectoryAttributes(pFileInfo);
  1625. if (!bReturn) {
  1626. DBGPRINT((sdlInfo, "SdbGetFileAttributes", "Error retrieving directory attributes\n"));
  1627. }
  1628. bReturn = SdbpGetVersionAttributes(NULL, pFileInfo);
  1629. if (!bReturn) {
  1630. DBGPRINT((sdlInfo, "SdbGetFileAttributes", "Error retrieving version attributes\n"));
  1631. }
  1632. bReturn = SdbpGetHeaderAttributes(NULL, pFileInfo);
  1633. if (!bReturn) {
  1634. DBGPRINT((sdlInfo, "SdbGetFileAttributes", "Error retrieving header attributes\n"));
  1635. }
  1636. pFileInfo->dwMagic = FILEINFO_MAGIC;
  1637. //
  1638. // Now that we are done, put the return pointer.
  1639. //
  1640. if (lpdwAttrCount != NULL) {
  1641. *lpdwAttrCount = ATTRIBUTE_COUNT;
  1642. }
  1643. if (ppAttrInfo != NULL) {
  1644. //
  1645. // Return the pointer to the attribute info itself.
  1646. // It is the same pointer we expect to get in a complimentary
  1647. // call to SdbFreeFileInfo.
  1648. //
  1649. *ppAttrInfo = &pFileInfo->Attributes[0];
  1650. } else {
  1651. //
  1652. // Pointer is not needed. Release the memory.
  1653. //
  1654. SdbFreeFileInfo(pFileInfo);
  1655. }
  1656. return TRUE;
  1657. }
  1658. BOOL
  1659. SdbFreeFileAttributes(
  1660. IN PATTRINFO pFileAttributes // pointer returned by SdbGetFileAttributes
  1661. )
  1662. /*++
  1663. Return: FALSE if a wrong pointer was passed in (not the one
  1664. from SdbGetFileAttributes).
  1665. Desc: Self explanatory.
  1666. --*/
  1667. {
  1668. PFILEINFO pFileInfo;
  1669. //
  1670. // We are assuming the pointer that was passed in points inside of a
  1671. // larger structure FILEINFO. To verify that we step back a pre-determined number
  1672. // of bytes (calculated below as an offset) and check the "magic" signature.
  1673. //
  1674. pFileInfo = (PFILEINFO)((PBYTE)pFileAttributes - OFFSETOF(FILEINFO, Attributes));
  1675. if (pFileInfo->dwMagic != FILEINFO_MAGIC) {
  1676. DBGPRINT((sdlError, "SdbFreeFileAttributes", "Bad pointer to attributes.\n"));
  1677. return FALSE;
  1678. }
  1679. SdbFreeFileInfo(pFileInfo);
  1680. return TRUE;
  1681. }
  1682. BOOL
  1683. SdbpQuery16BitDescription(
  1684. OUT LPSTR szBuffer, // min length 256 chars !
  1685. IN PIMAGEFILEDATA pImageData
  1686. )
  1687. /*++
  1688. Return: TRUE on success, FALSE otherwise.
  1689. Desc: Gets the 16 bit description for a DOS executable.
  1690. --*/
  1691. {
  1692. PIMAGE_DOS_HEADER pDosHeader;
  1693. PIMAGE_OS2_HEADER pNEHeader;
  1694. PBYTE pSize;
  1695. DWORD ModuleType;
  1696. if (!SdbpGetModuleType(&ModuleType, pImageData)) {
  1697. return FALSE;
  1698. }
  1699. if (ModuleType != MT_W16_MODULE) {
  1700. return FALSE;
  1701. }
  1702. pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase;
  1703. pNEHeader = (PIMAGE_OS2_HEADER)((PBYTE)pImageData->pBase + pDosHeader->e_lfanew);
  1704. //
  1705. // Now we know that pNEHeader is valid, just have to make sure that
  1706. // the next offset is valid as well, make a check against file size.
  1707. //
  1708. if (pImageData->ViewSize < pDosHeader->e_lfanew + sizeof(*pNEHeader)) {
  1709. return FALSE;
  1710. }
  1711. if (pImageData->ViewSize < pNEHeader->ne_nrestab + sizeof(*pSize)) {
  1712. return FALSE;
  1713. }
  1714. pSize = (PBYTE)((PBYTE)pImageData->pBase + pNEHeader->ne_nrestab);
  1715. if (*pSize == 0) {
  1716. return FALSE;
  1717. }
  1718. //
  1719. // Now check for the string size.
  1720. //
  1721. if (pImageData->ViewSize < pNEHeader->ne_nrestab + sizeof(*pSize) + *pSize) {
  1722. return FALSE;
  1723. }
  1724. RtlCopyMemory(szBuffer, pSize + 1, *pSize);
  1725. szBuffer[*pSize] = '\0';
  1726. return TRUE;
  1727. }
  1728. BOOL
  1729. SdbpQuery16BitModuleName(
  1730. OUT LPSTR szBuffer,
  1731. IN PIMAGEFILEDATA pImageData
  1732. )
  1733. {
  1734. PIMAGE_DOS_HEADER pDosHeader;
  1735. PIMAGE_OS2_HEADER pNEHeader;
  1736. PBYTE pSize;
  1737. DWORD ModuleType;
  1738. if (!SdbpGetModuleType(&ModuleType, pImageData)) {
  1739. return FALSE;
  1740. }
  1741. if (ModuleType != MT_W16_MODULE) {
  1742. return FALSE;
  1743. }
  1744. pDosHeader = (PIMAGE_DOS_HEADER)pImageData->pBase;
  1745. pNEHeader = (PIMAGE_OS2_HEADER)((PBYTE)pImageData->pBase + pDosHeader->e_lfanew);
  1746. //
  1747. // Now we know that pNEHeader is valid, just have to make sure that
  1748. // the next offset is valid as well, make a check against file size.
  1749. //
  1750. if (pImageData->ViewSize < pDosHeader->e_lfanew + sizeof(*pNEHeader)) {
  1751. return FALSE;
  1752. }
  1753. if (pImageData->ViewSize < pNEHeader->ne_restab + sizeof(*pSize)) {
  1754. return FALSE;
  1755. }
  1756. pSize = (PBYTE)((PBYTE)pImageData->pBase + pDosHeader->e_lfanew + pNEHeader->ne_restab);
  1757. if (*pSize == 0) {
  1758. return FALSE;
  1759. }
  1760. //
  1761. // Now check for the string size.
  1762. //
  1763. if (pImageData->ViewSize <
  1764. pDosHeader->e_lfanew + pNEHeader->ne_restab + sizeof(*pSize) + *pSize) {
  1765. return FALSE;
  1766. }
  1767. RtlCopyMemory(szBuffer, pSize + 1, *pSize);
  1768. szBuffer[*pSize] = '\0';
  1769. return TRUE;
  1770. }
  1771. #endif // KERNEL_MODE