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.

443 lines
12 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. sdbapi.c
  5. Abstract:
  6. ANTI-BUGBUG: This module implements ...
  7. NT-only version information retrieval
  8. Author:
  9. VadimB created sometime toward the end of November 2000
  10. Revision History:
  11. several people contributed (vadimb, clupu, ...)
  12. --*/
  13. #include "sdbp.h"
  14. BOOL
  15. SdbpGetFileVersionInformation(
  16. IN PIMAGEFILEDATA pImageData, // we assume that the file has been mapped
  17. // in for other purposes
  18. OUT LPVOID* ppVersionInfo, // receives pointer to the (allocated) version
  19. // resource
  20. OUT VS_FIXEDFILEINFO** ppFixedVersionInfo // receives pointer to fixed version info
  21. );
  22. BOOL
  23. SdbpVerQueryValue(
  24. const LPVOID pb,
  25. LPVOID lpSubBlockX, // can be only unicode
  26. LPVOID* lplpBuffer,
  27. PUINT puLen
  28. );
  29. #if defined(KERNEL_MODE) && defined(ALLOC_DATA_PRAGMA)
  30. #pragma data_seg()
  31. #endif // KERNEL_MODE && ALLOC_DATA_PRAGMA
  32. #if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
  33. #pragma alloc_text(PAGE, SdbpGetFileVersionInformation)
  34. #pragma alloc_text(PAGE, SdbpVerQueryValue)
  35. #endif // KERNEL_MODE && ALLOC_PRAGMA
  36. typedef struct _RESOURCE_DATAW {
  37. USHORT TotalSize;
  38. USHORT DataSize;
  39. USHORT Type;
  40. WCHAR szName[16]; // L"VS_VERSION_INFO" + unicode nul
  41. VS_FIXEDFILEINFO FixedFileInfo;
  42. } VERSIONINFOW, *PVERSIONINFOW;
  43. BOOL
  44. SdbpGetFileVersionInformation(
  45. IN PIMAGEFILEDATA pImageData, // we assume that the file has been mapped
  46. // in for other purposes
  47. OUT LPVOID* ppVersionInfo, // receives pointer to the (allocated) version
  48. // resource
  49. OUT VS_FIXEDFILEINFO** ppFixedVersionInfo // receives pointer to fixed version info
  50. )
  51. /*++
  52. Return: BUGBUG: ?
  53. Desc: BUGBUG: ?
  54. --*/
  55. {
  56. NTSTATUS Status;
  57. ULONG_PTR ulPath[3];
  58. ULONG ulSize; // size of the resource
  59. LPVOID pImageBase;
  60. PVERSIONINFOW pVersionInfo = NULL;
  61. ULONG ulVersionSize = 0;
  62. LPVOID pVersionBuffer;
  63. DWORD dwModuleType = MT_UNKNOWN_MODULE;
  64. PIMAGE_RESOURCE_DATA_ENTRY pImageResourceData;
  65. //
  66. // Check module type first. We only recognize win32 modules.
  67. //
  68. if (!SdbpGetModuleType(&dwModuleType, pImageData) || dwModuleType != MT_W32_MODULE) {
  69. DBGPRINT((sdlError,
  70. "SdbpGetFileVersionInformation",
  71. "Bad module type 0x%x\n",
  72. dwModuleType));
  73. return FALSE;
  74. }
  75. pImageBase = (LPVOID)pImageData->pBase;
  76. //
  77. // Setup the path to the resource
  78. //
  79. ulPath[0] = PtrToUlong(RT_VERSION);
  80. ulPath[1] = PtrToUlong(MAKEINTRESOURCE(VS_VERSION_INFO));
  81. ulPath[2] = 0;
  82. //
  83. // See if the resource has come through.
  84. //
  85. __try {
  86. Status = LdrFindResource_U(pImageBase, ulPath, 3, &pImageResourceData);
  87. if (!NT_SUCCESS(Status)) {
  88. DBGPRINT((sdlError,
  89. "SdbpGetFileVersionInformation",
  90. "LdrFindResource_U failed status 0x%x\n",
  91. Status));
  92. return FALSE;
  93. }
  94. Status = LdrAccessResource(pImageBase, pImageResourceData, &pVersionInfo, &ulVersionSize);
  95. if (!NT_SUCCESS(Status)) {
  96. DBGPRINT((sdlError,
  97. "SdbpGetFileVersionInformation",
  98. "LdrAccessResource failed Status 0x%x\n",
  99. Status));
  100. return FALSE;
  101. }
  102. } __except(EXCEPTION_EXECUTE_HANDLER) {
  103. DBGPRINT((sdlError,
  104. "SdbpGetFileVersionInformation",
  105. "Exception while trying to retrieve version-related information\n"));
  106. Status = STATUS_UNSUCCESSFUL;
  107. }
  108. if (!NT_SUCCESS(Status)) {
  109. return FALSE;
  110. }
  111. //
  112. // Check to make sure that what we have got is good.
  113. //
  114. if (sizeof(*pVersionInfo) > ulVersionSize ||
  115. _wcsicmp(pVersionInfo->szName, L"VS_VERSION_INFO") != 0) {
  116. DBGPRINT((sdlError,
  117. "SdbpGetFileVersionInformation",
  118. "Bad version resource\n"));
  119. return FALSE;
  120. }
  121. //
  122. // Now we have a pointer to the resource data. Allocate version information.
  123. //
  124. pVersionBuffer = (LPVOID)SdbAlloc(ulVersionSize);
  125. if (pVersionBuffer == NULL) {
  126. DBGPRINT((sdlError,
  127. "SdbpGetFileVersionInformation",
  128. "Failed to allocate %d bytes for version information\n",
  129. ulVersionSize));
  130. return FALSE;
  131. }
  132. //
  133. // Copy all the version-related information
  134. //
  135. RtlMoveMemory(pVersionBuffer, pVersionInfo, ulVersionSize);
  136. if (ppFixedVersionInfo != NULL) {
  137. *ppFixedVersionInfo = &(((PVERSIONINFOW)pVersionBuffer)->FixedFileInfo);
  138. }
  139. assert(ppVersionInfo != NULL);
  140. *ppVersionInfo = pVersionBuffer;
  141. return TRUE;
  142. }
  143. ////////////////////////////////////////////////////////////////////////////
  144. //
  145. // This code was taken from Cornel's win2k tree
  146. //
  147. #define DWORDUP(x) (((x) + 3) & ~3)
  148. typedef struct tagVERBLOCK {
  149. WORD wTotLen;
  150. WORD wValLen;
  151. WORD wType;
  152. WCHAR szKey[1];
  153. } VERBLOCK ;
  154. typedef struct tagVERHEAD {
  155. WORD wTotLen;
  156. WORD wValLen;
  157. WORD wType; /* always 0 */
  158. WCHAR szKey[(sizeof("VS_VERSION_INFO") + 3) & ~03];
  159. VS_FIXEDFILEINFO vsf;
  160. } VERHEAD ;
  161. BOOL
  162. SdbpVerQueryValue(
  163. const LPVOID pb,
  164. LPVOID lpSubBlockX, // can be only unicode
  165. LPVOID* lplpBuffer,
  166. PUINT puLen
  167. )
  168. /*++
  169. Return: BUGBUG: ?
  170. Desc: BUGBUG: ?
  171. --*/
  172. {
  173. ANSI_STRING AnsiString;
  174. UNICODE_STRING UnicodeString;
  175. LPWSTR lpSubBlockOrg;
  176. LPWSTR lpSubBlock;
  177. NTSTATUS Status;
  178. VERBLOCK* pBlock = (PVOID)pb;
  179. LPWSTR lpStart, lpEndBlock, lpEndSubBlock;
  180. WCHAR cTemp, cEndBlock;
  181. DWORD dwHeadLen, dwTotBlockLen;
  182. BOOL bLastSpec;
  183. int nCmp;
  184. BOOL bString;
  185. int nIndex = -1;
  186. *puLen = 0;
  187. //
  188. // wType is 0 for win32 versions, but holds 56 ('V') for win16.
  189. //
  190. if (((VERHEAD*)pb)->wType) {
  191. return 0;
  192. }
  193. //
  194. // If doesn't need unicode, then we must thunk the input parameter
  195. // to unicode.
  196. //
  197. STACK_ALLOC(lpSubBlockOrg, (wcslen(lpSubBlockX) + 1) * sizeof(WCHAR));
  198. if (lpSubBlockOrg == NULL) {
  199. DBGPRINT((sdlError,
  200. "SdbpVerQueryValue",
  201. "Failed to allocate %d bytes\n",
  202. (wcslen(lpSubBlockX) + 1) * sizeof(WCHAR)));
  203. return FALSE;
  204. }
  205. wcscpy(lpSubBlockOrg, lpSubBlockX);
  206. lpSubBlock = lpSubBlockOrg;
  207. //
  208. // Ensure that the total length is less than 32K but greater than the
  209. // size of a block header; we will assume that the size of pBlock is at
  210. // least the value of this first int.
  211. // Put a '\0' at the end of the block so that none of the wcslen's will
  212. // go past then end of the block. We will replace it before returning.
  213. //
  214. if ((int)pBlock->wTotLen < sizeof(VERBLOCK)) {
  215. goto Fail;
  216. }
  217. lpEndBlock = (LPWSTR)((LPSTR)pBlock + pBlock->wTotLen - sizeof(WCHAR));
  218. cEndBlock = *lpEndBlock;
  219. *lpEndBlock = 0;
  220. bString = FALSE;
  221. bLastSpec = FALSE;
  222. while ((*lpSubBlock || nIndex != -1)) {
  223. //
  224. // Ignore leading '\\'s
  225. //
  226. while (*lpSubBlock == TEXT('\\')) {
  227. ++lpSubBlock;
  228. }
  229. if ((*lpSubBlock || nIndex != -1)) {
  230. //
  231. // Make sure we still have some of the block left to play with.
  232. //
  233. dwTotBlockLen = (DWORD)((LPSTR)lpEndBlock - (LPSTR)pBlock + sizeof(WCHAR));
  234. if ((int)dwTotBlockLen < sizeof(VERBLOCK) || pBlock->wTotLen > (WORD)dwTotBlockLen) {
  235. goto NotFound;
  236. }
  237. //
  238. // Calculate the length of the "header" (the two length WORDs plus
  239. // the data type flag plus the identifying string) and skip
  240. // past the value.
  241. //
  242. dwHeadLen = (DWORD)(DWORDUP(sizeof(VERBLOCK) - sizeof(WCHAR) +
  243. (wcslen(pBlock->szKey) + 1) * sizeof(WCHAR)) +
  244. DWORDUP(pBlock->wValLen));
  245. if (dwHeadLen > pBlock->wTotLen) {
  246. goto NotFound;
  247. }
  248. lpEndSubBlock = (LPWSTR)((LPSTR)pBlock + pBlock->wTotLen);
  249. pBlock = (VERBLOCK*)((LPSTR)pBlock+dwHeadLen);
  250. //
  251. // Look for the first sub-block name and terminate it
  252. //
  253. for (lpStart = lpSubBlock;
  254. *lpSubBlock && *lpSubBlock != TEXT('\\');
  255. lpSubBlock++) {
  256. /* find next '\\' */ ;
  257. }
  258. cTemp = *lpSubBlock;
  259. *lpSubBlock = 0;
  260. //
  261. // Continue while there are sub-blocks left
  262. // pBlock->wTotLen should always be a valid pointer here because
  263. // we have validated dwHeadLen above, and we validated the previous
  264. // value of pBlock->wTotLen before using it
  265. //
  266. nCmp = 1;
  267. while ((int)pBlock->wTotLen > sizeof(VERBLOCK) &&
  268. (int)pBlock->wTotLen <= (LPSTR)lpEndSubBlock-(LPSTR)pBlock) {
  269. //
  270. // Index functionality: if we are at the end of the path
  271. // (cTemp == 0 set below) and nIndex is NOT -1 (index search)
  272. // then break on nIndex zero. Else do normal wscicmp.
  273. //
  274. if (bLastSpec && nIndex != -1) {
  275. if (!nIndex) {
  276. nCmp=0;
  277. //
  278. // Index found, set nInde to -1
  279. // so that we exit this loop
  280. //
  281. nIndex = -1;
  282. break;
  283. }
  284. nIndex--;
  285. } else {
  286. //
  287. // Check if the sub-block name is what we are looking for
  288. //
  289. if (!(nCmp = _wcsicmp(lpStart, pBlock->szKey))) {
  290. break;
  291. }
  292. }
  293. //
  294. // Skip to the next sub-block
  295. //
  296. pBlock=(VERBLOCK*)((LPSTR)pBlock+DWORDUP(pBlock->wTotLen));
  297. }
  298. //
  299. // Restore the char NULLed above and return failure if the sub-block
  300. // was not found
  301. //
  302. *lpSubBlock = cTemp;
  303. if (nCmp) {
  304. goto NotFound;
  305. }
  306. }
  307. bLastSpec = !cTemp;
  308. }
  309. //
  310. // Fill in the appropriate buffers and return success
  311. ///
  312. *puLen = pBlock->wValLen;
  313. //
  314. // Add code to handle the case of a null value.
  315. //
  316. // If zero-len, then return the pointer to the null terminator
  317. // of the key. Remember that this is thunked in the ansi case.
  318. //
  319. // We can't just look at pBlock->wValLen. Check if it really is
  320. // zero-len by seeing if the end of the key string is the end of the
  321. // block (i.e., the val string is outside of the current block).
  322. //
  323. lpStart = (LPWSTR)((LPSTR)pBlock + DWORDUP((sizeof(VERBLOCK) - sizeof(WCHAR)) +
  324. (wcslen(pBlock->szKey)+1)*sizeof(WCHAR)));
  325. *lplpBuffer = lpStart < (LPWSTR)((LPBYTE)pBlock + pBlock->wTotLen) ?
  326. lpStart :
  327. (LPWSTR)(pBlock->szKey + wcslen(pBlock->szKey));
  328. bString = pBlock->wType;
  329. *lpEndBlock = cEndBlock;
  330. //
  331. // Must free string we allocated above.
  332. //
  333. STACK_FREE(lpSubBlockOrg);
  334. return TRUE;
  335. NotFound:
  336. //
  337. // Restore the char we NULLed above
  338. //
  339. *lpEndBlock = cEndBlock;
  340. Fail:
  341. STACK_FREE(lpSubBlockOrg);
  342. return FALSE;
  343. }