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.

460 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Version.c
  5. Abstract:
  6. This module implements a function to compare OS versions. Its the basis for
  7. VerifyVersionInfoW API. The Rtl version can be called from device drivers.
  8. Author:
  9. Nar Ganapathy [Narg] 19-Oct-1998
  10. Environment:
  11. Pure utility routine
  12. Revision History:
  13. --*/
  14. #include <stdio.h>
  15. #include <ntrtlp.h>
  16. #if !defined(NTOS_KERNEL_RUNTIME)
  17. #include <winerror.h>
  18. #endif
  19. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  20. #pragma alloc_text(PAGE, RtlGetVersion)
  21. #endif
  22. //
  23. // The following comment explains the old and the new style layouts for the
  24. // condition masks. The condition mask is passed as a parameter to the
  25. // VerifyVersionInfo API. The condition mask encodes conditions like VER_AND,
  26. // VER_OR, VER_EQUAL for various types like VER_PLATFORMID, VER_MINORVERSION
  27. // etc., When the API was originally designed the application used a macro
  28. // called VER_SET_CONDTION which was defined to be _m_=(_m_|(_c_<<(1<<_t_))).
  29. // where _c_ is the condition and _t_ is the type. This macro is buggy for
  30. // types >= VER_PLATFORMID. Unfortunately a lot of application code already
  31. // uses this buggy macro (notably this terminal server) and have been shipped.
  32. // To fix this bug, a new API VerSetConditionMask is defined which has a new
  33. // bit layout. To provide backwards compatibility, we need to know if a
  34. // specific condition mask is a new style mask (has the new bit layout) or is
  35. // an old style mask. In both bit layouts bit 64 can never be set.
  36. // So the new API sets this bit to indicate that the condition mask is a new
  37. // style condition mask. So the code in this function that extracts the
  38. // condition uses the new bit layout if bit 63 is set and the old layout if
  39. // bit 63 is not set. This should allow applications that was compiled with
  40. // the old macro to work.
  41. //
  42. //
  43. // Use bit 63 to indicate that the new style bit layout is followed.
  44. //
  45. #define NEW_STYLE_BIT_MASK 0x8000000000000000
  46. //
  47. // Condition extractor for the old style mask.
  48. //
  49. #define OLD_CONDITION(_m_,_t_) (ULONG)((_m_&(0xff<<(1<<_t_)))>>(1<<_t_))
  50. //
  51. // Test to see if the mask is an old style mask.
  52. //
  53. #define OLD_STYLE_CONDITION_MASK(_m_) (((_m_) & NEW_STYLE_BIT_MASK) == 0)
  54. #define RTL_GET_CONDITION(_m_, _t_) \
  55. (OLD_STYLE_CONDITION_MASK(_m_) ? (OLD_CONDITION(_m_,_t_)) : \
  56. RtlpVerGetConditionMask((_m_), (_t_)))
  57. #define LEXICAL_COMPARISON 1 /* Do string comparison. Used for minor numbers */
  58. #define MAX_STRING_LENGTH 20 /* Maximum number of digits for sprintf */
  59. ULONG
  60. RtlpVerGetConditionMask(
  61. ULONGLONG ConditionMask,
  62. ULONG TypeMask
  63. );
  64. /*++
  65. Routine Description:
  66. This function retrieves the OS version information. Its the kernel equivalent of
  67. the GetVersionExW win 32 API.
  68. Arguments:
  69. lpVersionInformation - Supplies a pointer to the version info structure.
  70. In the kernel always assume that the structure is of type
  71. PRTL_OSVERSIONINFOEXW as its not exported to drivers. The signature
  72. is kept the same as for the user level RtlGetVersion.
  73. Return Value:
  74. Always succeeds and returns STATUS_SUCCESS.
  75. --*/
  76. #if defined(NTOS_KERNEL_RUNTIME)
  77. NTSTATUS
  78. RtlGetVersion (
  79. OUT PRTL_OSVERSIONINFOW lpVersionInformation
  80. )
  81. {
  82. NT_PRODUCT_TYPE NtProductType;
  83. RTL_PAGED_CODE();
  84. lpVersionInformation->dwMajorVersion = NtMajorVersion;
  85. lpVersionInformation->dwMinorVersion = NtMinorVersion;
  86. lpVersionInformation->dwBuildNumber = (USHORT)(NtBuildNumber & 0x3FFF);
  87. lpVersionInformation->dwPlatformId = 2; // VER_PLATFORM_WIN32_NT from winbase.h
  88. if (lpVersionInformation->dwOSVersionInfoSize == sizeof( RTL_OSVERSIONINFOEXW )) {
  89. ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wServicePackMajor = ((USHORT)CmNtCSDVersion >> 8) & (0xFF);
  90. ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wServicePackMinor = (USHORT)CmNtCSDVersion & 0xFF;
  91. ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask = (USHORT)(USER_SHARED_DATA->SuiteMask&0xffff);
  92. ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wProductType = (RtlGetNtProductType(&NtProductType) ? NtProductType :0);
  93. /* Not set as its not needed by VerifyVersionInfoW */
  94. ((PRTL_OSVERSIONINFOEXW)lpVersionInformation)->wReserved = (UCHAR)0;
  95. }
  96. return STATUS_SUCCESS;
  97. }
  98. #else
  99. NTSTATUS
  100. RtlGetVersion(
  101. OUT PRTL_OSVERSIONINFOW lpVersionInformation
  102. )
  103. {
  104. PPEB Peb;
  105. NT_PRODUCT_TYPE NtProductType;
  106. Peb = NtCurrentPeb();
  107. lpVersionInformation->dwMajorVersion = Peb->OSMajorVersion;
  108. lpVersionInformation->dwMinorVersion = Peb->OSMinorVersion;
  109. lpVersionInformation->dwBuildNumber = Peb->OSBuildNumber;
  110. lpVersionInformation->dwPlatformId = Peb->OSPlatformId;
  111. if (Peb->CSDVersion.Buffer) {
  112. wcscpy( lpVersionInformation->szCSDVersion, Peb->CSDVersion.Buffer );
  113. } else {
  114. lpVersionInformation->szCSDVersion[0] = 0;
  115. }
  116. if (lpVersionInformation->dwOSVersionInfoSize == sizeof( OSVERSIONINFOEXW ))
  117. {
  118. ((POSVERSIONINFOEXW)lpVersionInformation)->wServicePackMajor = (Peb->OSCSDVersion >> 8) & 0xFF;
  119. ((POSVERSIONINFOEXW)lpVersionInformation)->wServicePackMinor = Peb->OSCSDVersion & 0xFF;
  120. ((POSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask = (USHORT)(USER_SHARED_DATA->SuiteMask&0xffff);
  121. ((POSVERSIONINFOEXW)lpVersionInformation)->wProductType = 0;
  122. if (RtlGetNtProductType( &NtProductType )) {
  123. ((POSVERSIONINFOEXW)lpVersionInformation)->wProductType = (UCHAR)NtProductType;
  124. if (NtProductType == VER_NT_WORKSTATION) {
  125. //
  126. // For workstation product never return VER_SUITE_TERMINAL
  127. //
  128. ((POSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask = ((POSVERSIONINFOEXW)lpVersionInformation)->wSuiteMask & 0xffef;
  129. }
  130. }
  131. }
  132. return STATUS_SUCCESS;
  133. }
  134. #endif
  135. BOOLEAN
  136. RtlpVerCompare(
  137. LONG Condition,
  138. LONG Value1,
  139. LONG Value2,
  140. BOOLEAN *Equal,
  141. int Flags
  142. )
  143. {
  144. char String1[MAX_STRING_LENGTH];
  145. char String2[MAX_STRING_LENGTH];
  146. LONG Comparison;
  147. if (Flags & LEXICAL_COMPARISON) {
  148. sprintf(String1, "%d", Value1);
  149. sprintf(String2, "%d", Value2);
  150. Comparison = strcmp(String2, String1);
  151. Value1 = 0;
  152. Value2 = Comparison;
  153. }
  154. *Equal = (Value1 == Value2);
  155. switch (Condition) {
  156. case VER_EQUAL:
  157. return (Value2 == Value1);
  158. case VER_GREATER:
  159. return (Value2 > Value1);
  160. case VER_LESS:
  161. return (Value2 < Value1);
  162. case VER_GREATER_EQUAL:
  163. return (Value2 >= Value1);
  164. case VER_LESS_EQUAL:
  165. return (Value2 <= Value1);
  166. default:
  167. break;
  168. }
  169. return FALSE;
  170. }
  171. NTSTATUS
  172. RtlVerifyVersionInfo(
  173. IN PRTL_OSVERSIONINFOEXW VersionInfo,
  174. IN ULONG TypeMask,
  175. IN ULONGLONG ConditionMask
  176. )
  177. /*+++
  178. This function verifies a version condition. Basically, this
  179. function lets an app query the system to see if the app is
  180. running on a specific version combination.
  181. Arguments:
  182. VersionInfo - a version structure containing the comparison data
  183. TypeMask - a mask comtaining the data types to look at
  184. ConditionMask - a mask containing conditionals for doing the comparisons
  185. Return Value:
  186. STATUS_INVALID_PARAMETER if the parameters are not valid.
  187. STATUS_REVISION_MISMATCH if the versions don't match.
  188. STATUS_SUCCESS if the versions match.
  189. --*/
  190. {
  191. ULONG i;
  192. OSVERSIONINFOEXW CurrVersion;
  193. BOOLEAN SuiteFound = FALSE;
  194. BOOLEAN Equal;
  195. NTSTATUS Status;
  196. ULONG Condition;
  197. if (TypeMask == 0) {
  198. return STATUS_INVALID_PARAMETER;
  199. }
  200. RtlZeroMemory( &CurrVersion, sizeof(OSVERSIONINFOEXW) );
  201. CurrVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
  202. Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&CurrVersion);
  203. if (Status != STATUS_SUCCESS)
  204. return Status;
  205. if ((TypeMask & VER_SUITENAME) && (VersionInfo->wSuiteMask != 0)) {
  206. for (i=0; i<16; i++) {
  207. if (VersionInfo->wSuiteMask&(1<<i)) {
  208. switch (RTL_GET_CONDITION(ConditionMask,VER_SUITENAME)) {
  209. case VER_AND:
  210. if (!(CurrVersion.wSuiteMask&(1<<i))) {
  211. return STATUS_REVISION_MISMATCH;
  212. }
  213. break;
  214. case VER_OR:
  215. if (CurrVersion.wSuiteMask&(1<<i)) {
  216. SuiteFound = TRUE;
  217. }
  218. break;
  219. default:
  220. return STATUS_INVALID_PARAMETER;
  221. }
  222. }
  223. }
  224. if ((RtlpVerGetConditionMask(ConditionMask,VER_SUITENAME) == VER_OR) && (SuiteFound == FALSE)) {
  225. return STATUS_REVISION_MISMATCH;
  226. }
  227. }
  228. Equal = TRUE;
  229. Condition = VER_EQUAL;
  230. if (TypeMask & VER_MAJORVERSION) {
  231. Condition = RTL_GET_CONDITION( ConditionMask, VER_MAJORVERSION);
  232. if (RtlpVerCompare(
  233. Condition,
  234. VersionInfo->dwMajorVersion,
  235. CurrVersion.dwMajorVersion,
  236. &Equal,
  237. 0
  238. ) == FALSE)
  239. {
  240. if (!Equal) {
  241. return STATUS_REVISION_MISMATCH;
  242. }
  243. }
  244. }
  245. if (Equal) {
  246. ASSERT(Condition);
  247. if (TypeMask & VER_MINORVERSION) {
  248. if (Condition == VER_EQUAL) {
  249. Condition = RTL_GET_CONDITION(ConditionMask, VER_MINORVERSION);
  250. }
  251. if (RtlpVerCompare(
  252. Condition,
  253. VersionInfo->dwMinorVersion,
  254. CurrVersion.dwMinorVersion,
  255. &Equal,
  256. LEXICAL_COMPARISON
  257. ) == FALSE)
  258. {
  259. if (!Equal) {
  260. return STATUS_REVISION_MISMATCH;
  261. }
  262. }
  263. }
  264. if (Equal) {
  265. if (TypeMask & VER_SERVICEPACKMAJOR) {
  266. if (Condition == VER_EQUAL) {
  267. Condition = RTL_GET_CONDITION(ConditionMask, VER_SERVICEPACKMAJOR);
  268. }
  269. if (RtlpVerCompare(
  270. Condition,
  271. VersionInfo->wServicePackMajor,
  272. CurrVersion.wServicePackMajor,
  273. &Equal,
  274. 0
  275. ) == FALSE)
  276. {
  277. if (!Equal) {
  278. return STATUS_REVISION_MISMATCH;
  279. }
  280. }
  281. }
  282. if (Equal) {
  283. if (TypeMask & VER_SERVICEPACKMINOR) {
  284. if (Condition == VER_EQUAL) {
  285. Condition = RTL_GET_CONDITION(ConditionMask, VER_SERVICEPACKMINOR);
  286. }
  287. if (RtlpVerCompare(
  288. Condition,
  289. (ULONG)VersionInfo->wServicePackMinor,
  290. (ULONG)CurrVersion.wServicePackMinor,
  291. &Equal,
  292. LEXICAL_COMPARISON
  293. ) == FALSE)
  294. {
  295. return STATUS_REVISION_MISMATCH;
  296. }
  297. }
  298. }
  299. }
  300. }
  301. if ((TypeMask & VER_BUILDNUMBER) &&
  302. RtlpVerCompare(
  303. RTL_GET_CONDITION( ConditionMask, VER_BUILDNUMBER),
  304. VersionInfo->dwBuildNumber,
  305. CurrVersion.dwBuildNumber,
  306. &Equal,
  307. 0
  308. ) == FALSE)
  309. {
  310. return STATUS_REVISION_MISMATCH;
  311. }
  312. if ((TypeMask & VER_PLATFORMID) &&
  313. RtlpVerCompare(
  314. RTL_GET_CONDITION( ConditionMask, VER_PLATFORMID),
  315. VersionInfo->dwPlatformId,
  316. CurrVersion.dwPlatformId,
  317. &Equal,
  318. 0
  319. ) == FALSE)
  320. {
  321. return STATUS_REVISION_MISMATCH;
  322. }
  323. if ((TypeMask & VER_PRODUCT_TYPE) &&
  324. RtlpVerCompare(
  325. RTL_GET_CONDITION( ConditionMask, VER_PRODUCT_TYPE),
  326. VersionInfo->wProductType,
  327. CurrVersion.wProductType,
  328. &Equal,
  329. 0
  330. ) == FALSE)
  331. {
  332. return STATUS_REVISION_MISMATCH;
  333. }
  334. return STATUS_SUCCESS;
  335. }
  336. ULONG
  337. RtlpVerGetConditionMask(
  338. ULONGLONG ConditionMask,
  339. ULONG TypeMask
  340. )
  341. {
  342. ULONG NumBitsToShift;
  343. ULONG Condition = 0;
  344. if (!TypeMask) {
  345. return 0;
  346. }
  347. for (NumBitsToShift = 0; TypeMask; NumBitsToShift++) {
  348. TypeMask >>= 1;
  349. }
  350. Condition |= (ConditionMask) >> ((NumBitsToShift - 1)
  351. * VER_NUM_BITS_PER_CONDITION_MASK);
  352. Condition &= VER_CONDITION_MASK;
  353. return Condition;
  354. }
  355. ULONGLONG
  356. VerSetConditionMask(
  357. ULONGLONG ConditionMask,
  358. ULONG TypeMask,
  359. UCHAR Condition
  360. )
  361. {
  362. int NumBitsToShift;
  363. Condition &= VER_CONDITION_MASK;
  364. if (!TypeMask) {
  365. return 0;
  366. }
  367. for (NumBitsToShift = 0; TypeMask; NumBitsToShift++) {
  368. TypeMask >>= 1;
  369. }
  370. //
  371. // Mark that we are using a new style condition mask
  372. //
  373. ConditionMask |= NEW_STYLE_BIT_MASK;
  374. ConditionMask |= (Condition) << ((NumBitsToShift - 1)
  375. * VER_NUM_BITS_PER_CONDITION_MASK);
  376. return ConditionMask;
  377. }