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.

1842 lines
49 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. LkQuorum.c
  5. Abstract:
  6. Resource DLL for Local Quorum
  7. Author:
  8. Sivaprasad Padisetty (sivapad) April 21, 1997
  9. Revision History:
  10. --*/
  11. #define UNICODE 1
  12. #include "clusres.h"
  13. #include "clusrtl.h"
  14. //
  15. // Type and constant definitions.
  16. //
  17. #define MAX_RETRIES 20
  18. #define DBG_PRINT printf
  19. // ADDPARAM: Add new parameters here.
  20. #define PARAM_NAME__PATH L"Path"
  21. #define PARAM_NAME__DEBUG L"Debug"
  22. // ADDPARAM: Add new parameters here.
  23. typedef struct _LKQUORUM_PARAMS {
  24. PWSTR Path;
  25. DWORD Debug;
  26. } LKQUORUM_PARAMS, *PLKQUORUM_PARAMS;
  27. typedef struct _LKQUORUM_RESOURCE {
  28. RESID ResId; // for validation
  29. LKQUORUM_PARAMS Params;
  30. HKEY ParametersKey;
  31. RESOURCE_HANDLE ResourceHandle;
  32. CLUSTER_RESOURCE_STATE State;
  33. } LKQUORUM_RESOURCE, *PLKQUORUM_RESOURCE;
  34. //
  35. // Global data.
  36. //
  37. WCHAR LkQuorumDefaultPath[MAX_PATH]=L"%SystemRoot%\\cluster";
  38. //
  39. // Local Quorum resource read-write private properties.
  40. //
  41. RESUTIL_PROPERTY_ITEM
  42. LkQuorumResourcePrivateProperties[] = {
  43. { PARAM_NAME__PATH, NULL, CLUSPROP_FORMAT_SZ,
  44. (DWORD_PTR) LkQuorumDefaultPath, 0, 0, 0,
  45. FIELD_OFFSET(LKQUORUM_PARAMS,Path) },
  46. { PARAM_NAME__DEBUG, NULL, CLUSPROP_FORMAT_DWORD,
  47. 0, 0, 1, 0,
  48. FIELD_OFFSET(LKQUORUM_PARAMS,Debug) },
  49. { 0 }
  50. };
  51. #ifdef OLD
  52. // Event Logging routine.
  53. PLOG_EVENT_ROUTINE g_LogEvent = NULL;
  54. // Resource Status routine for pending Online and Offline calls.
  55. PSET_RESOURCE_STATUS_ROUTINE g_SetResourceStatus = NULL;
  56. #else
  57. #define g_LogEvent ClusResLogEvent
  58. #endif
  59. // Forward reference to our RESAPI function table.
  60. extern CLRES_FUNCTION_TABLE g_LkQuorumFunctionTable;
  61. //
  62. // Function prototypes.
  63. //
  64. DWORD
  65. WINAPI
  66. Startup(
  67. IN LPCWSTR ResourceType,
  68. IN DWORD MinVersionSupported,
  69. IN DWORD MaxVersionSupported,
  70. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  71. IN PLOG_EVENT_ROUTINE LogEvent,
  72. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  73. );
  74. RESID
  75. WINAPI
  76. LkQuorumOpen(
  77. IN LPCWSTR ResourceName,
  78. IN HKEY ResourceKey,
  79. IN RESOURCE_HANDLE ResourceHandle
  80. );
  81. VOID
  82. WINAPI
  83. LkQuorumClose(
  84. IN RESID ResourceId
  85. );
  86. DWORD
  87. WINAPI
  88. LkQuorumOnline(
  89. IN RESID ResourceId,
  90. IN OUT PHANDLE EventHandle
  91. );
  92. DWORD
  93. WINAPI
  94. LkQuorumOffline(
  95. IN RESID ResourceId
  96. );
  97. VOID
  98. WINAPI
  99. LkQuorumTerminate(
  100. IN RESID ResourceId
  101. );
  102. DWORD
  103. LkQuorumDoTerminate(
  104. IN PLKQUORUM_RESOURCE ResourceEntry
  105. );
  106. BOOL
  107. WINAPI
  108. LkQuorumLooksAlive(
  109. IN RESID ResourceId
  110. );
  111. BOOL
  112. WINAPI
  113. LkQuorumIsAlive(
  114. IN RESID ResourceId
  115. );
  116. BOOL
  117. LkQuorumCheckIsAlive(
  118. IN PLKQUORUM_RESOURCE ResourceEntry
  119. );
  120. DWORD
  121. WINAPI
  122. LkQuorumResourceControl(
  123. IN RESID ResourceId,
  124. IN DWORD ControlCode,
  125. IN PVOID InBuffer,
  126. IN DWORD InBufferSize,
  127. OUT PVOID OutBuffer,
  128. IN DWORD OutBufferSize,
  129. OUT LPDWORD BytesReturned
  130. );
  131. DWORD
  132. LkQuorumGetPrivateResProperties(
  133. IN OUT PLKQUORUM_RESOURCE ResourceEntry,
  134. OUT PVOID OutBuffer,
  135. IN DWORD OutBufferSize,
  136. OUT LPDWORD BytesReturned
  137. );
  138. DWORD
  139. LkQuorumValidatePrivateResProperties(
  140. IN OUT PLKQUORUM_RESOURCE ResourceEntry,
  141. IN PVOID InBuffer,
  142. IN DWORD InBufferSize,
  143. OUT PLKQUORUM_PARAMS Params
  144. );
  145. DWORD
  146. LkQuorumSetPrivateResProperties(
  147. IN OUT PLKQUORUM_RESOURCE ResourceEntry,
  148. IN PVOID InBuffer,
  149. IN DWORD InBufferSize
  150. );
  151. DWORD
  152. LkQuorumGetDiskInfo(
  153. IN LPWSTR lpszPath,
  154. OUT PVOID *OutBuffer,
  155. IN DWORD OutBufferSize,
  156. OUT LPDWORD BytesReturned
  157. ) ;
  158. BOOLEAN
  159. LkQuorumInit(
  160. VOID
  161. )
  162. {
  163. return(TRUE);
  164. }
  165. BOOLEAN
  166. WINAPI
  167. LkQuorumDllEntryPoint(
  168. IN HINSTANCE DllHandle,
  169. IN DWORD Reason,
  170. IN LPVOID Reserved
  171. )
  172. {
  173. switch( Reason ) {
  174. case DLL_PROCESS_ATTACH:
  175. if ( !LkQuorumInit() ) {
  176. return(FALSE);
  177. }
  178. break;
  179. case DLL_PROCESS_DETACH:
  180. break;
  181. default:
  182. break;
  183. }
  184. return(TRUE);
  185. } // LkQuorumDllEntryPoint
  186. DWORD BreakIntoDebugger (LPCWSTR) ;
  187. #ifdef OLD
  188. DWORD
  189. WINAPI
  190. Startup(
  191. IN LPCWSTR ResourceType,
  192. IN DWORD MinVersionSupported,
  193. IN DWORD MaxVersionSupported,
  194. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  195. IN PLOG_EVENT_ROUTINE LogEvent,
  196. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  197. )
  198. /*++
  199. Routine Description:
  200. Startup the resource DLL. This routine verifies that at least one
  201. currently supported version of the resource DLL is between
  202. MinVersionSupported and MaxVersionSupported. If not, then the resource
  203. DLL should return ERROR_REVISION_MISMATCH.
  204. If more than one version of the resource DLL interface is supported by
  205. the resource DLL, then the highest version (up to MaxVersionSupported)
  206. should be returned as the resource DLL's interface. If the returned
  207. version is not within range, then startup fails.
  208. The ResourceType is passed in so that if the resource DLL supports more
  209. than one ResourceType, it can pass back the correct function table
  210. associated with the ResourceType.
  211. Arguments:
  212. ResourceType - The type of resource requesting a function table.
  213. MinVersionSupported - The minimum resource DLL interface version
  214. supported by the cluster software.
  215. MaxVersionSupported - The maximum resource DLL interface version
  216. supported by the cluster software.
  217. SetResourceStatus - Pointer to a routine that the resource DLL should
  218. call to update the state of a resource after the Online or Offline
  219. routine returns a status of ERROR_IO_PENDING.
  220. LogEvent - Pointer to a routine that handles the reporting of events
  221. from the resource DLL.
  222. FunctionTable - Returns a pointer to the function table defined for the
  223. version of the resource DLL interface returned by the resource DLL.
  224. Return Value:
  225. ERROR_SUCCESS - The operation was successful.
  226. ERROR_MOD_NOT_FOUND - The resource type is unknown by this DLL.
  227. ERROR_REVISION_MISMATCH - The version of the cluster service doesn't
  228. match the versrion of the DLL.
  229. Win32 error code - The operation failed.
  230. --*/
  231. {
  232. if ( (MinVersionSupported > CLRES_VERSION_V1_00) ||
  233. (MaxVersionSupported < CLRES_VERSION_V1_00) ) {
  234. return(ERROR_REVISION_MISMATCH);
  235. }
  236. if ( !g_LogEvent ) {
  237. g_LogEvent = LogEvent;
  238. g_SetResourceStatus = SetResourceStatus;
  239. }
  240. *FunctionTable = &g_LkQuorumFunctionTable;
  241. return(ERROR_SUCCESS);
  242. } // Startup
  243. #endif
  244. RESID
  245. WINAPI
  246. LkQuorumOpen(
  247. IN LPCWSTR ResourceName,
  248. IN HKEY ResourceKey,
  249. IN RESOURCE_HANDLE ResourceHandle
  250. )
  251. /*++
  252. Routine Description:
  253. Open routine for Local Quourm resources.
  254. Open the specified resource (create an instance of the resource).
  255. Allocate all structures necessary to bring the specified resource
  256. online.
  257. Arguments:
  258. ResourceName - Supplies the name of the resource to open.
  259. ResourceKey - Supplies handle to the resource's cluster configuration
  260. database key.
  261. ResourceHandle - A handle that is passed back to the resource monitor
  262. when the SetResourceStatus or LogEvent method is called. See the
  263. description of the SetResourceStatus and LogEvent methods on the
  264. LkQuorumStatup routine. This handle should never be closed or used
  265. for any purpose other than passing it as an argument back to the
  266. Resource Monitor in the SetResourceStatus or LogEvent callback.
  267. Return Value:
  268. RESID of created resource.
  269. NULL on failure.
  270. --*/
  271. {
  272. DWORD status = ERROR_SUCCESS;
  273. DWORD disposition;
  274. RESID resid = 0;
  275. HKEY parametersKey = NULL;
  276. PLKQUORUM_RESOURCE resourceEntry = NULL;
  277. DWORD dwStrLen = 0;
  278. DWORD dwSubStrLen = 0;
  279. LPWSTR lpszNameofPropInError;
  280. //
  281. // Open the Parameters registry key for this resource.
  282. //
  283. status = ClusterRegOpenKey( ResourceKey,
  284. L"Parameters",
  285. KEY_READ,
  286. &parametersKey);
  287. if ( status != ERROR_SUCCESS ) {
  288. (g_LogEvent)(
  289. ResourceHandle,
  290. LOG_ERROR,
  291. L"Unable to open Parameters key. Error: %1!u!.\n",
  292. status );
  293. goto exit;
  294. }
  295. //
  296. // Allocate a resource entry.
  297. //
  298. resourceEntry = (PLKQUORUM_RESOURCE) LocalAlloc( LMEM_FIXED, sizeof(LKQUORUM_RESOURCE) );
  299. if ( resourceEntry == NULL ) {
  300. status = GetLastError();
  301. (g_LogEvent)(
  302. ResourceHandle,
  303. LOG_ERROR,
  304. L"Unable to allocate resource entry structure. Error: %1!u!.\n",
  305. status );
  306. goto exit;
  307. }
  308. //
  309. // Initialize the resource entry..
  310. //
  311. ZeroMemory( resourceEntry, sizeof(LKQUORUM_RESOURCE) );
  312. resourceEntry->ResId = (RESID)resourceEntry; // for validation
  313. resourceEntry->ResourceHandle = ResourceHandle;
  314. resourceEntry->ParametersKey = parametersKey;
  315. resourceEntry->State = ClusterResourceOffline;
  316. //
  317. // Read the resource's properties.
  318. //
  319. status = ResUtilGetPropertiesToParameterBlock( resourceEntry->ParametersKey,
  320. LkQuorumResourcePrivateProperties,
  321. (LPBYTE) &resourceEntry->Params,
  322. TRUE, // CheckForRequiredProperties
  323. &lpszNameofPropInError );
  324. if (status != ERROR_SUCCESS)
  325. {
  326. (g_LogEvent)(
  327. resourceEntry->ResourceHandle,
  328. LOG_ERROR,
  329. L"Unable to read the parameter lock\n");
  330. goto exit;
  331. }
  332. //
  333. // Startup for the resource.
  334. //
  335. resid = (RESID)resourceEntry;
  336. exit:
  337. if ( resid == 0 ) {
  338. if ( parametersKey != NULL ) {
  339. ClusterRegCloseKey( parametersKey );
  340. }
  341. if ( resourceEntry != NULL ) {
  342. LocalFree( resourceEntry );
  343. }
  344. }
  345. SetLastError( status );
  346. return(resid);
  347. } // LkQuorumOpen
  348. VOID
  349. WINAPI
  350. LkQuorumClose(
  351. IN RESID ResourceId
  352. )
  353. /*++
  354. Routine Description:
  355. Close routine for Local Quourm resources.
  356. Close the specified resource and deallocate all structures, etc.,
  357. allocated in the Open call. If the resource is not in the offline state,
  358. then the resource should be taken offline (by calling Terminate) before
  359. the close operation is performed.
  360. Arguments:
  361. ResourceId - Supplies the RESID of the resource to close.
  362. Return Value:
  363. None.
  364. --*/
  365. {
  366. PLKQUORUM_RESOURCE resourceEntry;
  367. resourceEntry = (PLKQUORUM_RESOURCE)ResourceId;
  368. if ( resourceEntry == NULL ) {
  369. DBG_PRINT( "LkQuorum: Close request for a nonexistent resource id 0x%p\n",
  370. ResourceId );
  371. return;
  372. }
  373. if ( resourceEntry->ResId != ResourceId ) {
  374. (g_LogEvent)(
  375. resourceEntry->ResourceHandle,
  376. LOG_ERROR,
  377. L"Close resource sanity check failed! ResourceId = %1!u!.\n",
  378. ResourceId );
  379. return;
  380. }
  381. #ifdef LOG_VERBOSE
  382. (g_LogEvent)(
  383. resourceEntry->ResourceHandle,
  384. LOG_INFORMATION,
  385. L"Close request.\n" );
  386. #endif
  387. //
  388. // Close the Parameters key.
  389. //
  390. if ( resourceEntry->ParametersKey ) {
  391. ClusterRegCloseKey( resourceEntry->ParametersKey );
  392. }
  393. //
  394. // Deallocate the resource entry.
  395. //
  396. // ADDPARAM: Add new parameters here.
  397. LocalFree( resourceEntry->Params.Path );
  398. LocalFree( resourceEntry );
  399. } // LkQuorumClose
  400. DWORD
  401. WINAPI
  402. LkQuorumOnline(
  403. IN RESID ResourceId,
  404. IN OUT PHANDLE EventHandle
  405. )
  406. /*++
  407. Routine Description:
  408. Online routine for Local Quourm resources.
  409. Bring the specified resource online (available for use).
  410. Arguments:
  411. ResourceId - Supplies the resource id for the resource to be brought
  412. online (available for use).
  413. EventHandle - Returns a signalable handle that is signaled when the
  414. resource DLL detects a failure on the resource. This argument is
  415. NULL on input, and the resource DLL returns NULL if asynchronous
  416. notification of failures is not supported, otherwise this must be
  417. the address of a handle that is signaled on resource failures.
  418. Return Value:
  419. ERROR_SUCCESS - The operation was successful, and the resource is now
  420. online.
  421. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  422. Win32 error code - The operation failed.
  423. --*/
  424. {
  425. PLKQUORUM_RESOURCE resourceEntry = NULL;
  426. DWORD status = ERROR_SUCCESS;
  427. LPWSTR lpszNameofPropInError;
  428. resourceEntry = (PLKQUORUM_RESOURCE)ResourceId;
  429. if ( resourceEntry == NULL ) {
  430. DBG_PRINT( "LkQuorum: Online request for a nonexistent resource id 0x%p.\n",
  431. ResourceId );
  432. return(ERROR_RESOURCE_NOT_FOUND);
  433. }
  434. if ( resourceEntry->ResId != ResourceId ) {
  435. (g_LogEvent)(
  436. resourceEntry->ResourceHandle,
  437. LOG_ERROR,
  438. L"Online service sanity check failed! ResourceId = %1!u!.\n",
  439. ResourceId );
  440. return(ERROR_RESOURCE_NOT_FOUND);
  441. }
  442. //
  443. // Read the resource's properties.
  444. //
  445. status = ResUtilGetPropertiesToParameterBlock( resourceEntry->ParametersKey,
  446. LkQuorumResourcePrivateProperties,
  447. (LPBYTE) &resourceEntry->Params,
  448. TRUE, // CheckForRequiredProperties
  449. &lpszNameofPropInError );
  450. if (status != ERROR_SUCCESS)
  451. {
  452. (g_LogEvent)(
  453. resourceEntry->ResourceHandle,
  454. LOG_ERROR,
  455. L"Unable to read the parameter lock\n");
  456. return( status );
  457. }
  458. #ifdef LOG_VERBOSE
  459. (g_LogEvent)(
  460. resourceEntry->ResourceHandle,
  461. LOG_INFORMATION,
  462. L"Online request.\n" );
  463. #endif
  464. resourceEntry->State = ClusterResourceOnline;
  465. return(status);
  466. } // LkQuorumOnline
  467. DWORD
  468. WINAPI
  469. LkQuorumOffline(
  470. IN RESID ResourceId
  471. )
  472. /*++
  473. Routine Description:
  474. Offline routine for Local Quourm resources.
  475. Take the specified resource offline gracefully (unavailable for use).
  476. Wait for any cleanup operations to complete before returning.
  477. Arguments:
  478. ResourceId - Supplies the resource id for the resource to be shutdown
  479. gracefully.
  480. Return Value:
  481. ERROR_SUCCESS - The request completed successfully and the resource is
  482. offline.
  483. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  484. ERROR_IO_PENDING - The request is still pending, a thread has been
  485. activated to process the offline request. The thread that is
  486. processing the offline will periodically report status by calling
  487. the SetResourceStatus callback method, until the resource is placed
  488. into the ClusterResourceOffline state (or the resource monitor decides
  489. to timeout the offline request and Terminate the resource).
  490. Win32 error code - Will cause the resource monitor to log an event and
  491. call the Terminate routine.
  492. --*/
  493. {
  494. PLKQUORUM_RESOURCE resourceEntry;
  495. resourceEntry = (PLKQUORUM_RESOURCE)ResourceId;
  496. if ( resourceEntry == NULL ) {
  497. DBG_PRINT( "LkQuorum: Offline request for a nonexistent resource id 0x%p\n",
  498. ResourceId );
  499. return(ERROR_RESOURCE_NOT_FOUND);
  500. }
  501. if ( resourceEntry->ResId != ResourceId ) {
  502. (g_LogEvent)(
  503. resourceEntry->ResourceHandle,
  504. LOG_ERROR,
  505. L"Offline resource sanity check failed! ResourceId = %1!u!.\n",
  506. ResourceId );
  507. return(ERROR_RESOURCE_NOT_FOUND);
  508. }
  509. #ifdef LOG_VERBOSE
  510. (g_LogEvent)(
  511. resourceEntry->ResourceHandle,
  512. LOG_INFORMATION,
  513. L"Offline request.\n" );
  514. #endif
  515. // TODO: Offline code
  516. // NOTE: Offline should try to shut the resource down gracefully, whereas
  517. // Terminate must shut the resource down immediately. If there are no
  518. // differences between a graceful shut down and an immediate shut down,
  519. // Terminate can be called for Offline, as it is below. However, if there
  520. // are differences, replace the call to Terminate below with your graceful
  521. // shutdown code.
  522. //
  523. // Terminate the resource.
  524. //
  525. LkQuorumDoTerminate( resourceEntry );
  526. return ERROR_SUCCESS ;
  527. } // LkQuorumOffline
  528. VOID
  529. WINAPI
  530. LkQuorumTerminate(
  531. IN RESID ResourceId
  532. )
  533. /*++
  534. Routine Description:
  535. Terminate routine for Local Quourm resources.
  536. Take the specified resource offline immediately (the resource is
  537. unavailable for use).
  538. Arguments:
  539. ResourceId - Supplies the resource id for the resource to be brought
  540. offline.
  541. Return Value:
  542. None.
  543. --*/
  544. {
  545. PLKQUORUM_RESOURCE resourceEntry;
  546. resourceEntry = (PLKQUORUM_RESOURCE)ResourceId;
  547. if ( resourceEntry == NULL ) {
  548. DBG_PRINT( "LkQuorum: Terminate request for a nonexistent resource id 0x%p\n",
  549. ResourceId );
  550. return;
  551. }
  552. if ( resourceEntry->ResId != ResourceId ) {
  553. (g_LogEvent)(
  554. resourceEntry->ResourceHandle,
  555. LOG_ERROR,
  556. L"Terminate resource sanity check failed! ResourceId = %1!u!.\n",
  557. ResourceId );
  558. return;
  559. }
  560. #ifdef LOG_VERBOSE
  561. (g_LogEvent)(
  562. resourceEntry->ResourceHandle,
  563. LOG_INFORMATION,
  564. L"Terminate request.\n" );
  565. #endif
  566. //
  567. // Terminate the resource.
  568. //
  569. LkQuorumDoTerminate( resourceEntry );
  570. } // LkQuorumTerminate
  571. DWORD
  572. LkQuorumDoTerminate(
  573. IN PLKQUORUM_RESOURCE ResourceEntry
  574. )
  575. /*++
  576. Routine Description:
  577. Do the actual Terminate work for Local Quourm resources.
  578. Arguments:
  579. ResourceEntry - Supplies resource entry for resource to be terminated
  580. Return Value:
  581. ERROR_SUCCESS - The request completed successfully and the resource is
  582. offline.
  583. Win32 error code - Will cause the resource monitor to log an event and
  584. call the Terminate routine.
  585. --*/
  586. {
  587. DWORD status = ERROR_SUCCESS;
  588. ResourceEntry->State = ClusterResourceOffline;
  589. return(status);
  590. } // LkQuorumDoTerminate
  591. BOOL
  592. WINAPI
  593. LkQuorumLooksAlive(
  594. IN RESID ResourceId
  595. )
  596. /*++
  597. Routine Description:
  598. LooksAlive routine for Local Quourm resources.
  599. Perform a quick check to determine if the specified resource is probably
  600. online (available for use). This call should not block for more than
  601. 300 ms, preferably less than 50 ms.
  602. Arguments:
  603. ResourceId - Supplies the resource id for the resource to polled.
  604. Return Value:
  605. TRUE - The specified resource is probably online and available for use.
  606. FALSE - The specified resource is not functioning normally.
  607. --*/
  608. {
  609. PLKQUORUM_RESOURCE resourceEntry;
  610. resourceEntry = (PLKQUORUM_RESOURCE)ResourceId;
  611. if ( resourceEntry == NULL ) {
  612. DBG_PRINT("LkQuorum: LooksAlive request for a nonexistent resource id 0x%p\n",
  613. ResourceId );
  614. return(FALSE);
  615. }
  616. if ( resourceEntry->ResId != ResourceId ) {
  617. (g_LogEvent)(
  618. resourceEntry->ResourceHandle,
  619. LOG_ERROR,
  620. L"LooksAlive sanity check failed! ResourceId = %1!u!.\n",
  621. ResourceId );
  622. return(FALSE);
  623. }
  624. #ifdef LOG_VERBOSE
  625. (g_LogEvent)(
  626. resourceEntry->ResourceHandle,
  627. LOG_INFORMATION,
  628. L"LooksAlive request.\n" );
  629. #endif
  630. // TODO: LooksAlive code
  631. // NOTE: LooksAlive should be a quick check to see if the resource is
  632. // available or not, whereas IsAlive should be a thorough check. If
  633. // there are no differences between a quick check and a thorough check,
  634. // IsAlive can be called for LooksAlive, as it is below. However, if there
  635. // are differences, replace the call to IsAlive below with your quick
  636. // check code.
  637. //
  638. // Check to see if the resource is alive.
  639. //
  640. return(LkQuorumCheckIsAlive( resourceEntry ));
  641. } // LkQuorumLooksAlive
  642. BOOL
  643. WINAPI
  644. LkQuorumIsAlive(
  645. IN RESID ResourceId
  646. )
  647. /*++
  648. Routine Description:
  649. IsAlive routine for Local Quourm resources.
  650. Perform a thorough check to determine if the specified resource is online
  651. (available for use). This call should not block for more than 400 ms,
  652. preferably less than 100 ms.
  653. Arguments:
  654. ResourceId - Supplies the resource id for the resource to polled.
  655. Return Value:
  656. TRUE - The specified resource is online and functioning normally.
  657. FALSE - The specified resource is not functioning normally.
  658. --*/
  659. {
  660. PLKQUORUM_RESOURCE resourceEntry;
  661. resourceEntry = (PLKQUORUM_RESOURCE)ResourceId;
  662. if ( resourceEntry == NULL ) {
  663. DBG_PRINT("LkQuorum: IsAlive request for a nonexistent resource id 0x%p\n",
  664. ResourceId );
  665. return(FALSE);
  666. }
  667. if ( resourceEntry->ResId != ResourceId ) {
  668. (g_LogEvent)(
  669. resourceEntry->ResourceHandle,
  670. LOG_ERROR,
  671. L"IsAlive sanity check failed! ResourceId = %1!u!.\n",
  672. ResourceId );
  673. return(FALSE);
  674. }
  675. #ifdef LOG_VERBOSE
  676. (g_LogEvent)(
  677. resourceEntry->ResourceHandle,
  678. LOG_INFORMATION,
  679. L"IsAlive request.\n" );
  680. #endif
  681. //
  682. // Check to see if the resource is alive.
  683. //
  684. return(LkQuorumCheckIsAlive( resourceEntry ));
  685. } // LkQuorumIsAlive
  686. BOOL
  687. LkQuorumCheckIsAlive(
  688. IN PLKQUORUM_RESOURCE ResourceEntry
  689. )
  690. /*++
  691. Routine Description:
  692. Check to see if the resource is alive for Local Quourm resources.
  693. Arguments:
  694. ResourceEntry - Supplies the resource entry for the resource to polled.
  695. Return Value:
  696. TRUE - The specified resource is online and functioning normally.
  697. FALSE - The specified resource is not functioning normally.
  698. --*/
  699. {
  700. return(TRUE);
  701. } // LkQuorumCheckIsAlive
  702. DWORD
  703. WINAPI
  704. LkQuorumResourceControl(
  705. IN RESID ResourceId,
  706. IN DWORD ControlCode,
  707. IN PVOID InBuffer,
  708. IN DWORD InBufferSize,
  709. OUT PVOID OutBuffer,
  710. IN DWORD OutBufferSize,
  711. OUT LPDWORD BytesReturned
  712. )
  713. /*++
  714. Routine Description:
  715. ResourceControl routine for Local Quourm resources.
  716. Perform the control request specified by ControlCode on the specified
  717. resource.
  718. Arguments:
  719. ResourceId - Supplies the resource id for the specific resource.
  720. ControlCode - Supplies the control code that defines the action
  721. to be performed.
  722. InBuffer - Supplies a pointer to a buffer containing input data.
  723. InBufferSize - Supplies the size, in bytes, of the data pointed
  724. to by InBuffer.
  725. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  726. OutBufferSize - Supplies the size, in bytes, of the available space
  727. pointed to by OutBuffer.
  728. BytesReturned - Returns the number of bytes of OutBuffer actually
  729. filled in by the resource. If OutBuffer is too small, BytesReturned
  730. contains the total number of bytes for the operation to succeed.
  731. Return Value:
  732. ERROR_SUCCESS - The function completed successfully.
  733. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  734. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  735. In some cases, this allows the cluster software to perform the work.
  736. Win32 error code - The function failed.
  737. --*/
  738. {
  739. DWORD status;
  740. PLKQUORUM_RESOURCE resourceEntry;
  741. DWORD required;
  742. resourceEntry = (PLKQUORUM_RESOURCE)ResourceId;
  743. if ( resourceEntry == NULL ) {
  744. DBG_PRINT("LkQuorum: ResourceControl request for a nonexistent resource id 0x%p\n",
  745. ResourceId );
  746. return(ERROR_RESOURCE_NOT_FOUND);
  747. }
  748. if ( resourceEntry->ResId != ResourceId ) {
  749. (g_LogEvent)(
  750. resourceEntry->ResourceHandle,
  751. LOG_ERROR,
  752. L"ResourceControl sanity check failed! ResourceId = %1!u!.\n",
  753. ResourceId );
  754. return(ERROR_RESOURCE_NOT_FOUND);
  755. }
  756. switch ( ControlCode ) {
  757. case CLUSCTL_RESOURCE_UNKNOWN:
  758. *BytesReturned = 0;
  759. status = ERROR_SUCCESS;
  760. break;
  761. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTY_FMTS:
  762. status = ResUtilGetPropertyFormats( LkQuorumResourcePrivateProperties,
  763. OutBuffer,
  764. OutBufferSize,
  765. BytesReturned,
  766. &required );
  767. if ( status == ERROR_MORE_DATA ) {
  768. *BytesReturned = required;
  769. }
  770. break;
  771. case CLUSCTL_RESOURCE_GET_CHARACTERISTICS:
  772. *BytesReturned = sizeof(DWORD);
  773. if ( OutBufferSize < sizeof(DWORD) ) {
  774. status = ERROR_MORE_DATA;
  775. } else {
  776. LPDWORD ptrDword = OutBuffer;
  777. *ptrDword = CLUS_CHAR_QUORUM | CLUS_CHAR_LOCAL_QUORUM |
  778. ((resourceEntry->Params.Debug == TRUE) ?
  779. CLUS_CHAR_LOCAL_QUORUM_DEBUG : 0);
  780. status = ERROR_SUCCESS;
  781. }
  782. break;
  783. case CLUSCTL_RESOURCE_GET_CLASS_INFO:
  784. *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO);
  785. if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) {
  786. status = ERROR_MORE_DATA;
  787. } else {
  788. PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer;
  789. ptrResClassInfo->rc = CLUS_RESCLASS_STORAGE;
  790. ptrResClassInfo->SubClass = (DWORD) CLUS_RESSUBCLASS_SHARED;
  791. status = ERROR_SUCCESS;
  792. }
  793. break;
  794. case CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO:
  795. //
  796. // Chittur Subbaraman (chitturs) - 12/23/98
  797. //
  798. // If the local quorum drive letter cannot be found in the
  799. // path parameter, it defaults to "SystemDrive" environment
  800. // variable.
  801. //
  802. status = LkQuorumGetDiskInfo(resourceEntry->Params.Path,
  803. &OutBuffer,
  804. OutBufferSize,
  805. BytesReturned);
  806. // Add the endmark.
  807. if ( OutBufferSize > *BytesReturned ) {
  808. OutBufferSize -= *BytesReturned;
  809. } else {
  810. OutBufferSize = 0;
  811. }
  812. *BytesReturned += sizeof(CLUSPROP_SYNTAX);
  813. if ( OutBufferSize >= sizeof(CLUSPROP_SYNTAX) ) {
  814. PCLUSPROP_SYNTAX ptrSyntax = (PCLUSPROP_SYNTAX) OutBuffer;
  815. ptrSyntax->dw = CLUSPROP_SYNTAX_ENDMARK;
  816. }
  817. break;
  818. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  819. status = ResUtilEnumProperties( LkQuorumResourcePrivateProperties,
  820. OutBuffer,
  821. OutBufferSize,
  822. BytesReturned,
  823. &required );
  824. if ( status == ERROR_MORE_DATA ) {
  825. *BytesReturned = required;
  826. }
  827. break;
  828. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  829. status = LkQuorumGetPrivateResProperties( resourceEntry,
  830. OutBuffer,
  831. OutBufferSize,
  832. BytesReturned );
  833. break;
  834. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  835. status = LkQuorumValidatePrivateResProperties( resourceEntry,
  836. InBuffer,
  837. InBufferSize,
  838. NULL );
  839. break;
  840. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  841. status = LkQuorumSetPrivateResProperties( resourceEntry,
  842. InBuffer,
  843. InBufferSize );
  844. break;
  845. default:
  846. status = ERROR_INVALID_FUNCTION;
  847. break;
  848. }
  849. return(status);
  850. } // LkQuorumResourceControl
  851. DWORD
  852. WINAPI
  853. LkQuorumResourceTypeControl(
  854. IN LPCWSTR ResourceTypeName,
  855. IN DWORD ControlCode,
  856. IN PVOID InBuffer,
  857. IN DWORD InBufferSize,
  858. OUT PVOID OutBuffer,
  859. IN DWORD OutBufferSize,
  860. OUT LPDWORD BytesReturned
  861. )
  862. /*++
  863. Routine Description:
  864. ResourceTypeControl routine for Local Quourm resources.
  865. Perform the control request specified by ControlCode on this resource type.
  866. Arguments:
  867. ResourceTypeName - Supplies the resource type name.
  868. ControlCode - Supplies the control code that defines the action
  869. to be performed.
  870. InBuffer - Supplies a pointer to a buffer containing input data.
  871. InBufferSize - Supplies the size, in bytes, of the data pointed
  872. to by InBuffer.
  873. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  874. OutBufferSize - Supplies the size, in bytes, of the available space
  875. pointed to by OutBuffer.
  876. BytesReturned - Returns the number of bytes of OutBuffer actually
  877. filled in by the resource. If OutBuffer is too small, BytesReturned
  878. contains the total number of bytes for the operation to succeed.
  879. Return Value:
  880. ERROR_SUCCESS - The function completed successfully.
  881. ERROR_RESOURCE_NOT_FOUND - RESID is not valid.
  882. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  883. In some cases, this allows the cluster software to perform the work.
  884. Win32 error code - The function failed.
  885. --*/
  886. {
  887. DWORD status;
  888. DWORD required;
  889. switch ( ControlCode ) {
  890. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  891. *BytesReturned = 0;
  892. status = ERROR_SUCCESS;
  893. break;
  894. case CLUSCTL_RESOURCE_TYPE_GET_PRIVATE_RESOURCE_PROPERTY_FMTS:
  895. status = ResUtilGetPropertyFormats( LkQuorumResourcePrivateProperties,
  896. OutBuffer,
  897. OutBufferSize,
  898. BytesReturned,
  899. &required );
  900. if ( status == ERROR_MORE_DATA ) {
  901. *BytesReturned = required;
  902. }
  903. break;
  904. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  905. status = ResUtilEnumProperties( LkQuorumResourcePrivateProperties,
  906. OutBuffer,
  907. OutBufferSize,
  908. BytesReturned,
  909. &required );
  910. if ( status == ERROR_MORE_DATA ) {
  911. *BytesReturned = required;
  912. }
  913. break;
  914. case CLUSCTL_RESOURCE_TYPE_GET_CHARACTERISTICS:
  915. *BytesReturned = sizeof(DWORD);
  916. if ( OutBufferSize < sizeof(DWORD) ) {
  917. status = ERROR_MORE_DATA;
  918. } else {
  919. LPDWORD ptrDword = OutBuffer;
  920. *ptrDword = CLUS_CHAR_QUORUM | CLUS_CHAR_LOCAL_QUORUM ;
  921. status = ERROR_SUCCESS;
  922. }
  923. break;
  924. case CLUSCTL_RESOURCE_TYPE_GET_CLASS_INFO:
  925. *BytesReturned = sizeof(CLUS_RESOURCE_CLASS_INFO);
  926. if ( OutBufferSize < sizeof(CLUS_RESOURCE_CLASS_INFO) ) {
  927. status = ERROR_MORE_DATA;
  928. } else {
  929. PCLUS_RESOURCE_CLASS_INFO ptrResClassInfo = (PCLUS_RESOURCE_CLASS_INFO) OutBuffer;
  930. ptrResClassInfo->rc = CLUS_RESCLASS_STORAGE;
  931. ptrResClassInfo->SubClass = (DWORD) CLUS_RESSUBCLASS_SHARED;
  932. status = ERROR_SUCCESS;
  933. }
  934. break;
  935. default:
  936. status = ERROR_INVALID_FUNCTION;
  937. break;
  938. }
  939. return(status);
  940. } // LkQuorumResourceTypeControl
  941. DWORD
  942. LkQuorumGetPrivateResProperties(
  943. IN OUT PLKQUORUM_RESOURCE ResourceEntry,
  944. OUT PVOID OutBuffer,
  945. IN DWORD OutBufferSize,
  946. OUT LPDWORD BytesReturned
  947. )
  948. /*++
  949. Routine Description:
  950. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  951. for resources of type Local Quorum.
  952. Arguments:
  953. ResourceEntry - Supplies the resource entry on which to operate.
  954. OutBuffer - Returns the output data.
  955. OutBufferSize - Supplies the size, in bytes, of the data pointed
  956. to by OutBuffer.
  957. BytesReturned - The number of bytes returned in OutBuffer.
  958. Return Value:
  959. ERROR_SUCCESS - The function completed successfully.
  960. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  961. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  962. Win32 error code - The function failed.
  963. --*/
  964. {
  965. DWORD status;
  966. DWORD required;
  967. //
  968. // Get all our properties.
  969. //
  970. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  971. LkQuorumResourcePrivateProperties,
  972. OutBuffer,
  973. OutBufferSize,
  974. BytesReturned,
  975. &required );
  976. if ( status == ERROR_MORE_DATA ) {
  977. *BytesReturned = required;
  978. }
  979. return(status);
  980. } // LkQuorumGetPrivateResProperties
  981. DWORD
  982. LkQuorumValidatePrivateResProperties(
  983. IN OUT PLKQUORUM_RESOURCE ResourceEntry,
  984. IN PVOID InBuffer,
  985. IN DWORD InBufferSize,
  986. OUT PLKQUORUM_PARAMS Params
  987. )
  988. /*++
  989. Routine Description:
  990. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  991. function for resources of type Local Quourm.
  992. Arguments:
  993. ResourceEntry - Supplies the resource entry on which to operate.
  994. InBuffer - Supplies a pointer to a buffer containing input data.
  995. InBufferSize - Supplies the size, in bytes, of the data pointed
  996. to by InBuffer.
  997. Params - Supplies the parameter block to fill in.
  998. Return Value:
  999. ERROR_SUCCESS - The function completed successfully.
  1000. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1001. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1002. Win32 error code - The function failed.
  1003. --*/
  1004. {
  1005. DWORD status;
  1006. LKQUORUM_PARAMS params;
  1007. PLKQUORUM_PARAMS pParams;
  1008. HCLUSTER hCluster = NULL;
  1009. HCLUSENUM hEnum = NULL;
  1010. //
  1011. // Check if there is input data.
  1012. //
  1013. if ( (InBuffer == NULL) ||
  1014. (InBufferSize < sizeof(DWORD)) )
  1015. {
  1016. return(ERROR_INVALID_DATA);
  1017. }
  1018. //
  1019. // Duplicate the resource parameter block.
  1020. //
  1021. if ( Params == NULL )
  1022. {
  1023. pParams = &params;
  1024. } else
  1025. {
  1026. pParams = Params;
  1027. }
  1028. ZeroMemory( pParams, sizeof(LKQUORUM_PARAMS) );
  1029. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1030. (LPBYTE) &ResourceEntry->Params,
  1031. LkQuorumResourcePrivateProperties );
  1032. if ( status != ERROR_SUCCESS )
  1033. {
  1034. return(status);
  1035. }
  1036. //
  1037. // Parse and validate the properties.
  1038. //
  1039. status = ResUtilVerifyPropertyTable( LkQuorumResourcePrivateProperties,
  1040. NULL,
  1041. TRUE, // Accept unknowns
  1042. InBuffer,
  1043. InBufferSize,
  1044. (LPBYTE) pParams );
  1045. if ( status == ERROR_SUCCESS )
  1046. {
  1047. //initialize to the value already set
  1048. DWORD dwTmp = ResourceEntry->Params.Debug;
  1049. //
  1050. // Validate the parameter values.
  1051. //
  1052. // TODO: Code to validate interactions between parameters goes here.
  1053. // see if the Debug value is being set, if so we need to check if
  1054. // the number of nodes in the cluster allows it
  1055. if (ClRtlFindDwordProperty(InBuffer, InBufferSize,PARAM_NAME__DEBUG, &dwTmp) == ERROR_SUCCESS)
  1056. {
  1057. if (dwTmp == FALSE)
  1058. {
  1059. //dont allow the DEBUG parameter to be set to FALSE, if this
  1060. //cluster is multi-node
  1061. DWORD dwNumNodes;
  1062. hCluster = OpenCluster(NULL);
  1063. if (hCluster == NULL)
  1064. {
  1065. status = GetLastError();
  1066. (g_LogEvent)(
  1067. ResourceEntry->ResourceHandle,
  1068. LOG_ERROR,
  1069. L"ValidatePrivateProperties: OpenCluster() failed! status = %1!u!.\n",
  1070. status );
  1071. goto FnExit;
  1072. }
  1073. hEnum = ClusterOpenEnum(hCluster, CLUSTER_ENUM_NODE);
  1074. if (hEnum == NULL)
  1075. {
  1076. status = GetLastError();
  1077. (g_LogEvent)(
  1078. ResourceEntry->ResourceHandle,
  1079. LOG_ERROR,
  1080. L"ValidatePrivateProperties: ClusterOpenEnum() failed! status = %1!u!.\n",
  1081. status );
  1082. goto FnExit;
  1083. }
  1084. dwNumNodes = ClusterGetEnumCount(hEnum);
  1085. if (dwNumNodes > 1)
  1086. {
  1087. //if there are more than one node in the cluster,
  1088. //dont allow the user to set the debug property to FALSE
  1089. status = ERROR_INVALID_PARAMETER;
  1090. goto FnExit;
  1091. }
  1092. status = ClusterCloseEnum(hEnum);
  1093. if (status != ERROR_SUCCESS)
  1094. {
  1095. (g_LogEvent)(
  1096. ResourceEntry->ResourceHandle,
  1097. LOG_ERROR,
  1098. L"ValidatePrivateProperties: ClusterCloseEnum() failed! status = %1!u!.\n",
  1099. status );
  1100. goto FnExit;
  1101. }
  1102. hEnum = NULL;
  1103. }
  1104. }
  1105. }
  1106. FnExit:
  1107. if (hEnum) ClusterCloseEnum(hEnum);
  1108. if (hCluster) CloseCluster(hCluster);
  1109. //
  1110. // Cleanup our parameter block.
  1111. //
  1112. if ( pParams == &params ) {
  1113. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1114. (LPBYTE) &ResourceEntry->Params,
  1115. LkQuorumResourcePrivateProperties );
  1116. }
  1117. return(status);
  1118. } // LkQuorumValidatePrivateResProperties
  1119. DWORD
  1120. LkQuorumSetPrivateResProperties(
  1121. IN OUT PLKQUORUM_RESOURCE ResourceEntry,
  1122. IN PVOID InBuffer,
  1123. IN DWORD InBufferSize
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1128. for resources of type Local Quourm.
  1129. Arguments:
  1130. ResourceEntry - Supplies the resource entry on which to operate.
  1131. InBuffer - Supplies a pointer to a buffer containing input data.
  1132. InBufferSize - Supplies the size, in bytes, of the data pointed
  1133. to by InBuffer.
  1134. Return Value:
  1135. ERROR_SUCCESS - The function completed successfully.
  1136. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1137. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1138. Win32 error code - The function failed.
  1139. --*/
  1140. {
  1141. DWORD status = ERROR_SUCCESS;
  1142. LKQUORUM_PARAMS params;
  1143. ZeroMemory( &params, sizeof(LKQUORUM_PARAMS) );
  1144. //
  1145. // Parse the properties so they can be validated together.
  1146. // This routine does individual property validation.
  1147. //
  1148. status = LkQuorumValidatePrivateResProperties( ResourceEntry,
  1149. InBuffer,
  1150. InBufferSize,
  1151. &params );
  1152. if ( status != ERROR_SUCCESS ) {
  1153. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1154. (LPBYTE) &ResourceEntry->Params,
  1155. LkQuorumResourcePrivateProperties );
  1156. return(status);
  1157. }
  1158. //
  1159. // Save the parameter values.
  1160. //
  1161. status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1162. LkQuorumResourcePrivateProperties,
  1163. NULL,
  1164. (LPBYTE) &params,
  1165. InBuffer,
  1166. InBufferSize,
  1167. (LPBYTE) &ResourceEntry->Params );
  1168. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1169. (LPBYTE) &ResourceEntry->Params,
  1170. LkQuorumResourcePrivateProperties );
  1171. if ( status == ERROR_SUCCESS ) {
  1172. if ( ResourceEntry->State == ClusterResourceOnline ) {
  1173. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1174. } else if ( ResourceEntry->State == ClusterResourceOnlinePending ) {
  1175. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1176. } else {
  1177. status = ERROR_SUCCESS;
  1178. }
  1179. }
  1180. return(status);
  1181. } // LkQuorumSetPrivateResProperties
  1182. DWORD WINAPI LkQuorumArbitrate(
  1183. RESID ResourceId,
  1184. PQUORUM_RESOURCE_LOST LostQuorumResource
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. Perform full arbitration for a disk. Once arbitration has succeeded,
  1189. a thread is started that will keep reservations on the disk, one per second.
  1190. Arguments:
  1191. DiskResource - the disk info structure for the disk.
  1192. Return Value:
  1193. ERROR_SUCCESS if successful.
  1194. A Win32 error code on failure.
  1195. --*/
  1196. {
  1197. DWORD status = ERROR_SUCCESS ;
  1198. return status ;
  1199. }
  1200. DWORD
  1201. WINAPI
  1202. LkQuorumRelease(
  1203. IN RESID Resource
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. Release arbitration for a device by stopping the reservation thread.
  1208. Arguments:
  1209. Resource - supplies resource id to be brought online
  1210. Return Value:
  1211. ERROR_SUCCESS if successful.
  1212. ERROR_HOST_NODE_NOT_OWNER if the resource is not owned.
  1213. A Win32 error code if other failure.
  1214. --*/
  1215. {
  1216. DWORD status = ERROR_SUCCESS ;
  1217. return status ;
  1218. }
  1219. DWORD
  1220. LkQuorumGetDiskInfo(
  1221. IN LPWSTR lpszPath,
  1222. OUT PVOID * OutBuffer,
  1223. IN DWORD OutBufferSize,
  1224. OUT LPDWORD BytesReturned
  1225. )
  1226. /*++
  1227. Routine Description:
  1228. Gets all of the disk information for a given signature.
  1229. Arguments:
  1230. Signature - the signature of the disk to return info.
  1231. OutBuffer - pointer to the output buffer to return the data.
  1232. OutBufferSize - size of the output buffer.
  1233. BytesReturned - the actual number of bytes that were returned (or
  1234. the number of bytes that should have been returned if
  1235. OutBufferSize is too small).
  1236. Return Value:
  1237. ERROR_SUCCESS if successful.
  1238. A Win32 error on failure.
  1239. --*/
  1240. {
  1241. DWORD status;
  1242. DWORD bytesReturned = *BytesReturned;
  1243. PVOID ptrBuffer = *OutBuffer;
  1244. PCLUSPROP_DWORD ptrDword;
  1245. PCLUSPROP_PARTITION_INFO ptrPartitionInfo;
  1246. DWORD letterIndex;
  1247. DWORD letterCount = 1;
  1248. WCHAR driveLetters[1];
  1249. LPWSTR pszExpandedPath = NULL;
  1250. WCHAR chDrive;
  1251. DWORD dwLength;
  1252. // Return the signature - a DWORD
  1253. bytesReturned += sizeof(CLUSPROP_DWORD);
  1254. if ( bytesReturned <= OutBufferSize ) {
  1255. ptrDword = (PCLUSPROP_DWORD)ptrBuffer;
  1256. ptrDword->Syntax.dw = CLUSPROP_SYNTAX_DISK_SIGNATURE;
  1257. ptrDword->cbLength = sizeof(DWORD);
  1258. ptrDword->dw = 777;//return a bogus signature for now
  1259. ptrDword++;
  1260. ptrBuffer = ptrDword;
  1261. }
  1262. status = ERROR_SUCCESS;
  1263. pszExpandedPath = ClRtlExpandEnvironmentStrings(lpszPath);
  1264. if (!pszExpandedPath)
  1265. {
  1266. status = GetLastError();
  1267. goto FnExit;
  1268. }
  1269. //get a drive letter to fake the partition info
  1270. //if the first char is drive letter, use that
  1271. if ((lstrlenW(pszExpandedPath) > 2) && (pszExpandedPath[1] == L':'))
  1272. {
  1273. driveLetters[0] = pszExpandedPath[0];
  1274. }
  1275. else
  1276. {
  1277. WCHAR lpszTmpPath[MAX_PATH];
  1278. DWORD dwStrLen;
  1279. //the path name could not have a drive letter
  1280. //it can point to a share \\xyz\abc
  1281. dwStrLen = GetWindowsDirectoryW( lpszTmpPath,
  1282. MAX_PATH );
  1283. if (!dwStrLen)
  1284. {
  1285. status = GetLastError();
  1286. goto FnExit;
  1287. }
  1288. driveLetters[0] = lpszTmpPath[0];
  1289. }
  1290. for ( letterIndex = 0 ; letterIndex < letterCount ; letterIndex++ ) {
  1291. bytesReturned += sizeof(CLUSPROP_PARTITION_INFO);
  1292. if ( bytesReturned <= OutBufferSize ) {
  1293. ptrPartitionInfo = (PCLUSPROP_PARTITION_INFO) ptrBuffer;
  1294. ZeroMemory( ptrPartitionInfo, sizeof(CLUSPROP_PARTITION_INFO) );
  1295. ptrPartitionInfo->Syntax.dw = CLUSPROP_SYNTAX_PARTITION_INFO;
  1296. ptrPartitionInfo->cbLength = sizeof(CLUSPROP_PARTITION_INFO) - sizeof(CLUSPROP_VALUE);
  1297. if ( iswlower( driveLetters[letterIndex] ) ) {
  1298. driveLetters[letterIndex] = towupper( driveLetters[letterIndex] );
  1299. } else {
  1300. ptrPartitionInfo->dwFlags = CLUSPROP_PIFLAG_STICKY;
  1301. }
  1302. ptrPartitionInfo->dwFlags |= CLUSPROP_PIFLAG_USABLE;
  1303. ptrPartitionInfo->dwFlags |= CLUSPROP_PIFLAG_DEFAULT_QUORUM;
  1304. wsprintfW( ptrPartitionInfo->szDeviceName,
  1305. L"%hc:\\",
  1306. driveLetters[letterIndex] );
  1307. if ( !GetVolumeInformationW( ptrPartitionInfo->szDeviceName,
  1308. ptrPartitionInfo->szVolumeLabel,
  1309. sizeof(ptrPartitionInfo->szVolumeLabel)/sizeof(WCHAR),
  1310. &ptrPartitionInfo->dwSerialNumber,
  1311. &ptrPartitionInfo->rgdwMaximumComponentLength,
  1312. &ptrPartitionInfo->dwFileSystemFlags,
  1313. ptrPartitionInfo->szFileSystem,
  1314. sizeof(ptrPartitionInfo->szFileSystem)/sizeof(WCHAR) ) ) {
  1315. ptrPartitionInfo->szVolumeLabel[0] = L'\0';
  1316. }
  1317. //set the partition name to the path
  1318. //in future, siva wants to be able to provide an smb name here
  1319. lstrcpy(ptrPartitionInfo->szDeviceName, pszExpandedPath);
  1320. dwLength = lstrlenW(ptrPartitionInfo->szDeviceName);
  1321. //this should not be terminated in a '\'
  1322. if (ptrPartitionInfo->szDeviceName[dwLength-1] == L'\\')
  1323. {
  1324. ptrPartitionInfo->szDeviceName[dwLength-1] = L'\0';
  1325. }
  1326. ptrPartitionInfo++;
  1327. ptrBuffer = ptrPartitionInfo;
  1328. }
  1329. }
  1330. //
  1331. // Check if we got what we were looking for.
  1332. //
  1333. *OutBuffer = ptrBuffer;
  1334. *BytesReturned = bytesReturned;
  1335. FnExit:
  1336. if (pszExpandedPath)
  1337. LocalFree(pszExpandedPath);
  1338. return(status);
  1339. } // LkQuorumGetDiskInfo
  1340. //***********************************************************
  1341. //
  1342. // Define Function Table
  1343. //
  1344. //***********************************************************
  1345. CLRES_V1_FUNCTION_TABLE( LkQuorumFunctionTable, // Name
  1346. CLRES_VERSION_V1_00, // Version
  1347. LkQuorum, // Prefix
  1348. LkQuorumArbitrate, // Arbitrate
  1349. LkQuorumRelease, // Release
  1350. LkQuorumResourceControl, // ResControl
  1351. LkQuorumResourceTypeControl); // ResTypeControl