|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
Version.c
Abstract:
This module implements a function to compare OS versions. Its the basis for VerifyVersionInfoW API. The Rtl version can be called from device drivers.
Author:
Nar Ganapathy [Narg] 19-Oct-1998
Environment:
Pure utility routine
Revision History:
--*/
#include <stdio.h>
#include <ntrtlp.h>
#if !defined(NTOS_KERNEL_RUNTIME)
#include <winerror.h>
#endif
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
#pragma alloc_text(PAGE, RtlGetVersion)
#endif
//
// The following comment explains the old and the new style layouts for the
// condition masks. The condition mask is passed as a parameter to the
// VerifyVersionInfo API. The condition mask encodes conditions like VER_AND,
// VER_OR, VER_EQUAL for various types like VER_PLATFORMID, VER_MINORVERSION
// etc., When the API was originally designed the application used a macro
// called VER_SET_CONDTION which was defined to be _m_=(_m_|(_c_<<(1<<_t_))).
// where _c_ is the condition and _t_ is the type. This macro is buggy for
// types >= VER_PLATFORMID. Unfortunately a lot of application code already
// uses this buggy macro (notably this terminal server) and have been shipped.
// To fix this bug, a new API VerSetConditionMask is defined which has a new
// bit layout. To provide backwards compatibility, we need to know if a
// specific condition mask is a new style mask (has the new bit layout) or is
// an old style mask. In both bit layouts bit 64 can never be set.
// So the new API sets this bit to indicate that the condition mask is a new
// style condition mask. So the code in this function that extracts the
// condition uses the new bit layout if bit 63 is set and the old layout if
// bit 63 is not set. This should allow applications that was compiled with
// the old macro to work.
//
//
// Use bit 63 to indicate that the new style bit layout is followed.
//
#define NEW_STYLE_BIT_MASK 0x8000000000000000
//
// Condition extractor for the old style mask.
//
#define OLD_CONDITION(_m_,_t_) (ULONG)((_m_&(0xff<<(1<<_t_)))>>(1<<_t_))
//
// Test to see if the mask is an old style mask.
//
#define OLD_STYLE_CONDITION_MASK(_m_) (((_m_) & NEW_STYLE_BIT_MASK) == 0)
#define RTL_GET_CONDITION(_m_, _t_) \
(OLD_STYLE_CONDITION_MASK(_m_) ? (OLD_CONDITION(_m_,_t_)) : \ RtlpVerGetConditionMask((_m_), (_t_)))
#define LEXICAL_COMPARISON 1 /* Do string comparison. Used for minor numbers */
#define MAX_STRING_LENGTH 20 /* Maximum number of digits for sprintf */
ULONG RtlpVerGetConditionMask( ULONGLONG ConditionMask, ULONG TypeMask );
/*++
Routine Description:
This function retrieves the OS version information. Its the kernel equivalent of the GetVersionExW win 32 API.
Arguments:
lpVersionInformation - Supplies a pointer to the version info structure. In the kernel always assume that the structure is of type PRTL_OSVERSIONINFOEXW as its not exported to drivers. The signature is kept the same as for the user level RtlGetVersion.
Return Value:
Always succeeds and returns STATUS_SUCCESS. --*/ #if defined(NTOS_KERNEL_RUNTIME)
NTSTATUS RtlGetVersion ( OUT PRTL_OSVERSIONINFOW lpVersionInformation ) { NT_PRODUCT_TYPE NtProductType; RTL_PAGED_CODE();
lpVersionInformation->dwMajorVersion = NtMajorVersion; lpVersionInformation->dwMinorVersion = NtMinorVersion; lpVersionInformation->dwBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF); lpVersionInformation->dwPlatformId = 2; // VER_PLATFORM_WIN32_NT from winbase.h
if (lpVersionInformation->dwOSVersionInfoSize == sizeof( RTL_OSVERSIONINFOEXW )) { ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wServicePackMajor = ((USHORT)CmNtCSDVersion >> 8) & (0xFF); ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wServicePackMinor = (USHORT)CmNtCSDVersion & 0xFF; ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask = (USHORT)(USER_SHARED_DATA->SuiteMask&0xffff); ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wProductType = (RtlGetNtProductType(&NtProductType) ? NtProductType :0);
/* Not set as its not needed by VerifyVersionInfoW */ ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wReserved = (UCHAR)0; }
return STATUS_SUCCESS; } #else
NTSTATUS RtlGetVersion( OUT PRTL_OSVERSIONINFOW lpVersionInformation ) { PPEB Peb; NT_PRODUCT_TYPE NtProductType;
Peb = NtCurrentPeb(); lpVersionInformation->dwMajorVersion = Peb->OSMajorVersion; lpVersionInformation->dwMinorVersion = Peb->OSMinorVersion; lpVersionInformation->dwBuildNumber = Peb->OSBuildNumber; lpVersionInformation->dwPlatformId = Peb->OSPlatformId; if (Peb->CSDVersion.Buffer) { wcscpy( lpVersionInformation->szCSDVersion, Peb->CSDVersion.Buffer ); } else { lpVersionInformation->szCSDVersion[0] = 0; }
if (lpVersionInformation->dwOSVersionInfoSize == sizeof( OSVERSIONINFOEXW )) { ((POSVERSIONINFOEXW)lpVersionInformation)->wServicePackMajor = (Peb->OSCSDVersion >> 8) & 0xFF; ((POSVERSIONINFOEXW)lpVersionInformation)->wServicePackMinor = Peb->OSCSDVersion & 0xFF; ((POSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask = (USHORT)(USER_SHARED_DATA->SuiteMask&0xffff); ((POSVERSIONINFOEXW)lpVersionInformation)->wProductType = 0; if (RtlGetNtProductType( &NtProductType )) { ((POSVERSIONINFOEXW)lpVersionInformation)->wProductType = (UCHAR)NtProductType; if (NtProductType == VER_NT_WORKSTATION) { //
// For workstation product never return VER_SUITE_TERMINAL
//
((POSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask = ((POSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask & 0xffef; }
} }
return STATUS_SUCCESS; } #endif
BOOLEAN RtlpVerCompare( LONG Condition, LONG Value1, LONG Value2, BOOLEAN *Equal, int Flags ) { char String1[MAX_STRING_LENGTH]; char String2[MAX_STRING_LENGTH]; LONG Comparison;
if (Flags & LEXICAL_COMPARISON) { sprintf(String1, "%d", Value1); sprintf(String2, "%d", Value2); Comparison = strcmp(String2, String1); Value1 = 0; Value2 = Comparison; } *Equal = (Value1 == Value2); switch (Condition) { case VER_EQUAL: return (Value2 == Value1);
case VER_GREATER: return (Value2 > Value1);
case VER_LESS: return (Value2 < Value1);
case VER_GREATER_EQUAL: return (Value2 >= Value1);
case VER_LESS_EQUAL: return (Value2 <= Value1);
default: break; }
return FALSE; }
NTSTATUS RtlVerifyVersionInfo( IN PRTL_OSVERSIONINFOEXW VersionInfo, IN ULONG TypeMask, IN ULONGLONG ConditionMask )
/*+++
This function verifies a version condition. Basically, this function lets an app query the system to see if the app is running on a specific version combination.
Arguments:
VersionInfo - a version structure containing the comparison data TypeMask - a mask comtaining the data types to look at ConditionMask - a mask containing conditionals for doing the comparisons
Return Value:
STATUS_INVALID_PARAMETER if the parameters are not valid. STATUS_REVISION_MISMATCH if the versions don't match. STATUS_SUCCESS if the versions match.
--*/
{ ULONG i; OSVERSIONINFOEXW CurrVersion; BOOLEAN SuiteFound = FALSE; BOOLEAN Equal; NTSTATUS Status; ULONG Condition;
if (TypeMask == 0) { return STATUS_INVALID_PARAMETER; }
RtlZeroMemory( &CurrVersion, sizeof(OSVERSIONINFOEXW) ); CurrVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&CurrVersion); if (Status != STATUS_SUCCESS) return Status;
if ((TypeMask & VER_SUITENAME) && (VersionInfo->wSuiteMask != 0)) { for (i=0; i<16; i++) { if (VersionInfo->wSuiteMask&(1<<i)) { switch (RTL_GET_CONDITION(ConditionMask,VER_SUITENAME)) { case VER_AND: if (!(CurrVersion.wSuiteMask&(1<<i))) { return STATUS_REVISION_MISMATCH; } break;
case VER_OR: if (CurrVersion.wSuiteMask&(1<<i)) { SuiteFound = TRUE; } break;
default: return STATUS_INVALID_PARAMETER; } } } if ((RtlpVerGetConditionMask(ConditionMask,VER_SUITENAME) == VER_OR) && (SuiteFound == FALSE)) { return STATUS_REVISION_MISMATCH; } }
Equal = TRUE; Condition = VER_EQUAL; if (TypeMask & VER_MAJORVERSION) { Condition = RTL_GET_CONDITION( ConditionMask, VER_MAJORVERSION); if (RtlpVerCompare( Condition, VersionInfo->dwMajorVersion, CurrVersion.dwMajorVersion, &Equal, 0 ) == FALSE) { if (!Equal) { return STATUS_REVISION_MISMATCH; } } }
if (Equal) { ASSERT(Condition); if (TypeMask & VER_MINORVERSION) { if (Condition == VER_EQUAL) { Condition = RTL_GET_CONDITION(ConditionMask, VER_MINORVERSION); } if (RtlpVerCompare( Condition, VersionInfo->dwMinorVersion, CurrVersion.dwMinorVersion, &Equal, LEXICAL_COMPARISON ) == FALSE) { if (!Equal) { return STATUS_REVISION_MISMATCH; } } }
if (Equal) { if (TypeMask & VER_SERVICEPACKMAJOR) { if (Condition == VER_EQUAL) { Condition = RTL_GET_CONDITION(ConditionMask, VER_SERVICEPACKMAJOR); } if (RtlpVerCompare( Condition, VersionInfo->wServicePackMajor, CurrVersion.wServicePackMajor, &Equal, 0 ) == FALSE) { if (!Equal) { return STATUS_REVISION_MISMATCH; } } } if (Equal) { if (TypeMask & VER_SERVICEPACKMINOR) { if (Condition == VER_EQUAL) { Condition = RTL_GET_CONDITION(ConditionMask, VER_SERVICEPACKMINOR); } if (RtlpVerCompare( Condition, (ULONG)VersionInfo->wServicePackMinor, (ULONG)CurrVersion.wServicePackMinor, &Equal, LEXICAL_COMPARISON ) == FALSE) { return STATUS_REVISION_MISMATCH; } } } } }
if ((TypeMask & VER_BUILDNUMBER) && RtlpVerCompare( RTL_GET_CONDITION( ConditionMask, VER_BUILDNUMBER), VersionInfo->dwBuildNumber, CurrVersion.dwBuildNumber, &Equal, 0 ) == FALSE) { return STATUS_REVISION_MISMATCH; }
if ((TypeMask & VER_PLATFORMID) && RtlpVerCompare( RTL_GET_CONDITION( ConditionMask, VER_PLATFORMID), VersionInfo->dwPlatformId, CurrVersion.dwPlatformId, &Equal, 0 ) == FALSE) { return STATUS_REVISION_MISMATCH; }
if ((TypeMask & VER_PRODUCT_TYPE) && RtlpVerCompare( RTL_GET_CONDITION( ConditionMask, VER_PRODUCT_TYPE), VersionInfo->wProductType, CurrVersion.wProductType, &Equal, 0 ) == FALSE) { return STATUS_REVISION_MISMATCH; }
return STATUS_SUCCESS; }
ULONG RtlpVerGetConditionMask( ULONGLONG ConditionMask, ULONG TypeMask ) { ULONG NumBitsToShift; ULONG Condition = 0;
if (!TypeMask) { return 0; }
for (NumBitsToShift = 0; TypeMask; NumBitsToShift++) { TypeMask >>= 1; }
Condition |= (ConditionMask) >> ((NumBitsToShift - 1) * VER_NUM_BITS_PER_CONDITION_MASK); Condition &= VER_CONDITION_MASK; return Condition; }
ULONGLONG VerSetConditionMask( ULONGLONG ConditionMask, ULONG TypeMask, UCHAR Condition ) { int NumBitsToShift;
Condition &= VER_CONDITION_MASK;
if (!TypeMask) { return 0; }
for (NumBitsToShift = 0; TypeMask; NumBitsToShift++) { TypeMask >>= 1; }
//
// Mark that we are using a new style condition mask
//
ConditionMask |= NEW_STYLE_BIT_MASK; ConditionMask |= (Condition) << ((NumBitsToShift - 1) * VER_NUM_BITS_PER_CONDITION_MASK);
return ConditionMask; }
|