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.

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