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.

565 lines
14 KiB

  1. /*++
  2. Copyright (c) 1987-2002 Microsoft Corporation
  3. Module Name:
  4. log_gmt.cpp (originally named loghours.c)
  5. Abstract:
  6. Private routines to support rotation of logon hours between local time
  7. and GMT time.
  8. Environment:
  9. User mode only.
  10. Contains NT-specific code.
  11. Requires ANSI C extensions: slash-slash comments, long external names.
  12. Revision History:
  13. 16-Mar-93 cliffv Creation.
  14. 22-Jul-97 t-danm Copied from /nt/private/nw/convert/nwconv/loghours.c
  15. and adapted to loghours.dll.
  16. --*/
  17. #include "stdafx.h"
  18. #pragma warning (disable : 4514)
  19. #pragma warning (push,3)
  20. #include <limits.h>
  21. #include <math.h>
  22. #include <lmcons.h>
  23. #include <lmaccess.h>
  24. #pragma warning (pop)
  25. #include "log_gmt.h"
  26. #include "debug.h"
  27. #ifdef _DEBUG
  28. #define new DEBUG_NEW
  29. #undef THIS_FILE
  30. static char THIS_FILE[] = __FILE__;
  31. #endif
  32. //#pragma hdrstop
  33. /*++
  34. Routine NetpRotateLogonHoursPhase1()
  35. Determine the amount to rotate the logon hours by to convert to/from GMT
  36. Arguments:
  37. bConvertToGmt -
  38. True to convert the logon hours from local time to GMT relative
  39. False to convert the logon hours from GMT relative to local time
  40. pRotateCount - Returns the number of bits to shift by.
  41. Must be non NULL pointer.
  42. Return Value:
  43. TRUE if the pRotateCount could be computed
  44. FALSE if a pRotateCount could not be computed
  45. --*/
  46. BOOLEAN
  47. NetpRotateLogonHoursPhase1(
  48. IN BOOL bConvertToGmt,
  49. IN bool bAddDaylightBias,
  50. OUT PLONG pRotateCount)
  51. {
  52. if ( !pRotateCount )
  53. return FALSE;
  54. _TRACE (1, L"Entering NetpRotateLogonHoursPhase1\n");
  55. TIME_ZONE_INFORMATION tzi;
  56. LONG lBiasInHours = 0;
  57. LONG lDSTBias = 0;
  58. const LONG HOURS_IN_DAY = 24;
  59. //
  60. // Get the timezone data from the registry
  61. //
  62. DWORD dwResult = GetTimeZoneInformation( &tzi );
  63. if ( TIME_ZONE_ID_INVALID == dwResult )
  64. {
  65. return FALSE;
  66. }
  67. //
  68. // Compute the amount to rotate the logon hours by
  69. //
  70. // Round the bias in minutes to the closest bias in hours.
  71. // Take into consideration that Bias can be negative.
  72. // Do this by forcing the Bias to be positive, rounding,
  73. // then adjusting it back negative again.
  74. //
  75. if ( bAddDaylightBias )
  76. {
  77. switch (dwResult)
  78. {
  79. case TIME_ZONE_ID_DAYLIGHT:
  80. lDSTBias = tzi.DaylightBias;
  81. break;
  82. case TIME_ZONE_ID_UNKNOWN:
  83. case TIME_ZONE_ID_STANDARD:
  84. lDSTBias = tzi.StandardBias;
  85. break;
  86. default:
  87. return FALSE;
  88. }
  89. }
  90. ASSERT( tzi.Bias > -(HOURS_IN_DAY*60) );
  91. lBiasInHours = ((tzi.Bias + lDSTBias + (HOURS_IN_DAY*60) + 30)/60) - HOURS_IN_DAY;
  92. if ( !bConvertToGmt )
  93. {
  94. lBiasInHours = - lBiasInHours;
  95. }
  96. /// TODO: Account for user changing the locale while the schedule grid is open
  97. // Adjust for first day of week, if nFirstDay == 6, then no adjustment is required
  98. // because the vector passed in starts on Sunday
  99. int nFirstDay = GetFirstDayOfWeek ();
  100. LONG lFirstDayShiftInHours = (bConvertToGmt ? 1 : -1);
  101. switch (nFirstDay)
  102. {
  103. case 0:
  104. lFirstDayShiftInHours *= 1 * HOURS_IN_DAY;
  105. break;
  106. case 1:
  107. lFirstDayShiftInHours *= 2 * HOURS_IN_DAY;
  108. break;
  109. case 2:
  110. lFirstDayShiftInHours *= 3 * HOURS_IN_DAY;
  111. break;
  112. case 3:
  113. lFirstDayShiftInHours *= 4 * HOURS_IN_DAY;
  114. break;
  115. case 4:
  116. lFirstDayShiftInHours *= 5 * HOURS_IN_DAY;
  117. break;
  118. case 5:
  119. lFirstDayShiftInHours *= 6 * HOURS_IN_DAY;
  120. break;
  121. case 6:
  122. lFirstDayShiftInHours *= 0 * HOURS_IN_DAY;
  123. break;
  124. default:
  125. ASSERT (0);
  126. break;
  127. }
  128. lBiasInHours += lFirstDayShiftInHours;
  129. // NOTICE-NTRAID#NTBUG9-547513-2002/02/19-artm pRotateCount != NULL validated
  130. // Check was added at beginning of function.
  131. *pRotateCount = lBiasInHours;
  132. _TRACE (-1, L"Leaving NetpRotateLogonHoursPhase1\n");
  133. return TRUE;
  134. } // NetpRotateLogonHoursPhase1()
  135. /*++
  136. Routine NetpRotateLogonHoursPhase2()
  137. Rotate the pLogonHours bit mask by the required amount.
  138. Arguments:
  139. pLogonHours - Pointer to LogonHour bit mask
  140. dwUnitsPerWeek - Number of bits in the bit mask. Must be UNITS_PER_WEEK (168).
  141. lRotateCount - Number of bits to rotate by.
  142. Negative means to rotate left.
  143. Positive means to rotate right.
  144. Return Value:
  145. TRUE if the rotation succeeded.
  146. FALSE if a parameter was out of range
  147. --*/
  148. BOOLEAN
  149. NetpRotateLogonHoursPhase2(
  150. IN PBYTE pLogonHours,
  151. IN DWORD dwUnitsPerWeek,
  152. IN LONG lRotateCount)
  153. {
  154. if ( !pLogonHours )
  155. return FALSE;
  156. _TRACE (1, L"Entering NetpRotateLogonHoursPhase2\n");
  157. //
  158. // Useful constants
  159. //
  160. const int BYTES_PER_WEEK = (UNITS_PER_WEEK/8);
  161. BYTE byAlignedLogonHours[BYTES_PER_WEEK*2];
  162. ::ZeroMemory (byAlignedLogonHours, BYTES_PER_WEEK*2);
  163. LONG i = 0;
  164. BOOLEAN bRotateLeft = FALSE;
  165. //
  166. // Ensure there are 8 bits per byte,
  167. // 32 bits per DWORD and
  168. // units per week is even number of bytes.
  169. //
  170. #pragma warning(disable : 4127)
  171. ASSERT( CHAR_BIT == 8 );
  172. ASSERT( sizeof(DWORD) * CHAR_BIT == 32 );
  173. ASSERT( UNITS_PER_WEEK/8*8 == UNITS_PER_WEEK );
  174. #pragma warning (default : 4127)
  175. //
  176. // Validate the input parameters
  177. //
  178. if ( dwUnitsPerWeek != UNITS_PER_WEEK )
  179. {
  180. #pragma warning(disable : 4127)
  181. ASSERT( dwUnitsPerWeek == UNITS_PER_WEEK );
  182. #pragma warning (default : 4127)
  183. return FALSE;
  184. }
  185. if ( lRotateCount == 0 )
  186. {
  187. return TRUE;
  188. }
  189. // NOTICE-NTRAID#NTBUG9-547513-2002/02/19-artm pLogonHours != NULL was checked
  190. // Check was added to the beginning of the function.
  191. bRotateLeft = (lRotateCount < 0);
  192. lRotateCount = labs( lRotateCount );
  193. // New algorithm: get numBytes by dividing lRotateCount/32. Shift entire array
  194. // left or right by numBytes and then do the loop below for the remainder.
  195. // Move bytes from the beginning to the end, or bytes from the end to the beginning
  196. // depending on the rotation direction.
  197. LONG lNumBYTES = lRotateCount/8;
  198. if ( lNumBYTES > 0 )
  199. {
  200. RtlCopyMemory (byAlignedLogonHours, pLogonHours, BYTES_PER_WEEK);
  201. RtlCopyMemory (((PBYTE)byAlignedLogonHours) + BYTES_PER_WEEK,
  202. pLogonHours,
  203. BYTES_PER_WEEK );
  204. size_t nBytesToEnd = sizeof (byAlignedLogonHours) - lNumBYTES;
  205. BYTE* pTemp = new BYTE[lNumBYTES];
  206. if ( pTemp )
  207. {
  208. //
  209. // Do the left rotate.
  210. //
  211. if ( bRotateLeft )
  212. {
  213. memcpy (pTemp, byAlignedLogonHours, lNumBYTES);
  214. memmove (byAlignedLogonHours,
  215. byAlignedLogonHours + lNumBYTES,
  216. nBytesToEnd);
  217. memcpy (byAlignedLogonHours + nBytesToEnd,
  218. pTemp,
  219. lNumBYTES);
  220. }
  221. else
  222. {
  223. // Do the right rotate
  224. memcpy (pTemp,
  225. byAlignedLogonHours + nBytesToEnd,
  226. lNumBYTES);
  227. memmove (byAlignedLogonHours + lNumBYTES,
  228. byAlignedLogonHours,
  229. nBytesToEnd);
  230. memcpy (byAlignedLogonHours, pTemp, lNumBYTES);
  231. }
  232. delete [] pTemp;
  233. }
  234. lRotateCount = lRotateCount%8;
  235. RtlCopyMemory (pLogonHours, byAlignedLogonHours, BYTES_PER_WEEK );
  236. }
  237. if ( lRotateCount )
  238. {
  239. //
  240. // Do the left rotate.
  241. //
  242. if (bRotateLeft)
  243. {
  244. //
  245. // Copy the logon hours to a buffer.
  246. //
  247. // Duplicate the entire pLogonHours buffer at the end of the
  248. // byAlignedLogonHours buffer to make the rotation code trivial.
  249. //
  250. RtlCopyMemory (byAlignedLogonHours, pLogonHours, BYTES_PER_WEEK);
  251. RtlCopyMemory (((PBYTE)byAlignedLogonHours)+BYTES_PER_WEEK,
  252. pLogonHours,
  253. BYTES_PER_WEEK);
  254. //
  255. // Actually rotate the data.
  256. //
  257. for ( i=0; i < BYTES_PER_WEEK; i++ )
  258. {
  259. byAlignedLogonHours[i] =
  260. (byAlignedLogonHours[i] >> (BYTE) lRotateCount) |
  261. (byAlignedLogonHours[i+1] << (BYTE) (8-lRotateCount));
  262. }
  263. //
  264. // Copy the logon hours back to the input buffer.
  265. //
  266. RtlCopyMemory (pLogonHours, byAlignedLogonHours, BYTES_PER_WEEK);
  267. }
  268. else
  269. {
  270. //
  271. // Do the right rotate.
  272. //
  273. //
  274. // Copy the logon hours to a DWORD aligned buffer.
  275. //
  276. // Duplicate the last DWORD at the front of the buffer to make
  277. // the rotation code trivial.
  278. //
  279. RtlCopyMemory (&byAlignedLogonHours[1], pLogonHours, BYTES_PER_WEEK);
  280. RtlCopyMemory (byAlignedLogonHours,
  281. &pLogonHours[BYTES_PER_WEEK-1],
  282. sizeof(BYTE));
  283. //
  284. // Actually rotate the data.
  285. //
  286. for (i = BYTES_PER_WEEK - 1; i >= 0; i-- )
  287. {
  288. byAlignedLogonHours[i+1] =
  289. (byAlignedLogonHours[i+1] << (BYTE) lRotateCount) |
  290. (byAlignedLogonHours[i] >> (BYTE) (8-lRotateCount));
  291. }
  292. //
  293. // Copy the logon hours back to the input buffer.
  294. //
  295. RtlCopyMemory (pLogonHours, &byAlignedLogonHours[1], BYTES_PER_WEEK);
  296. }
  297. }
  298. _TRACE (-1, L"Leaving NetpRotateLogonHoursPhase2\n");
  299. return TRUE;
  300. } // NetpRotateLogonHoursPhase2()
  301. /*++
  302. Routine NetpRotateLogonHours()
  303. Rotate the pLogonHours bit mask to/from GMT relative time.
  304. Arguments:
  305. pLogonHours - Pointer to LogonHour bit mask
  306. dwUnitsPerWeek - Number of bits in the bit mask. Must be UNITS_PER_WEEK (168).
  307. bConvertToGmt -
  308. True to convert the logon hours from local time to GMT relative
  309. False to convert the logon hours from GMT relative to local time
  310. Return Value:
  311. TRUE if the rotation succeeded.
  312. FALSE if a parameter was out of range
  313. --*/
  314. BOOLEAN
  315. NetpRotateLogonHours(
  316. IN OUT PBYTE rgbLogonHours, // Array of 21 bytes
  317. IN DWORD cbitUnitsPerWeek, // Must be 21 * 8 = 168
  318. IN BOOL fConvertToGmt,
  319. IN bool bAddDaylightBias)
  320. {
  321. if ( !rgbLogonHours )
  322. return FALSE;
  323. LONG lRotateCount = 0;
  324. //
  325. // Break the functionality into two phases so that if the caller is doing
  326. // this multiple time, he just calls Phase 1 once and Phase 2 multiple
  327. // times.
  328. //
  329. if ( !NetpRotateLogonHoursPhase1 (fConvertToGmt, bAddDaylightBias, &lRotateCount) )
  330. {
  331. return FALSE;
  332. }
  333. return NetpRotateLogonHoursPhase2 (rgbLogonHours, cbitUnitsPerWeek, lRotateCount );
  334. } // NetpRotateLogonHours()
  335. /*++
  336. Routine NetpRotateLogonHoursBYTE()
  337. Rotate the pLogonHours BYTE array to/from GMT relative time.
  338. Each BYTE is one hour. The contents of a BYTE must not change
  339. Arguments:
  340. pLogonHours - Pointer to LogonHour bit mask
  341. dwUnitsPerWeek - Number of BYTES in the BYTE array. Must be UNITS_PER_WEEK (168).
  342. bConvertToGmt -
  343. True to convert the logon hours from local time to GMT relative
  344. False to convert the logon hours from GMT relative to local time
  345. Return Value:
  346. TRUE if the rotation succeeded.
  347. FALSE if a parameter was out of range
  348. --*/
  349. BOOLEAN
  350. NetpRotateLogonHoursBYTE(
  351. IN OUT PBYTE rgbLogonHours, // Array of 168 bytes
  352. IN DWORD cbitUnitsPerWeek, // Must be 21 * 8 = 168
  353. IN BOOL fConvertToGmt,
  354. IN bool bAddDaylightBias)
  355. {
  356. if ( !rgbLogonHours )
  357. return FALSE;
  358. LONG lRotateCount = 0;
  359. //
  360. // Break the functionality into two phases so that if the caller is doing
  361. // this multiple time, he just calls Phase 1 once and Phase 2 multiple
  362. // times.
  363. //
  364. if ( !NetpRotateLogonHoursPhase1 (fConvertToGmt, bAddDaylightBias, &lRotateCount) )
  365. {
  366. return FALSE;
  367. }
  368. // NOTICE-NTRAID#NTBUG9-547513-2002/02/19-artm Validate rgbLogonHours
  369. // Check correctly done at beginning of function.
  370. // FUTURE-2002/04/05-artm cbitUnitsPerWeek should be validated
  371. // rgbLogonHours should not be NULL and cbitUnitsPerWeek should equal UNITS_PER_WEEK
  372. BOOLEAN bResult = TRUE;
  373. if ( lRotateCount != 0 )
  374. {
  375. size_t numBytes = abs (lRotateCount);
  376. PBYTE pTemp = new BYTE[cbitUnitsPerWeek + numBytes];
  377. if ( pTemp )
  378. {
  379. if ( lRotateCount < 0 ) // shift left
  380. {
  381. // Copy the entire array and then start over with numBytes BYTES from
  382. // the start of the array to fill up to the end of the temp array.
  383. // Then shift over numBytes BYTES and copy 168 bytes from the temp
  384. // array back to the original array.
  385. memcpy (pTemp, rgbLogonHours, cbitUnitsPerWeek);
  386. memcpy (pTemp + cbitUnitsPerWeek, rgbLogonHours, numBytes);
  387. memcpy (rgbLogonHours, pTemp + numBytes, cbitUnitsPerWeek);
  388. }
  389. else // lRotateCount > 0 -- shift right
  390. {
  391. // Copy numBytes BYTES from the end of the array and then copy
  392. // the entire array to fill up to the end of the temp array.
  393. // The copy 168 bytes from the beginning of the temp array back
  394. // to the original array.
  395. memcpy (pTemp, rgbLogonHours + (cbitUnitsPerWeek - numBytes), numBytes);
  396. memcpy (pTemp + numBytes, rgbLogonHours, cbitUnitsPerWeek);
  397. memcpy (rgbLogonHours, pTemp, cbitUnitsPerWeek);
  398. }
  399. delete [] pTemp;
  400. }
  401. else
  402. bResult = FALSE;
  403. }
  404. return bResult;
  405. } // NetpRotateLogonHours()
  406. //****************************************************************************
  407. //
  408. // GetFirstDayOfWeek
  409. //
  410. // Use the locale API to get the "official" first day of the week.
  411. //
  412. //****************************************************************************
  413. int GetFirstDayOfWeek()
  414. {
  415. _TRACE (1, L"Entering GetFirstDayOfWeek\n");
  416. int nFirstDay = -1;
  417. WCHAR szBuf[10];
  418. int nRet = ::GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK,
  419. szBuf, sizeof(szBuf)/sizeof(WCHAR));
  420. if ( nRet > 0 )
  421. {
  422. int nDay = ::_wtoi( szBuf );
  423. if ( nDay < 0 || nDay > 6 )
  424. {
  425. _TRACE (0, L"Out of range, IFIRSTDAYOFWEEK = %d\n", nDay);
  426. }
  427. else
  428. nFirstDay = nDay;
  429. }
  430. else
  431. {
  432. _TRACE (0, L"GetLocaleInfo(IFIRSTDAYOFWEEK) failed - %d\n", GetLastError ());
  433. }
  434. _TRACE (-1, L"Leaving GetFirstDayOfWeek: first day = %d\n", nFirstDay);
  435. return nFirstDay;
  436. }