WindowsXP-SP1/windows/appcompat/sdbapi/ntver.c
2020-09-30 16:53:49 +02:00

444 lines
12 KiB
C

/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
sdbapi.c
Abstract:
ANTI-BUGBUG: This module implements ...
NT-only version information retrieval
Author:
VadimB created sometime toward the end of November 2000
Revision History:
several people contributed (vadimb, clupu, ...)
--*/
#include "sdbp.h"
BOOL
SdbpGetFileVersionInformation(
IN PIMAGEFILEDATA pImageData, // we assume that the file has been mapped
// in for other purposes
OUT LPVOID* ppVersionInfo, // receives pointer to the (allocated) version
// resource
OUT VS_FIXEDFILEINFO** ppFixedVersionInfo // receives pointer to fixed version info
);
BOOL
SdbpVerQueryValue(
const LPVOID pb,
LPVOID lpSubBlockX, // can be only unicode
LPVOID* lplpBuffer,
PUINT puLen
);
#if defined(KERNEL_MODE) && defined(ALLOC_DATA_PRAGMA)
#pragma data_seg()
#endif // KERNEL_MODE && ALLOC_DATA_PRAGMA
#if defined(KERNEL_MODE) && defined(ALLOC_PRAGMA)
#pragma alloc_text(PAGE, SdbpGetFileVersionInformation)
#pragma alloc_text(PAGE, SdbpVerQueryValue)
#endif // KERNEL_MODE && ALLOC_PRAGMA
typedef struct _RESOURCE_DATAW {
USHORT TotalSize;
USHORT DataSize;
USHORT Type;
WCHAR szName[16]; // L"VS_VERSION_INFO" + unicode nul
VS_FIXEDFILEINFO FixedFileInfo;
} VERSIONINFOW, *PVERSIONINFOW;
BOOL
SdbpGetFileVersionInformation(
IN PIMAGEFILEDATA pImageData, // we assume that the file has been mapped
// in for other purposes
OUT LPVOID* ppVersionInfo, // receives pointer to the (allocated) version
// resource
OUT VS_FIXEDFILEINFO** ppFixedVersionInfo // receives pointer to fixed version info
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
NTSTATUS Status;
ULONG_PTR ulPath[3];
ULONG ulSize; // size of the resource
LPVOID pImageBase;
PVERSIONINFOW pVersionInfo = NULL;
ULONG ulVersionSize = 0;
LPVOID pVersionBuffer;
DWORD dwModuleType = MT_UNKNOWN_MODULE;
PIMAGE_RESOURCE_DATA_ENTRY pImageResourceData;
//
// Check module type first. We only recognize win32 modules.
//
if (!SdbpGetModuleType(&dwModuleType, pImageData) || dwModuleType != MT_W32_MODULE) {
DBGPRINT((sdlError,
"SdbpGetFileVersionInformation",
"Bad module type 0x%x\n",
dwModuleType));
return FALSE;
}
pImageBase = (LPVOID)pImageData->pBase;
//
// Setup the path to the resource
//
ulPath[0] = PtrToUlong(RT_VERSION);
ulPath[1] = PtrToUlong(MAKEINTRESOURCE(VS_VERSION_INFO));
ulPath[2] = 0;
//
// See if the resource has come through.
//
__try {
Status = LdrFindResource_U(pImageBase, ulPath, 3, &pImageResourceData);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpGetFileVersionInformation",
"LdrFindResource_U failed status 0x%x\n",
Status));
return FALSE;
}
Status = LdrAccessResource(pImageBase, pImageResourceData, &pVersionInfo, &ulVersionSize);
if (!NT_SUCCESS(Status)) {
DBGPRINT((sdlError,
"SdbpGetFileVersionInformation",
"LdrAccessResource failed Status 0x%x\n",
Status));
return FALSE;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
DBGPRINT((sdlError,
"SdbpGetFileVersionInformation",
"Exception while trying to retrieve version-related information\n"));
Status = STATUS_UNSUCCESSFUL;
}
if (!NT_SUCCESS(Status)) {
return FALSE;
}
//
// Check to make sure that what we have got is good.
//
if (sizeof(*pVersionInfo) > ulVersionSize ||
_wcsicmp(pVersionInfo->szName, L"VS_VERSION_INFO") != 0) {
DBGPRINT((sdlError,
"SdbpGetFileVersionInformation",
"Bad version resource\n"));
return FALSE;
}
//
// Now we have a pointer to the resource data. Allocate version information.
//
pVersionBuffer = (LPVOID)SdbAlloc(ulVersionSize);
if (pVersionBuffer == NULL) {
DBGPRINT((sdlError,
"SdbpGetFileVersionInformation",
"Failed to allocate %d bytes for version information\n",
ulVersionSize));
return FALSE;
}
//
// Copy all the version-related information
//
RtlMoveMemory(pVersionBuffer, pVersionInfo, ulVersionSize);
if (ppFixedVersionInfo != NULL) {
*ppFixedVersionInfo = &(((PVERSIONINFOW)pVersionBuffer)->FixedFileInfo);
}
assert(ppVersionInfo != NULL);
*ppVersionInfo = pVersionBuffer;
return TRUE;
}
////////////////////////////////////////////////////////////////////////////
//
// This code was taken from Cornel's win2k tree
//
#define DWORDUP(x) (((x) + 3) & ~3)
typedef struct tagVERBLOCK {
WORD wTotLen;
WORD wValLen;
WORD wType;
WCHAR szKey[1];
} VERBLOCK ;
typedef struct tagVERHEAD {
WORD wTotLen;
WORD wValLen;
WORD wType; /* always 0 */
WCHAR szKey[(sizeof("VS_VERSION_INFO") + 3) & ~03];
VS_FIXEDFILEINFO vsf;
} VERHEAD ;
BOOL
SdbpVerQueryValue(
const LPVOID pb,
LPVOID lpSubBlockX, // can be only unicode
LPVOID* lplpBuffer,
PUINT puLen
)
/*++
Return: BUGBUG: ?
Desc: BUGBUG: ?
--*/
{
ANSI_STRING AnsiString;
UNICODE_STRING UnicodeString;
LPWSTR lpSubBlockOrg;
LPWSTR lpSubBlock;
NTSTATUS Status;
VERBLOCK* pBlock = (PVOID)pb;
LPWSTR lpStart, lpEndBlock, lpEndSubBlock;
WCHAR cTemp, cEndBlock;
DWORD dwHeadLen, dwTotBlockLen;
BOOL bLastSpec;
int nCmp;
BOOL bString;
int nIndex = -1;
*puLen = 0;
//
// wType is 0 for win32 versions, but holds 56 ('V') for win16.
//
if (((VERHEAD*)pb)->wType) {
return 0;
}
//
// If doesn't need unicode, then we must thunk the input parameter
// to unicode.
//
STACK_ALLOC(lpSubBlockOrg, (wcslen(lpSubBlockX) + 1) * sizeof(WCHAR));
if (lpSubBlockOrg == NULL) {
DBGPRINT((sdlError,
"SdbpVerQueryValue",
"Failed to allocate %d bytes\n",
(wcslen(lpSubBlockX) + 1) * sizeof(WCHAR)));
return FALSE;
}
wcscpy(lpSubBlockOrg, lpSubBlockX);
lpSubBlock = lpSubBlockOrg;
//
// Ensure that the total length is less than 32K but greater than the
// size of a block header; we will assume that the size of pBlock is at
// least the value of this first int.
// Put a '\0' at the end of the block so that none of the wcslen's will
// go past then end of the block. We will replace it before returning.
//
if ((int)pBlock->wTotLen < sizeof(VERBLOCK)) {
goto Fail;
}
lpEndBlock = (LPWSTR)((LPSTR)pBlock + pBlock->wTotLen - sizeof(WCHAR));
cEndBlock = *lpEndBlock;
*lpEndBlock = 0;
bString = FALSE;
bLastSpec = FALSE;
while ((*lpSubBlock || nIndex != -1)) {
//
// Ignore leading '\\'s
//
while (*lpSubBlock == TEXT('\\')) {
++lpSubBlock;
}
if ((*lpSubBlock || nIndex != -1)) {
//
// Make sure we still have some of the block left to play with.
//
dwTotBlockLen = (DWORD)((LPSTR)lpEndBlock - (LPSTR)pBlock + sizeof(WCHAR));
if ((int)dwTotBlockLen < sizeof(VERBLOCK) || pBlock->wTotLen > (WORD)dwTotBlockLen) {
goto NotFound;
}
//
// Calculate the length of the "header" (the two length WORDs plus
// the data type flag plus the identifying string) and skip
// past the value.
//
dwHeadLen = (DWORD)(DWORDUP(sizeof(VERBLOCK) - sizeof(WCHAR) +
(wcslen(pBlock->szKey) + 1) * sizeof(WCHAR)) +
DWORDUP(pBlock->wValLen));
if (dwHeadLen > pBlock->wTotLen) {
goto NotFound;
}
lpEndSubBlock = (LPWSTR)((LPSTR)pBlock + pBlock->wTotLen);
pBlock = (VERBLOCK*)((LPSTR)pBlock+dwHeadLen);
//
// Look for the first sub-block name and terminate it
//
for (lpStart = lpSubBlock;
*lpSubBlock && *lpSubBlock != TEXT('\\');
lpSubBlock++) {
/* find next '\\' */ ;
}
cTemp = *lpSubBlock;
*lpSubBlock = 0;
//
// Continue while there are sub-blocks left
// pBlock->wTotLen should always be a valid pointer here because
// we have validated dwHeadLen above, and we validated the previous
// value of pBlock->wTotLen before using it
//
nCmp = 1;
while ((int)pBlock->wTotLen > sizeof(VERBLOCK) &&
(int)pBlock->wTotLen <= (LPSTR)lpEndSubBlock-(LPSTR)pBlock) {
//
// Index functionality: if we are at the end of the path
// (cTemp == 0 set below) and nIndex is NOT -1 (index search)
// then break on nIndex zero. Else do normal wscicmp.
//
if (bLastSpec && nIndex != -1) {
if (!nIndex) {
nCmp=0;
//
// Index found, set nInde to -1
// so that we exit this loop
//
nIndex = -1;
break;
}
nIndex--;
} else {
//
// Check if the sub-block name is what we are looking for
//
if (!(nCmp = _wcsicmp(lpStart, pBlock->szKey))) {
break;
}
}
//
// Skip to the next sub-block
//
pBlock=(VERBLOCK*)((LPSTR)pBlock+DWORDUP(pBlock->wTotLen));
}
//
// Restore the char NULLed above and return failure if the sub-block
// was not found
//
*lpSubBlock = cTemp;
if (nCmp) {
goto NotFound;
}
}
bLastSpec = !cTemp;
}
//
// Fill in the appropriate buffers and return success
///
*puLen = pBlock->wValLen;
//
// Add code to handle the case of a null value.
//
// If zero-len, then return the pointer to the null terminator
// of the key. Remember that this is thunked in the ansi case.
//
// We can't just look at pBlock->wValLen. Check if it really is
// zero-len by seeing if the end of the key string is the end of the
// block (i.e., the val string is outside of the current block).
//
lpStart = (LPWSTR)((LPSTR)pBlock + DWORDUP((sizeof(VERBLOCK) - sizeof(WCHAR)) +
(wcslen(pBlock->szKey)+1)*sizeof(WCHAR)));
*lplpBuffer = lpStart < (LPWSTR)((LPBYTE)pBlock + pBlock->wTotLen) ?
lpStart :
(LPWSTR)(pBlock->szKey + wcslen(pBlock->szKey));
bString = pBlock->wType;
*lpEndBlock = cEndBlock;
//
// Must free string we allocated above.
//
STACK_FREE(lpSubBlockOrg);
return TRUE;
NotFound:
//
// Restore the char we NULLed above
//
*lpEndBlock = cEndBlock;
Fail:
STACK_FREE(lpSubBlockOrg);
return FALSE;
}