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.

2769 lines
78 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name:
  4. clusrtl.c
  5. Abstract:
  6. Provides run-time library support common to any module
  7. of the NT Cluster.
  8. Author:
  9. John Vert (jvert) 1-Dec-1995
  10. Revision History:
  11. --*/
  12. #include "clusrtlp.h"
  13. #include "stdarg.h"
  14. #include "stdlib.h"
  15. #include "clusverp.h"
  16. #include "windns.h"
  17. #include "security.h"
  18. #include "secext.h"
  19. #include "sddl.h"
  20. #define WMI_TRACING 1
  21. #define RPC_WMI_TRACING 1
  22. #if defined(WMI_TRACING)
  23. // 789aa2d3-e298-4d8b-a3a3-a8a0ec9c7702 -- Rpc
  24. // b1599392-1a0f-11d3-ba86-00c04f8eed00 -- ClusSvc
  25. #define WPP_CONTROL_GUIDS \
  26. WPP_DEFINE_CONTROL_GUID(ClusRtl,(b1599392,1a0f,11d3,ba86,00c04f8eed00), \
  27. WPP_DEFINE_BIT(Error) \
  28. WPP_DEFINE_BIT(Unusual) \
  29. WPP_DEFINE_BIT(Noise) \
  30. WPP_DEFINE_BIT(Watchdog) \
  31. ) \
  32. WPP_DEFINE_CONTROL_GUID(ClusRpc,(789aa2d3,e298,4d8b,a3a3,a8a0ec9c7702), \
  33. WPP_DEFINE_BIT(RpcTrace) \
  34. )
  35. //#define WppDebug(x,y) ClRtlPrintf y
  36. #include "clusrtl.tmh"
  37. #define REG_TRACE_CLUSTERING L"Clustering Service"
  38. #endif // defined(WMI_TRACING)
  39. //
  40. // Local Macros
  41. //
  42. //
  43. // SC Manager failure action parameters. set STARTUP_FAILURE_RESTART to one
  44. // before shipping to get the normal backoff behavior.
  45. //
  46. #if STARTUP_FAILURE_RESTART
  47. #define CLUSTER_FAILURE_RETRY_COUNT -1 // forever
  48. #else
  49. #define CLUSTER_FAILURE_RETRY_COUNT 0
  50. #endif
  51. #define CLUSTER_FAILURE_MAX_STARTUP_RETRIES 30
  52. #define CLUSTER_FAILURE_INITIAL_RETRY_INTERVAL 60 * 1000 // 60 secs
  53. #define CLUSTER_FAILURE_FINAL_RETRY_INTERVAL ( 60 * 1000 * 16) // 16 mins
  54. #define ClRtlAcquirePrintLock() \
  55. WaitForSingleObject( ClRtlPrintFileMutex, INFINITE );
  56. #define ClRtlReleasePrintLock() \
  57. ReleaseMutex( ClRtlPrintFileMutex );
  58. #define LOGFILE_NAME L"Cluster.log"
  59. //
  60. // DON'T CHANGE THIS CONSTANT UNLESS YOU REALLY KNOW WHAT YOU'RE
  61. // DOING. ASSUMPTIONS HAVE BEEN MADE ABOUT IT'S SIZE AND THINGS WILL BREAK IF
  62. // YOU MAKE IT TOO SMALL. - charlwi 4/1/02 (and, no, this is not an April
  63. // Fool's joke).
  64. //
  65. #define LOGENTRY_BUFFER_SIZE 512
  66. //
  67. // Private Data
  68. //
  69. BOOL ClRtlpDbgOutputToConsole = FALSE;
  70. BOOL ClRtlpInitialized = FALSE;
  71. BOOL ClRtlPrintToFile = FALSE;
  72. HANDLE ClRtlPrintFile = NULL;
  73. HANDLE ClRtlPrintFileMutex = NULL;
  74. DWORD ClRtlProcessId;
  75. PDWORD ClRtlDbgLogLevel;
  76. HANDLE ClRtlWatchdogTimerQueue = NULL;
  77. #define MAX_NUMBER_LENGTH 20
  78. // Specify maximum file size ( DWORD / 1MB )
  79. #define MAX_FILE_SIZE ( 0xFFFFF000 / ( 1024 * 1024 ) )
  80. DWORD ClRtlPrintFileLimit = ( 8 * 1024 * 1024 ); // 8 MB default
  81. DWORD ClRtlPrintFileLoWater = 0;
  82. //
  83. // Public Routines
  84. //
  85. // !!!!NOTE!!!!
  86. //
  87. // This initialization routine is call from DllMain(), do not add anyting out
  88. // here that requires synchronization. Do not add any win32 api calls here.
  89. //
  90. DWORD
  91. ClRtlInitialize(
  92. IN BOOL DbgOutputToConsole,
  93. IN PDWORD DbgLogLevel
  94. )
  95. {
  96. WCHAR logFileBuffer[MAX_PATH];
  97. LPWSTR logFileName = NULL;
  98. DWORD Status = ERROR_SUCCESS;
  99. DWORD defaultLogSize = 8;
  100. HKEY ClusterKey;
  101. WCHAR modulePath[MAX_PATH];
  102. DWORD envLength;
  103. WCHAR logFileSize[MAX_NUMBER_LENGTH];
  104. DWORD logSize;
  105. LPWSTR lpszBakFileName = NULL;
  106. DWORD fileSizeHigh = 0;
  107. DWORD fileSizeLow;
  108. UNICODE_STRING logFileString;
  109. SECURITY_ATTRIBUTES logFileSecurityAttr;
  110. PSECURITY_DESCRIPTOR logFileSecurityDesc;
  111. //
  112. // init event stuff so we have a means for logging other failures
  113. //
  114. ClRtlEventLogInit();
  115. if (!ClRtlpInitialized) {
  116. ClRtlpDbgOutputToConsole = DbgOutputToConsole;
  117. ClRtlpInitialized = TRUE;
  118. ClRtlDbgLogLevel = DbgLogLevel;
  119. //
  120. // GetEnvironmentVariable returns the count minus the null if the
  121. // buffer is large enough. Otherwise, the return length includes space
  122. // for the trailing null.
  123. //
  124. // the code that deals with the clusterlog and clusterlogsize
  125. // env. variables is dup'ed in OmpOpenObjectLog
  126. // (service\om\omlog.c). Any changes made here should be prop'ed to
  127. // that area if appropriate.
  128. //
  129. envLength = GetEnvironmentVariable(L"ClusterLog",
  130. logFileBuffer,
  131. RTL_NUMBER_OF( logFileBuffer ));
  132. if ( envLength > RTL_NUMBER_OF( logFileBuffer )) {
  133. logFileName = LocalAlloc( LMEM_FIXED,
  134. envLength * sizeof( WCHAR ) );
  135. if ( logFileName == NULL ) {
  136. return GetLastError();
  137. }
  138. envLength = GetEnvironmentVariable(L"ClusterLog",
  139. logFileName,
  140. envLength);
  141. if ( envLength == 0 ) {
  142. LocalFree( logFileName );
  143. logFileName = NULL;
  144. }
  145. } else if ( envLength != 0 ) {
  146. logFileName = logFileBuffer;
  147. }
  148. //
  149. // remove any trailing white space. go to the end of the string and
  150. // scan backwards; stop when we find the first non-white space char or
  151. // we hit the beginning of the buffer.
  152. //
  153. if ( logFileName != NULL ) {
  154. PWCHAR p = logFileName + envLength - 1;
  155. while ( iswspace( *p )) {
  156. *p = UNICODE_NULL;
  157. if ( p == logFileName ) {
  158. break;
  159. }
  160. --p;
  161. }
  162. //
  163. // make sure something useful is left
  164. //
  165. if ( wcslen( logFileName ) == 0 ) {
  166. if ( logFileName != logFileBuffer ) {
  167. LocalFree( logFileName );
  168. }
  169. logFileName = NULL;
  170. }
  171. }
  172. #if CLUSTER_BETA
  173. //
  174. // always turn on logging when in beta mode
  175. //
  176. if ( ( logFileName != NULL ) && ( *logFileName == UNICODE_NULL ) ) {
  177. WCHAR *p;
  178. if ( GetModuleFileName(NULL,
  179. modulePath,
  180. MAX_PATH - sizeof(LOGFILE_NAME)/sizeof(WCHAR) ) ) {
  181. p = wcsrchr( modulePath, '\\' );
  182. if ( p != UNICODE_NULL ) {
  183. p++;
  184. *p = UNICODE_NULL;
  185. wcscat( modulePath, LOGFILE_NAME );
  186. logFileName = modulePath;
  187. }
  188. }
  189. }
  190. #endif
  191. if ( logFileName != NULL ) {
  192. //
  193. // Try to get a limit on the log file size.
  194. // This number is the number of MB.
  195. //
  196. envLength = GetEnvironmentVariable(L"ClusterLogSize",
  197. logFileSize,
  198. RTL_NUMBER_OF( logFileSize ));
  199. if ( (envLength != 0) &&
  200. (envLength < MAX_NUMBER_LENGTH) ) {
  201. RtlInitUnicodeString( &logFileString, logFileSize );
  202. Status = RtlUnicodeStringToInteger( &logFileString,
  203. 10,
  204. &logSize );
  205. if ( NT_SUCCESS( Status ) ) {
  206. ClRtlPrintFileLimit = logSize;
  207. }
  208. } else {
  209. ClRtlPrintFileLimit = defaultLogSize;
  210. }
  211. Status = ERROR_SUCCESS;
  212. if ( ClRtlPrintFileLimit == 0 ) {
  213. goto exit;
  214. }
  215. if ( ClRtlPrintFileLimit > MAX_FILE_SIZE ) {
  216. ClRtlPrintFileLimit = MAX_FILE_SIZE;
  217. }
  218. ClRtlPrintFileLimit = ClRtlPrintFileLimit * ( 1024 * 1024 );
  219. ClRtlPrintFileMutex = CreateMutex( NULL,
  220. FALSE,
  221. L"ClusterRtlPrintFileMutex" );
  222. if ( ClRtlPrintFileMutex != NULL ) {
  223. BOOL createdDirectory = FALSE;
  224. //
  225. // Chittur Subbaraman (chitturs) - 11/11/98
  226. //
  227. // Check whether the ClusterLogOverwrite environment var is
  228. // defined.
  229. //
  230. envLength = GetEnvironmentVariable( L"ClusterLogOverwrite",
  231. NULL,
  232. 0 );
  233. if ( envLength != 0 )
  234. {
  235. HANDLE hLogFile = INVALID_HANDLE_VALUE;
  236. WCHAR bakExtension[] = L".bak";
  237. //
  238. // Check whether someone else has an open handle to
  239. // the log file. If so, don't attempt anything.
  240. //
  241. hLogFile = CreateFile( logFileName,
  242. GENERIC_READ | GENERIC_WRITE,
  243. 0, // Exclusive file share mode
  244. NULL,
  245. OPEN_EXISTING,
  246. 0,
  247. NULL );
  248. if ( hLogFile != INVALID_HANDLE_VALUE )
  249. {
  250. CloseHandle( hLogFile );
  251. lpszBakFileName = LocalAlloc( LMEM_FIXED,
  252. ( RTL_NUMBER_OF( bakExtension ) + lstrlenW( logFileName ) ) *
  253. sizeof( WCHAR ) );
  254. if ( lpszBakFileName == NULL )
  255. {
  256. Status = GetLastError();
  257. ClRtlDbgPrint(LOG_CRITICAL,
  258. "[ClRtl] Mem alloc for .bak file name failed. Error %1!u!\n",
  259. Status);
  260. goto exit;
  261. }
  262. //
  263. // Append ".bak" to the log file name
  264. //
  265. lstrcpyW( lpszBakFileName, logFileName );
  266. lstrcatW( lpszBakFileName, bakExtension );
  267. //
  268. // Move the log file (if it exists) to a bak
  269. // file. Moving preserves the ACL on the file.
  270. //
  271. if ( !MoveFileExW( logFileName, lpszBakFileName, MOVEFILE_REPLACE_EXISTING )) {
  272. //
  273. // There is no reason for this to happen since the
  274. // log file should be deletable.
  275. //
  276. Status = GetLastError();
  277. ClRtlDbgPrint(LOG_CRITICAL,
  278. "[ClRtl] Error %1!u! in renaming cluster log file.\n",
  279. Status);
  280. goto exit;
  281. }
  282. }
  283. }
  284. //
  285. // create a SD giving only local admins and localsystem
  286. // access.
  287. //
  288. if ( !ConvertStringSecurityDescriptorToSecurityDescriptor(
  289. L"D:(A;;FA;;;BA)(A;;FA;;;SY)",
  290. SDDL_REVISION_1,
  291. &logFileSecurityDesc,
  292. NULL
  293. )
  294. )
  295. {
  296. logFileSecurityDesc = NULL;
  297. }
  298. logFileSecurityAttr.nLength = sizeof( logFileSecurityAttr );
  299. logFileSecurityAttr.lpSecurityDescriptor = logFileSecurityDesc;
  300. logFileSecurityAttr.bInheritHandle = FALSE;
  301. openFileRetry:
  302. ClRtlPrintFile = CreateFile(logFileName,
  303. GENERIC_READ | GENERIC_WRITE,
  304. FILE_SHARE_READ | FILE_SHARE_WRITE,
  305. &logFileSecurityAttr,
  306. OPEN_ALWAYS,
  307. 0,
  308. NULL );
  309. if ( ClRtlPrintFile == INVALID_HANDLE_VALUE ) {
  310. Status = GetLastError();
  311. if ( !createdDirectory && Status == ERROR_PATH_NOT_FOUND ) {
  312. PWCHAR lastSlash = wcsrchr( logFileName, '\\' );
  313. WCHAR slashChar;
  314. if ( lastSlash == NULL ) {
  315. lastSlash = wcsrchr( logFileName, '/' );
  316. }
  317. if ( lastSlash != NULL ) {
  318. slashChar = *lastSlash;
  319. *lastSlash = UNICODE_NULL;
  320. Status = ClRtlCreateDirectory( logFileName );
  321. if ( Status == ERROR_SUCCESS ) {
  322. createdDirectory = TRUE;
  323. *lastSlash = slashChar;
  324. goto openFileRetry;
  325. }
  326. }
  327. }
  328. ClRtlDbgPrint(LOG_CRITICAL,
  329. "[ClRtl] Open of log file failed. Error %1!u!\n",
  330. Status);
  331. goto exit;
  332. } else {
  333. ClRtlPrintToFile = TRUE;
  334. ClRtlProcessId = GetCurrentProcessId();
  335. //
  336. // determine the initial low water mark. We have 3 cases
  337. // we need to handle:
  338. // 1) log size is less than 1/2 limit
  339. // 2) log size is within limit but more than 1/2 limit
  340. // 3) log size is greater than limit
  341. //
  342. // case 1 requires nothing special; the low water mark
  343. // will be updated on the next log write.
  344. //
  345. // for case 2, we need to find the beginning of a line
  346. // near 1/2 the current limit. for case 3, the place to
  347. // start looking is current log size - 1/2 limit. In this
  348. // case, the log will be truncated before the first write
  349. // occurs, so we need to take the last 1/2 limit bytes and
  350. // copy them down to the front.
  351. //
  352. //
  353. ClRtlAcquirePrintLock();
  354. fileSizeLow = GetFileSize( ClRtlPrintFile, &fileSizeHigh );
  355. if ( fileSizeLow < ( ClRtlPrintFileLimit / 2 )) {
  356. //
  357. // case 1: leave low water at zero; it will be updated
  358. // with next log write
  359. //
  360. ;
  361. } else {
  362. #define LOGBUF_SIZE 1024
  363. CHAR buffer[LOGBUF_SIZE];
  364. LONG currentPosition;
  365. DWORD bytesRead;
  366. if ( fileSizeLow < ClRtlPrintFileLimit ) {
  367. //
  368. // case 2; start looking at the 1/2 the current
  369. // limit to find the starting position
  370. //
  371. currentPosition = ClRtlPrintFileLimit / 2;
  372. } else {
  373. //
  374. // case 3: start at current size minus 1/2 limit
  375. // to find our starting position.
  376. //
  377. currentPosition = fileSizeLow - ( ClRtlPrintFileLimit / 2 );
  378. }
  379. //
  380. // read in a block (backwards) from the initial file
  381. // position and look for a newline char. When we find
  382. // one, the next char is the first char on a new log
  383. // line. use that as the initial starting position
  384. // when we finally truncate the file.
  385. //
  386. ClRtlPrintFileLoWater = 0;
  387. currentPosition -= LOGBUF_SIZE;
  388. SetFilePointer(ClRtlPrintFile,
  389. currentPosition,
  390. &fileSizeHigh,
  391. FILE_BEGIN);
  392. if ( ReadFile(ClRtlPrintFile,
  393. buffer,
  394. LOGBUF_SIZE,
  395. &bytesRead,
  396. NULL ) )
  397. {
  398. PCHAR p = &buffer[ bytesRead - 1 ];
  399. while ( *p != '\n' && bytesRead-- != 0 ) {
  400. --p;
  401. }
  402. if ( *p == '\n' ) {
  403. ClRtlPrintFileLoWater = (DWORD)(currentPosition + ( p - buffer + 1 ));
  404. }
  405. }
  406. if ( ClRtlPrintFileLoWater == 0 ) {
  407. //
  408. // couldn't find any reasonable data. just set it to
  409. // initial current position.
  410. //
  411. ClRtlPrintFileLoWater = currentPosition + LOGBUF_SIZE;
  412. }
  413. }
  414. ClRtlReleasePrintLock();
  415. }
  416. LocalFree( logFileSecurityDesc );
  417. } else {
  418. Status = GetLastError();
  419. ClRtlDbgPrint(LOG_UNUSUAL,
  420. "[ClRtl] Unable to create print file mutex. Error %1!u!.\n",
  421. Status);
  422. Status = ERROR_SUCCESS;
  423. //goto exit;
  424. }
  425. }
  426. }
  427. exit:
  428. if ( logFileName != logFileBuffer && logFileName != modulePath ) {
  429. LocalFree( logFileName );
  430. }
  431. //
  432. // Chittur Subbaraman (chitturs) - 11/11/98
  433. //
  434. if ( lpszBakFileName != NULL )
  435. {
  436. LocalFree( lpszBakFileName );
  437. }
  438. return Status;
  439. } // ClRtlInitialize
  440. #ifdef RPC_WMI_TRACING
  441. typedef
  442. DWORD (*I_RpcEnableWmiTraceFunc )(
  443. VOID* fn, // Rpc now uses TraceMessage, no need to pass trace func
  444. WPP_WIN2K_CONTROL_BLOCK ** pHandle
  445. );
  446. HINSTANCE hInstRpcrt4;
  447. #endif
  448. DWORD
  449. ClRtlIsServicesForMacintoshInstalled(
  450. OUT BOOL * pfInstalled
  451. )
  452. /*++
  453. Routine Description:
  454. Determines if SFM is installed on the local system.
  455. Arguments:
  456. pfInstalled - pointer to a boolean flag to return whether SFM is installed
  457. returns: TRUE if SFM is installed
  458. FALSE if SFM is not installed
  459. Return Value:
  460. Status of request. ERROR_SUCCESS if valid info in pfInstalled.
  461. Error Code otherwise. On error pfInstalled (if present) is set to FALSE
  462. --*/
  463. {
  464. HANDLE scHandle;
  465. HANDLE scServiceHandle;
  466. if ( ARGUMENT_PRESENT( pfInstalled ) ) {
  467. *pfInstalled = FALSE;
  468. } else {
  469. return ERROR_INVALID_PARAMETER;
  470. }
  471. scHandle = OpenSCManager(
  472. NULL, // Open on local machine
  473. NULL, // Open SERVICES_ACTIVE_DATABASE
  474. GENERIC_READ );
  475. if ( scHandle == NULL ) {
  476. return( GetLastError() );
  477. }
  478. scServiceHandle = OpenService(
  479. scHandle,
  480. L"macfile",
  481. READ_CONTROL );
  482. if ( scServiceHandle != NULL ) {
  483. *pfInstalled = TRUE;
  484. }
  485. CloseServiceHandle( scServiceHandle );
  486. CloseServiceHandle( scHandle );
  487. return ERROR_SUCCESS;
  488. } // ClRtlIsServicesForMacintoshInstalled
  489. DWORD
  490. ClRtlInitWmi(
  491. LPCWSTR ComponentName
  492. )
  493. {
  494. #if defined(RPC_WMI_TRACING)
  495. {
  496. DWORD Status = ERROR_SUCCESS;
  497. PWPP_WIN2K_CONTROL_BLOCK RpcCb;
  498. I_RpcEnableWmiTraceFunc RpcEnableWmiTrace = 0;
  499. hInstRpcrt4 = LoadLibrary(L"rpcrt4.dll");
  500. if (hInstRpcrt4) {
  501. RpcEnableWmiTrace = (I_RpcEnableWmiTraceFunc)
  502. GetProcAddress(hInstRpcrt4, "I_RpcEnableWmiTrace");
  503. if (RpcEnableWmiTrace) {
  504. Status = (*RpcEnableWmiTrace)(0, &RpcCb);
  505. if (Status == ERROR_SUCCESS) {
  506. WPP_SET_FORWARD_PTR(RpcTrace, WPP_VER_WIN2K_CB_FORWARD_PTR, RpcCb);
  507. }
  508. } else {
  509. ClRtlDbgPrint(LOG_UNUSUAL,
  510. "[ClRtl] rpcrt4.dll GetWmiTraceEntryPoint failed, status %1!d!.\n",
  511. GetLastError() );
  512. }
  513. }
  514. }
  515. #endif // RPC_WMI_TRACING
  516. WPP_INIT_TRACING(NULL); // Don't need publishing
  517. WppAutoStart(ComponentName);
  518. return ERROR_SUCCESS;
  519. }
  520. VOID
  521. ClRtlCleanup(
  522. VOID
  523. )
  524. {
  525. if (ClRtlpInitialized) {
  526. ClRtlpInitialized = FALSE;
  527. ClRtlEventLogCleanup();
  528. CloseHandle ( ClRtlPrintFileMutex );
  529. CloseHandle ( ClRtlPrintFile );
  530. //Cleaning up watchdog stuff
  531. if(ClRtlWatchdogTimerQueue != NULL) {
  532. DeleteTimerQueue(ClRtlWatchdogTimerQueue);
  533. ClRtlWatchdogTimerQueue = NULL;
  534. }
  535. WPP_CLEANUP();
  536. #if defined(RPC_WMI_TRACING)
  537. if (hInstRpcrt4) {
  538. FreeLibrary(hInstRpcrt4);
  539. hInstRpcrt4 = NULL;
  540. }
  541. #endif
  542. }
  543. return;
  544. }
  545. VOID
  546. ClRtlpWatchdogCallback(
  547. PVOID par,
  548. BOOLEAN timedOut
  549. )
  550. {
  551. PWATCHDOGPAR pPar=(PWATCHDOGPAR)par;
  552. if(!timedOut) {
  553. // The timer was cancelled, get out.
  554. ClRtlLogPrint(LOG_NOISE,
  555. "[ClRtl] Watchdog Timer Cancelled, ThreadId= 0x%1!x! par= %2!ws!.\n",
  556. pPar->threadId,
  557. pPar->par
  558. );
  559. return;
  560. }
  561. ClRtlLogPrint(LOG_CRITICAL,
  562. "[ClRtl] Watchdog timer timed out, ThreadId= 0x%1!x! par= %2!ws!.\n",
  563. pPar->threadId,
  564. pPar->par
  565. );
  566. #if CLUSTER_BETA
  567. if (WPP_LEVEL_ENABLED(Watchdog)) {
  568. // Breaking into NTSD if available or KD. Do it only for cluster beta builds.
  569. DebugBreak();
  570. }
  571. #endif
  572. }
  573. PVOID
  574. ClRtlSetWatchdogTimer(
  575. DWORD timeout,
  576. LPWSTR par
  577. )
  578. {
  579. PWATCHDOGPAR pPar;
  580. // Do the initialization here not in ClRtlInitialize()
  581. if(ClRtlWatchdogTimerQueue == NULL) {
  582. if((ClRtlWatchdogTimerQueue = CreateTimerQueue()) == NULL) {
  583. return NULL;
  584. }
  585. }
  586. if((pPar = LocalAlloc(LMEM_FIXED, sizeof(WATCHDOGPAR))) == NULL) {
  587. return NULL;
  588. }
  589. pPar->par = par;
  590. pPar->threadId = GetCurrentThreadId();
  591. if(!CreateTimerQueueTimer(
  592. &pPar->wTimer,
  593. ClRtlWatchdogTimerQueue,
  594. ClRtlpWatchdogCallback,
  595. (PVOID)pPar,
  596. timeout,
  597. 0,
  598. 0)) {
  599. LocalFree(pPar);
  600. return NULL;
  601. }
  602. #if CLUSTER_BETA
  603. ClRtlLogPrint(LOG_NOISE,
  604. "[ClRtl] Setting watchdog timer= 0x%1!x!, Timeout= %2!u!(ms), par= %3!ws!.\n",
  605. pPar->wTimer,
  606. timeout,
  607. par
  608. );
  609. #endif
  610. return (PVOID)pPar;
  611. }
  612. VOID
  613. ClRtlCancelWatchdogTimer(
  614. PVOID wTimer
  615. )
  616. {
  617. PWATCHDOGPAR pPar=(PWATCHDOGPAR)wTimer;
  618. if((ClRtlWatchdogTimerQueue == NULL) || (wTimer == NULL)) {
  619. return;
  620. }
  621. if(!DeleteTimerQueueTimer(
  622. ClRtlWatchdogTimerQueue,
  623. pPar->wTimer,
  624. INVALID_HANDLE_VALUE
  625. )) {
  626. ClRtlLogPrint(LOG_CRITICAL,
  627. "[ClRtl] Failed to cancel watchdog timer 0x%1!x!.\n",
  628. pPar->wTimer
  629. );
  630. }
  631. else {
  632. #if CLUSTER_BETA
  633. ClRtlLogPrint(LOG_NOISE,
  634. "[ClRtl] Cancelled watchdog timer 0x%1!x!.\n",
  635. pPar->wTimer
  636. );
  637. #endif
  638. }
  639. LocalFree(wTimer);
  640. }
  641. BOOL
  642. ClRtlCheckForLogCorruption(
  643. LPSTR pszOutBuffer
  644. )
  645. //
  646. // Find the log corrupter. There should never be move than 4
  647. // question marks in a row or character below 32 or above 128
  648. // if English.
  649. //
  650. // Returns:
  651. // TRUE if it is safe to write
  652. // FALSE if it is NOT safe to write
  653. //
  654. {
  655. DWORD count;
  656. WCHAR szLocale[ 32 ];
  657. static BOOL fLocaleFound = FALSE;
  658. static BOOL fEnglish = FALSE;
  659. DWORD localeBytes;
  660. if ( !pszOutBuffer )
  661. return FALSE;
  662. if ( !fLocaleFound )
  663. {
  664. localeBytes = GetLocaleInfoW(LOCALE_SYSTEM_DEFAULT,
  665. LOCALE_SENGLANGUAGE,
  666. szLocale,
  667. RTL_NUMBER_OF( szLocale ));
  668. if ( localeBytes != 0 )
  669. {
  670. if ( lstrcmpiW( szLocale, L"ENGLISH" ) == 0 )
  671. {
  672. fEnglish = TRUE;
  673. }
  674. fLocaleFound = TRUE;
  675. }
  676. }
  677. for( count = 0; *pszOutBuffer; pszOutBuffer++ )
  678. {
  679. if ( *pszOutBuffer == '?' )
  680. {
  681. count++;
  682. if ( count > 4 )
  683. {
  684. return FALSE;
  685. }
  686. }
  687. else if ( fEnglish
  688. && ( ( *pszOutBuffer < 32
  689. && *pszOutBuffer != 0x0A // linefeed
  690. && *pszOutBuffer != 0x0D // creturn
  691. && *pszOutBuffer != 0x09 ) // tab
  692. || *pszOutBuffer > 128 ) )
  693. {
  694. return FALSE;
  695. }
  696. }
  697. return TRUE;
  698. } // ClRtlCheckForLogCorruption
  699. __inline BOOL
  700. ClRtlpIsOutputDeviceAvailable(
  701. VOID
  702. )
  703. /*++
  704. Routine Description:
  705. Description
  706. Arguments:
  707. None
  708. Return Value:
  709. None
  710. --*/
  711. {
  712. //
  713. // normally, there is nothing to do
  714. //
  715. return ( ClRtlpDbgOutputToConsole || IsDebuggerPresent());
  716. } // ClRtlpIsOutputDeviceAvailable
  717. VOID
  718. ClRtlpOutputString(
  719. IN PCHAR String
  720. )
  721. /*++
  722. Routine Description:
  723. Outputs the specified string based on the current settings
  724. Arguments:
  725. String - Specifies the string to output.
  726. Return Value:
  727. None.
  728. --*/
  729. {
  730. static PCRITICAL_SECTION dbgPrintLock = NULL;
  731. PCRITICAL_SECTION testPrintLock;
  732. //
  733. // synchronize threads by interlocking the assignment of the global lock.
  734. //
  735. if ( dbgPrintLock == NULL ) {
  736. testPrintLock = LocalAlloc( LMEM_FIXED, sizeof( CRITICAL_SECTION ));
  737. if ( testPrintLock == NULL ) {
  738. return;
  739. }
  740. InitializeCriticalSection( testPrintLock );
  741. InterlockedCompareExchangePointer( &dbgPrintLock, testPrintLock, NULL );
  742. //
  743. // only one thread did the exchange; the loser deallocates its
  744. // allocation and switches over to using the real lock
  745. //
  746. if ( dbgPrintLock != testPrintLock ) {
  747. DeleteCriticalSection( testPrintLock );
  748. LocalFree( testPrintLock );
  749. }
  750. }
  751. EnterCriticalSection( dbgPrintLock );
  752. //
  753. // print to console window has precedence. Besides, if console is the
  754. // debugger window, you get double output
  755. //
  756. if (ClRtlpDbgOutputToConsole) {
  757. printf( "%hs", String );
  758. } else if ( IsDebuggerPresent()) {
  759. OutputDebugStringA(String);
  760. }
  761. LeaveCriticalSection( dbgPrintLock );
  762. } // ClRtlpOutputString
  763. VOID
  764. ClRtlMsgPrint(
  765. IN DWORD MessageId,
  766. ...
  767. )
  768. /*++
  769. Routine Description:
  770. Prints a message to the debugger or console, as appropriate
  771. Does not alter the formatting of the message as it occurs in the message
  772. file.
  773. Arguments:
  774. MessageId - The message id of the string to print
  775. Any FormatMessage compatible arguments to be inserted in the ErrorMessage
  776. before it is logged.
  777. Return Value:
  778. None.
  779. --*/
  780. {
  781. CHAR szOutBuffer[LOGENTRY_BUFFER_SIZE];
  782. DWORD Bytes;
  783. NTSTATUS Status;
  784. va_list ArgList;
  785. //
  786. // don't go any further if nothing to do
  787. //
  788. if ( !ClRtlpIsOutputDeviceAvailable()) {
  789. return;
  790. }
  791. va_start(ArgList, MessageId);
  792. try {
  793. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE,
  794. NULL,
  795. MessageId,
  796. 0,
  797. szOutBuffer,
  798. RTL_NUMBER_OF( szOutBuffer ),
  799. &ArgList);
  800. }
  801. except ( EXCEPTION_EXECUTE_HANDLER ) {
  802. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_STRING
  803. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  804. L"LOGERROR(exception): Could not format message ID #%1!u!\n",
  805. 0,
  806. 0,
  807. szOutBuffer,
  808. RTL_NUMBER_OF( szOutBuffer ),
  809. (va_list *) &MessageId );
  810. }
  811. va_end(ArgList);
  812. if (Bytes != 0) {
  813. if ( !ClRtlCheckForLogCorruption( szOutBuffer ) ) {
  814. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_STRING
  815. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  816. "LOGERROR: non-ASCII characters detected after formatting of message ID #%1!u!\n",
  817. 0,
  818. 0,
  819. szOutBuffer,
  820. RTL_NUMBER_OF( szOutBuffer ),
  821. (va_list *) &MessageId );
  822. }
  823. ClRtlpOutputString(szOutBuffer);
  824. }
  825. } // ClRtlMsgPrint
  826. VOID
  827. ClRtlpDbgPrint(
  828. DWORD LogLevel,
  829. PCHAR FormatString,
  830. va_list ArgList
  831. )
  832. /*++
  833. Routine Description:
  834. Prints a message to the debugger or console, as appropriate.
  835. Arguments:
  836. LogLevel - Supplies the logging level, one of
  837. LOG_CRITICAL 1
  838. LOG_UNUSUAL 2
  839. LOG_NOISE 3
  840. String - The initial message string to print.
  841. Any FormatMessage-compatible arguments to be inserted in the
  842. ErrorMessage before it is logged.
  843. Return Value:
  844. None.
  845. --*/
  846. {
  847. UNICODE_STRING UnicodeString;
  848. ANSI_STRING AnsiString;
  849. WCHAR wszOutBuffer[LOGENTRY_BUFFER_SIZE];
  850. WCHAR wszInBuffer[LOGENTRY_BUFFER_SIZE];
  851. CHAR szOutBuffer[LOGENTRY_BUFFER_SIZE];
  852. NTSTATUS Status;
  853. DWORD Bytes;
  854. //
  855. // don't go any further if nothing to do
  856. //
  857. if ( !ClRtlpIsOutputDeviceAvailable()) {
  858. return;
  859. }
  860. //
  861. // next check that this message isn't filtered out by the current logging
  862. // level
  863. //
  864. if ( ClRtlDbgLogLevel != NULL ) {
  865. if ( LogLevel > *ClRtlDbgLogLevel ) {
  866. return;
  867. }
  868. }
  869. RtlInitAnsiString( &AnsiString, FormatString );
  870. UnicodeString.MaximumLength = LOGENTRY_BUFFER_SIZE;
  871. UnicodeString.Buffer = wszInBuffer;
  872. Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
  873. if ( !NT_SUCCESS( Status ) ) {
  874. return;
  875. }
  876. try {
  877. Bytes = FormatMessageW(FORMAT_MESSAGE_FROM_STRING,
  878. UnicodeString.Buffer,
  879. 0,
  880. 0,
  881. wszOutBuffer,
  882. RTL_NUMBER_OF( wszOutBuffer ),
  883. &ArgList);
  884. }
  885. except ( EXCEPTION_EXECUTE_HANDLER ) {
  886. Bytes = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
  887. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  888. L"LOGERROR(exception): Could not print message: %1!hs!.",
  889. 0,
  890. 0,
  891. wszOutBuffer,
  892. RTL_NUMBER_OF( wszOutBuffer ),
  893. (va_list *) &FormatString );
  894. }
  895. if (Bytes != 0) {
  896. UnicodeString.Length = (USHORT) Bytes * sizeof(WCHAR);
  897. UnicodeString.Buffer = wszOutBuffer;
  898. AnsiString.MaximumLength = LOGENTRY_BUFFER_SIZE;
  899. AnsiString.Buffer = szOutBuffer;
  900. Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, FALSE );
  901. if ( NT_SUCCESS( Status ) ) {
  902. if ( ClRtlCheckForLogCorruption( AnsiString.Buffer ) ) {
  903. ClRtlpOutputString(szOutBuffer);
  904. }
  905. else
  906. {
  907. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_STRING
  908. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  909. "LOGERROR: non-ASCII characters in formatted message: %1!hs!",
  910. 0,
  911. 0,
  912. szOutBuffer,
  913. RTL_NUMBER_OF( szOutBuffer ),
  914. (va_list *) &FormatString );
  915. if ( Bytes > 0 ) {
  916. ClRtlpOutputString(szOutBuffer);
  917. if ( szOutBuffer[ Bytes - 1 ] != '\n' ) {
  918. ClRtlpOutputString( "\n" );
  919. }
  920. }
  921. }
  922. }
  923. }
  924. } // ClRtlpDbgPrint
  925. VOID
  926. ClRtlDbgPrint(
  927. DWORD LogLevel,
  928. PCHAR FormatString,
  929. ...
  930. )
  931. /*++
  932. Routine Description:
  933. Prints a message to the debugger or console, as appropriate.
  934. Arguments:
  935. LogLevel - Supplies the logging level, one of
  936. LOG_CRITICAL 1
  937. LOG_UNUSUAL 2
  938. LOG_NOISE 3
  939. String - The initial message string to print.
  940. Any FormatMessage-compatible arguments to be inserted in the
  941. ErrorMessage before it is logged.
  942. Return Value:
  943. None.
  944. --*/
  945. {
  946. va_list ArgList;
  947. va_start(ArgList, FormatString);
  948. ClRtlpDbgPrint( LogLevel, FormatString, ArgList );
  949. va_end(ArgList);
  950. } // ClRtlDbgPrint
  951. VOID
  952. ClRtlPrintf(
  953. PCHAR FormatString,
  954. ...
  955. )
  956. /*++
  957. Routine Description:
  958. Prints a message to the debugger or console, as appropriate.
  959. Arguments:
  960. Just like printf
  961. Return Value:
  962. None.
  963. --*/
  964. {
  965. char buf[128];
  966. va_list ArgList;
  967. va_start(ArgList, FormatString);
  968. _vsnprintf(buf, RTL_NUMBER_OF(buf), FormatString, ArgList);
  969. buf[ RTL_NUMBER_OF(buf) - 1 ] = 0;
  970. ClRtlLogPrint( 1, "%1!hs!", buf);
  971. va_end(ArgList);
  972. } // ClRtlPrintf
  973. DWORD
  974. ClRtlpTruncateFile(
  975. IN HANDLE FileHandle,
  976. IN DWORD FileSize,
  977. IN LPDWORD LastPosition
  978. )
  979. /*++
  980. Routine Description:
  981. Truncate a file from the front.
  982. Arguments:
  983. FileHandle - File handle.
  984. FileSize - Current End of File.
  985. LastPosition - Move from this last position to end-of-file to beginning.
  986. Return Value:
  987. New end of file.
  988. --*/
  989. {
  990. //
  991. // The following buffer size should never be more than 1/4 the size of the
  992. // file.
  993. //
  994. #define BUFFER_SIZE ( 64 * 1024 )
  995. DWORD bytesLeft;
  996. DWORD endPosition = 0;
  997. DWORD bufferSize;
  998. DWORD bytesRead;
  999. DWORD bytesWritten;
  1000. DWORD fileSizeHigh = 0;
  1001. DWORD readPosition;
  1002. DWORD writePosition;
  1003. PVOID dataBuffer;
  1004. if ( *LastPosition >= FileSize ) {
  1005. goto error_exit;
  1006. }
  1007. bytesLeft = FileSize - *LastPosition;
  1008. dataBuffer = LocalAlloc( LMEM_FIXED, BUFFER_SIZE );
  1009. if ( !dataBuffer ) {
  1010. goto error_exit;
  1011. }
  1012. endPosition = bytesLeft;
  1013. //
  1014. // Point back to last position for reading.
  1015. //
  1016. readPosition = *LastPosition;
  1017. writePosition = 0;
  1018. while ( bytesLeft ) {
  1019. if ( bytesLeft >= BUFFER_SIZE ) {
  1020. bufferSize = BUFFER_SIZE;
  1021. } else {
  1022. bufferSize = bytesLeft;
  1023. }
  1024. bytesLeft -= bufferSize;
  1025. SetFilePointer( FileHandle,
  1026. readPosition,
  1027. &fileSizeHigh,
  1028. FILE_BEGIN );
  1029. if ( ReadFile( FileHandle,
  1030. dataBuffer,
  1031. bufferSize,
  1032. &bytesRead,
  1033. NULL ) ) {
  1034. SetFilePointer( FileHandle,
  1035. writePosition,
  1036. &fileSizeHigh,
  1037. FILE_BEGIN );
  1038. WriteFile( FileHandle,
  1039. dataBuffer,
  1040. bytesRead,
  1041. &bytesWritten,
  1042. NULL );
  1043. } else {
  1044. endPosition = 0;
  1045. break;
  1046. }
  1047. readPosition += bytesRead;
  1048. writePosition += bytesWritten;
  1049. }
  1050. LocalFree( dataBuffer );
  1051. error_exit:
  1052. //
  1053. // Force end of file to get set.
  1054. //
  1055. SetFilePointer( FileHandle,
  1056. endPosition,
  1057. &fileSizeHigh,
  1058. FILE_BEGIN );
  1059. SetEndOfFile( FileHandle );
  1060. *LastPosition = endPosition;
  1061. return(endPosition);
  1062. } // ClRtlpTruncateFile
  1063. VOID
  1064. ClRtlLogPrint(
  1065. ULONG LogLevel,
  1066. PCHAR FormatString,
  1067. ...
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. Prints a message to a log file.
  1072. Arguments:
  1073. LogLevel - Supplies the logging level, one of
  1074. LOG_CRITICAL 1
  1075. LOG_UNUSUAL 2
  1076. LOG_NOISE 3
  1077. String - The initial message string to print.
  1078. Any FormatMessage-compatible arguments to be inserted in the
  1079. ErrorMessage before it is logged.
  1080. Return Value:
  1081. None.
  1082. --*/
  1083. {
  1084. UNICODE_STRING UnicodeString;
  1085. ANSI_STRING AnsiString;
  1086. WCHAR wszInBuffer[LOGENTRY_BUFFER_SIZE];
  1087. WCHAR wszOutBuffer[LOGENTRY_BUFFER_SIZE];
  1088. CHAR szOutBuffer[LOGENTRY_BUFFER_SIZE];
  1089. DWORD MsgChars;
  1090. DWORD PrefixChars;
  1091. DWORD BytesWritten;
  1092. DWORD FileSize;
  1093. DWORD FileSizeHigh;
  1094. NTSTATUS Status;
  1095. SYSTEMTIME Time;
  1096. ULONG_PTR ArgArray[9];
  1097. va_list ArgList;
  1098. PWCHAR logLabel;
  1099. #define CLRTL_LOG_LABEL_LENGTH 5
  1100. //
  1101. // init the variable arg list
  1102. //
  1103. va_start(ArgList, FormatString);
  1104. ClRtlpDbgPrint( LogLevel, FormatString, ArgList );
  1105. if ( !ClRtlPrintToFile ) {
  1106. va_end(ArgList);
  1107. return;
  1108. }
  1109. // begin_wpp config
  1110. // CUSTOM_TYPE(level, ItemListByte(UNK0, ERR_, WARN, INFO) );
  1111. // end_wpp
  1112. //
  1113. // convert nuemric LogLevel to something readable. If you change the
  1114. // labels, make sure all log labels are the same length and that
  1115. // CLRTL_LOG_LABEL_LENGTH reflects the new length.
  1116. //
  1117. switch ( LogLevel ) {
  1118. case LOG_NOISE:
  1119. logLabel = L"INFO ";
  1120. break;
  1121. case LOG_UNUSUAL:
  1122. logLabel = L"WARN ";
  1123. break;
  1124. case LOG_CRITICAL:
  1125. logLabel = L"ERR ";
  1126. break;
  1127. default:
  1128. ASSERT( 0 );
  1129. logLabel = L"UNKN ";
  1130. break;
  1131. }
  1132. GetSystemTime(&Time);
  1133. ArgArray[0] = ClRtlProcessId;
  1134. ArgArray[1] = GetCurrentThreadId();
  1135. ArgArray[2] = Time.wYear;
  1136. ArgArray[3] = Time.wMonth;
  1137. ArgArray[4] = Time.wDay;
  1138. ArgArray[5] = Time.wHour;
  1139. ArgArray[6] = Time.wMinute;
  1140. ArgArray[7] = Time.wSecond;
  1141. ArgArray[8] = Time.wMilliseconds;
  1142. //
  1143. // length of this format is 43 chars without trailing null under normal
  1144. // circumstances. FormatMessage will write a larger number if given one
  1145. // that doesn't fit within the field width.
  1146. //
  1147. PrefixChars = FormatMessageW(FORMAT_MESSAGE_FROM_STRING |
  1148. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1149. L"%1!08lx!.%2!08lx!::%3!02d!/%4!02d!/%5!02d!-%6!02d!:%7!02d!:%8!02d!.%9!03d! ",
  1150. 0,
  1151. 0,
  1152. wszOutBuffer,
  1153. RTL_NUMBER_OF( wszOutBuffer ),
  1154. (va_list*)ArgArray);
  1155. if ( PrefixChars == 0 ) {
  1156. va_end(ArgList);
  1157. WmiTrace("Prefix format failed, %d: %!ARSTR!", GetLastError(), FormatString);
  1158. return;
  1159. }
  1160. //
  1161. // make sure we have some space for the log label and the message
  1162. //
  1163. if (( PrefixChars + CLRTL_LOG_LABEL_LENGTH + 1 ) >= LOGENTRY_BUFFER_SIZE ) {
  1164. va_end(ArgList);
  1165. WmiTrace("Prefix format filled buffer, %!ARSTR!", FormatString);
  1166. return;
  1167. }
  1168. //
  1169. // add on the log label at the end and adjust PrefixChars.
  1170. //
  1171. wcsncat( wszOutBuffer + PrefixChars, logLabel, LOGENTRY_BUFFER_SIZE - PrefixChars );
  1172. PrefixChars += CLRTL_LOG_LABEL_LENGTH;
  1173. // convert the message into unicode
  1174. RtlInitAnsiString( &AnsiString, FormatString );
  1175. UnicodeString.MaximumLength = LOGENTRY_BUFFER_SIZE;
  1176. UnicodeString.Buffer = wszInBuffer;
  1177. Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
  1178. if ( !NT_SUCCESS( Status ) ) {
  1179. va_end(ArgList);
  1180. WmiTrace("AnsiToUni failed, %x: %!ARSTR!", Status, FormatString);
  1181. return;
  1182. }
  1183. try {
  1184. MsgChars = FormatMessageW(FORMAT_MESSAGE_FROM_STRING,
  1185. UnicodeString.Buffer,
  1186. 0,
  1187. 0,
  1188. &wszOutBuffer[PrefixChars],
  1189. RTL_NUMBER_OF( wszOutBuffer ) - PrefixChars,
  1190. &ArgList);
  1191. }
  1192. except ( EXCEPTION_EXECUTE_HANDLER ) {
  1193. MsgChars = FormatMessageW(FORMAT_MESSAGE_FROM_STRING
  1194. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1195. L"LOGERROR(exception): Could not print message: %1!hs!",
  1196. 0,
  1197. 0,
  1198. &wszOutBuffer[PrefixChars],
  1199. RTL_NUMBER_OF( wszOutBuffer ) - PrefixChars,
  1200. (va_list *) &FormatString );
  1201. }
  1202. va_end(ArgList);
  1203. if (MsgChars != 0) {
  1204. // convert the out to Ansi
  1205. UnicodeString.Buffer = wszOutBuffer;
  1206. UnicodeString.Length = ((USHORT) MsgChars + (USHORT) PrefixChars) * sizeof(WCHAR);
  1207. AnsiString.Buffer = szOutBuffer;
  1208. AnsiString.MaximumLength = LOGENTRY_BUFFER_SIZE;
  1209. Status = RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeString, FALSE );
  1210. if ( !NT_SUCCESS( Status ) ) {
  1211. WmiTrace("UniToAnsi failed, %x: %!ARWSTR!", Status, wszOutBuffer + PrefixChars);
  1212. return;
  1213. }
  1214. ClRtlAcquirePrintLock();
  1215. FileSize = GetFileSize( ClRtlPrintFile,
  1216. &FileSizeHigh );
  1217. ASSERT( FileSizeHigh == 0 ); // We're only using DWORDs!
  1218. if ( FileSize > ClRtlPrintFileLimit ) {
  1219. FileSize = ClRtlpTruncateFile( ClRtlPrintFile,
  1220. FileSize,
  1221. &ClRtlPrintFileLoWater );
  1222. }
  1223. SetFilePointer( ClRtlPrintFile,
  1224. FileSize,
  1225. &FileSizeHigh,
  1226. FILE_BEGIN );
  1227. if ( ClRtlCheckForLogCorruption( AnsiString.Buffer ) )
  1228. {
  1229. #if defined(ENCRYPT_TEXT_LOG)
  1230. int i;
  1231. for (i = 0; i < AnsiString.Length; ++i) {
  1232. AnsiString.Buffer[i] ^= 'a';
  1233. }
  1234. #endif
  1235. WriteFile(ClRtlPrintFile,
  1236. AnsiString.Buffer,
  1237. AnsiString.Length,
  1238. &BytesWritten,
  1239. NULL);
  1240. #if defined(ENCRYPT_TEXT_LOG)
  1241. for (i = 0; i < AnsiString.Length; ++i) {
  1242. AnsiString.Buffer[i] ^= 'a';
  1243. }
  1244. #endif
  1245. }
  1246. else
  1247. {
  1248. MsgChars = FormatMessageA(FORMAT_MESSAGE_FROM_STRING
  1249. | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  1250. "LOGERROR: non-ASCII characters in formatted message: %1!hs!",
  1251. 0,
  1252. 0,
  1253. &szOutBuffer[PrefixChars],
  1254. RTL_NUMBER_OF( szOutBuffer ) - PrefixChars,
  1255. (va_list *) &FormatString );
  1256. if ( MsgChars > 0 ) {
  1257. WriteFile(ClRtlPrintFile,
  1258. szOutBuffer,
  1259. PrefixChars + MsgChars,
  1260. &BytesWritten,
  1261. NULL);
  1262. if ( szOutBuffer[ PrefixChars + MsgChars - 1 ] != '\n' ) {
  1263. WriteFile(ClRtlPrintFile,
  1264. "\n",
  1265. 1,
  1266. &BytesWritten,
  1267. NULL);
  1268. }
  1269. RtlInitAnsiString( &AnsiString, szOutBuffer );
  1270. }
  1271. }
  1272. if ( (ClRtlPrintFileLoWater == 0) &&
  1273. (FileSize > (ClRtlPrintFileLimit / 2)) ) {
  1274. ClRtlPrintFileLoWater = FileSize + BytesWritten;
  1275. }
  1276. ClRtlReleasePrintLock();
  1277. WmiTrace("%!level! %!ARSTR!", *(UCHAR*)&LogLevel, AnsiString.Buffer + PrefixChars);
  1278. /*
  1279. #if defined(WMI_TRACING)
  1280. if (ClRtlWml.Trace && ClRtlWmiReg.EnableFlags) {
  1281. ClRtlWml.Trace(10, &ClRtlTraceGuid, ClRtlWmiReg.LoggerHandle,
  1282. LOG(UINT, ClRtlProcessId)
  1283. LOGASTR(AnsiString.Buffer + PrefixChars)
  1284. 0);
  1285. }
  1286. #endif // defined(WMI_TRACING)
  1287. */
  1288. } else {
  1289. WmiTrace("Format returned 0 bytes: %!ARSTR!", FormatString);
  1290. }
  1291. return;
  1292. } // ClRtlLogPrint
  1293. VOID
  1294. ClRtlpFlushLogBuffers(
  1295. VOID
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. Flush the cluster log file
  1300. Arguments:
  1301. none
  1302. Return Value:
  1303. none
  1304. --*/
  1305. {
  1306. FlushFileBuffers( ClRtlPrintFile );
  1307. }
  1308. DWORD
  1309. ClRtlCreateDirectory(
  1310. IN LPCWSTR lpszPath
  1311. )
  1312. /*++
  1313. Routine Description:
  1314. Creates a directory creating any subdirectories as required. Allows the
  1315. following forms:
  1316. [drive:][\]dir[\dir...]
  1317. \\?\drive:\dir[\dir...]
  1318. \\?\unc\server\share\dir[\dir...]
  1319. \\server\share\dir[\dir...]
  1320. Arguments:
  1321. lpszPath - Supplies the path to the directory. It may or
  1322. may not be terminated by a back slash.
  1323. Return Value:
  1324. ERROR_SUCCESS if successful, else the error code.
  1325. --*/
  1326. {
  1327. WCHAR backSlash = L'\\';
  1328. WCHAR fwdSlash = L'/';
  1329. DWORD dwLen;
  1330. LPWSTR pszNext = NULL;
  1331. DWORD dwError = ERROR_SUCCESS;
  1332. WCHAR expandedPathPrefix[] = L"\\\\?\\";
  1333. WCHAR uncPrefix[] = L"\\\\?\\UNC\\";
  1334. DWORD slashSkipCount = 0;
  1335. PWCHAR p;
  1336. LPWSTR dirPath = (LPWSTR)lpszPath;
  1337. BOOL charsAfterSlash = FALSE;
  1338. //
  1339. // get input string length and validate that we have a string worth using
  1340. //
  1341. dwLen = lstrlenW( lpszPath );
  1342. if ( !lpszPath || dwLen == 0 )
  1343. {
  1344. return ERROR_INVALID_PARAMETER;
  1345. }
  1346. //
  1347. // find the first slash after the first dir spec past the "root". The
  1348. // input string can have a number of different forms at the beginning, so
  1349. // we look for them first.
  1350. //
  1351. // check for a double backslash sequence at the beginning of the
  1352. // string. This could be an SMB path (\\server\share), a expanded storage
  1353. // path (\\?\c:\...) or a UNC path (\\?\UNC\server\share\...)
  1354. //
  1355. if ( dwLen > 2 && dirPath[0]== L'\\' && dirPath[1] == L'\\')
  1356. {
  1357. //
  1358. // is it expanded storage or UNC?
  1359. //
  1360. if (dwLen >= RTL_NUMBER_OF( expandedPathPrefix )
  1361. &&
  1362. wcsncmp( dirPath, expandedPathPrefix, RTL_NUMBER_OF( expandedPathPrefix ) - 1 ) == 0 )
  1363. {
  1364. //
  1365. // now see if it is a UNC name
  1366. //
  1367. if (dwLen >= RTL_NUMBER_OF( uncPrefix )
  1368. &&
  1369. ClRtlStrNICmp( dirPath, uncPrefix, RTL_NUMBER_OF( uncPrefix ) - 1 ) == 0 )
  1370. {
  1371. //
  1372. // skip to end of "\\?\UNC\server\share\xxx\"
  1373. //
  1374. slashSkipCount = 7;
  1375. }
  1376. else
  1377. {
  1378. //
  1379. // it's a expanded storage path. skip to end of \\?\c:\xxx\
  1380. //
  1381. slashSkipCount = 5;
  1382. }
  1383. }
  1384. else
  1385. {
  1386. //
  1387. // it looks like an SMB path; skip to end of \\server\share\xxx\
  1388. //
  1389. slashSkipCount = 5;
  1390. }
  1391. }
  1392. else
  1393. {
  1394. //
  1395. // it should be a normal file path but it could relative or fully
  1396. // qualified, with or without a drive letter. All that really matters
  1397. // is whether there is a slash before the first dir spec. If there is,
  1398. // then skip to the 2nd slash otherwise skip to the first slash.
  1399. //
  1400. if ( dirPath[0] == backSlash || dirPath[0] == fwdSlash )
  1401. {
  1402. //
  1403. // skip to end of \xxx\
  1404. //
  1405. slashSkipCount = 2;
  1406. }
  1407. else if ( dwLen > 1 && dirPath[1] == L':' )
  1408. {
  1409. //
  1410. // might be fully qualified path; check for slash in slot 2
  1411. //
  1412. if ( dwLen > 2 && ( dirPath[2] == L'\\' || dirPath[2] == L'/' )) {
  1413. //
  1414. // skip to end of c:\xxx\
  1415. //
  1416. slashSkipCount = 2;
  1417. } else {
  1418. //
  1419. // skip to the end of c:xxx\
  1420. //
  1421. slashSkipCount = 1;
  1422. }
  1423. }
  1424. else
  1425. {
  1426. //
  1427. // no colon in slot 1 so must be a relative path with no drive
  1428. // letter
  1429. //
  1430. slashSkipCount = 1;
  1431. }
  1432. }
  1433. //
  1434. // get pszNext to point to the appropriate slash; this allows for mixed
  1435. // fwd and bwd slashes which is pretty sick but...
  1436. //
  1437. if ( slashSkipCount > 0 )
  1438. {
  1439. pszNext = dirPath;
  1440. while ( *pszNext != UNICODE_NULL ) {
  1441. if ( *pszNext == backSlash || *pszNext == fwdSlash ) {
  1442. charsAfterSlash = FALSE;
  1443. if ( --slashSkipCount == 0 ) {
  1444. break;
  1445. }
  1446. } else {
  1447. charsAfterSlash = TRUE;
  1448. }
  1449. ++pszNext;
  1450. }
  1451. } else {
  1452. return ERROR_INVALID_PARAMETER;
  1453. }
  1454. //
  1455. // check that we found all the slashes. If we're missing one slash but
  1456. // we're sitting at the end of the string, then that is the same as
  1457. // finding a slash
  1458. //
  1459. if ( !( slashSkipCount == 0 || ( charsAfterSlash && slashSkipCount == 1 ))) {
  1460. return ERROR_INVALID_PARAMETER;
  1461. }
  1462. //
  1463. // run down the directory path, inserting a NULL at every slash and call
  1464. // CreateDirectory to create that portion of the path
  1465. //
  1466. while ( pszNext)
  1467. {
  1468. DWORD_PTR dwptrLen;
  1469. WCHAR oldSlash;
  1470. dwptrLen = pszNext - dirPath;
  1471. dwLen = (DWORD)dwptrLen;
  1472. oldSlash = dirPath[ dwLen ];
  1473. dirPath[ dwLen ] = UNICODE_NULL;
  1474. if (!CreateDirectory(dirPath, NULL))
  1475. {
  1476. dwError = GetLastError();
  1477. if (dwError == ERROR_ALREADY_EXISTS)
  1478. {
  1479. DWORD fileAttrs;
  1480. //
  1481. // make sure it is a directory
  1482. //
  1483. fileAttrs = GetFileAttributes( dirPath );
  1484. if ( fileAttrs != INVALID_FILE_ATTRIBUTES )
  1485. {
  1486. if ( fileAttrs & FILE_ATTRIBUTE_DIRECTORY )
  1487. {
  1488. dwError = ERROR_SUCCESS;
  1489. }
  1490. else
  1491. {
  1492. dwError = ERROR_FILE_EXISTS;
  1493. }
  1494. }
  1495. else
  1496. {
  1497. dwError = ERROR_FILE_EXISTS;
  1498. }
  1499. }
  1500. if ( dwError != ERROR_SUCCESS )
  1501. {
  1502. ClRtlDbgPrint(LOG_CRITICAL,
  1503. "[ClRtl] CreateDirectory Failed on %1!ws!. Error %2!u!\n",
  1504. dirPath, dwError);
  1505. }
  1506. }
  1507. dirPath[ dwLen ] = oldSlash;
  1508. //
  1509. // bail out if we hit an error or we're at the end of the input string
  1510. //
  1511. if ( dwError != ERROR_SUCCESS || *pszNext == UNICODE_NULL ) {
  1512. break;
  1513. }
  1514. p = pszNext + 1;
  1515. while ( *p != backSlash && *p != fwdSlash && *p != UNICODE_NULL )
  1516. ++p;
  1517. pszNext = p;
  1518. }
  1519. return(dwError);
  1520. }
  1521. BOOL
  1522. WINAPI
  1523. ClRtlIsPathValid(
  1524. LPCWSTR Path
  1525. )
  1526. /*++
  1527. Routine Description:
  1528. Returns true if the given path looks syntactically valid.
  1529. This call is NOT network-aware.
  1530. Arguments:
  1531. Path - String containing a path.
  1532. Return Value:
  1533. TRUE if the path looks valid, otherwise FALSE.
  1534. --*/
  1535. {
  1536. WCHAR chPrev;
  1537. WCHAR chCur;
  1538. DWORD charCount = 0;
  1539. #ifdef DBCS
  1540. BOOL fPrevLead = FALSE;
  1541. #endif
  1542. CL_ASSERT(Path);
  1543. CL_ASSERT(!*Path || !iswspace(*Path)); // no leading whitespace
  1544. if ( iswalpha(*Path) && *(Path+1) == L':' ) {
  1545. Path += 2;
  1546. }
  1547. chCur = *Path;
  1548. chPrev = 0;
  1549. while (chCur) {
  1550. charCount++;
  1551. if ( charCount > MAX_PATH ) {
  1552. return(FALSE);
  1553. }
  1554. #ifdef DBCS
  1555. if (fPrevLead) {
  1556. fPrevLead = FALSE;
  1557. chPrev = 0;
  1558. } else {
  1559. fPrevLead = IsDBCSLeadByte(chCur);
  1560. #endif // DBCS
  1561. switch ( chCur ) {
  1562. // Explicit invalid characters
  1563. case L'*' :
  1564. case L';' :
  1565. case L',' :
  1566. case L'=' :
  1567. case L'?' :
  1568. case L'<' :
  1569. case L'>' :
  1570. case L'|' :
  1571. case L':' : // no ":" except as second char
  1572. return(FALSE); // no ":" allowed other than second char */
  1573. #if 0 // The following should be okay
  1574. case L'\\' :
  1575. if ( chPrev == chDirSep ) {
  1576. return(FALSE); // no double "\\" in middle - but legal
  1577. }
  1578. break;
  1579. #endif
  1580. default:
  1581. #if 0 // accept anything else for now
  1582. if ( !iswalnum( chCur ) ) {
  1583. return(FALSE);
  1584. }
  1585. #endif
  1586. break;
  1587. }
  1588. chPrev = chCur;
  1589. #ifdef DBCS
  1590. }
  1591. #endif
  1592. chCur = *(++Path);
  1593. }
  1594. #ifdef DBCS
  1595. if (fPrevLead)
  1596. return(FALSE); // ends w/ lead byte
  1597. #endif
  1598. return(TRUE);
  1599. } // ClRtlIsPathValid
  1600. /****
  1601. @func DWORD | ClRtlGetClusterDirectory | Get the directory in which
  1602. the cluster service is installed
  1603. @parm IN LPWSTR | lpBuffer | Supplies the buffer in which the
  1604. directory path is to be copied.
  1605. @parm IN DWORD | dwBufSize | Supplies the size of the buffer.
  1606. @rdesc Returns a Win32 error code if the operation is
  1607. unsuccessful. ERROR_SUCCESS on success.
  1608. ****/
  1609. DWORD
  1610. ClRtlGetClusterDirectory(
  1611. IN LPWSTR lpBuffer,
  1612. IN DWORD dwBufSize
  1613. )
  1614. {
  1615. DWORD dwLen;
  1616. DWORD dwStatus;
  1617. LPWSTR szRegKeyName = NULL;
  1618. HKEY hClusSvcKey = NULL;
  1619. LPWSTR lpImagePath = NULL;
  1620. WCHAR *pTemp = NULL;
  1621. //
  1622. // Chittur Subbaraman (chitturs) - 10/29/98
  1623. //
  1624. if ( lpBuffer == NULL )
  1625. {
  1626. dwStatus = ERROR_INVALID_PARAMETER;
  1627. goto FnExit;
  1628. }
  1629. //
  1630. // Open key to SYSTEM\CurrentControlSet\Services\ClusSvc
  1631. //
  1632. dwLen = lstrlenW( CLUSREG_KEYNAME_CLUSSVC_PARAMETERS );
  1633. szRegKeyName = (LPWSTR) LocalAlloc ( LMEM_FIXED,
  1634. ( dwLen + 1 ) *
  1635. sizeof ( WCHAR ) );
  1636. if ( szRegKeyName == NULL )
  1637. {
  1638. dwStatus = GetLastError();
  1639. goto FnExit;
  1640. }
  1641. dwLen -= lstrlenW( CLUSREG_KEYNAME_PARAMETERS );
  1642. lstrcpyW( szRegKeyName, CLUSREG_KEYNAME_CLUSSVC_PARAMETERS );
  1643. szRegKeyName [dwLen-1] = L'\0';
  1644. if ( ( dwStatus = RegOpenKeyW( HKEY_LOCAL_MACHINE,
  1645. szRegKeyName,
  1646. &hClusSvcKey ) ) != ERROR_SUCCESS )
  1647. {
  1648. goto FnExit;
  1649. }
  1650. lstrcpyW ( szRegKeyName, L"ImagePath" );
  1651. //
  1652. // Try to query the clussvc key. If the ImagePath
  1653. // value is present, then get the length of the image
  1654. // path
  1655. //
  1656. dwLen = 0;
  1657. if ( ( dwStatus = ClRtlRegQueryString( hClusSvcKey,
  1658. szRegKeyName,
  1659. REG_EXPAND_SZ,
  1660. &lpImagePath,
  1661. &dwLen,
  1662. &dwLen ) ) != ERROR_SUCCESS )
  1663. {
  1664. goto FnExit;
  1665. }
  1666. //
  1667. // Now expand any environment strings present in the
  1668. // ImagePath
  1669. //
  1670. if ( ( dwLen = ExpandEnvironmentStringsW( lpImagePath,
  1671. lpBuffer,
  1672. dwBufSize ) ) == 0 )
  1673. {
  1674. dwStatus = GetLastError();
  1675. goto FnExit;
  1676. }
  1677. //
  1678. // If the caller-supplied buffer is not big enough to hold the
  1679. // path value, then return an error
  1680. //
  1681. if ( dwLen > dwBufSize )
  1682. {
  1683. dwStatus = ERROR_INVALID_PARAMETER;
  1684. goto FnExit;
  1685. }
  1686. //
  1687. // Replace the last '\\' character in the image path with
  1688. // a NULL character
  1689. //
  1690. pTemp = wcsrchr( lpBuffer, L'\\' );
  1691. if ( pTemp != NULL )
  1692. {
  1693. *pTemp = L'\0';
  1694. } else
  1695. {
  1696. dwStatus = ERROR_INVALID_PARAMETER;
  1697. goto FnExit;
  1698. }
  1699. FnExit:
  1700. LocalFree( szRegKeyName );
  1701. if( hClusSvcKey != NULL )
  1702. {
  1703. RegCloseKey( hClusSvcKey );
  1704. }
  1705. LocalFree( lpImagePath );
  1706. return( dwStatus );
  1707. } // ClRtlGetClusterDirectory
  1708. BOOL
  1709. ClRtlGetDriveLayoutTable(
  1710. IN HANDLE hDisk,
  1711. OUT PDRIVE_LAYOUT_INFORMATION * DriveLayout,
  1712. OUT PDWORD InfoSize OPTIONAL
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. Get the partition table for a drive. If the buffer is not large enough,
  1717. then realloc until we get the right sized buffer. This routine is not in
  1718. disk.cpp since that causes additional symbols to be defined.
  1719. Arguments:
  1720. hDisk - handle to a file on the partition
  1721. DriveLayout - address of pointer that points to
  1722. InfoSize - address of dword that receives size of partition table
  1723. Return Value:
  1724. TRUE if everything went ok
  1725. --*/
  1726. {
  1727. DWORD dwSize = 0;
  1728. PDRIVE_LAYOUT_INFORMATION driveLayout = NULL;
  1729. DWORD status = ERROR_INSUFFICIENT_BUFFER;
  1730. DWORD partitionCount = 4;
  1731. DWORD layoutSize;
  1732. while ( status == ERROR_INSUFFICIENT_BUFFER
  1733. || status == ERROR_BAD_LENGTH
  1734. )
  1735. {
  1736. layoutSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
  1737. (sizeof(PARTITION_INFORMATION) * partitionCount);
  1738. if ( layoutSize > 2<<16 ) {
  1739. break;
  1740. }
  1741. driveLayout = (PDRIVE_LAYOUT_INFORMATION)LocalAlloc( LMEM_FIXED, layoutSize );
  1742. if ( driveLayout == NULL ) {
  1743. break;
  1744. }
  1745. if (DeviceIoControl(hDisk,
  1746. IOCTL_DISK_GET_DRIVE_LAYOUT,
  1747. NULL,
  1748. 0,
  1749. driveLayout,
  1750. layoutSize,
  1751. &dwSize,
  1752. NULL))
  1753. {
  1754. status = ERROR_SUCCESS;
  1755. break;
  1756. } else {
  1757. status = GetLastError();
  1758. LocalFree( driveLayout );
  1759. driveLayout = NULL;
  1760. partitionCount *= 2;
  1761. }
  1762. }
  1763. *DriveLayout = driveLayout;
  1764. if ( ARGUMENT_PRESENT( InfoSize )) {
  1765. *InfoSize = dwSize;
  1766. }
  1767. return status == ERROR_SUCCESS ? TRUE : FALSE;
  1768. } // ClRtlGetDriveLayoutTable
  1769. BOOL
  1770. ClRtlPathFileExists(
  1771. LPWSTR pwszPath
  1772. )
  1773. /*++
  1774. Routine Description:
  1775. Determines if a file/directory exists. This is fast.
  1776. Arguments:
  1777. pwszPath - Path to validate.
  1778. Return Value:
  1779. TRUE if it exists, otherwise FALSE.
  1780. NOTE: This was borrowed from SHLWAPI.
  1781. --*/
  1782. {
  1783. DWORD dwErrMode;
  1784. BOOL fResult;
  1785. dwErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
  1786. fResult = ( (UINT) GetFileAttributes( pwszPath ) != (UINT) -1 );
  1787. SetErrorMode( dwErrMode );
  1788. return fResult;
  1789. }
  1790. DWORD
  1791. SetClusterFailureInformation(
  1792. LPWSTR NodeName OPTIONAL,
  1793. DWORD ResetPeriod,
  1794. LONG RetryCount,
  1795. DWORD RetryInterval
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. Set the SC failure parameters for the cluster service.
  1800. Arguments:
  1801. The args are loosely similar to the members of the SERVICE_FAILURE_ACTIONS
  1802. structure. If RetryCount equals -1, then we set up a series of actions
  1803. where the SC will exponentially back off restarting the service until it
  1804. reaches 5 minutes, where it will continue to retry forever (well, until
  1805. something good or bad happens). Otherwise, if RetryCount is positive, then
  1806. we'll retry that many times (and zero is a valid number of retries) still
  1807. using the same back off technique.
  1808. Return Value:
  1809. ERROR_SUCCESS if everything worked ok
  1810. --*/
  1811. {
  1812. DWORD status;
  1813. BOOL success;
  1814. HANDLE schSCManager;
  1815. HANDLE serviceHandle;
  1816. SERVICE_FAILURE_ACTIONS failureData;
  1817. LPSC_ACTION failureActions;
  1818. LONG i;
  1819. BOOL tryForever = FALSE;
  1820. CL_ASSERT( RetryCount >= -1 && RetryCount <= CLUSTER_FAILURE_MAX_STARTUP_RETRIES );
  1821. ++RetryCount; // add one more for the final action
  1822. if ( RetryCount == 0 ) {
  1823. DWORD tempInterval = RetryInterval;
  1824. //
  1825. // count the entries we need to go from our initial retry interval to
  1826. // the final (longest) retry interval.
  1827. //
  1828. while ( tempInterval < CLUSTER_FAILURE_FINAL_RETRY_INTERVAL ) {
  1829. tempInterval *= 2;
  1830. ++RetryCount;
  1831. }
  1832. ++RetryCount;
  1833. tryForever = TRUE;
  1834. }
  1835. CL_ASSERT( RetryCount > 0 );
  1836. //
  1837. // open the SC mgr and the service
  1838. //
  1839. schSCManager = OpenSCManager(NodeName,
  1840. NULL, // database (NULL == default)
  1841. SC_MANAGER_ALL_ACCESS); // access required
  1842. if ( schSCManager ) {
  1843. serviceHandle = OpenService(schSCManager,
  1844. CLUSTER_SERVICE_NAME,
  1845. SERVICE_ALL_ACCESS);
  1846. if ( serviceHandle ) {
  1847. failureActions = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  1848. RetryCount * sizeof( SC_ACTION ));
  1849. if ( failureActions != NULL ) {
  1850. //
  1851. // build a list that exponentially backs off but does
  1852. // exactly the number of retries that were specified.
  1853. //
  1854. for ( i = 0; i < RetryCount-1; ++i ) {
  1855. failureActions[i].Type = SC_ACTION_RESTART;
  1856. failureActions[i].Delay = RetryInterval;
  1857. RetryInterval = RetryInterval * 2;
  1858. if ( RetryInterval > CLUSTER_FAILURE_FINAL_RETRY_INTERVAL ) {
  1859. RetryInterval = CLUSTER_FAILURE_FINAL_RETRY_INTERVAL;
  1860. }
  1861. }
  1862. if ( tryForever ) {
  1863. failureActions[i].Type = SC_ACTION_RESTART;
  1864. failureActions[i].Delay = RetryInterval;
  1865. } else {
  1866. failureActions[i].Type = SC_ACTION_NONE;
  1867. failureActions[i].Delay = 0;
  1868. }
  1869. failureData.dwResetPeriod = ResetPeriod;
  1870. failureData.lpRebootMsg = NULL;
  1871. failureData.lpCommand = NULL;
  1872. failureData.cActions = RetryCount;
  1873. failureData.lpsaActions = failureActions;
  1874. success = ChangeServiceConfig2(serviceHandle,
  1875. SERVICE_CONFIG_FAILURE_ACTIONS,
  1876. &failureData);
  1877. LocalFree( failureActions );
  1878. if ( success ) {
  1879. status = ERROR_SUCCESS;
  1880. } else {
  1881. status = GetLastError();
  1882. ClRtlDbgPrint(LOG_CRITICAL,"[ClRtl] Couldn't set SC failure info %1!u!\n", status);
  1883. }
  1884. } else {
  1885. status = ERROR_OUTOFMEMORY;
  1886. ClRtlDbgPrint(LOG_CRITICAL,"[ClRtl] Couldn't allocate memory to set SM Failure actions\n");
  1887. }
  1888. CloseServiceHandle( serviceHandle );
  1889. } else {
  1890. status = GetLastError();
  1891. ClRtlDbgPrint(LOG_CRITICAL,"[ClRtl] Couldn't get SC handle to Cluster Service %1!u!\n", status);
  1892. }
  1893. CloseServiceHandle( schSCManager );
  1894. } else {
  1895. status = GetLastError();
  1896. ClRtlDbgPrint(LOG_CRITICAL,"[ClRtl] Couldn't get a handle to the SC Manager %1!u!\n", status);
  1897. }
  1898. return status;
  1899. } // SetClusterFailureInformation
  1900. DWORD
  1901. ClRtlSetSCMFailureActions(
  1902. LPWSTR NodeName OPTIONAL
  1903. )
  1904. /*++
  1905. Routine Description:
  1906. Set the service controller failure parameters for the cluster service.
  1907. Arguments:
  1908. NodeName - pointer to string that identifies on which node to modify the
  1909. settings. NULL indicates the local node.
  1910. Return Value:
  1911. ERROR_SUCCESS if everything worked ok
  1912. --*/
  1913. {
  1914. DWORD Status;
  1915. //
  1916. // during startup, we start with a short retry period and then
  1917. // exponentially back off. Set the reset period to 30 minutes.
  1918. //
  1919. Status = SetClusterFailureInformation(NodeName,
  1920. 30 * 60,
  1921. CLUSTER_FAILURE_RETRY_COUNT,
  1922. CLUSTER_FAILURE_INITIAL_RETRY_INTERVAL);
  1923. if ( Status != ERROR_SUCCESS ) {
  1924. ClRtlDbgPrint(LOG_CRITICAL,
  1925. "[ClRtl] Couldn't set SC startup failure info %1!u!\n",
  1926. Status);
  1927. }
  1928. return Status;
  1929. } // ClRtlSetSCMFailureActions
  1930. DWORD
  1931. ClRtlGetRunningAccountInfo(
  1932. LPWSTR * AccountBuffer
  1933. )
  1934. /*++
  1935. Routine Description:
  1936. Get the calling thread's token to obtain account info. It is returned in
  1937. an allocated buffer in the form of "domain\user". Caller is responsible
  1938. for freeing the buffer.
  1939. Arguments:
  1940. AccountBuffer - address of pointer to receive allocated buffer
  1941. Return Value:
  1942. ERROR_SUCCESS if everything worked ok
  1943. --*/
  1944. {
  1945. HANDLE currentToken;
  1946. PTOKEN_USER tokenUserData;
  1947. DWORD sizeRequired;
  1948. BOOL success;
  1949. DWORD status = ERROR_SUCCESS;
  1950. DWORD accountNameSize = 128;
  1951. LPWSTR accountName;
  1952. DWORD domainNameSize = DNS_MAX_NAME_BUFFER_LENGTH;
  1953. LPWSTR domainName;
  1954. SID_NAME_USE sidType;
  1955. DWORD nameSize = 0;
  1956. HMODULE secur32Handle;
  1957. FARPROC getUserNameEx;
  1958. INT_PTR returnValue;
  1959. //
  1960. // initialize in case the caller doesn't check the return status (tsk, tsk!)
  1961. //
  1962. *AccountBuffer = NULL;
  1963. //
  1964. // rather than link in yet another DLL, we'll load secur32 dynamically and
  1965. // get a pointer to GetUserNameEx.
  1966. //
  1967. secur32Handle = LoadLibraryW( L"secur32.dll" );
  1968. if ( secur32Handle ) {
  1969. getUserNameEx = GetProcAddress( secur32Handle, "GetUserNameExW" );
  1970. if ( getUserNameEx ) {
  1971. //
  1972. // get the length the first time, allocate a buffer and then get the data
  1973. //
  1974. returnValue = (*getUserNameEx)( NameSamCompatible, NULL, &nameSize );
  1975. success = (BOOL)returnValue;
  1976. *AccountBuffer = LocalAlloc( LMEM_FIXED, nameSize * sizeof( WCHAR ));
  1977. if ( *AccountBuffer != NULL ) {
  1978. returnValue = (*getUserNameEx)( NameSamCompatible, *AccountBuffer, &nameSize );
  1979. success = (BOOL)returnValue;
  1980. if ( !success ) {
  1981. status = GetLastError();
  1982. }
  1983. }
  1984. else {
  1985. status = GetLastError();
  1986. }
  1987. } else {
  1988. status = GetLastError();
  1989. }
  1990. FreeLibrary( secur32Handle );
  1991. }
  1992. else {
  1993. status = GetLastError();
  1994. }
  1995. return status;
  1996. #if 0
  1997. //
  1998. // check if there is a thread token
  1999. //
  2000. if (!OpenThreadToken(GetCurrentThread(),
  2001. MAXIMUM_ALLOWED,
  2002. TRUE,
  2003. &currentToken))
  2004. {
  2005. // get the process token
  2006. if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &currentToken )) {
  2007. return GetLastError();
  2008. }
  2009. }
  2010. //
  2011. // get the size needed
  2012. //
  2013. success = GetTokenInformation(currentToken,
  2014. TokenUser,
  2015. NULL,
  2016. 0,
  2017. &sizeRequired);
  2018. tokenUserData = LocalAlloc( LMEM_FIXED, sizeRequired );
  2019. if ( tokenUserData == NULL ) {
  2020. CloseHandle( currentToken );
  2021. return GetLastError();
  2022. }
  2023. success = GetTokenInformation(currentToken,
  2024. TokenUser,
  2025. tokenUserData,
  2026. sizeRequired,
  2027. &sizeRequired);
  2028. if ( !success ) {
  2029. CloseHandle( currentToken );
  2030. return GetLastError();
  2031. }
  2032. do {
  2033. //
  2034. // make initial allocs for account and domain name; 1 more byte to
  2035. // hold slash separator. domain buffer holds the complete
  2036. // 'domain\user' entry so it gets more space
  2037. //
  2038. domainName = LocalAlloc( LMEM_FIXED,
  2039. (accountNameSize + domainNameSize + 1) * sizeof(WCHAR) );
  2040. accountName = (LPWSTR) LocalAlloc( LMEM_FIXED, accountNameSize * sizeof(WCHAR) );
  2041. if ( accountName == NULL || domainName == NULL ) {
  2042. if ( accountName != NULL ) {
  2043. LocalFree( accountName );
  2044. }
  2045. if ( domainName != NULL ) {
  2046. LocalFree( domainName );
  2047. }
  2048. return ERROR_NOT_ENOUGH_MEMORY;
  2049. }
  2050. //
  2051. // Attempt to Retrieve the account and domain name. If
  2052. // LookupAccountName fails because of insufficient buffer size(s)
  2053. // accountNameSize and domainNameSize will be correctly set for the
  2054. // next attempt.
  2055. //
  2056. if ( LookupAccountSid(NULL,
  2057. tokenUserData->User.Sid,
  2058. accountName,
  2059. &accountNameSize,
  2060. domainName,
  2061. &domainNameSize,
  2062. &sidType ))
  2063. {
  2064. wcscat( domainName, L"\\" );
  2065. wcscat( domainName, accountName );
  2066. *AccountBuffer = domainName;
  2067. }
  2068. else {
  2069. // free the account name buffer and find out why we failed
  2070. LocalFree( domainName );
  2071. status = GetLastError();
  2072. }
  2073. //
  2074. // domain buffer holds complete string so we can lose the account name
  2075. // at this point
  2076. //
  2077. LocalFree( accountName );
  2078. accountName = NULL;
  2079. } while ( status == ERROR_INSUFFICIENT_BUFFER );
  2080. return status;
  2081. #endif
  2082. } // ClRtlGetRunningAccountInfo
  2083. #if 0
  2084. //
  2085. // no longer needed. Keep it around just in case
  2086. //
  2087. DWORD
  2088. ClRtlGetServiceAccountInfo(
  2089. LPWSTR * AccountBuffer
  2090. )
  2091. /*++
  2092. Routine Description:
  2093. Query SCM for the cluster service account info. It is returned in an
  2094. allocated buffer in the form of "domain\user". Caller is responsible for
  2095. freeing the buffer.
  2096. Arguments:
  2097. AccountBuffer - address of pointer to receive allocated buffer
  2098. Return Value:
  2099. ERROR_SUCCESS if everything worked ok
  2100. --*/
  2101. {
  2102. DWORD status = ERROR_SUCCESS;
  2103. HANDLE schSCManager;
  2104. HANDLE serviceHandle = NULL;
  2105. LPQUERY_SERVICE_CONFIG scConfigData = NULL;
  2106. ULONG bytesNeeded;
  2107. BOOL success;
  2108. //
  2109. // open a handle to the service controller manager to query the account
  2110. // under which the cluster service was started
  2111. //
  2112. schSCManager = OpenSCManager(NULL, // machine (NULL == local)
  2113. NULL, // database (NULL == default)
  2114. SC_MANAGER_ALL_ACCESS); // access required
  2115. if ( schSCManager == NULL ) {
  2116. status = GetLastError();
  2117. goto error_exit;
  2118. }
  2119. serviceHandle = OpenService(schSCManager,
  2120. CLUSTER_SERVICE_NAME,
  2121. SERVICE_ALL_ACCESS);
  2122. if ( serviceHandle == NULL ) {
  2123. status = GetLastError();
  2124. goto error_exit;
  2125. }
  2126. success = QueryServiceConfig(serviceHandle, NULL, 0, &bytesNeeded);
  2127. if ( !success ) {
  2128. status = GetLastError();
  2129. if ( status != ERROR_INSUFFICIENT_BUFFER ) {
  2130. goto error_exit;
  2131. } else {
  2132. status = ERROR_SUCCESS;
  2133. }
  2134. }
  2135. scConfigData = LocalAlloc( LMEM_FIXED, bytesNeeded );
  2136. if ( scConfigData == NULL ) {
  2137. status = GetLastError();
  2138. goto error_exit;
  2139. }
  2140. success = QueryServiceConfig(serviceHandle,
  2141. scConfigData,
  2142. bytesNeeded,
  2143. &bytesNeeded);
  2144. if ( !success ) {
  2145. status = GetLastError();
  2146. goto error_exit;
  2147. }
  2148. *AccountBuffer = LocalAlloc(LMEM_FIXED,
  2149. (wcslen( scConfigData->lpServiceStartName ) + 1 ) * sizeof(WCHAR));
  2150. if ( *AccountBuffer == NULL ) {
  2151. status = GetLastError();
  2152. goto error_exit;
  2153. }
  2154. wcscpy( *AccountBuffer, scConfigData->lpServiceStartName );
  2155. error_exit:
  2156. if ( serviceHandle != NULL ) {
  2157. CloseServiceHandle( serviceHandle );
  2158. }
  2159. if ( schSCManager != NULL ) {
  2160. CloseServiceHandle( schSCManager );
  2161. }
  2162. if ( scConfigData != NULL ) {
  2163. LocalFree( scConfigData );
  2164. }
  2165. return status;
  2166. } // ClRtlGetServiceAccountInfo
  2167. #endif
  2168. BOOL
  2169. ClRtlCopyFileAndFlushBuffers(
  2170. IN LPCWSTR lpszSourceFile,
  2171. IN LPCWSTR lpszDestinationFile
  2172. )
  2173. /*++
  2174. Routine Description:
  2175. Copy a source file to a destination file and flush the destination file buffers.
  2176. Arguments:
  2177. lpszSourceFile - The source file name.
  2178. lpszDestinationFile - The destination file name.
  2179. Return Value:
  2180. TRUE if successful, FALSE otherwise.
  2181. --*/
  2182. {
  2183. HANDLE hFile = INVALID_HANDLE_VALUE;
  2184. DWORD dwStatus = ERROR_SUCCESS;
  2185. //
  2186. // Copy the file, block until completed. Note that CopyFile family of APIs do not flush the metadata or
  2187. // the data. So, we need to do that explicitly here.
  2188. //
  2189. if ( !CopyFileEx( lpszSourceFile, // Source file
  2190. lpszDestinationFile, // Destination file
  2191. NULL, // Progress routine
  2192. NULL, // Callback parameter
  2193. NULL, // Cancel status
  2194. 0 ) ) // Copy flags
  2195. {
  2196. dwStatus = GetLastError();
  2197. ClRtlLogPrint(LOG_CRITICAL,
  2198. "[CLRTL] ClRtlCopyFileAndFlushBuffers:: Failed to copy %1!ws! to %2!ws!, Status=%3!u!\n",
  2199. lpszSourceFile,
  2200. lpszDestinationFile,
  2201. dwStatus);
  2202. goto FnExit;
  2203. }
  2204. //
  2205. // Open the newly created destination file
  2206. //
  2207. hFile = CreateFile( lpszDestinationFile, // File name
  2208. GENERIC_READ | GENERIC_WRITE, // Access mode
  2209. 0, // Share mode
  2210. NULL, // Security attribs
  2211. OPEN_EXISTING, // Creation disposition
  2212. FILE_ATTRIBUTE_NORMAL, // Flags and attributes
  2213. NULL ); // Template file
  2214. if ( hFile == INVALID_HANDLE_VALUE )
  2215. {
  2216. dwStatus = GetLastError();
  2217. ClRtlLogPrint(LOG_CRITICAL,
  2218. "[CLRTL] ClRtlCopyFileAndFlushBuffers: Failed to open file %1!ws!, Status=%2!u!...\n",
  2219. lpszDestinationFile,
  2220. dwStatus);
  2221. goto FnExit;
  2222. }
  2223. //
  2224. // Flush the file buffers to avoid corrupting the file on a power failure.
  2225. //
  2226. if ( !FlushFileBuffers( hFile ) )
  2227. {
  2228. dwStatus = GetLastError();
  2229. ClRtlLogPrint(LOG_CRITICAL,
  2230. "[CLRTL] ClRtlCopyFileAndFlushBuffers: Failed to flush buffers for %1!ws!, Status=%2!u!...\n",
  2231. lpszDestinationFile,
  2232. dwStatus);
  2233. goto FnExit;
  2234. }
  2235. FnExit:
  2236. if ( hFile != INVALID_HANDLE_VALUE )
  2237. {
  2238. CloseHandle ( hFile );
  2239. }
  2240. if ( dwStatus != ERROR_SUCCESS )
  2241. {
  2242. SetLastError( dwStatus );
  2243. return ( FALSE );
  2244. } else
  2245. {
  2246. return ( TRUE );
  2247. }
  2248. }// ClRtlCopyFileAndFlushBuffers