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.

2624 lines
70 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. pnp
  5. Abstract:
  6. This module processes disk related PnP notifications
  7. and tries to adjust partitions and drive letter information
  8. accordingly.
  9. Author:
  10. Gor Nishanov (gorn) 21-Dec-1998
  11. Environment:
  12. User Mode
  13. Revision History:
  14. --*/
  15. #define UNICODE 1
  16. #define INITGUID 1
  17. #include <nt.h>
  18. #include <ntdef.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <windows.h>
  22. #include <dbt.h>
  23. #include <devioctl.h>
  24. #include <devguid.h>
  25. #include <ioevent.h>
  26. #include <stdio.h>
  27. #include <stddef.h>
  28. #include <stdlib.h>
  29. #include <mountmgr.h>
  30. #include <pnpmgr.h>
  31. #include <setupapi.h>
  32. //#include <windows.h>
  33. #include "disksp.h"
  34. #include "newmount.h"
  35. #include "newdisks.h"
  36. #include <strsafe.h> // Should be included last.
  37. #define LOG_CURRENT_MODULE LOG_MODULE_DISK
  38. static HWND DummyWindow = 0;
  39. static BOOL PnPInitialized = FALSE;
  40. static HANDLE NotificationWatcherThreadHandle;
  41. static HANDLE PnpInterfacesRegistered;
  42. static LONG VolumeListUpdateInProcess = 0;
  43. RTL_RESOURCE PnpVolumeLock;
  44. RTL_RESOURCE PnpWaitingListLock;
  45. PWCHAR g_DiskResource = L"rtPhysical Disk";
  46. #define RESOURCE_TYPE ((RESOURCE_HANDLE)g_DiskResource)
  47. LIST_ENTRY WaitingDisks;
  48. typedef struct _WAITING_DISK {
  49. LIST_ENTRY ListEntry;
  50. PDISK_RESOURCE ResourceEntry;
  51. HANDLE Event;
  52. DWORD Signature;
  53. ULONG PartitionCount;
  54. } WAITING_DISK, *PWAITING_DISK;
  55. #define AcquireShared( _res_lock ) \
  56. RtlAcquireResourceShared( _res_lock, TRUE );
  57. #define ReleaseShared( _res_lock ) \
  58. RtlReleaseResource( _res_lock );
  59. #define AcquireExclusive( _res_lock ) \
  60. RtlAcquireResourceExclusive( _res_lock, TRUE );
  61. #define ReleaseExclusive( _res_lock ) \
  62. RtlReleaseResource( _res_lock );
  63. DWORD
  64. NotificationWatcherThread(
  65. IN LPVOID
  66. );
  67. VOID
  68. ProcessMountPointChange(
  69. HDEVNOTIFY devNotify,
  70. DWORD Signature
  71. );
  72. PWAITING_DISK
  73. FindWaitingDisk(
  74. DWORD Signature
  75. );
  76. DWORD
  77. GetVolName(
  78. PWCHAR Name,
  79. PWCHAR *VolGuid
  80. );
  81. DWORD
  82. StartNotificationWatcherThread(
  83. VOID)
  84. {
  85. DWORD status = ERROR_SUCCESS;
  86. HANDLE thread;
  87. if ( InterlockedCompareExchange(&PnPInitialized, TRUE, FALSE) ) {
  88. (DiskpLogEvent)(
  89. RESOURCE_TYPE,
  90. LOG_WARNING,
  91. L"[PnP] PnP was already initialized.\n",
  92. status );
  93. return ERROR_SUCCESS;
  94. }
  95. PnpInterfacesRegistered = NULL;
  96. PnpInterfacesRegistered = CreateEvent( NULL, // security attributes
  97. TRUE, // manual reset
  98. FALSE, // initial state nonsignaled
  99. NULL ); // event name
  100. if ( NULL == PnpInterfacesRegistered ) {
  101. status = GetLastError();
  102. (DiskpLogEvent)(
  103. RESOURCE_TYPE,
  104. LOG_WARNING,
  105. L"[PnP] Unable to create event for PnP interface registration. \n",
  106. status );
  107. status = ERROR_SUCCESS;
  108. }
  109. thread =
  110. CreateThread( NULL, // security attributes
  111. 0, // stack_size = default
  112. NotificationWatcherThread,
  113. (LPVOID)0, // no parameters
  114. 0, // runs immediately
  115. 0 ); // don't need thread id
  116. if(thread == NULL) {
  117. status = GetLastError();
  118. (DiskpLogEvent)(
  119. RESOURCE_TYPE,
  120. LOG_ERROR,
  121. L"[PnP] StartNotificationWatcherThread failed, error: %1!u!. \n",
  122. status );
  123. } else {
  124. if ( NULL != PnpInterfacesRegistered ) {
  125. //
  126. // Before returning to caller, make sure all PnP interfaces
  127. // are registered.
  128. //
  129. (DiskpLogEvent)(
  130. RESOURCE_TYPE,
  131. LOG_INFORMATION,
  132. L"[PnP] Waiting for PnP interface registration to complete.\n" );
  133. status = WaitForSingleObject( PnpInterfacesRegistered, 30 * 1000 );
  134. if ( WAIT_TIMEOUT == status ) {
  135. (DiskpLogEvent)(
  136. RESOURCE_TYPE,
  137. LOG_ERROR,
  138. L"[PnP] PnP interface registration failed to complete in time, error: %1!u! \n",
  139. status );
  140. }
  141. CloseHandle( PnpInterfacesRegistered );
  142. PnpInterfacesRegistered = NULL;
  143. status = ERROR_SUCCESS;
  144. }
  145. }
  146. NotificationWatcherThreadHandle = thread;
  147. return status;
  148. }
  149. VOID
  150. StopNotificationWatcher(
  151. VOID
  152. )
  153. /*++
  154. Routine Description:
  155. Handler for console control events
  156. Arguments:
  157. dwCtrlType - Indicates the console event to handle.
  158. Return Value:
  159. TRUE if the event was handled, FALSE otherwise.
  160. --*/
  161. {
  162. HANDLE localHandle = NotificationWatcherThreadHandle;
  163. if (DummyWindow) {
  164. PostMessage(DummyWindow, WM_QUIT, 0, 0);
  165. if (localHandle) {
  166. WaitForSingleObject(localHandle, 10 * 1000);
  167. CloseHandle(localHandle);
  168. }
  169. }
  170. }
  171. #define WM_WatchDisk (WM_USER + 1)
  172. #define WM_StopWatchingDisk (WM_USER + 2)
  173. VOID
  174. WatchDisk(
  175. IN PDISK_RESOURCE ResourceEntry
  176. )
  177. {
  178. if (DummyWindow) {
  179. PostMessage(DummyWindow, WM_WatchDisk, 0, (LPARAM)ResourceEntry);
  180. }
  181. }
  182. VOID
  183. StopWatchingDisk(
  184. IN PDISK_RESOURCE ResourceEntry
  185. )
  186. {
  187. if (DummyWindow) {
  188. SendMessage(DummyWindow, WM_StopWatchingDisk, 0, (LPARAM)ResourceEntry);
  189. }
  190. }
  191. ///////////////////////////////////////////////////////////////////////////
  192. VOID
  193. MyUnregisterDeviceNotification(HDEVNOTIFY hNotify)
  194. {
  195. #if DBG
  196. (DiskpLogEvent)(
  197. RESOURCE_TYPE,
  198. LOG_INFORMATION,
  199. L"[PnP] Unregistering device notification - HDEVNOTIFY %1!x! \n",
  200. hNotify );
  201. #endif
  202. UnregisterDeviceNotification( hNotify );
  203. }
  204. HDEVNOTIFY
  205. MyRegisterDeviceNotification(
  206. IN HANDLE hRecipient,
  207. IN LPVOID NotificationFilter,
  208. IN DWORD Flags
  209. )
  210. {
  211. #if DBG
  212. (DiskpLogEvent)(
  213. RESOURCE_TYPE,
  214. LOG_INFORMATION,
  215. L"[PnP] Registering device notification - Recipient %1!x! Flags %2!x! \n",
  216. hRecipient,
  217. Flags );
  218. #endif
  219. return RegisterDeviceNotification( hRecipient,
  220. NotificationFilter,
  221. Flags
  222. );
  223. }
  224. DWORD
  225. RegisterDeviceHandle(
  226. IN HANDLE wnd,
  227. IN HANDLE device,
  228. OUT HDEVNOTIFY *devNotify)
  229. {
  230. DEV_BROADCAST_HANDLE DbtHandle;
  231. DWORD status = ERROR_SUCCESS;
  232. *devNotify = 0;
  233. ZeroMemory(&DbtHandle,sizeof(DEV_BROADCAST_HANDLE));
  234. DbtHandle.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
  235. DbtHandle.dbch_devicetype = DBT_DEVTYP_HANDLE;
  236. DbtHandle.dbch_handle = device;
  237. *devNotify = MyRegisterDeviceNotification(
  238. (HANDLE)wnd,
  239. &DbtHandle,
  240. DEVICE_NOTIFY_WINDOW_HANDLE
  241. );
  242. if (!*devNotify) {
  243. status = GetLastError();
  244. (DiskpLogEvent)(
  245. RESOURCE_TYPE,
  246. LOG_ERROR,
  247. L"[PnP] DBT_DEVTYP_HANDLE failed, error %1!u!\n",
  248. status );
  249. }
  250. return status;
  251. }
  252. DWORD
  253. RegisterDeviceInterface(
  254. IN HANDLE wnd,
  255. IN const GUID * guid,
  256. OUT HDEVNOTIFY *devNotify)
  257. {
  258. DEV_BROADCAST_DEVICEINTERFACE filter;
  259. DWORD status = ERROR_SUCCESS;
  260. *devNotify = 0;
  261. ZeroMemory(&filter, sizeof(filter));
  262. filter.dbcc_size = sizeof(filter);
  263. filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  264. CopyMemory(&filter.dbcc_classguid, guid, sizeof(filter.dbcc_classguid));
  265. *devNotify = MyRegisterDeviceNotification(
  266. (HANDLE)wnd,
  267. &filter,
  268. DEVICE_NOTIFY_WINDOW_HANDLE
  269. );
  270. if (!*devNotify) {
  271. status = GetLastError();
  272. (DiskpLogEvent)(
  273. RESOURCE_TYPE,
  274. LOG_ERROR,
  275. L"[PnP] DBT_DEVTYP_DEVICEINTERFACE failed, error %1!u!\n",
  276. status );
  277. }
  278. return status;
  279. }
  280. ///////////// Forward Declarations /////////////////
  281. typedef struct _VOLUME *PVOLUME;
  282. #define LOG_GUID_START( _Broadcast_, _Vol_ ) LogPnpGuid( _Broadcast_, _Vol_, L"Received" );
  283. #define LOG_GUID_END( _Broadcast_, _Vol_ ) LogPnpGuid( _Broadcast_, _Vol_, L"Processed" );
  284. VOID
  285. LogPnpGuid(
  286. PDEV_BROADCAST_HANDLE Broadcast,
  287. PVOLUME Vol,
  288. PWSTR BeginEndStr
  289. );
  290. VOID
  291. PokeDiskResource(
  292. PVOLUME vol
  293. );
  294. /*++
  295. Routine Description:
  296. Updates ClusterRegistry info if necessary
  297. Arguments:
  298. Volume of interest (used only to get the disk signature)
  299. Updates a per disk basis
  300. Return Value:
  301. None
  302. --*/
  303. DWORD
  304. GetVolumeInfo(
  305. PVOLUME Vol,
  306. PHANDLE FileHandle
  307. );
  308. ///////////// End Forward Declarations /////////////
  309. ////////////// Notification List Management //////////////////////////////
  310. //
  311. // We maintain a list of all volumes we are getting PnP notifications for
  312. //
  313. // PVOLUME FindVolume(HDEVNOTIFY Key);
  314. // VOID DestroyVolume(PVOLUME vol);
  315. // VOID RemoveVolume(HDEVNOTIFY devNotify);
  316. // VOID AddVolume(PWCHAR Name)
  317. //
  318. LIST_ENTRY VolumeList;
  319. typedef struct _VOLUME {
  320. LIST_ENTRY ListEntry;
  321. HDEVNOTIFY DevNotify;
  322. DWORD Signature;
  323. LONG UpdateActive;
  324. LARGE_INTEGER PartOffset;
  325. LARGE_INTEGER PartLength;
  326. ULONG PartNo;
  327. BYTE PartitionType;
  328. CHAR DriveLetter;
  329. WCHAR Name[1];
  330. } VOLUME;
  331. PVOLUME
  332. FindVolume(HDEVNOTIFY Key)
  333. {
  334. PLIST_ENTRY entry;
  335. for ( entry = VolumeList.Flink;
  336. entry != &VolumeList;
  337. entry = entry->Flink
  338. )
  339. {
  340. PVOLUME vol = CONTAINING_RECORD(
  341. entry,
  342. VOLUME,
  343. ListEntry
  344. );
  345. if (vol->DevNotify == Key) {
  346. return(vol);
  347. }
  348. }
  349. return 0;
  350. }
  351. VOID
  352. DestroyVolume(
  353. PVOLUME vol)
  354. {
  355. // (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  356. // L"Destroying entry for %1!s!\n", vol->Name);
  357. MyUnregisterDeviceNotification(vol->DevNotify);
  358. LocalFree(vol);
  359. }
  360. VOID
  361. RemoveVolume(HDEVNOTIFY devNotify)
  362. {
  363. PVOLUME vol = NULL;
  364. // Use a lock here as the online thread might be parsing the volume list.
  365. AcquireExclusive( &PnpVolumeLock );
  366. vol = FindVolume( devNotify );
  367. if (!vol) {
  368. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  369. L"[PnP] RemoveVolume: devNotify %1!d! is not in the list\n", devNotify);
  370. ReleaseExclusive( &PnpVolumeLock );
  371. return;
  372. }
  373. PokeDiskResource(vol);
  374. RemoveEntryList(&vol->ListEntry);
  375. ReleaseExclusive( &PnpVolumeLock );
  376. DestroyVolume(vol);
  377. }
  378. VOID
  379. AddVolume(
  380. PWCHAR Name
  381. )
  382. {
  383. PWAITING_DISK waitDisk;
  384. PLIST_ENTRY entry;
  385. PVOLUME volList;
  386. PVOLUME vol = NULL;
  387. PWCHAR volGuid = NULL;
  388. DWORD status;
  389. DWORD signature;
  390. size_t len;
  391. HANDLE fileHandle;
  392. BOOL duplicateEntry;
  393. BOOL keepVolume = FALSE;
  394. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  395. L"[PnP] AddVolume: Adding Name %1!s! \n", Name );
  396. //
  397. // Convert name to VolGuid name. If name is already a VolGuid
  398. // name, the correct name will be returned. GetVolName will
  399. // always return a name with a trailing backslash.
  400. //
  401. status = GetVolName( Name, &volGuid );
  402. if ( ERROR_SUCCESS != status || !volGuid ) {
  403. goto FnExit;
  404. }
  405. len = wcslen(volGuid);
  406. // VOLUME structure includes 1 char for Name, so just add the
  407. // length of the VolGuid (not length + 1).
  408. vol = LocalAlloc(LPTR, sizeof(VOLUME) + len * sizeof(WCHAR));
  409. if ( NULL == vol ) {
  410. status = GetLastError();
  411. (DiskpLogEvent)(RESOURCE_TYPE, LOG_ERROR,
  412. L"[PnP] AddVolume: can't alloc VOL+%1!d!, error %2!u!\n", len, status );
  413. goto FnExit;
  414. }
  415. wcsncpy( vol->Name, volGuid, len );
  416. vol->Name[len] = L'\0'; // Allocation included space for NULL.
  417. //
  418. // Skip CDROM devices. This requires a trailing backslash and
  419. // prefix \\?\.
  420. //
  421. if ( DRIVE_CDROM == GetDriveType( vol->Name ) ) {
  422. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  423. L"[PnP] AddVolume: Skipping CDROM volume %1!s!\n", vol->Name );
  424. goto FnExit;
  425. }
  426. //
  427. // Skip floppy devices. This requires a trailing backslash and
  428. // prefix \\?\.
  429. //
  430. if ( DRIVE_REMOVABLE == GetDriveType( vol->Name ) ) {
  431. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  432. L"[PnP] AddVolume: Skipping floppy volume %1!s!\n", vol->Name );
  433. goto FnExit;
  434. }
  435. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  436. L"[PnP] AddVolume: Attempting to add volume %1!s!\n", volGuid );
  437. if (len > 0 && vol->Name[len-1] == L'\\')
  438. {
  439. // remove trailing backslash
  440. vol->Name[len-1] = 0;
  441. }
  442. if (len > 2 && vol->Name[0] == L'\\' && vol->Name[1] == L'\\') {
  443. // Convert to NT file name
  444. vol->Name[1] = L'?';
  445. }
  446. //
  447. // Make sure the volume isn't already in the list. If so,
  448. // skip it.
  449. //
  450. duplicateEntry = FALSE;
  451. AcquireShared( &PnpVolumeLock );
  452. len = wcslen( vol->Name );
  453. for ( entry = VolumeList.Flink;
  454. entry != &VolumeList;
  455. entry = entry->Flink
  456. )
  457. {
  458. volList = CONTAINING_RECORD( entry,
  459. VOLUME,
  460. ListEntry
  461. );
  462. if ( ( len == wcslen( volList->Name) ) &&
  463. ( 0 == ClRtlStrNICmp( vol->Name, volList->Name, len ) ) ) {
  464. duplicateEntry = TRUE;
  465. break;
  466. }
  467. }
  468. ReleaseShared( &PnpVolumeLock );
  469. if ( duplicateEntry ) {
  470. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  471. L"[PnP] AddVolume: Skipping duplicate volume %1!s!\n", vol->Name );
  472. goto FnExit;
  473. }
  474. status = GetVolumeInfo( vol, &fileHandle );
  475. //
  476. // We might have a clustered disk now, but we can't read the
  477. // partition info or drive layout because the disk is reserved
  478. // by another node.
  479. //
  480. // If the disk is reserved by another node, we typically see
  481. // this returned:
  482. // 170 ERROR_BUSY
  483. // If the disk is offline, we can see this:
  484. // 2 ERROR_FILE_NOT_FOUND
  485. //
  486. // About all we know for sure is that if this is a non-fixed device,
  487. // ERROR_INVALID_FUNCTION will be returned. For now, skip these
  488. // devices and track any other volumes coming through.
  489. //
  490. if ( ERROR_INVALID_FUNCTION == status ) {
  491. if ( INVALID_HANDLE_VALUE != fileHandle) {
  492. DevfileClose( fileHandle );
  493. }
  494. // Change this from LOG_ERROR to LOG_INFORMATION. This thread gets
  495. // notified when non-fixed disks arrive (i.e. floppy), so logging
  496. // an error for a floppy disk is misleading.
  497. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  498. L"[PnP] AddVolume: Skipping volume %1!ws! \n",
  499. vol->Name);
  500. goto FnExit;
  501. }
  502. if ( INVALID_HANDLE_VALUE == fileHandle ) {
  503. (DiskpLogEvent)(RESOURCE_TYPE, LOG_WARNING,
  504. L"[PnP] AddVolume: Unable to get volume handle (%1!ws!), error %2!u!\n",
  505. vol->Name, status);
  506. goto FnExit;
  507. }
  508. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  509. L"[PnP] AddVolume: adding volume %1!s!\n", vol->Name );
  510. status = RegisterDeviceHandle(DummyWindow, fileHandle, &vol->DevNotify);
  511. DevfileClose( fileHandle );
  512. if (status != ERROR_SUCCESS) {
  513. (DiskpLogEvent)(RESOURCE_TYPE, LOG_ERROR,
  514. L"[PnP] AddVolume: RDN(%1!ws!), error %2!u!\n",
  515. vol->Name,
  516. status);
  517. goto FnExit;
  518. }
  519. GetAssignedLetter(vol->Name, &vol->DriveLetter);
  520. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  521. L"[PnP] AddVolume: %1!s! '%2!c!', %3!d! (%4!u!)\n",
  522. Name, (vol->DriveLetter)?vol->DriveLetter:' ', vol->PartitionType, vol->DevNotify);
  523. // Use a lock here as the online thread might be parsing the volume list.
  524. // As soon as the volume is added to the list, another thread could come
  525. // through and remove it. Save the signature to a local variable so
  526. // we can check the waiting list.
  527. signature = vol->Signature;
  528. keepVolume = TRUE;
  529. AcquireExclusive( &PnpVolumeLock );
  530. InsertTailList(&VolumeList, &vol->ListEntry);
  531. ReleaseExclusive( &PnpVolumeLock );
  532. AcquireShared( &PnpWaitingListLock );
  533. waitDisk = FindWaitingDisk( signature );
  534. if ( waitDisk ) {
  535. //
  536. // We have a waiting disk that matches this volume signature.
  537. // Now see if all the volumes are in the volume list.
  538. //
  539. if ( IsDiskInPnpVolumeList( waitDisk->ResourceEntry, FALSE ) ) {
  540. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  541. L"[PnP] AddVolume: All volumes present, signal event for signature %1!x!\n",
  542. signature );
  543. //
  544. // All volumes present, signal the event.
  545. //
  546. SetEvent( waitDisk->Event );
  547. } else {
  548. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  549. L"[PnP] AddVolume: All volumes not ready for signature %1!x!\n",
  550. signature );
  551. }
  552. } else {
  553. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  554. L"[PnP] AddVolume: Online request not queued for signature %1!x!\n",
  555. signature );
  556. }
  557. ReleaseShared( &PnpWaitingListLock );
  558. FnExit:
  559. if ( volGuid ) {
  560. LocalFree( volGuid );
  561. }
  562. if ( !keepVolume && vol ) {
  563. LocalFree( vol );
  564. }
  565. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  566. L"[PnP] AddVolume: Adding Name %1!s! - processed \n", Name );
  567. }
  568. DWORD
  569. GetVolName(
  570. PWCHAR Name,
  571. PWCHAR *VolGuid
  572. )
  573. {
  574. PWCHAR volName = NULL;
  575. PWCHAR tempName = NULL;
  576. DWORD volNameLenBytes;
  577. DWORD tempNameLenBytes;
  578. DWORD nameLen;
  579. DWORD dwError = ERROR_SUCCESS;
  580. if ( VolGuid ) {
  581. *VolGuid = NULL;
  582. }
  583. #if DBG
  584. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  585. L"[PnP] GetVolName: Name %1!s!\n", Name );
  586. #endif
  587. nameLen = wcslen( Name );
  588. //
  589. // Create a buffer with room for a backslash.
  590. //
  591. tempNameLenBytes = ( nameLen * sizeof(WCHAR) ) + sizeof(UNICODE_NULL) + sizeof(WCHAR);
  592. tempName = LocalAlloc( LPTR, tempNameLenBytes );
  593. if ( !tempName ) {
  594. dwError = GetLastError();
  595. (DiskpLogEvent)(
  596. RESOURCE_TYPE,
  597. LOG_WARNING,
  598. L"[PnP] GetVolName: LocalAlloc for tempName failed, error %1!d! \n",
  599. dwError );
  600. goto FnExit;
  601. }
  602. wcsncpy( tempName, Name, nameLen ); // Room for NULL and '\' in buffer.
  603. //
  604. // Add trailing backslash.
  605. //
  606. if ( nameLen > 0 && tempName[nameLen-1] != L'\\' ) {
  607. //
  608. // This is safe because temporary buffer is larger than
  609. // original buffer.
  610. //
  611. tempName[nameLen] = L'\\';
  612. }
  613. #if DBG
  614. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  615. L"[PnP] GetVolName: tempName %1!s!\n", tempName );
  616. #endif
  617. volNameLenBytes = MAX_PATH * sizeof(WCHAR);
  618. volName = LocalAlloc( LPTR, volNameLenBytes );
  619. if ( !volName ) {
  620. dwError = GetLastError();
  621. (DiskpLogEvent)(
  622. RESOURCE_TYPE,
  623. LOG_WARNING,
  624. L"[PnP] GetVolName: LocalAlloc for volName failed, error %1!d! \n",
  625. dwError );
  626. goto FnExit;
  627. }
  628. if ( !GetVolumeNameForVolumeMountPointW( tempName,
  629. volName,
  630. volNameLenBytes / sizeof(WCHAR) ) ) {
  631. dwError = GetLastError();
  632. (DiskpLogEvent)(
  633. RESOURCE_TYPE,
  634. LOG_WARNING,
  635. L"[PnP] GetVolName: GetVolumeNameForVolumeMountPoint failed, error %1!d! \n",
  636. dwError );
  637. goto FnExit;
  638. }
  639. if ( VolGuid ) {
  640. *VolGuid = volName;
  641. }
  642. FnExit:
  643. if ( dwError != ERROR_SUCCESS && volName ) {
  644. LocalFree( volName );
  645. }
  646. if ( tempName ) {
  647. LocalFree( tempName );
  648. }
  649. #if DBG
  650. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  651. L"[PnP] GetVolName: returns error %1!d!\n", dwError );
  652. #endif
  653. return dwError;
  654. } // GetVolName
  655. ///////////////////// VolumeManagement code ends //////////////////////////////////////////
  656. //////////////////// WatchedList //////////////////////
  657. //
  658. // We maintain a list of disks that are currently online
  659. // and under cluster control. Any PnP notification
  660. // coming for the volumes belonging to these disks,
  661. // need to be processed and cluster registry might need
  662. // to be updated
  663. //
  664. LIST_ENTRY WatchedList;
  665. PDISK_RESOURCE
  666. FindDisk(DWORD Signature)
  667. {
  668. PLIST_ENTRY entry;
  669. PDISK_RESOURCE watchedDisk = NULL;
  670. if ( !Signature ) {
  671. goto FnExit;
  672. }
  673. if ( IsListEmpty( &WatchedList ) ) {
  674. goto FnExit;
  675. }
  676. for ( entry = WatchedList.Flink;
  677. entry != &WatchedList;
  678. entry = entry->Flink ) {
  679. watchedDisk = CONTAINING_RECORD( entry,
  680. DISK_RESOURCE,
  681. PnpWatchedListEntry );
  682. if ( watchedDisk->DiskInfo.Params.Signature == Signature ) {
  683. goto FnExit;
  684. }
  685. watchedDisk = NULL;
  686. }
  687. FnExit:
  688. return watchedDisk;
  689. }
  690. VOID
  691. RemoveDisk(
  692. PDISK_RESOURCE ResourceEntry
  693. )
  694. {
  695. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_INFORMATION,
  696. L"[PnP] Stop watching PnP events for disk %1!x!\n",
  697. ResourceEntry->DiskInfo.Params.Signature );
  698. if ( IsListEmpty( &WatchedList ) ) {
  699. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  700. L"[PnP] RemoveDisk: WatchedList is empty \n");
  701. goto FnExit;
  702. }
  703. if ( ResourceEntry->PnpWatchedListEntry.Flink == 0 ||
  704. ResourceEntry->PnpWatchedListEntry.Blink == 0 ) {
  705. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  706. L"[PnP] RemoveDisk: disk %1!x! not found or previously removed \n",
  707. ResourceEntry->DiskInfo.Params.Signature);
  708. goto FnExit;
  709. }
  710. RemoveEntryList( &ResourceEntry->PnpWatchedListEntry );
  711. ResourceEntry->PnpWatchedListEntry.Flink = 0;
  712. ResourceEntry->PnpWatchedListEntry.Blink = 0;
  713. FnExit:
  714. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_INFORMATION,
  715. L"[PnP] Stop watching disk %1!x! - processed \n",
  716. ResourceEntry->DiskInfo.Params.Signature );
  717. return;
  718. }
  719. VOID
  720. MarkMatchingPartition(
  721. PVOLUME Volume,
  722. PDRIVE_LAYOUT_INFORMATION driveLayout)
  723. /*++
  724. Routine Description:
  725. Finds a partition in DRIVE_LAYOUT_INFORMATION corresponding to
  726. the Volume in question and marks it.
  727. This routine is used in the code that verifies that there is a
  728. volume in the VolumeList for every recognized partition on the disk.
  729. Arguments:
  730. Return Value:
  731. none
  732. --*/
  733. {
  734. PPARTITION_INFORMATION p = driveLayout->PartitionEntry;
  735. PPARTITION_INFORMATION end = p + driveLayout->PartitionCount;
  736. for(;p < end; ++p)
  737. {
  738. if(p->RecognizedPartition &&
  739. p->StartingOffset.QuadPart == Volume->PartOffset.QuadPart &&
  740. p->PartitionLength.QuadPart == Volume->PartLength.QuadPart)
  741. {
  742. p->PartitionType = 1;
  743. }
  744. }
  745. }
  746. VOID
  747. AddDisk(
  748. PDISK_RESOURCE ResourceEntry
  749. )
  750. {
  751. DWORD idx;
  752. PDRIVE_LAYOUT_INFORMATION driveLayout = NULL;
  753. HANDLE fileHandle;
  754. WCHAR deviceName[MAX_PATH];
  755. PLIST_ENTRY entry;
  756. BOOL success;
  757. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_INFORMATION,
  758. L"[PnP] Start watching PnP events for disk %1!x!\n",
  759. ResourceEntry->DiskInfo.Params.Signature );
  760. if ( ResourceEntry->PnpWatchedListEntry.Flink != NULL &&
  761. ResourceEntry->PnpWatchedListEntry.Blink != NULL ) {
  762. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  763. L"[PnP] AddDisk: disk %1!x! is already being watched\n",
  764. ResourceEntry->DiskInfo.Params.Signature);
  765. goto FnExit;
  766. }
  767. InsertHeadList( &WatchedList, &ResourceEntry->PnpWatchedListEntry );
  768. // Now we need to verify that we are watching for changes on every //
  769. // recognized partition on this drive //
  770. if ( FAILED( StringCchPrintf( deviceName,
  771. RTL_NUMBER_OF(deviceName),
  772. TEXT("\\\\.\\PhysicalDrive%d"),
  773. ResourceEntry->DiskInfo.PhysicalDrive ) ) ) {
  774. goto FnExit;
  775. }
  776. fileHandle = CreateFile(deviceName,
  777. GENERIC_READ | GENERIC_WRITE,
  778. FILE_SHARE_READ | FILE_SHARE_WRITE,
  779. NULL,
  780. OPEN_EXISTING,
  781. 0,
  782. NULL);
  783. if (fileHandle == INVALID_HANDLE_VALUE) {
  784. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  785. L"[PnP] AddDisk: Can't open %1!s!, error %2!d! \n", deviceName, GetLastError() );
  786. goto FnExit;
  787. }
  788. UpdateCachedDriveLayout( fileHandle );
  789. success = ClRtlGetDriveLayoutTable(fileHandle, &driveLayout, 0);
  790. CloseHandle( fileHandle );
  791. if ( !success ) {
  792. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_ERROR,
  793. L"[PnP] AddDisk: Error performing GetDriveLayout; error %1!d!\n",
  794. GetLastError() );
  795. goto FnExit;
  796. }
  797. // Clear PartitionType field. We will be using it to mark partions
  798. // which are in the our list of watched volumes
  799. for ( idx = 0; idx < (INT)driveLayout->PartitionCount; ++idx ) {
  800. driveLayout->PartitionEntry[idx].PartitionType = 0;
  801. }
  802. // Walk the list of all volumes and mark if this volume is in the partition table //
  803. for ( entry = VolumeList.Flink;
  804. entry != &VolumeList;
  805. entry = entry->Flink
  806. )
  807. {
  808. PVOLUME vol = CONTAINING_RECORD(
  809. entry,
  810. VOLUME,
  811. ListEntry
  812. );
  813. if (vol->Signature == driveLayout->Signature) {
  814. MarkMatchingPartition(vol, driveLayout);
  815. }
  816. }
  817. // Now all partitions that are in our list is marked
  818. // We need to add all unmarked partitions to the list
  819. for ( idx = 0; idx < (INT)driveLayout->PartitionCount; ++idx ) {
  820. if (driveLayout->PartitionEntry[idx].PartitionType == 0
  821. && driveLayout->PartitionEntry[idx].RecognizedPartition
  822. )
  823. {
  824. if ( FAILED( StringCchPrintf( deviceName,
  825. RTL_NUMBER_OF( deviceName ),
  826. GLOBALROOT_HARDDISK_PARTITION_FMT,
  827. ResourceEntry->DiskInfo.PhysicalDrive,
  828. driveLayout->PartitionEntry[idx].PartitionNumber ) ) ) {
  829. continue;
  830. }
  831. AddVolume( deviceName );
  832. }
  833. }
  834. FnExit:
  835. if ( driveLayout ) {
  836. LocalFree( driveLayout );
  837. }
  838. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_INFORMATION,
  839. L"[PnP] Start watching PnP events for disk %1!x! - processed \n",
  840. ResourceEntry->DiskInfo.Params.Signature );
  841. }
  842. //////////////////// WatchedList management end //////////////////////
  843. void PokeDiskResource(
  844. PVOLUME vol)
  845. /*++
  846. Routine Description:
  847. Updates ClusterRegistry info if necessary
  848. Arguments:
  849. Volume of interest (used only to get the disk signature)
  850. Updates a per disk basis
  851. Return Value:
  852. None
  853. --*/
  854. {
  855. PDISK_RESOURCE ResourceEntry;
  856. MOUNTIE_INFO Info;
  857. HANDLE fileHandle;
  858. DWORD status;
  859. PVOID OldMountieVolume;
  860. WCHAR deviceName[MAX_PATH];
  861. ResourceEntry = FindDisk( vol->Signature );
  862. if ( !ResourceEntry ) {
  863. return;
  864. }
  865. if( ResourceEntry->MountieInfo.UpdateThreadIsActive ) {
  866. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  867. L"[PnP] PokeDiskResource: ClusApi is read only. PnP request ignored\n");
  868. return;
  869. }
  870. ZeroMemory( &Info, sizeof(Info) );
  871. (VOID) StringCchPrintf( deviceName,
  872. RTL_NUMBER_OF(deviceName),
  873. TEXT("\\\\.\\PhysicalDrive%d"),
  874. ResourceEntry->DiskInfo.PhysicalDrive );
  875. fileHandle = CreateFile(deviceName,
  876. GENERIC_READ | GENERIC_WRITE,
  877. FILE_SHARE_READ | FILE_SHARE_WRITE,
  878. NULL,
  879. OPEN_EXISTING,
  880. 0,
  881. NULL);
  882. if (fileHandle == INVALID_HANDLE_VALUE) {
  883. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  884. L"[PnP] PokeDiskResource: Can't open %1!s!\n", deviceName);
  885. return;
  886. }
  887. status = MountieRecreateVolumeInfoFromHandle(
  888. fileHandle,
  889. ResourceEntry->MountieInfo.HarddiskNo,
  890. 0,
  891. &Info);
  892. CloseHandle(fileHandle);
  893. if (status != ERROR_SUCCESS) {
  894. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  895. L"[PnP] PokeDiskResource: Can't read partition table, error %1!d!\n", status);
  896. return;
  897. }
  898. MountiePrint(&Info, ResourceEntry->ResourceHandle);
  899. status = VolumesReady(&Info, ResourceEntry);
  900. if ( status != ERROR_SUCCESS ) {
  901. (DiskpLogEvent)(ResourceEntry->ResourceHandle, LOG_WARNING,
  902. L"[PnP] PokeDiskResource: Volumes not ready, error %1!d!\n", status);
  903. MountieCleanup(&Info);
  904. return;
  905. }
  906. MountieVerify(&Info, ResourceEntry, TRUE);
  907. ResourceEntry->MountieInfo.DriveLetters = Info.DriveLetters;
  908. OldMountieVolume = InterlockedExchangePointer(&ResourceEntry->MountieInfo.Volume, Info.Volume);
  909. Info.Volume = OldMountieVolume;
  910. ResourceEntry->MountieInfo.NeedsUpdate = Info.NeedsUpdate;
  911. ResourceEntry->MountieInfo.VolumeStructSize = Info.VolumeStructSize;
  912. MountiePrint(&ResourceEntry->MountieInfo, ResourceEntry->ResourceHandle);
  913. MountieUpdate(&ResourceEntry->MountieInfo, ResourceEntry);
  914. MountieCleanup(&Info);
  915. }
  916. //
  917. // [HACKHACK] Currently, there is not polically correct way
  918. // for the resource to learn whether it is a quorum resource or not
  919. //
  920. DWORD
  921. GetQuorumSignature(
  922. OUT PDWORD QuorumSignature)
  923. {
  924. WCHAR buf[MAX_PATH];
  925. WCHAR guid[ sizeof(GUID) * 3 + 1];
  926. // 2 character per byte + 1, in case somebody will put a dash //
  927. // between every byte //
  928. DWORD BufSize;
  929. DWORD Status;
  930. DWORD Type;
  931. HKEY Key;
  932. Status = RegOpenKey( HKEY_LOCAL_MACHINE,
  933. DISKS_REG_CLUSTER_QUORUM,
  934. &Key );
  935. if (Status != ERROR_SUCCESS) {
  936. return Status;
  937. }
  938. BufSize = sizeof(guid);
  939. Status = RegQueryValueExW(Key,
  940. CLUSREG_NAME_QUORUM_RESOURCE,
  941. 0,
  942. &Type,
  943. (LPBYTE)guid,
  944. &BufSize );
  945. RegCloseKey( Key );
  946. if (Status != ERROR_SUCCESS) {
  947. return Status;
  948. }
  949. //
  950. // Now, we got a quorum resource guid.
  951. // Let's try to open this resource and read its parameters.
  952. //
  953. (VOID) StringCchPrintf( buf,
  954. RTL_NUMBER_OF(buf),
  955. TEXT("Cluster\\Resources\\%ws\\Parameters"),
  956. guid );
  957. Status = RegOpenKey( HKEY_LOCAL_MACHINE,
  958. buf,
  959. &Key );
  960. if (Status != ERROR_SUCCESS) {
  961. return Status;
  962. }
  963. BufSize = sizeof(DWORD);
  964. Status = RegQueryValueExW(Key,
  965. CLUSREG_NAME_PHYSDISK_SIGNATURE,
  966. 0,
  967. &Type,
  968. (LPBYTE)QuorumSignature,
  969. &BufSize );
  970. if (Status != ERROR_SUCCESS) {
  971. // During cluster install, the registry key doesn't yet exist.
  972. (DiskpLogEvent)(RESOURCE_TYPE, LOG_WARNING,
  973. L"[PnP] DriveLetterChange: failed to open Path = %1!ws!\n", buf);
  974. }
  975. RegCloseKey(Key);
  976. return Status;
  977. }
  978. DWORD
  979. CheckQuorumLetterChange(
  980. HDEVNOTIFY devNotify,
  981. UCHAR Old,
  982. UCHAR New,
  983. DWORD Signature)
  984. {
  985. static HDEVNOTIFY QuorumDevNotify = 0;
  986. static UCHAR StoredDriveLetter = 0;
  987. DWORD status;
  988. UCHAR QuorumDriveLetter;
  989. LPWSTR QuorumPath;
  990. DWORD QuorumSignature;
  991. //
  992. // If we are not watching the disk this volume is on, do nothing
  993. //
  994. if ( FindDisk(Signature) == NULL ) {
  995. return ERROR_SUCCESS;
  996. }
  997. status = GetQuorumSignature(&QuorumSignature);
  998. if (status != ERROR_SUCCESS) {
  999. (DiskpLogEvent)(RESOURCE_TYPE, LOG_ERROR,
  1000. L"[PnP] DriveLetterChange: Unable to query quorum drive signature, status %1!u!\n", status);
  1001. QuorumDevNotify = 0;
  1002. StoredDriveLetter = 0;
  1003. return status;
  1004. }
  1005. //
  1006. // Not a quorum disk. Ignore this notification
  1007. //
  1008. if ( QuorumSignature != Signature ) {
  1009. return ERROR_SUCCESS;
  1010. }
  1011. status = DiskspGetQuorumPath(&QuorumPath);
  1012. if (status != ERROR_SUCCESS) {
  1013. (DiskpLogEvent)(RESOURCE_TYPE, LOG_ERROR,
  1014. L"[PnP] DriveLetterChange: Unable to query quorum drive letter, status %1!u!\n", status);
  1015. QuorumDevNotify = 0;
  1016. StoredDriveLetter = 0;
  1017. return status;
  1018. }
  1019. QuorumDriveLetter = (UCHAR) QuorumPath[0];
  1020. if (QuorumDriveLetter == Old) {
  1021. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  1022. L"[PnP] DriveLetterChange: Quorum drive letter %1!c! is being changed\n", QuorumDriveLetter);
  1023. QuorumDevNotify = devNotify;
  1024. StoredDriveLetter = QuorumDriveLetter;
  1025. }
  1026. if (New && QuorumDevNotify == devNotify
  1027. && QuorumDriveLetter != New
  1028. && QuorumDriveLetter == StoredDriveLetter)
  1029. {
  1030. WCHAR szOld[2] = {QuorumDriveLetter, 0};
  1031. WCHAR szNew[2] = {New, 0};
  1032. ClusterLogEvent2(
  1033. LOG_UNUSUAL, LOG_CURRENT_MODULE,
  1034. __FILE__, __LINE__,
  1035. RES_DISK_PNP_CHANGING_QUORUM,
  1036. 0, NULL,
  1037. szOld, szNew);
  1038. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  1039. L"[PnP] DriveLetterChange: Quorum drive letter changed from %1!c! to %2!c!\n",
  1040. QuorumDriveLetter, New);
  1041. QuorumPath[0] = New;
  1042. status = DiskspSetQuorumPath(QuorumPath);
  1043. if (status != ERROR_SUCCESS) {
  1044. (DiskpLogEvent)(RESOURCE_TYPE, LOG_SEVERE,
  1045. L"[PnP] DriveLetterChange: Unable to update QuorumPath (%1!c!: => %2!c!:), status %3!u!\n",
  1046. QuorumDriveLetter, New, status);
  1047. }
  1048. }
  1049. LocalFree(QuorumPath);
  1050. return status;
  1051. }
  1052. VOID
  1053. ProcessDriveLetterChange( HDEVNOTIFY devNotify )
  1054. {
  1055. PVOLUME vol = FindVolume(devNotify);
  1056. CHAR ch;
  1057. if (!vol) {
  1058. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  1059. L"[PnP] DriveLetterChange: devNotify %1!d! is not in the list\n", devNotify);
  1060. return;
  1061. }
  1062. GetAssignedLetter(vol->Name, &ch);
  1063. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  1064. L"[PnP] DriveLetterChange: %1!c! => %2!c!\n",
  1065. NICE_DRIVE_LETTER(vol->DriveLetter),
  1066. NICE_DRIVE_LETTER(ch)
  1067. );
  1068. if (vol->PartitionType == PARTITION_IFS
  1069. && vol->DriveLetter != ch)
  1070. {
  1071. CheckQuorumLetterChange(devNotify, vol->DriveLetter, ch, vol->Signature);
  1072. PokeDiskResource(vol);
  1073. }
  1074. vol->DriveLetter = ch;
  1075. }
  1076. VOID
  1077. ProcessVolumeInfoChange( HDEVNOTIFY devNotify )
  1078. {
  1079. PVOLUME vol = FindVolume(devNotify);
  1080. BOOL success;
  1081. HANDLE fileHandle = NULL;
  1082. PARTITION_INFORMATION partInfo;
  1083. DWORD bytesReturned;
  1084. NTSTATUS ntStatus;
  1085. if (!vol) {
  1086. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  1087. L"[PnP] VolumeInfoChange: devNotify %1!d! is not in the list\n", devNotify);
  1088. return;
  1089. }
  1090. ntStatus = DevfileOpen(&fileHandle, vol->Name);
  1091. if ( !NT_SUCCESS(ntStatus) || !fileHandle ) {
  1092. (DiskpLogEvent)(
  1093. RESOURCE_TYPE,
  1094. LOG_ERROR,
  1095. L"[PnP] VolumeInfoChange: Can't open %1!ws!, error %2!X!.\n",
  1096. vol->Name, ntStatus);
  1097. return;
  1098. }
  1099. success = DeviceIoControl( fileHandle,
  1100. IOCTL_DISK_GET_PARTITION_INFO,
  1101. NULL,
  1102. 0,
  1103. &partInfo,
  1104. sizeof(PARTITION_INFORMATION),
  1105. &bytesReturned,
  1106. FALSE );
  1107. DevfileClose( fileHandle );
  1108. if (!success) {
  1109. (DiskpLogEvent)(RESOURCE_TYPE, LOG_ERROR,
  1110. L"[PnP] VolumeInfoChange: Error performing GetPartitionInfo; error %1!d!\n",
  1111. GetLastError());
  1112. return;
  1113. }
  1114. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  1115. L"[PnP] VolumeInfoChange: partType %1!d! => %2!d!\n",
  1116. vol->PartitionType,
  1117. partInfo.PartitionType
  1118. );
  1119. if (vol->PartitionType != partInfo.PartitionType
  1120. && (partInfo.PartitionType == PARTITION_IFS
  1121. || vol->PartitionType == PARTITION_IFS) )
  1122. {
  1123. PokeDiskResource(vol);
  1124. }
  1125. vol->PartitionType = partInfo.PartitionType;
  1126. }
  1127. //////////////////////////// WindowProc /////////////////////////////////////
  1128. #ifndef PDEV_BROADCAST_HEADER
  1129. typedef struct _DEV_BROADCAST_HEADER * PDEV_BROADCAST_HEADER;
  1130. #endif
  1131. LRESULT CALLBACK TestWndProc(
  1132. HWND hwnd, // handle to window
  1133. UINT uMsg, // message identifier
  1134. WPARAM wParam, // first message parameter
  1135. LPARAM lParam // second message parameter
  1136. ) {
  1137. if (uMsg == WM_WatchDisk) {
  1138. PDISK_RESOURCE p = (PDISK_RESOURCE)lParam;
  1139. if (p) {
  1140. AddDisk(p);
  1141. }
  1142. return TRUE;
  1143. }
  1144. if (uMsg == WM_StopWatchingDisk) {
  1145. PDISK_RESOURCE p = (PDISK_RESOURCE)lParam;
  1146. if (p) {
  1147. RemoveDisk(p);
  1148. }
  1149. return TRUE;
  1150. }
  1151. if (uMsg != WM_DEVICECHANGE) {
  1152. LRESULT result;
  1153. #if DBG
  1154. (DiskpLogEvent)(
  1155. RESOURCE_TYPE,
  1156. LOG_INFORMATION,
  1157. L"[PnP] WM_DEVICECHANGE - calling DefWindowProc \n"
  1158. );
  1159. #endif
  1160. result = DefWindowProc(hwnd, uMsg, wParam, lParam);
  1161. #if DBG
  1162. (DiskpLogEvent)(
  1163. RESOURCE_TYPE,
  1164. LOG_INFORMATION,
  1165. L"[PnP] WM_DEVICECHANGE - DefWindowProc returns %1!x! \n",
  1166. result );
  1167. #endif
  1168. return result;
  1169. }
  1170. if (!lParam) {
  1171. return TRUE;
  1172. }
  1173. #if DBG
  1174. (DiskpLogEvent)(
  1175. RESOURCE_TYPE,
  1176. LOG_INFORMATION,
  1177. L"[PnP] Event %1!x! received\n",
  1178. wParam );
  1179. #endif
  1180. switch( ((PDEV_BROADCAST_HEADER)lParam)->dbcd_devicetype )
  1181. {
  1182. case DBT_DEVTYP_DEVICEINTERFACE:
  1183. {
  1184. PDEV_BROADCAST_DEVICEINTERFACE p = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
  1185. if (wParam == DBT_DEVICEARRIVAL &&
  1186. IsEqualGUID(&p->dbcc_classguid, &GUID_IO_VOLUME_DEVICE_INTERFACE)
  1187. )
  1188. {
  1189. AddVolume( p->dbcc_name );
  1190. }
  1191. break;
  1192. }
  1193. case DBT_DEVTYP_HANDLE:
  1194. {
  1195. PDEV_BROADCAST_HANDLE p = (PDEV_BROADCAST_HANDLE)lParam;
  1196. if (wParam == DBT_DEVICEREMOVECOMPLETE) {
  1197. PVOLUME vol = 0;
  1198. DWORD signature = 0;
  1199. (DiskpLogEvent)(
  1200. RESOURCE_TYPE,
  1201. LOG_INFORMATION,
  1202. L"[PnP] Event DBT_DEVICEREMOVECOMPLETE received \n" );
  1203. // First, save the signature because we are going
  1204. // to remove the volume.
  1205. vol = FindVolume( p->dbch_hdevnotify );
  1206. if ( vol ) {
  1207. signature = vol->Signature;
  1208. }
  1209. RemoveVolume(p->dbch_hdevnotify);
  1210. if ( signature ) {
  1211. ProcessMountPointChange( p->dbch_hdevnotify, signature );
  1212. }
  1213. (DiskpLogEvent)(
  1214. RESOURCE_TYPE,
  1215. LOG_INFORMATION,
  1216. L"[PnP] Event DBT_DEVICEREMOVECOMPLETE processed \n" );
  1217. } else if (wParam == DBT_CUSTOMEVENT) {
  1218. PVOLUME Vol = 0;
  1219. Vol = FindVolume( p->dbch_hdevnotify );
  1220. LOG_GUID_START( p, Vol );
  1221. //
  1222. // If we are watching this volume and it has a valid disk
  1223. // resource structure, find out if we are re-creating the
  1224. // drive letter. If so, we can safely ignore the following
  1225. // pnp events.
  1226. //
  1227. if ( Vol && Vol->Signature ) {
  1228. PDISK_RESOURCE resourceEntry = NULL;
  1229. resourceEntry = FindDisk( Vol->Signature );
  1230. if ( resourceEntry &&
  1231. resourceEntry->IgnoreMPNotifications ) {
  1232. (DiskpLogEvent)(
  1233. RESOURCE_TYPE,
  1234. LOG_INFORMATION,
  1235. L"[PnP] Skipping event processing for signature %x \n",
  1236. Vol->Signature );
  1237. LOG_GUID_END( p, Vol );
  1238. break;
  1239. }
  1240. }
  1241. if ( IsEqualGUID(&p->dbch_eventguid, &GUID_IO_VOLUME_NAME_CHANGE) )
  1242. {
  1243. // Update disk info.
  1244. GetVolumeInfo( Vol, NULL );
  1245. ProcessDriveLetterChange( p->dbch_hdevnotify );
  1246. ProcessMountPointChange( p->dbch_hdevnotify, 0 );
  1247. }
  1248. else if (IsEqualGUID(&p->dbch_eventguid, &GUID_IO_VOLUME_CHANGE) )
  1249. {
  1250. // Update disk info.
  1251. GetVolumeInfo( Vol, NULL );
  1252. ProcessVolumeInfoChange( p->dbch_hdevnotify );
  1253. if ( Vol ) {
  1254. ProcessMountPointChange( p->dbch_hdevnotify, Vol->Signature );
  1255. }
  1256. }
  1257. else if (IsEqualGUID(&p->dbch_eventguid, &GUID_IO_VOLUME_PHYSICAL_CONFIGURATION_CHANGE) )
  1258. {
  1259. // Update disk info.
  1260. GetVolumeInfo( Vol, NULL );
  1261. ProcessVolumeInfoChange( p->dbch_hdevnotify );
  1262. if ( Vol ) {
  1263. ProcessMountPointChange( p->dbch_hdevnotify, 0 );
  1264. }
  1265. }
  1266. else if (IsEqualGUID(&p->dbch_eventguid, &GUID_IO_VOLUME_MOUNT) )
  1267. {
  1268. // ProcessDriveLetterChange( p->dbch_hdevnotify );
  1269. }
  1270. LOG_GUID_END( p, Vol );
  1271. }
  1272. break;
  1273. }
  1274. }
  1275. return TRUE;
  1276. }
  1277. VOID
  1278. LogPnpGuid(
  1279. PDEV_BROADCAST_HANDLE Broadcast,
  1280. PVOLUME Vol,
  1281. PWSTR BeginEndStr
  1282. )
  1283. {
  1284. PWCHAR guidName = 0;
  1285. LPDWORD dw = (LPDWORD)&Broadcast->dbch_eventguid;
  1286. if ( IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_NAME_CHANGE) )
  1287. {
  1288. guidName = L"GUID_IO_VOLUME_NAME_CHANGE";
  1289. }
  1290. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_CHANGE) )
  1291. {
  1292. guidName = L"GUID_IO_VOLUME_CHANGE";
  1293. }
  1294. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_PHYSICAL_CONFIGURATION_CHANGE) )
  1295. {
  1296. guidName = L"GUID_IO_VOLUME_PHYSICAL_CONFIGURATION_CHANGE";
  1297. }
  1298. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_LOCK) )
  1299. {
  1300. #if DBG
  1301. guidName = L"GUID_IO_VOLUME_LOCK";
  1302. #else
  1303. return;
  1304. #endif
  1305. }
  1306. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_UNLOCK) )
  1307. {
  1308. #if DBG
  1309. guidName = L"GUID_IO_VOLUME_UNLOCK";
  1310. #else
  1311. return;
  1312. #endif
  1313. }
  1314. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_MOUNT) )
  1315. {
  1316. #if DBG
  1317. guidName = L"GUID_IO_VOLUME_MOUNT";
  1318. #else
  1319. return;
  1320. #endif
  1321. }
  1322. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_DISMOUNT) )
  1323. {
  1324. guidName = L"GUID_IO_VOLUME_DISMOUNT";
  1325. }
  1326. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_LOCK_FAILED) )
  1327. {
  1328. guidName = L"GUID_IO_VOLUME_LOCK_FAILED";
  1329. }
  1330. else if (IsEqualGUID(&Broadcast->dbch_eventguid, &GUID_IO_VOLUME_DISMOUNT_FAILED) )
  1331. {
  1332. guidName = L"GUID_IO_VOLUME_DISMOUNT_FAILED";
  1333. }
  1334. if (guidName) {
  1335. if (Vol) {
  1336. (DiskpLogEvent)(
  1337. RESOURCE_TYPE,
  1338. LOG_INFORMATION,
  1339. L"[PnP] Event %1!s! for %2!c! (Partition%3!d!) - %4!s! \n",
  1340. guidName, NICE_DRIVE_LETTER(Vol->DriveLetter), Vol->PartNo,
  1341. BeginEndStr );
  1342. } else {
  1343. (DiskpLogEvent)(
  1344. RESOURCE_TYPE,
  1345. LOG_INFORMATION,
  1346. L"[PnP] Event %1!s! for %2!d! - %3!s! \n",
  1347. guidName, Broadcast->dbch_hdevnotify,
  1348. BeginEndStr );
  1349. }
  1350. } else {
  1351. (DiskpLogEvent)(
  1352. RESOURCE_TYPE,
  1353. LOG_INFORMATION,
  1354. L"[PnP] Event %2!x! %3!x! %4!x! %5!x! for %1!d! - %6!s! \n",
  1355. Broadcast->dbch_hdevnotify, dw[0], dw[1], dw[2], dw[3],
  1356. BeginEndStr );
  1357. }
  1358. } // LogPnpGuid
  1359. VOID
  1360. AddVolumes()
  1361. /*++
  1362. Routine Description:
  1363. Enumerate all known volumes and register for the notifications on these volumes
  1364. Arguments:
  1365. None
  1366. Return Value:
  1367. None
  1368. --*/
  1369. {
  1370. PSP_DEVICE_INTERFACE_DETAIL_DATA pDiDetail = NULL;
  1371. DWORD dwError = ERROR_SUCCESS;
  1372. DWORD count;
  1373. DWORD sizeDiDetail;
  1374. LONG oldValue;
  1375. BOOL result;
  1376. HDEVINFO hdevInfo = INVALID_HANDLE_VALUE;
  1377. SP_DEVICE_INTERFACE_DATA devInterfaceData;
  1378. SP_DEVINFO_DATA devInfoData;
  1379. //
  1380. // If this routine is currently running, the old value will be 1. If so,
  1381. // we don't need to run again. This call will set the flag to 1 if it is 0.
  1382. //
  1383. oldValue = InterlockedCompareExchange( &VolumeListUpdateInProcess,
  1384. 1,
  1385. 0 );
  1386. if ( 1 == oldValue ) {
  1387. (DiskpLogEvent)(
  1388. RESOURCE_TYPE,
  1389. LOG_INFORMATION,
  1390. L"[PnP] AddVolumes: Volume list update in process, skipping update \n" );
  1391. goto FnExit;
  1392. }
  1393. //
  1394. // Get a device interface set which includes all volume devices
  1395. // present on the machine. VolumeClassGuid is a predefined GUID that
  1396. // will return all volume-type device interfaces
  1397. //
  1398. hdevInfo = SetupDiGetClassDevs( &VolumeClassGuid,
  1399. NULL,
  1400. NULL,
  1401. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
  1402. if ( INVALID_HANDLE_VALUE == hdevInfo ) {
  1403. dwError = GetLastError();
  1404. goto FnExit;
  1405. }
  1406. ZeroMemory( &devInterfaceData, sizeof( SP_DEVICE_INTERFACE_DATA) );
  1407. //
  1408. // Iterate over all devices interfaces in the set
  1409. //
  1410. for ( count = 0; ; count++ ) {
  1411. // must set size first
  1412. devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  1413. //
  1414. // Retrieve the device interface data for each device interface
  1415. //
  1416. result = SetupDiEnumDeviceInterfaces( hdevInfo,
  1417. NULL,
  1418. &VolumeClassGuid,
  1419. count,
  1420. &devInterfaceData );
  1421. if ( !result ) {
  1422. //
  1423. // If we retrieved the last item, break
  1424. //
  1425. dwError = GetLastError();
  1426. if ( ERROR_NO_MORE_ITEMS == dwError ) {
  1427. dwError = ERROR_SUCCESS;
  1428. break;
  1429. }
  1430. //
  1431. // Some other error occurred. Stop processing.
  1432. //
  1433. goto FnExit;
  1434. }
  1435. //
  1436. // Get the required buffer-size for the device path. Note that
  1437. // this call is expected to fail with insufficient buffer error.
  1438. //
  1439. result = SetupDiGetDeviceInterfaceDetail( hdevInfo,
  1440. &devInterfaceData,
  1441. NULL,
  1442. 0,
  1443. &sizeDiDetail,
  1444. NULL
  1445. );
  1446. if ( !result ) {
  1447. dwError = GetLastError();
  1448. //
  1449. // If a value other than "insufficient buffer" is returned,
  1450. // we have to skip this device.
  1451. //
  1452. if ( ERROR_INSUFFICIENT_BUFFER != dwError ) {
  1453. continue;
  1454. }
  1455. } else {
  1456. //
  1457. // The call should have failed since we're getting the
  1458. // required buffer size. If it doesn't fail, something bad
  1459. // happened.
  1460. //
  1461. continue;
  1462. }
  1463. //
  1464. // Allocate memory for the device interface detail.
  1465. //
  1466. pDiDetail = LocalAlloc( LPTR, sizeDiDetail );
  1467. if ( !pDiDetail ) {
  1468. dwError = GetLastError();
  1469. goto FnExit;
  1470. }
  1471. // must set the struct's size member
  1472. pDiDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  1473. devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
  1474. //
  1475. // Finally, retrieve the device interface detail info.
  1476. //
  1477. result = SetupDiGetDeviceInterfaceDetail( hdevInfo,
  1478. &devInterfaceData,
  1479. pDiDetail,
  1480. sizeDiDetail,
  1481. NULL,
  1482. &devInfoData
  1483. );
  1484. if ( !result ) {
  1485. dwError = GetLastError();
  1486. LocalFree( pDiDetail );
  1487. pDiDetail = NULL;
  1488. //
  1489. // Shouldn't fail, if it does, try the next device.
  1490. //
  1491. continue;
  1492. }
  1493. #if DBG
  1494. (DiskpLogEvent)(
  1495. RESOURCE_TYPE,
  1496. LOG_INFORMATION,
  1497. L"[PnP] AddVolumes: Found volume %1!ws! \n",
  1498. pDiDetail->DevicePath );
  1499. #endif
  1500. AddVolume( pDiDetail->DevicePath );
  1501. LocalFree( pDiDetail );
  1502. pDiDetail = NULL;
  1503. }
  1504. FnExit:
  1505. //
  1506. // If old update value was zero, then it is now 1. Reset it to
  1507. // zero so another update can take place if needed.
  1508. //
  1509. if ( 0 == oldValue ) {
  1510. InterlockedExchange( &VolumeListUpdateInProcess, 0 );
  1511. }
  1512. if ( INVALID_HANDLE_VALUE != hdevInfo ) {
  1513. SetupDiDestroyDeviceInfoList( hdevInfo );
  1514. }
  1515. if ( pDiDetail ) {
  1516. LocalFree( pDiDetail );
  1517. }
  1518. #if DBG
  1519. if ( ERROR_SUCCESS != dwError ) {
  1520. (DiskpLogEvent)(
  1521. RESOURCE_TYPE,
  1522. LOG_WARNING,
  1523. L"[PnP] AddVolumes: returns error %1!d! \n",
  1524. dwError );
  1525. }
  1526. #endif
  1527. } // AddVolumes
  1528. DWORD
  1529. GetVolumeInfo(
  1530. PVOLUME Vol,
  1531. PHANDLE FileHandle
  1532. )
  1533. /*++
  1534. Routine Description:
  1535. Get drive layout info and partition info for the specified volume.
  1536. Arguments:
  1537. Vol - Pointer to PVOLUME structure. Caller is responsible for allocating
  1538. and freeing.
  1539. FileHandle - Returned handle to volume. Caller is responsible for closing.
  1540. This parameter is optional. If not specified by the user,
  1541. the volume handle will be closed by this routine.
  1542. Return Value:
  1543. Win32 error value.
  1544. --*/
  1545. {
  1546. PARTITION_INFORMATION partInfo;
  1547. PDRIVE_LAYOUT_INFORMATION driveLayout;
  1548. DWORD status = ERROR_SUCCESS;
  1549. DWORD bytesReturned;
  1550. DWORD oldValue;
  1551. NTSTATUS ntStatus;
  1552. HANDLE hFile = NULL;
  1553. BOOL success;
  1554. //
  1555. // If no VOL parameter specified or the signature is already set,
  1556. // we don't need to update the volume information.
  1557. //
  1558. if ( !Vol || Vol->Signature ) {
  1559. return ERROR_INVALID_PARAMETER;
  1560. }
  1561. if ( FileHandle ) {
  1562. *FileHandle = INVALID_HANDLE_VALUE;
  1563. }
  1564. #if DBG
  1565. (DiskpLogEvent)(RESOURCE_TYPE, LOG_INFORMATION,
  1566. L"[PnP] GetVolumeInfo: Updating info: %1!s!\n", Vol->Name );
  1567. #endif
  1568. ntStatus = DevfileOpen(&hFile, Vol->Name);
  1569. if ( !NT_SUCCESS(ntStatus) ) {
  1570. (DiskpLogEvent)(
  1571. RESOURCE_TYPE,
  1572. LOG_ERROR,
  1573. L"[PnP] GetVolumeInfo: error opening: %1!ws!, error %2!X!.\n",
  1574. Vol->Name, ntStatus);
  1575. return RtlNtStatusToDosError(ntStatus);
  1576. }
  1577. //
  1578. // If update already in progress for this disk, skip the update.
  1579. //
  1580. oldValue = InterlockedCompareExchange( &Vol->UpdateActive,
  1581. 1,
  1582. 0 );
  1583. if ( 1 == oldValue ) {
  1584. (DiskpLogEvent)(
  1585. RESOURCE_TYPE,
  1586. LOG_WARNING,
  1587. L"[PnP] GetVolumeInfo: Skip update: %1!ws! \n",
  1588. Vol->Name);
  1589. goto FnExit;
  1590. }
  1591. success = DeviceIoControl( hFile,
  1592. IOCTL_DISK_GET_PARTITION_INFO,
  1593. NULL,
  1594. 0,
  1595. &partInfo,
  1596. sizeof(PARTITION_INFORMATION),
  1597. &bytesReturned,
  1598. FALSE );
  1599. if (!success) {
  1600. status = GetLastError();
  1601. // Change this from LOG_ERROR to LOG_WARNING. This thread gets
  1602. // notified when non-fixed disks arrive (i.e. floppy), so logging
  1603. // an error for a floppy disk is misleading.
  1604. (DiskpLogEvent)(RESOURCE_TYPE, LOG_WARNING,
  1605. L"[PnP] GetVolumeInfo: GetPartitionInfo (%1!ws!), error %2!u!\n",
  1606. Vol->Name, status);
  1607. goto FnExit;
  1608. }
  1609. Vol->PartOffset = partInfo.StartingOffset;
  1610. Vol->PartLength = partInfo.PartitionLength;
  1611. Vol->PartNo = partInfo.PartitionNumber;
  1612. Vol->PartitionType = partInfo.PartitionType;
  1613. success = ClRtlGetDriveLayoutTable(hFile, &driveLayout, 0);
  1614. if ( !success ) {
  1615. status = GetLastError();
  1616. if ( ERROR_NOT_READY != status ) {
  1617. (DiskpLogEvent)(RESOURCE_TYPE, LOG_WARNING,
  1618. L"[PnP] GetVolumeInfo: GetDriveLayout (%1!ws!), error %2!u!\n",
  1619. Vol->Name,
  1620. status );
  1621. }
  1622. goto FnExit;
  1623. }
  1624. Vol->Signature = driveLayout->Signature;
  1625. LocalFree(driveLayout);
  1626. GetAssignedLetter(Vol->Name, &Vol->DriveLetter);
  1627. FnExit:
  1628. if ( FileHandle ) {
  1629. *FileHandle = hFile;
  1630. } else {
  1631. DevfileClose( hFile );
  1632. }
  1633. //
  1634. // If old update value was zero, then it is now 1. Reset it to
  1635. // zero so another update can take place if needed.
  1636. //
  1637. if ( 0 == oldValue ) {
  1638. InterlockedExchange( &Vol->UpdateActive, 0 );
  1639. }
  1640. return status;
  1641. } // GetVolumeInfo
  1642. DWORD
  1643. NotificationWatcherThread(
  1644. IN LPVOID unused
  1645. )
  1646. /*++
  1647. Routine Description:
  1648. Creates window. Process messages until WM_QUIT is received
  1649. Arguments:
  1650. unused
  1651. Return Value:
  1652. status
  1653. --*/
  1654. {
  1655. WNDCLASSEX cl;
  1656. ATOM classAtom;
  1657. DWORD status = ERROR_SUCCESS;
  1658. static WCHAR* clsname = L"RESDLL!DISKS!MESSAGEWND";
  1659. HDEVNOTIFY devNotify = 0;
  1660. MSG msg;
  1661. try {
  1662. SetErrorMode(SEM_FAILCRITICALERRORS);
  1663. InitializeListHead( &VolumeList );
  1664. InitializeListHead( &WaitingDisks );
  1665. InitializeListHead( &WatchedList );
  1666. ZeroMemory( &cl, sizeof(cl) );
  1667. cl.cbSize = sizeof(cl);
  1668. cl.lpfnWndProc = TestWndProc;
  1669. cl.lpszClassName = clsname;
  1670. classAtom = RegisterClassEx( &cl );
  1671. if (classAtom == 0) {
  1672. status = GetLastError();
  1673. (DiskpLogEvent)(
  1674. RESOURCE_TYPE,
  1675. LOG_ERROR,
  1676. L"[PnP] Failed to register window class, error %1!u!.\n", status );
  1677. return status;
  1678. }
  1679. DummyWindow = CreateWindowEx(
  1680. 0, // extended window style
  1681. clsname, // pointer to registered class name
  1682. L"ClusterDiskPnPWatcher",// pointer to window name
  1683. 0, // window style
  1684. 0, // horizontal position of window
  1685. 0, // vertical position of window
  1686. 0, // window width
  1687. 0, // window height
  1688. HWND_MESSAGE, // handle to parent or owner window
  1689. 0, // handle to menu, or child-window identifier
  1690. 0, // handle to application instance (ignored on NT)
  1691. NULL // pointer to window-creation data
  1692. );
  1693. if (DummyWindow == 0) {
  1694. status = GetLastError();
  1695. (DiskpLogEvent)(
  1696. RESOURCE_TYPE,
  1697. LOG_ERROR,
  1698. L"[PnP] Failed to create message window, error %u.\n", status );
  1699. UnregisterClass( clsname , 0);
  1700. return status;
  1701. }
  1702. (DiskpLogEvent)(
  1703. RESOURCE_TYPE,
  1704. LOG_INFORMATION,
  1705. L"[PnP] PnP window created successfully.\n");
  1706. //
  1707. // Call AddVolumes after registering for device arrival notification.
  1708. //
  1709. status = RegisterDeviceInterface(DummyWindow, &MOUNTDEV_MOUNTED_DEVICE_GUID, &devNotify);
  1710. AddVolumes();
  1711. (DiskpLogEvent)(
  1712. RESOURCE_TYPE,
  1713. LOG_INFORMATION,
  1714. L"[PnP] PnP interface registration complete.\n");
  1715. if ( NULL != PnpInterfacesRegistered ) {
  1716. (DiskpLogEvent)(
  1717. RESOURCE_TYPE,
  1718. LOG_INFORMATION,
  1719. L"[PnP] Setting PnP interface registration event.\n");
  1720. SetEvent( PnpInterfacesRegistered );
  1721. }
  1722. if (status == ERROR_SUCCESS) {
  1723. (DiskpLogEvent)(
  1724. RESOURCE_TYPE,
  1725. LOG_INFORMATION,
  1726. L"[PnP] NotifierThread is waiting for messages.\n");
  1727. while(GetMessage(&msg, 0, 0, 0)) {
  1728. if (msg.message == WM_QUIT) {
  1729. break;
  1730. }
  1731. DispatchMessage(&msg);
  1732. }
  1733. MyUnregisterDeviceNotification( devNotify );
  1734. #if 0
  1735. (DiskpLogEvent)(
  1736. RESOURCE_TYPE,
  1737. LOG_INFORMATION,
  1738. L"[PnP] NotifierThread is shutting down.\n");
  1739. #endif
  1740. } else {
  1741. (DiskpLogEvent)(
  1742. RESOURCE_TYPE,
  1743. LOG_ERROR,
  1744. L"[PnP] Unable to register for MOUNTDEV_MOUNTED_DEVICE_GUID, error %1!u!.\n", status );
  1745. }
  1746. DestroyWindow( DummyWindow );
  1747. DummyWindow = 0;
  1748. UnregisterClass( clsname , 0 );
  1749. // Use a lock here as the online thread might be parsing the volume list.
  1750. AcquireExclusive( &PnpVolumeLock );
  1751. while ( !IsListEmpty(&VolumeList) ) {
  1752. PLIST_ENTRY listEntry;
  1753. PVOLUME vol;
  1754. listEntry = RemoveHeadList(&VolumeList);
  1755. vol = CONTAINING_RECORD( listEntry,
  1756. VOLUME,
  1757. ListEntry );
  1758. DestroyVolume(vol);
  1759. }
  1760. ReleaseExclusive( &PnpVolumeLock );
  1761. #if 0
  1762. (DiskpLogEvent)(
  1763. RESOURCE_TYPE,
  1764. LOG_ERROR,
  1765. L"[PnP] PnpThread: Volumes destroyed.\n");
  1766. #endif
  1767. } except (EXCEPTION_EXECUTE_HANDLER) {
  1768. //
  1769. // We can leave without this thread
  1770. //
  1771. status = GetExceptionCode();
  1772. (DiskpLogEvent)(
  1773. RESOURCE_TYPE,
  1774. LOG_ERROR,
  1775. L"[PnP] PnpThread: Exception caught, error %1!u!.\n", status );
  1776. }
  1777. InterlockedCompareExchange(&PnPInitialized, FALSE, TRUE);
  1778. return status;
  1779. }
  1780. VOID
  1781. ProcessMountPointChange(
  1782. HDEVNOTIFY devNotify,
  1783. DWORD Signature
  1784. )
  1785. /*++
  1786. Routine Description:
  1787. Updates mount point info in the cluster registry.
  1788. Arguments:
  1789. devNotify - Handle to the device notification.
  1790. Signature - Disk signature when a volume is being added or removed
  1791. from the system. If zero, then volume is not added
  1792. or removed.
  1793. Return Value:
  1794. None
  1795. --*/
  1796. {
  1797. PDISK_RESOURCE resourceEntry;
  1798. PVOLUME vol = 0;
  1799. DWORD diskSig = 0;
  1800. if ( !Signature ) {
  1801. //
  1802. // Get the volume for the device notification.
  1803. //
  1804. vol = FindVolume( devNotify );
  1805. if ( !vol ) {
  1806. (DiskpLogEvent)(
  1807. RESOURCE_TYPE,
  1808. LOG_INFORMATION,
  1809. L"[PnP] ProcessMountPointChange: devNotify %1!d! is not in the list \n",
  1810. devNotify );
  1811. return;
  1812. }
  1813. diskSig = vol->Signature;
  1814. } else {
  1815. diskSig = Signature;
  1816. }
  1817. //
  1818. // Search the WatchedList to find a disk that matches the signature.
  1819. // If no entry found, we are not watching this disk.
  1820. //
  1821. resourceEntry = FindDisk( diskSig );
  1822. if ( !resourceEntry ) {
  1823. (DiskpLogEvent)(
  1824. RESOURCE_TYPE,
  1825. LOG_INFORMATION,
  1826. L"[PnP] ProcessMountPointChange: Unable to get ResourceEntry for signature %1!x! \n",
  1827. diskSig );
  1828. return;
  1829. }
  1830. //
  1831. // If disk not online, don't do anything.
  1832. //
  1833. if ( !resourceEntry->Valid ) {
  1834. return;
  1835. }
  1836. //
  1837. // If a new volume is being added to or removed from the system, then
  1838. // rebuild the mountpoint list. Otherwise, just validate mountpoints.
  1839. //
  1840. if ( Signature ) {
  1841. DisksProcessMountPointInfo( resourceEntry );
  1842. } else {
  1843. DisksUpdateMPList( resourceEntry );
  1844. }
  1845. } // ProcessMountPointChange
  1846. //////////////////////////////////////////////////////////////////////////////////
  1847. DWORD
  1848. QueueWaitForVolumeEvent(
  1849. HANDLE Event,
  1850. PDISK_RESOURCE ResourceEntry
  1851. )
  1852. /*++
  1853. Routine Description:
  1854. Queues a request to watch for particular volume arrivals.
  1855. The event will be signaled only when all volumes are
  1856. available on the system.
  1857. Arguments:
  1858. Event - event to be signaled when all volumes for the specified
  1859. disk are available.
  1860. ResourceEntry - A pointer to the DISK_RESOURCE block for this resource.
  1861. Return Value:
  1862. ERROR_SUCCESS - request queued.
  1863. Win32 error on failure.
  1864. --*/
  1865. {
  1866. PWAITING_DISK waitDisk;
  1867. PMOUNTIE_VOLUME mountVol = ResourceEntry->MountieInfo.Volume;
  1868. DWORD dwError = ERROR_SUCCESS;
  1869. waitDisk = LocalAlloc( LPTR, sizeof(WAITING_DISK) );
  1870. if ( !waitDisk ) {
  1871. dwError = GetLastError();
  1872. (DiskpLogEvent)(
  1873. ResourceEntry->ResourceHandle,
  1874. LOG_ERROR,
  1875. L"[PnP] QueueWaitForVolumeEvent: can't allocate storage for disk entry. Error %1!u! \n",
  1876. dwError );
  1877. goto FnExit;
  1878. }
  1879. waitDisk->ResourceEntry = ResourceEntry;
  1880. waitDisk->Event = Event;
  1881. waitDisk->Signature = mountVol->Signature;
  1882. waitDisk->PartitionCount = mountVol->PartitionCount;
  1883. AcquireExclusive( &PnpWaitingListLock );
  1884. InsertHeadList( &WaitingDisks, &waitDisk->ListEntry );
  1885. ReleaseExclusive( &PnpWaitingListLock );
  1886. FnExit:
  1887. return dwError;
  1888. } // QueueWaitForVolumeEvent
  1889. BOOL
  1890. IsDiskInPnpVolumeList(
  1891. PDISK_RESOURCE ResourceEntry,
  1892. BOOL UpdateVolumeList
  1893. )
  1894. /*++
  1895. Routine Description:
  1896. Checks all the volumes currently known by the PnP thread and see if
  1897. all volumes for the specified disk are recognized.
  1898. Arguments:
  1899. ResourceEntry - A pointer to the DISK_RESOURCE block for this resource.
  1900. UpdateVolumeList - TRUE means call AddVolumes to make sure all volumes
  1901. are in the volume list.
  1902. Return Value:
  1903. TRUE - If all volumes for the specified disk are available on the system.
  1904. --*/
  1905. {
  1906. PLIST_ENTRY entry;
  1907. PVOLUME vol = 0;
  1908. PMOUNTIE_VOLUME mountVol = ResourceEntry->MountieInfo.Volume;
  1909. DWORD partitionCount = 0;
  1910. BOOL retVal = FALSE;
  1911. partitionCount = 0;
  1912. AcquireShared( &PnpVolumeLock );
  1913. for ( entry = VolumeList.Flink;
  1914. entry != &VolumeList;
  1915. entry = entry->Flink
  1916. )
  1917. {
  1918. vol = CONTAINING_RECORD(
  1919. entry,
  1920. VOLUME,
  1921. ListEntry
  1922. );
  1923. GetVolumeInfo( vol, NULL );
  1924. if ( vol->Signature && vol->Signature == mountVol->Signature ) {
  1925. partitionCount++;
  1926. }
  1927. }
  1928. ReleaseShared( &PnpVolumeLock );
  1929. //
  1930. // Might be some non-NTFS partitions on the disk, so if there
  1931. // are more volumes than partitions, we are good.
  1932. //
  1933. retVal = ( partitionCount >= mountVol->PartitionCount ) ? TRUE : FALSE;
  1934. //
  1935. // If we didn't find all the volumes, ask system to walk through the
  1936. // volumes again.
  1937. //
  1938. if ( !retVal && UpdateVolumeList ) {
  1939. //
  1940. // This call shouldn't be required. However, sometimes we can't
  1941. // find volumes that should be available. So we need to walk through
  1942. // the pnp list again.
  1943. //
  1944. AddVolumes();
  1945. //
  1946. // Walk the list one more time...
  1947. //
  1948. partitionCount = 0;
  1949. AcquireShared( &PnpVolumeLock );
  1950. for ( entry = VolumeList.Flink;
  1951. entry != &VolumeList;
  1952. entry = entry->Flink
  1953. )
  1954. {
  1955. vol = CONTAINING_RECORD(
  1956. entry,
  1957. VOLUME,
  1958. ListEntry
  1959. );
  1960. GetVolumeInfo( vol, NULL );
  1961. if ( vol->Signature && vol->Signature == mountVol->Signature ) {
  1962. partitionCount++;
  1963. }
  1964. }
  1965. ReleaseShared( &PnpVolumeLock );
  1966. //
  1967. // Might be some non-NTFS partitions on the disk, so if there
  1968. // are more volumes than partitions, we are good.
  1969. //
  1970. retVal = ( partitionCount >= mountVol->PartitionCount ) ? TRUE : FALSE;
  1971. }
  1972. return retVal;
  1973. } // IsDiskInPnpVolumeList
  1974. PWAITING_DISK
  1975. FindWaitingDisk(
  1976. DWORD Signature
  1977. )
  1978. /*++
  1979. Routine Description:
  1980. Find the entry in the waiting list for the specified disk
  1981. signature.
  1982. The caller will hold the critical section.
  1983. Arguments:
  1984. Signature - Disk signature of the entry to be removed.
  1985. Return Value:
  1986. Pointer to a WAITING_DISK entry for the disk.
  1987. NULL if entry not found.
  1988. --*/
  1989. {
  1990. PLIST_ENTRY entry;
  1991. PWAITING_DISK waitDisk = NULL;
  1992. if ( !Signature ) {
  1993. goto FnExit;
  1994. }
  1995. for ( entry = WaitingDisks.Flink;
  1996. entry != &WaitingDisks;
  1997. entry = entry->Flink
  1998. )
  1999. {
  2000. waitDisk = CONTAINING_RECORD( entry,
  2001. WAITING_DISK,
  2002. ListEntry
  2003. );
  2004. if ( waitDisk->Signature == Signature ) {
  2005. goto FnExit;
  2006. }
  2007. waitDisk = 0;
  2008. }
  2009. FnExit:
  2010. return waitDisk;
  2011. } // FindWaitingDisk
  2012. DWORD
  2013. RemoveWaitForVolumeEvent(
  2014. PDISK_RESOURCE ResourceEntry
  2015. )
  2016. /*++
  2017. Routine Description:
  2018. Remove from the disk waiting list the entry for the specified disk.
  2019. Arguments:
  2020. ResourceEntry - A pointer to the DISK_RESOURCE block for this resource.
  2021. Return Value:
  2022. --*/
  2023. {
  2024. PWAITING_DISK waitDisk = NULL;
  2025. PMOUNTIE_VOLUME mountVol = ResourceEntry->MountieInfo.Volume;
  2026. AcquireExclusive( &PnpWaitingListLock );
  2027. waitDisk = FindWaitingDisk( mountVol->Signature );
  2028. if ( !waitDisk ) {
  2029. #if DBG
  2030. (DiskpLogEvent)(
  2031. ResourceEntry->ResourceHandle,
  2032. LOG_INFORMATION,
  2033. L"[PnP] RemoveWaitForVolumeEvent: can't locate waiting volume in list \n" );
  2034. #endif
  2035. ReleaseExclusive( &PnpWaitingListLock );
  2036. return ERROR_INVALID_PARAMETER;
  2037. }
  2038. RemoveEntryList( &waitDisk->ListEntry );
  2039. ReleaseExclusive( &PnpWaitingListLock );
  2040. LocalFree( waitDisk );
  2041. return ERROR_SUCCESS;
  2042. } // RemoveWaitForVolumeEvent