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

444 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. LPVOID pImageBase;
  59. PVERSIONINFOW pVersionInfo = NULL;
  60. ULONG ulVersionSize = 0;
  61. LPVOID pVersionBuffer;
  62. DWORD dwModuleType = MT_UNKNOWN_MODULE;
  63. PIMAGE_RESOURCE_DATA_ENTRY pImageResourceData;
  64. //
  65. // Check module type first. We only recognize win32 modules.
  66. //
  67. if (!SdbpGetModuleType(&dwModuleType, pImageData) || dwModuleType != MT_W32_MODULE) {
  68. DBGPRINT((sdlError,
  69. "SdbpGetFileVersionInformation",
  70. "Bad module type 0x%x\n",
  71. dwModuleType));
  72. return FALSE;
  73. }
  74. pImageBase = (LPVOID)pImageData->pBase;
  75. //
  76. // Setup the path to the resource
  77. //
  78. ulPath[0] = PtrToUlong(RT_VERSION);
  79. ulPath[1] = PtrToUlong(MAKEINTRESOURCE(VS_VERSION_INFO));
  80. ulPath[2] = 0;
  81. //
  82. // See if the resource has come through.
  83. //
  84. __try {
  85. Status = LdrFindResource_U(pImageBase, ulPath, 3, &pImageResourceData);
  86. if (!NT_SUCCESS(Status)) {
  87. DBGPRINT((sdlError,
  88. "SdbpGetFileVersionInformation",
  89. "LdrFindResource_U failed status 0x%x\n",
  90. Status));
  91. return FALSE;
  92. }
  93. Status = LdrAccessResource(pImageBase, pImageResourceData, &pVersionInfo, &ulVersionSize);
  94. if (!NT_SUCCESS(Status)) {
  95. DBGPRINT((sdlError,
  96. "SdbpGetFileVersionInformation",
  97. "LdrAccessResource failed Status 0x%x\n",
  98. Status));
  99. return FALSE;
  100. }
  101. } __except(EXCEPTION_EXECUTE_HANDLER) {
  102. DBGPRINT((sdlError,
  103. "SdbpGetFileVersionInformation",
  104. "Exception while trying to retrieve version-related information\n"));
  105. Status = STATUS_UNSUCCESSFUL;
  106. }
  107. if (!NT_SUCCESS(Status)) {
  108. return FALSE;
  109. }
  110. //
  111. // Check to make sure that what we have got is good.
  112. //
  113. if (sizeof(*pVersionInfo) > ulVersionSize ||
  114. _wcsicmp(pVersionInfo->szName, L"VS_VERSION_INFO") != 0) {
  115. DBGPRINT((sdlError,
  116. "SdbpGetFileVersionInformation",
  117. "Bad version resource\n"));
  118. return FALSE;
  119. }
  120. //
  121. // Now we have a pointer to the resource data. Allocate version information.
  122. //
  123. pVersionBuffer = (LPVOID)SdbAlloc(ulVersionSize);
  124. if (pVersionBuffer == NULL) {
  125. DBGPRINT((sdlError,
  126. "SdbpGetFileVersionInformation",
  127. "Failed to allocate %d bytes for version information\n",
  128. ulVersionSize));
  129. return FALSE;
  130. }
  131. //
  132. // Copy all the version-related information
  133. //
  134. RtlMoveMemory(pVersionBuffer, pVersionInfo, ulVersionSize);
  135. if (ppFixedVersionInfo != NULL) {
  136. *ppFixedVersionInfo = &(((PVERSIONINFOW)pVersionBuffer)->FixedFileInfo);
  137. }
  138. assert(ppVersionInfo != NULL);
  139. *ppVersionInfo = pVersionBuffer;
  140. return TRUE;
  141. }
  142. ////////////////////////////////////////////////////////////////////////////
  143. //
  144. // This code was taken from Cornel's win2k tree
  145. //
  146. #define DWORDUP(x) (((x) + 3) & ~3)
  147. typedef struct tagVERBLOCK {
  148. WORD wTotLen;
  149. WORD wValLen;
  150. WORD wType;
  151. WCHAR szKey[1];
  152. } VERBLOCK ;
  153. typedef struct tagVERHEAD {
  154. WORD wTotLen;
  155. WORD wValLen;
  156. WORD wType; /* always 0 */
  157. WCHAR szKey[(sizeof("VS_VERSION_INFO") + 3) & ~03];
  158. VS_FIXEDFILEINFO vsf;
  159. } VERHEAD ;
  160. BOOL
  161. SdbpVerQueryValue(
  162. const LPVOID pb,
  163. LPVOID lpSubBlockX, // can be only unicode
  164. LPVOID* lplpBuffer,
  165. PUINT puLen
  166. )
  167. /*++
  168. Return: BUGBUG: ?
  169. Desc: BUGBUG: ?
  170. --*/
  171. {
  172. LPWSTR lpSubBlockOrg;
  173. LPWSTR lpSubBlock;
  174. VERBLOCK* pBlock = (PVOID)pb;
  175. LPWSTR lpStart, lpEndBlock, lpEndSubBlock;
  176. WCHAR cTemp, cEndBlock;
  177. DWORD dwHeadLen, dwTotBlockLen;
  178. BOOL bLastSpec;
  179. int nCmp, nLen;
  180. BOOL bString;
  181. int nIndex = -1;
  182. *puLen = 0;
  183. //
  184. // wType is 0 for win32 versions, but holds 56 ('V') for win16.
  185. //
  186. if (((VERHEAD*)pb)->wType) {
  187. return 0;
  188. }
  189. //
  190. // If doesn't need unicode, then we must thunk the input parameter
  191. // to unicode. lpSubBlockX should always be far less than 0xffffffff
  192. // in length.
  193. //
  194. nLen = __max((int) wcslen(lpSubBlockX) + 1, 1);
  195. STACK_ALLOC(lpSubBlockOrg, nLen * sizeof(WCHAR));
  196. if (lpSubBlockOrg == NULL) {
  197. DBGPRINT((sdlError,
  198. "SdbpVerQueryValue",
  199. "Failed to allocate %d bytes\n",
  200. (wcslen(lpSubBlockX) + 1) * sizeof(WCHAR)));
  201. return FALSE;
  202. }
  203. *lpSubBlockOrg = L'\0'; // we know that the least we have is one character
  204. StringCchCopy(lpSubBlockOrg, nLen, lpSubBlockX);
  205. lpSubBlock = lpSubBlockOrg;
  206. //
  207. // Ensure that the total length is less than 32K but greater than the
  208. // size of a block header; we will assume that the size of pBlock is at
  209. // least the value of this first int.
  210. // Put a '\0' at the end of the block so that none of the wcslen's will
  211. // go past then end of the block. We will replace it before returning.
  212. //
  213. if ((int)pBlock->wTotLen < sizeof(VERBLOCK)) {
  214. goto Fail;
  215. }
  216. lpEndBlock = (LPWSTR)((LPSTR)pBlock + pBlock->wTotLen - sizeof(WCHAR));
  217. cEndBlock = *lpEndBlock;
  218. *lpEndBlock = 0;
  219. bString = FALSE;
  220. bLastSpec = FALSE;
  221. while ((*lpSubBlock || nIndex != -1)) {
  222. //
  223. // Ignore leading '\\'s
  224. //
  225. while (*lpSubBlock == TEXT('\\')) {
  226. ++lpSubBlock;
  227. }
  228. cTemp = 0;
  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. }