Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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