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.

1813 lines
66 KiB

  1. #define UNICODE
  2. #define _UNICODE
  3. #include <nt.h>
  4. #include <ntrtl.h>
  5. #include <nturtl.h>
  6. #pragma warning ( disable : 4201 )
  7. #include <ntdddisk.h>
  8. #pragma warning ( default : 4201 )
  9. #include <wtypes.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <ftapi.h>
  13. #include <mountmgr.h>
  14. #pragma warning ( disable : 4201 )
  15. #include <wmium.h>
  16. #pragma warning ( default : 4201 )
  17. #include <wmiguid.h>
  18. #include <assert.h>
  19. #include "diskutil.h"
  20. #include "perfutil.h"
  21. #define HEAP_FLAGS (HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS)
  22. #define INITIAL_MOUNTMGR_BUFFER_SIZE 8192
  23. // sizes are in characters (not bytes)
  24. #define SIZE_OF_DOSDEVICES 12L // size of "\DosDevices\" string
  25. #define SIZE_OF_DEVICE 8L // size of "\Device\" string
  26. #define SIZE_OF_HARDDISK 8L // size of "Harddisk" string
  27. static const LONGLONG llDosDevicesId = 0x0073006f0044005c; // "\Dos"
  28. static const LONGLONG llFloppyName = 0x0070006f006c0046; // "Flop"
  29. static const LONGLONG llCdRomName = 0x006f005200640043; // "CdRo"
  30. LONG g_lRefreshInterval = 300; // default to 5 mins
  31. BOOL bUseNT4InstanceNames = FALSE;
  32. NTSTATUS
  33. OpenDevice(
  34. IN PUNICODE_STRING DeviceName,
  35. OUT PHANDLE Handle
  36. );
  37. NTSTATUS
  38. GetDeviceName(
  39. PMOUNTMGR_MOUNT_POINTS pMountPoints,
  40. IN PMOUNTMGR_MOUNT_POINT Point,
  41. OUT PUNICODE_STRING DeviceName
  42. );
  43. VOID
  44. RefreshVolume(
  45. PDRIVE_VOLUME_ENTRY pVolume
  46. );
  47. ULONG
  48. GetDiskExtent(
  49. IN HANDLE hVol,
  50. IN OUT PVOLUME_DISK_EXTENTS *pVolExtents,
  51. IN OUT PULONG ReturnedSize
  52. );
  53. #if DBG
  54. VOID
  55. DumpDiskList(
  56. IN PDRIVE_VOLUME_ENTRY pList,
  57. IN ULONG nCount
  58. );
  59. #endif
  60. DWORD
  61. GetDriveNumberFromDevicePath (
  62. LPCWSTR szDevicePath,
  63. LPDWORD pdwDriveId
  64. )
  65. /*
  66. evaluates the device path and returns the Drive Number
  67. if the string is in the following format
  68. \Device\HarddiskX
  69. where X is a decimal number (consisting of 1 or more decimal
  70. digits representing a value between 0 and 65535 inclusive)
  71. The function returns a value of:
  72. ERROR_SUCCESS if successful
  73. ERROR_INVALID_PARAMETER if the input string is incorrectly formatted
  74. ERROR_INVALID_DATA if the volume number is too big
  75. */
  76. {
  77. PWCHAR pNumberChar;
  78. LONG lValue;
  79. DWORD dwDriveAndPartition;
  80. DWORD dwReturn;
  81. DWORD dwRetry = 4;
  82. // validate the input arguments
  83. assert (szDevicePath != NULL);
  84. assert (*szDevicePath != 0);
  85. assert (pdwDriveId != NULL);
  86. // start at the beginning of the string
  87. pNumberChar = (PWCHAR)szDevicePath;
  88. // make sure it starts with a backslash. if not then
  89. // try the next 4 characters to see if there's some garbage
  90. // in front of the string.
  91. while (*pNumberChar != L'\\') {
  92. --dwRetry;
  93. if (dwRetry) {
  94. pNumberChar++;
  95. } else {
  96. break;
  97. }
  98. }
  99. if (*pNumberChar == L'\\') {
  100. // and go to the end of the Device string to see
  101. // if this is a harddisk path
  102. pNumberChar += SIZE_OF_DEVICE;
  103. if (*pNumberChar == L'H') {
  104. // this is a volume Entry so go to the number
  105. pNumberChar += SIZE_OF_HARDDISK;
  106. lValue = _wtol(pNumberChar);
  107. if (lValue <= (LONG)0x0000FFFF) {
  108. // load the drive number into the DWORD
  109. dwDriveAndPartition = (DWORD)lValue;
  110. *pdwDriveId = dwDriveAndPartition;
  111. dwReturn = ERROR_SUCCESS;
  112. } else {
  113. // drive ID Is out of range
  114. dwReturn = ERROR_INVALID_DATA;
  115. }
  116. } else {
  117. // not a valid path
  118. dwReturn = ERROR_INVALID_PARAMETER;
  119. }
  120. } else {
  121. dwReturn = ERROR_INVALID_PARAMETER;
  122. }
  123. return dwReturn;
  124. }
  125. DWORD
  126. GetSymbolicLink (
  127. LPCWSTR szDeviceString,
  128. LPWSTR szLinkString,
  129. LPDWORD pcchLength
  130. )
  131. /*
  132. this functions opens the device string as a symbolic link
  133. and returns the corresponding link string
  134. */
  135. {
  136. OBJECT_ATTRIBUTES Attributes;
  137. UNICODE_STRING ObjectName;
  138. UNICODE_STRING LinkName;
  139. WORD wDevStrLen;
  140. NTSTATUS ntStatus;
  141. DWORD dwRetSize = 0;
  142. DWORD dwReturnStatus;
  143. HANDLE hObject = NULL;
  144. // validate arguments
  145. assert (szDeviceString != NULL);
  146. assert (*szDeviceString != 0);
  147. assert (szLinkString != NULL);
  148. assert (pcchLength != NULL);
  149. assert (*pcchLength > 0);
  150. // get the length of the input string
  151. wDevStrLen = (WORD)lstrlenW(szDeviceString);
  152. // create the object name UNICODE string structure
  153. ObjectName.Length = (WORD)(wDevStrLen * sizeof (WCHAR));
  154. ObjectName.MaximumLength = (WORD)((wDevStrLen + 1) * sizeof (WCHAR));
  155. ObjectName.Buffer = (LPWSTR)szDeviceString;
  156. // initialize the object attributes for the open call
  157. InitializeObjectAttributes( &Attributes,
  158. &ObjectName,
  159. OBJ_CASE_INSENSITIVE,
  160. NULL,
  161. NULL );
  162. // open the name as a symbolic link, if this fails, the input
  163. // name is probably not a link
  164. ntStatus = NtOpenSymbolicLinkObject(
  165. &hObject,
  166. SYMBOLIC_LINK_QUERY,
  167. &Attributes);
  168. if (NT_SUCCESS(ntStatus)) {
  169. // init a Unicode String for the return buffer using the caller's
  170. // buffer
  171. LinkName.Length = 0;
  172. LinkName.MaximumLength = (WORD)(*pcchLength * sizeof (WCHAR));
  173. LinkName.Buffer = szLinkString;
  174. RtlZeroMemory(LinkName.Buffer, LinkName.MaximumLength);
  175. // and look up the link
  176. ntStatus = NtQuerySymbolicLinkObject(
  177. hObject, &LinkName, &dwRetSize);
  178. if (NT_SUCCESS(ntStatus)) {
  179. // buffer is loaded so set the return status and length
  180. *pcchLength = LinkName.Length / sizeof (WCHAR);
  181. // make sure the string is 0 terminated
  182. szLinkString[*pcchLength] = 0;
  183. dwReturnStatus = ERROR_SUCCESS;
  184. } else {
  185. // unable to look up the link so return the error
  186. dwReturnStatus = RtlNtStatusToDosError(ntStatus);
  187. }
  188. // close the handle to the link
  189. NtClose (hObject);
  190. } else {
  191. dwReturnStatus = RtlNtStatusToDosError(ntStatus);
  192. }
  193. return dwReturnStatus;
  194. }
  195. LONG
  196. LookupInstanceName(
  197. LPCWSTR szName,
  198. PDRIVE_VOLUME_ENTRY pList,
  199. DWORD dwNumEntries,
  200. DWORD dwRetry
  201. )
  202. {
  203. LONG i, j;
  204. j = (LONG) dwRetry;
  205. for (i=(LONG) dwNumEntries; i>=0 && j>=0; i--, j--) {
  206. if (!lstrcmp(pList[i].wszInstanceName, szName))
  207. return (DWORD) i;
  208. }
  209. return -1;
  210. }
  211. DWORD
  212. BuildPhysDiskList (
  213. HANDLE hDiskPerf,
  214. PDRIVE_VOLUME_ENTRY pList,
  215. LPDWORD pdwNumEntries
  216. )
  217. {
  218. DWORD status = ERROR_SUCCESS; // return value of the function
  219. HANDLE hWmiDiskPerf = NULL; // local handle value
  220. DWORD dwLocalWmiItemCount = 0;
  221. // WMI Buffer variables
  222. DWORD WmiBufSize = 0;
  223. DWORD WmiAllocSize = 0x8000;
  224. LPBYTE WmiBuffer = NULL;
  225. // WMI buffer processing variables
  226. PWNODE_ALL_DATA WmiDiskInfo;
  227. DISK_PERFORMANCE *pDiskPerformance; // Disk driver returns counters here
  228. DWORD dwInstanceNameOffset;
  229. WORD wNameLen; // string length is first word in buffer
  230. LPWSTR wszInstanceName; // pointer to string in WMI buffer
  231. WCHAR wszInstName[MAX_PATH];
  232. DWORD dwBytesToCopy;
  233. DWORD dwListEntry;
  234. BOOL bNotDone = TRUE;
  235. DWORD dwLocalStatus;
  236. DWORD dwLocalDriveId;
  237. DWORD dwLocalPartition;
  238. WCHAR szDrivePartString[MAX_PATH];
  239. DWORD dwSymbLinkLen;
  240. WCHAR szSymbLinkString[MAX_PATH];
  241. if (hDiskPerf == NULL) {
  242. // open handle to disk perf device driver
  243. status = WmiOpenBlock (
  244. (GUID *)&DiskPerfGuid,
  245. GENERIC_READ,
  246. &hWmiDiskPerf);
  247. } else {
  248. // use caller's handle
  249. hWmiDiskPerf = hDiskPerf;
  250. }
  251. assert (pList != NULL);
  252. assert (pdwNumEntries != NULL);
  253. DebugPrint((3, "BuildPhysDisk: dwEntries is %d\n", *pdwNumEntries));
  254. dwListEntry = 0;
  255. if (status == ERROR_SUCCESS) {
  256. // allocate a buffer to send to WMI to get the diskperf data
  257. WmiBufSize = WmiAllocSize;
  258. WmiBuffer = (LPBYTE)ALLOCMEM (hLibHeap, HEAP_FLAGS, WmiBufSize);
  259. if (WmiBuffer == NULL) {
  260. status = ERROR_OUTOFMEMORY;
  261. } else {
  262. #if DBG
  263. HeapUsed += WmiBufSize;
  264. DebugPrint((4,"\tWmiBuffer add %d to %d\n", WmiBufSize, HeapUsed));
  265. #endif
  266. status = WmiQueryAllDataW (
  267. hWmiDiskPerf,
  268. &WmiBufSize,
  269. WmiBuffer);
  270. DebugPrint((2,
  271. "BuildPhysDisk: WmiQueryAllDataW status1=%d\n",
  272. status));
  273. #if DBG
  274. if (!HeapValidate(hLibHeap, 0, WmiBuffer)) {
  275. DebugPrint((2,
  276. "BuildPhysDisk: WmiQueryAllDataW corrupted WmiBuffer\n"));
  277. DbgBreakPoint();
  278. }
  279. #endif
  280. // if buffer size attempted is too big or too small, resize
  281. if ((WmiBufSize > 0) && (WmiBufSize != WmiAllocSize)) {
  282. WmiBuffer = (LPBYTE)REALLOCMEM (hLibHeap, HEAP_FLAGS, WmiBuffer, WmiBufSize);
  283. if (WmiBuffer == NULL) {
  284. // reallocation failed so bail out
  285. status = ERROR_OUTOFMEMORY;
  286. } else {
  287. #if DBG
  288. HeapUsed += (WmiBufSize - WmiAllocSize);
  289. DebugPrint((4, "\tRealloc WmiBuffer old %d new %d to %d\n",
  290. WmiAllocSize, WmiBufSize, HeapUsed));
  291. WmiAllocSize = WmiBufSize;
  292. if (!HeapValidate(hLibHeap, 0, WmiBuffer)) {
  293. DebugPrint((2, "\tHeapReAlloc is corrupted!\n"));
  294. DbgBreakPoint();
  295. }
  296. #endif
  297. }
  298. }
  299. if (status == ERROR_INSUFFICIENT_BUFFER) {
  300. // if it didn't work because it was too small the first time
  301. // try one more time
  302. status = WmiQueryAllDataW (
  303. hWmiDiskPerf,
  304. &WmiBufSize,
  305. WmiBuffer);
  306. #if DBG
  307. if (!HeapValidate(hLibHeap, 0, WmiBuffer)) {
  308. DebugPrint((2,
  309. "BuildPhysDisk: WmiQueryAllDataW2 corrupted WmiBuffer\n"));
  310. DbgBreakPoint();
  311. }
  312. #endif
  313. DebugPrint((2,
  314. "BuildPhysDisk: WmiQueryAllDataW status2=%d\n",
  315. status));
  316. } else {
  317. // it either worked the fisrt time or it failed because of
  318. // something other than a buffer size problem
  319. }
  320. }
  321. if (status == ERROR_SUCCESS) {
  322. WmiDiskInfo = (PWNODE_ALL_DATA)WmiBuffer;
  323. // go through returned names and add to the buffer
  324. while (bNotDone) {
  325. #if DBG
  326. if ((PCHAR) WmiDiskInfo > (PCHAR) WmiBuffer + WmiAllocSize) {
  327. DebugPrint((2,
  328. "BuildPhysDisk: WmiDiskInfo %d exceeded %d + %d\n",
  329. WmiDiskInfo, WmiBuffer, WmiAllocSize));
  330. }
  331. #endif
  332. pDiskPerformance = (PDISK_PERFORMANCE)(
  333. (PUCHAR)WmiDiskInfo + WmiDiskInfo->DataBlockOffset);
  334. #if DBG
  335. if ((PCHAR) pDiskPerformance > (PCHAR) WmiBuffer + WmiAllocSize) {
  336. DebugPrint((2,
  337. "BuildPhysDisk: pDiskPerformance %d exceeded %d + %d\n",
  338. pDiskPerformance, WmiBuffer, WmiAllocSize));
  339. }
  340. #endif
  341. dwInstanceNameOffset = WmiDiskInfo->DataBlockOffset +
  342. ((sizeof(DISK_PERFORMANCE) + 1) & ~1) ;
  343. #if DBG
  344. if ((dwInstanceNameOffset+(PCHAR)WmiDiskInfo) > (PCHAR) WmiBuffer + WmiAllocSize) {
  345. DebugPrint((2,
  346. "BuildPhysDisk: dwInstanceNameOffset %d exceeded %d + %d\n",
  347. dwInstanceNameOffset, WmiBuffer, WmiAllocSize));
  348. }
  349. #endif
  350. // get length of string (it's a counted string) length is in chars
  351. wNameLen = *(LPWORD)((LPBYTE)WmiDiskInfo + dwInstanceNameOffset);
  352. #if DBG
  353. if ((wNameLen + (PCHAR)WmiDiskInfo + dwInstanceNameOffset) >
  354. (PCHAR) WmiBuffer + WmiAllocSize) {
  355. DebugPrint((2,
  356. "BuildPhysDisk: wNameLen %d exceeded %d + %d\n",
  357. wNameLen, WmiBuffer, WmiAllocSize));
  358. }
  359. #endif
  360. if (wNameLen > 0) {
  361. // just a sanity check here
  362. assert (wNameLen < MAX_PATH);
  363. // get pointer to string text
  364. wszInstanceName = (LPWSTR)((LPBYTE)WmiDiskInfo + dwInstanceNameOffset + sizeof(WORD));
  365. // truncate to last characters if name is larger than the buffer in the table
  366. if (wNameLen >= DVE_DEV_NAME_LEN) {
  367. // copy the last DVE_DEV_NAME_LEN chars
  368. wszInstanceName += (wNameLen - DVE_DEV_NAME_LEN) + 1;
  369. dwBytesToCopy = (DVE_DEV_NAME_LEN - 1) * sizeof(WCHAR);
  370. wNameLen = DVE_DEV_NAME_LEN - 1;
  371. } else {
  372. dwBytesToCopy = wNameLen;
  373. }
  374. // copy it to the buffer to make it a SZ string
  375. memcpy (wszInstName, &wszInstanceName[0], dwBytesToCopy);
  376. // zero terminate it
  377. wszInstName[wNameLen/sizeof(WCHAR)] = 0;
  378. DebugPrint((2, "Checking PhysDisk: '%ws'\n",
  379. wszInstName));
  380. if (IsPhysicalDrive(pDiskPerformance)) {
  381. // enum partitions
  382. dwLocalDriveId = 0;
  383. dwLocalStatus = GetDriveNumberFromDevicePath (wszInstName, &dwLocalDriveId);
  384. if (dwLocalStatus == ERROR_SUCCESS) {
  385. // then take the drive ID and find all the matching partitions with logical
  386. // drives
  387. for (dwLocalPartition = 0;
  388. dwLocalPartition <= 0xFFFF;
  389. dwLocalPartition++) {
  390. swprintf (szDrivePartString, L"\\Device\\Harddisk%d\\Partition%d",
  391. dwLocalDriveId, dwLocalPartition);
  392. dwSymbLinkLen = sizeof (szSymbLinkString) / sizeof(szSymbLinkString[0]);
  393. dwLocalStatus = GetSymbolicLink (szDrivePartString,
  394. szSymbLinkString, &dwSymbLinkLen);
  395. if (dwLocalStatus == ERROR_SUCCESS) {
  396. if (dwListEntry < *pdwNumEntries) {
  397. if (LookupInstanceName(
  398. szSymbLinkString,
  399. pList,
  400. dwListEntry,
  401. dwLocalPartition) >= 0) {
  402. dwListEntry++;
  403. continue;
  404. }
  405. DebugPrint((2,
  406. "Adding Partition: '%ws' as '%ws'\n",
  407. szDrivePartString, szSymbLinkString));
  408. pList[dwListEntry].wPartNo = (WORD)dwLocalPartition;
  409. pList[dwListEntry].wDriveNo = (WORD)dwLocalDriveId;
  410. pList[dwListEntry].wcDriveLetter = 0;
  411. pList[dwListEntry].wReserved = 0;
  412. memcpy (&pList[dwListEntry].szVolumeManager,
  413. pDiskPerformance->StorageManagerName,
  414. sizeof(pDiskPerformance->StorageManagerName));
  415. pList[dwListEntry].dwVolumeNumber = pDiskPerformance->StorageDeviceNumber;
  416. pList[dwListEntry].hVolume = NULL;
  417. memset (&pList[dwListEntry].wszInstanceName[0],
  418. 0, (DVE_DEV_NAME_LEN * sizeof(WCHAR)));
  419. if (dwSymbLinkLen < DVE_DEV_NAME_LEN) {
  420. lstrcpyW (&pList[dwListEntry].wszInstanceName[0],
  421. szSymbLinkString);
  422. } else {
  423. memcpy (&pList[dwListEntry].wszInstanceName[0],
  424. szSymbLinkString, DVE_DEV_NAME_LEN * sizeof(WCHAR));
  425. pList[dwListEntry].wszInstanceName[DVE_DEV_NAME_LEN-1] = 0;
  426. }
  427. } else {
  428. status = ERROR_INSUFFICIENT_BUFFER;
  429. }
  430. dwListEntry++;
  431. } else {
  432. // that's it for this disk
  433. break;
  434. }
  435. } // end of partition search
  436. } // else unable to get the harddisk number from the path
  437. } else {
  438. // not a physical drive so ignore
  439. }
  440. // count the number of entries
  441. dwLocalWmiItemCount++;
  442. } else {
  443. // no string to examine (length == 0)
  444. }
  445. // bump pointers inside WMI data block
  446. if (WmiDiskInfo->WnodeHeader.Linkage != 0) {
  447. // continue
  448. WmiDiskInfo = (PWNODE_ALL_DATA) (
  449. (LPBYTE)WmiDiskInfo + WmiDiskInfo->WnodeHeader.Linkage);
  450. } else {
  451. bNotDone = FALSE;
  452. }
  453. } // end while looking through the WMI data block
  454. }
  455. if (hDiskPerf == NULL) {
  456. // then the disk perf handle is local so close it
  457. status = WmiCloseBlock (hWmiDiskPerf);
  458. }
  459. }
  460. if (WmiBuffer != NULL) {
  461. FREEMEM(hLibHeap, 0, WmiBuffer);
  462. #if DBG
  463. HeapUsed -= WmiBufSize;
  464. DebugPrint((4, "\tFreed WmiBuffer %d to %d\n", WmiBufSize, HeapUsed));
  465. #endif
  466. }
  467. #if DBG
  468. DumpDiskList(pList, *pdwNumEntries);
  469. #endif
  470. *pdwNumEntries = dwListEntry;
  471. DebugPrint((3,"BuildPhysDisk: Returning dwNumEntries=%d\n",*pdwNumEntries));
  472. return status;
  473. }
  474. DWORD
  475. BuildVolumeList (
  476. PDRIVE_VOLUME_ENTRY pList,
  477. LPDWORD pdwNumEntries
  478. )
  479. /*
  480. Using the Mount manager, this function builds a list of all mounted
  481. hard drive volumes (CD, Floppy & other types of disks are ignored).
  482. The calling function must pass in a buffer and indicate the maximum
  483. number of entries in the buffer. If successful, the buffer contains
  484. one entry for each disk volume found and the number of entries used
  485. is returned
  486. pList IN: pointer to a buffer that will receive the entries
  487. OUT: buffer containing disk entries
  488. pdwNumEntries IN: pointer to DWORD that specifies the max # of entries
  489. in the buffer referenced by pList
  490. OUT: pointer to DWORD that contains the number of entries
  491. written into the buffer referenced by pList
  492. pdwMaxVolume IN: ignored
  493. OUT: the max volume ID returned by the mount manager
  494. The function can return one of the following return values:
  495. ERROR_SUCCESS if successful
  496. If unsuccessful:
  497. an error returned by
  498. */
  499. {
  500. DWORD dwReturnValue = ERROR_SUCCESS; // return value of function
  501. HANDLE hMountMgr; // handle to mount manger service
  502. // mount manager function variables
  503. PMOUNTMGR_MOUNT_POINTS pMountPoints = NULL;
  504. MOUNTMGR_MOUNT_POINT mountPoint;
  505. DWORD dwBufferSize = 0;
  506. DWORD dwReturnSize;
  507. BOOL bStatus;
  508. // processing loop functions
  509. LONG nListEntry; // entry in caller's buffer
  510. DWORD dwBufEntry; // entry in mount manager buffer
  511. PMOUNTMGR_MOUNT_POINT point; // the current entry
  512. PWCHAR pDriveLetter;
  513. DWORD dwDone;
  514. NTSTATUS status;
  515. LPWSTR pThisChar;
  516. LPWSTR szDeviceName;
  517. DWORD dwBytesToCopy;
  518. BOOL bNeedMoreData = TRUE;
  519. DWORD dwRetryCount = 100;
  520. UINT dwOrigErrorMode;
  521. BOOL bIsHardDisk;
  522. LONG nExistingEntry = -1;
  523. LONG nOldListEntry = -1;
  524. // pList can be NULL for size queries
  525. assert (pdwNumEntries != NULL);
  526. DebugPrint((3, "BuildVolumeList: Building %d entries\n", *pdwNumEntries));
  527. hMountMgr = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, 0,
  528. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  529. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  530. INVALID_HANDLE_VALUE);
  531. if (hMountMgr == INVALID_HANDLE_VALUE) {
  532. dwReturnValue = GetLastError();
  533. DebugPrint((2,
  534. "VolumeList: Mount Manager connection returned %d\n",
  535. dwReturnValue));
  536. goto BVL_ERROR_EXIT;
  537. }
  538. while ((bNeedMoreData) && (dwRetryCount)) {
  539. dwBufferSize += INITIAL_MOUNTMGR_BUFFER_SIZE;
  540. if (pMountPoints != NULL) {
  541. FREEMEM(hLibHeap, HEAP_FLAGS, pMountPoints);
  542. pMountPoints = NULL;
  543. #if DBG
  544. HeapUsed -= dwBufferSize;
  545. DebugPrint((4,
  546. "\tFreed MountPoints %d to %d\n", dwBufferSize, HeapUsed));
  547. #endif
  548. }
  549. pMountPoints = (PMOUNTMGR_MOUNT_POINTS) ALLOCMEM (
  550. hLibHeap, HEAP_FLAGS, dwBufferSize);
  551. if (pMountPoints == NULL) {
  552. dwReturnValue = ERROR_OUTOFMEMORY;
  553. DebugPrint((2, "VolumeList: Buffer Alloc failed\n"));
  554. goto BVL_ERROR_EXIT;
  555. }
  556. #if DBG
  557. HeapUsed += dwBufferSize;
  558. DebugPrint((4,
  559. "\tAdded MountPoints %d to %d\n", dwBufferSize, HeapUsed));
  560. #endif
  561. dwReturnSize = 0;
  562. memset(&mountPoint, 0, sizeof(MOUNTMGR_MOUNT_POINT));
  563. bStatus = DeviceIoControl(hMountMgr,
  564. IOCTL_MOUNTMGR_QUERY_POINTS,
  565. &mountPoint, sizeof(MOUNTMGR_MOUNT_POINT),
  566. pMountPoints, dwBufferSize,
  567. &dwReturnSize, NULL);
  568. if (!bStatus) {
  569. dwReturnValue = GetLastError();
  570. if (dwReturnValue != ERROR_MORE_DATA) {
  571. DebugPrint((2,
  572. "VolumeList: Mount Manager IOCTL returned %d\n",
  573. dwReturnValue));
  574. goto BVL_ERROR_EXIT;
  575. } else {
  576. // we need a bigger buffer so try again
  577. dwReturnValue = ERROR_SUCCESS;
  578. }
  579. dwRetryCount--;
  580. } else {
  581. // everything worked so leave the loop
  582. bNeedMoreData = FALSE;
  583. }
  584. }
  585. if (!dwRetryCount) {
  586. // then we gave up trying to get a big enough buffer so return an error
  587. dwReturnValue = ERROR_MORE_DATA;
  588. } else {
  589. // see if there's room in the caller's buffer for this data
  590. // **note that even though not all mounted drives will be returned
  591. // this is an easy and fast, if overstated, check
  592. // load size for caller to know required buffer size
  593. DebugPrint((2,
  594. "VolumeList: Mount Manager returned %d Volume entries\n",
  595. pMountPoints->NumberOfMountPoints));
  596. if (pMountPoints->NumberOfMountPoints > *pdwNumEntries) {
  597. *pdwNumEntries = (DWORD)pMountPoints->NumberOfMountPoints;
  598. if (pList != NULL) {
  599. // they passed in a buffer that wasn't big enough
  600. dwReturnValue = ERROR_INSUFFICIENT_BUFFER;
  601. } else {
  602. // they just wanted to know the size
  603. dwReturnValue = ERROR_SUCCESS;
  604. }
  605. goto BVL_ERROR_EXIT;
  606. }
  607. // assume there's room in the buffer now
  608. // load the caller's buffer
  609. dwOrigErrorMode = SetErrorMode (
  610. SEM_FAILCRITICALERRORS |
  611. SEM_NOALIGNMENTFAULTEXCEPT |
  612. SEM_NOGPFAULTERRORBOX |
  613. SEM_NOOPENFILEERRORBOX);
  614. for (dwBufEntry=0, nListEntry = 0;
  615. dwBufEntry < pMountPoints->NumberOfMountPoints;
  616. dwBufEntry++) {
  617. point = &pMountPoints->MountPoints[dwBufEntry];
  618. // there are 2 steps to complete to know this is a good
  619. // entry for the caller. so set the count to 2 and decrement
  620. // it as the steps are successful.
  621. dwDone = 2;
  622. bIsHardDisk = TRUE;
  623. pList[nListEntry].hVolume = NULL;
  624. pList[nListEntry].dwVolumeNumber = 0;
  625. memset(&pList[nListEntry].DeviceName, 0, sizeof(UNICODE_STRING));
  626. pList[nListEntry].TotalBytes = 0;
  627. pList[nListEntry].FreeBytes = 0;
  628. nExistingEntry = -1;
  629. nOldListEntry = -1;
  630. if (point->DeviceNameLength) {
  631. UNALIGNED LONGLONG *pSig;
  632. WCHAR wszInstanceName[DVE_DEV_NAME_LEN+1];
  633. // device name is in bytes
  634. pList[nListEntry].dwVolumeNumber = 0;
  635. szDeviceName = (LPWSTR)((PCHAR) pMountPoints + point->DeviceNameOffset);
  636. if ((DWORD)point->DeviceNameLength >= (DVE_DEV_NAME_LEN * sizeof(WCHAR))) {
  637. // copy the last DVE_DEV_NAME_LEN chars
  638. szDeviceName += ((DWORD)point->DeviceNameLength - DVE_DEV_NAME_LEN) + 1;
  639. dwBytesToCopy = (DVE_DEV_NAME_LEN - 1) * sizeof(WCHAR);
  640. } else {
  641. dwBytesToCopy = (DWORD)point->DeviceNameLength;
  642. }
  643. memcpy(wszInstanceName, szDeviceName, dwBytesToCopy);
  644. // null terminate
  645. assert ((dwBytesToCopy / sizeof(WCHAR)) < DVE_DEV_NAME_LEN);
  646. wszInstanceName[dwBytesToCopy / sizeof(WCHAR)] = 0;
  647. // Lookup an existing instance in the list and reset nListEntry accordingly.
  648. // Save the current value of nListEntry so that we can restore the indexing through the pList.
  649. if (nListEntry > 0)
  650. {
  651. nExistingEntry = LookupInstanceName(wszInstanceName,
  652. pList, nListEntry, nListEntry);
  653. // Found it!
  654. if (nExistingEntry != -1)
  655. {
  656. // If a drive letter has already been added for the volume, skip any further processing here.
  657. // We've already processed this volume and we don't need to process it again. This is done
  658. // because mount manager returns the same volume twice: once for the drive letter, once for
  659. // the unique volume name. Skip ahead but don't increment nListEntry.
  660. if ((pList[nExistingEntry].wcDriveLetter >= L'A') && (pList[nExistingEntry].wcDriveLetter <= L'Z')) {
  661. continue;
  662. }
  663. // If the drive letter field has not already been set, then close the volume handle which will
  664. // be reset to a value later on in the loop.
  665. nOldListEntry = nListEntry;
  666. nListEntry = nExistingEntry;
  667. CloseHandle(pList[nListEntry].hVolume);
  668. pList[nListEntry].hVolume = NULL;
  669. }
  670. }
  671. memcpy (pList[nListEntry].wszInstanceName, wszInstanceName, dwBytesToCopy + 1);
  672. DebugPrint((4, "MNT_PT %d: Device %d %ws\n",
  673. dwBufEntry, nListEntry, pList[nListEntry].wszInstanceName));
  674. pSig = (UNALIGNED LONGLONG *)&(pList[nListEntry].wszInstanceName[SIZE_OF_DEVICE]);
  675. if ((*pSig == llFloppyName) || (*pSig == llCdRomName)) {
  676. // this to avoid opening drives that we won't be collecting data from
  677. bIsHardDisk = FALSE;
  678. }
  679. dwDone--;
  680. }
  681. if (point->SymbolicLinkNameLength) {
  682. PWCHAR szDeviceName = NULL;
  683. pDriveLetter = (PWCHAR)((PCHAR)pMountPoints + point->SymbolicLinkNameOffset);
  684. // make sure this is a \DosDevices path
  685. DebugPrint((4, "BuildVolumeList: From Symbolic %d %ws\n", nListEntry, pDriveLetter));
  686. if (*(UNALIGNED LONGLONG *)pDriveLetter == llDosDevicesId) {
  687. pDriveLetter += SIZE_OF_DOSDEVICES;
  688. if (((*pDriveLetter >= L'A') && (*pDriveLetter <= L'Z')) ||
  689. ((*pDriveLetter >= L'a') && (*pDriveLetter <= L'z'))) {
  690. pList[nListEntry].wcDriveLetter = towupper(*pDriveLetter);
  691. if (bIsHardDisk) {
  692. status = GetDeviceName(
  693. pMountPoints, point,
  694. &pList[nListEntry].DeviceName);
  695. if (!NT_SUCCESS(status)) {
  696. dwReturnValue = RtlNtStatusToDosError(status);
  697. }
  698. }
  699. dwDone--;
  700. }
  701. } else if (bIsHardDisk) {
  702. WCHAR szTempPath[MAX_PATH+1];
  703. pThisChar = (PWCHAR)((PCHAR) pMountPoints + point->SymbolicLinkNameOffset);
  704. memcpy (szTempPath, pThisChar, point->SymbolicLinkNameLength);
  705. pThisChar = &szTempPath[point->SymbolicLinkNameLength / sizeof(WCHAR)];
  706. *pThisChar++ = L'\\';
  707. *pThisChar = 0;
  708. DebugPrint((4, "BuildVolumeList: From HardDisk %d %ws\n", nListEntry, pThisChar));
  709. if (wcsstr(szTempPath, L"DosDevices") == NULL)
  710. {
  711. pList[nListEntry].wcDriveLetter = L'\0';
  712. status = GetDeviceName(
  713. pMountPoints, point,
  714. &pList[nListEntry].DeviceName);
  715. if (!NT_SUCCESS(status)) {
  716. dwReturnValue = RtlNtStatusToDosError(status);
  717. }
  718. dwDone--;
  719. }
  720. }
  721. }
  722. if (nOldListEntry != -1)
  723. {
  724. nListEntry = nOldListEntry;
  725. }
  726. if (dwDone == 0) {
  727. DebugPrint((4,
  728. "Perfdisk!BuildVolumeList - Added %ws as drive %c\n",
  729. pList[nListEntry].wszInstanceName,
  730. pList[nListEntry].wcDriveLetter));
  731. // then the data fields have been satisfied so
  732. // this entry is done and we can now go
  733. // to the next entry in the caller's buffer
  734. if (nOldListEntry == -1) {
  735. nListEntry++;
  736. }
  737. }
  738. }
  739. SetErrorMode (dwOrigErrorMode);
  740. // return the number of entries actually used here
  741. *pdwNumEntries = nListEntry;
  742. }
  743. BVL_ERROR_EXIT:
  744. CloseHandle(hMountMgr);
  745. if (pMountPoints != NULL) {
  746. FREEMEM (hLibHeap, 0, pMountPoints);
  747. #if DBG
  748. DebugPrint((4,
  749. "\tFreed mountpoints %d to %d\n", dwBufferSize, HeapUsed));
  750. dwBufferSize = 0;
  751. #endif
  752. }
  753. DebugPrint((3, "BuildVolumeList: returning with %d entries\n", *pdwNumEntries));
  754. return dwReturnValue;
  755. }
  756. DWORD
  757. MapLoadedDisks (
  758. HANDLE hDiskPerf,
  759. PDRIVE_VOLUME_ENTRY pList,
  760. LPDWORD pdwNumEntries,
  761. LPDWORD pdwMaxVolNo,
  762. LPDWORD pdwWmiItemCount
  763. )
  764. /*
  765. This function maps the hard disk partitions to the corresponding
  766. volume and drive letter found in the list of volume entries
  767. passed in by the caller.
  768. This function can use a handle to WMI if the caller has one, or if
  769. not, it will try to open it's own.
  770. */
  771. {
  772. DWORD status = ERROR_SUCCESS; // return value of the function
  773. HANDLE hWmiDiskPerf = NULL; // local handle value
  774. DWORD dwLocalMaxVolNo = 0;
  775. DWORD dwLocalWmiItemCount = 0;
  776. // WMI Buffer variables
  777. DWORD WmiBufSize = 0;
  778. DWORD WmiAllocSize = 0x8000;
  779. LPBYTE WmiBuffer = NULL;
  780. // WMI buffer processing variables
  781. PWNODE_ALL_DATA WmiDiskInfo;
  782. DISK_PERFORMANCE *pDiskPerformance; // Disk driver returns counters here
  783. DWORD dwInstanceNameOffset;
  784. WORD wNameLen; // string length is first word in buffer
  785. LPWSTR wszInstanceName; // pointer to string in WMI buffer
  786. WCHAR wszInstName[MAX_PATH];
  787. DWORD dwBytesToCopy;
  788. DWORD dwListEntry;
  789. BOOL bNotDone = TRUE;
  790. if (hDiskPerf == NULL) {
  791. // open handle to disk perf device driver
  792. status = WmiOpenBlock (
  793. (GUID *)&DiskPerfGuid,
  794. GENERIC_READ,
  795. &hWmiDiskPerf);
  796. } else {
  797. // use caller's handle
  798. hWmiDiskPerf = hDiskPerf;
  799. }
  800. assert (pList != NULL);
  801. assert (pdwNumEntries != NULL);
  802. assert (pdwMaxVolNo != NULL);
  803. DebugPrint((3, "MapLoadedDisks with %d entries %d volumes",
  804. *pdwNumEntries, *pdwMaxVolNo));
  805. if (status == ERROR_SUCCESS) {
  806. // allocate a buffer to send to WMI to get the diskperf data
  807. WmiBufSize = WmiAllocSize;
  808. WmiBuffer = (LPBYTE)ALLOCMEM (hLibHeap, HEAP_FLAGS, WmiBufSize);
  809. if (WmiBuffer == NULL) {
  810. status = ERROR_OUTOFMEMORY;
  811. } else {
  812. #if DBG
  813. HeapUsed += WmiBufSize;
  814. DebugPrint((4,"\tWmiBuffer add %d to %d\n", WmiBufSize, HeapUsed));
  815. #endif
  816. status = WmiQueryAllDataW (
  817. hWmiDiskPerf,
  818. &WmiBufSize,
  819. WmiBuffer);
  820. // if buffer size attempted is too big or too small, resize
  821. if ((WmiBufSize > 0) && (WmiBufSize != WmiAllocSize)) {
  822. WmiBuffer = (LPBYTE) REALLOCMEM (hLibHeap,
  823. HEAP_FLAGS, WmiBuffer, WmiBufSize);
  824. if (WmiBuffer == NULL) {
  825. // reallocation failed so bail out
  826. status = ERROR_OUTOFMEMORY;
  827. } else {
  828. #if DBG
  829. HeapUsed += (WmiBufSize - WmiAllocSize);
  830. DebugPrint((4, "\tRealloc WmiBuffer old %d new %d to %d\n",
  831. WmiAllocSize, WmiBufSize, HeapUsed));
  832. #endif
  833. WmiAllocSize = WmiBufSize;
  834. }
  835. }
  836. if (status == ERROR_INSUFFICIENT_BUFFER) {
  837. // if it didn't work because it was too small the first time
  838. // try one more time
  839. status = WmiQueryAllDataW (
  840. hWmiDiskPerf,
  841. &WmiBufSize,
  842. WmiBuffer);
  843. } else {
  844. // it either worked the fisrt time or it failed because of
  845. // something other than a buffer size problem
  846. }
  847. }
  848. if (status == ERROR_SUCCESS) {
  849. WmiDiskInfo = (PWNODE_ALL_DATA)WmiBuffer;
  850. // go through returned names and add to the buffer
  851. while (bNotDone) {
  852. pDiskPerformance = (PDISK_PERFORMANCE)(
  853. (PUCHAR)WmiDiskInfo + WmiDiskInfo->DataBlockOffset);
  854. dwInstanceNameOffset = WmiDiskInfo->DataBlockOffset +
  855. ((sizeof(DISK_PERFORMANCE) + 1) & ~1) ;
  856. // get length of string (it's a counted string) length is in chars
  857. wNameLen = *(LPWORD)((LPBYTE)WmiDiskInfo + dwInstanceNameOffset);
  858. if (wNameLen > 0) {
  859. // just a sanity check here
  860. assert (wNameLen < MAX_PATH);
  861. // get pointer to string text
  862. wszInstanceName = (LPWSTR)((LPBYTE)WmiDiskInfo + dwInstanceNameOffset + sizeof(WORD));
  863. // truncate to last characters if name is larger than the buffer in the table
  864. if (wNameLen >= DVE_DEV_NAME_LEN) {
  865. // copy the last DVE_DEV_NAME_LEN chars
  866. wszInstanceName += (wNameLen - DVE_DEV_NAME_LEN) + 1;
  867. dwBytesToCopy = (DVE_DEV_NAME_LEN - 1) * sizeof(WCHAR);
  868. wNameLen = DVE_DEV_NAME_LEN - 1;
  869. } else {
  870. dwBytesToCopy = wNameLen;
  871. }
  872. // copy it to the buffer to make it a SZ string
  873. memcpy (wszInstName, &wszInstanceName[0], dwBytesToCopy);
  874. // zero terminate it
  875. wszInstName[wNameLen/sizeof(WCHAR)] = 0;
  876. // find matching entry in list
  877. // sent by caller and update
  878. // the drive & partition info
  879. for (dwListEntry = 0;
  880. dwListEntry < *pdwNumEntries;
  881. dwListEntry++) {
  882. DebugPrint((6,
  883. "MapDrive: Comparing '%ws' to '%ws'(pList)\n",
  884. wszInstName,
  885. pList[dwListEntry].wszInstanceName));
  886. if (lstrcmpW(wszInstName, pList[dwListEntry].wszInstanceName) == 0) {
  887. // update entry and...
  888. pList[dwListEntry].dwVolumeNumber = pDiskPerformance->StorageDeviceNumber;
  889. memcpy (&pList[dwListEntry].szVolumeManager,
  890. pDiskPerformance->StorageManagerName,
  891. sizeof(pDiskPerformance->StorageManagerName));
  892. if (dwLocalMaxVolNo < pList[dwListEntry].dwVolumeNumber) {
  893. dwLocalMaxVolNo = pList[dwListEntry].dwVolumeNumber;
  894. }
  895. DebugPrint ((2,
  896. "MapDrive: Mapped %8.8s, %d to drive %c\n",
  897. pList[dwListEntry].szVolumeManager,
  898. pList[dwListEntry].dwVolumeNumber,
  899. pList[dwListEntry].wcDriveLetter));
  900. // break out of loop
  901. dwListEntry = *pdwNumEntries;
  902. }
  903. }
  904. // count the number of entries
  905. dwLocalWmiItemCount++;
  906. } else {
  907. // no string to examine (length == 0)
  908. }
  909. // bump pointers inside WMI data block
  910. if (WmiDiskInfo->WnodeHeader.Linkage != 0) {
  911. // continue
  912. WmiDiskInfo = (PWNODE_ALL_DATA) (
  913. (LPBYTE)WmiDiskInfo + WmiDiskInfo->WnodeHeader.Linkage);
  914. } else {
  915. bNotDone = FALSE;
  916. }
  917. } // end while looking through the WMI data block
  918. }
  919. if (hDiskPerf == NULL) {
  920. // then the disk perf handle is local so close it
  921. status = WmiCloseBlock (hWmiDiskPerf);
  922. }
  923. *pdwMaxVolNo = dwLocalMaxVolNo;
  924. *pdwWmiItemCount = dwLocalWmiItemCount;
  925. }
  926. if (WmiBuffer != NULL) {
  927. FREEMEM (hLibHeap, 0, WmiBuffer);
  928. #if DBG
  929. HeapUsed -= WmiBufSize;
  930. DebugPrint((4, "\tFreed WmiBuffer %d to %d\n", WmiBufSize, HeapUsed));
  931. #endif
  932. }
  933. DebugPrint((3, "MapLoadedDisks returning with %d entries %d volumes",
  934. *pdwNumEntries, *pdwMaxVolNo));
  935. return status;
  936. }
  937. DWORD
  938. GetDriveNameString (
  939. LPCWSTR szDevicePath,
  940. DWORD cchDevicePathSize,
  941. PDRIVE_VOLUME_ENTRY pList,
  942. DWORD dwNumEntries,
  943. LPWSTR szNameBuffer,
  944. LPDWORD pcchNameBufferSize,
  945. LPCWSTR szVolumeManagerName,
  946. DWORD dwVolumeNumber,
  947. PDRIVE_VOLUME_ENTRY *ppVolume
  948. )
  949. /*
  950. This function will try to look up a disk device referenced by
  951. it's Volume Manager Name and ID and return
  952. either the drive letter that corresponds to this disk as found in
  953. the pList buffer or the generic name \HarddiskX\PartitionY if no
  954. drive letter can be found.
  955. szDevicePath IN: a partition or volume name in the format of
  956. \Device\HarddiskX\PartitionY or
  957. \Device\VolumeX
  958. cchDevicePathSize IN: length of the device Path in chars.
  959. pList IN: pointer to an initialized list of drives,
  960. volumes and partitions
  961. dwNumEntries IN: the number of drive letter entries in the pList buffer
  962. szNameBuffer IN: pointer to buffer to receive the name of the
  963. drive letter or name that corresponds to the
  964. device specified by the szDevicePath buffer
  965. OUT: pointer to buffer containing the name or drive
  966. letter of disk partition
  967. pcchNameBufferSize IN: pointer to DWORD containing the size of the
  968. szNameBuffer in characters
  969. OUT: pointer to DWORD that contains the size of the
  970. string returned in szNameBuffer
  971. The return value of this function can be one of the following values
  972. ERROR_SUCCESS the function succeded and a string was returned in
  973. the buffer referenced by szNameBuffer
  974. */
  975. {
  976. DWORD dwReturnStatus = ERROR_SUCCESS;
  977. WCHAR szLocalDevicePath[MAX_PATH];
  978. LPWSTR szSrcPtr;
  979. DWORD dwBytesToCopy;
  980. DWORD dwThisEntry;
  981. DWORD dwDestSize;
  982. ULONG64 *pllVolMgrName;
  983. PDRIVE_VOLUME_ENTRY pVolume = NULL;
  984. // validate the input arguments
  985. assert (szDevicePath != NULL);
  986. assert (*szDevicePath != 0);
  987. assert (cchDevicePathSize > 0);
  988. assert (cchDevicePathSize <= MAX_PATH);
  989. assert (pList != NULL);
  990. assert (dwNumEntries > 0);
  991. assert (szNameBuffer != NULL);
  992. assert (pcchNameBufferSize != NULL);
  993. assert (*pcchNameBufferSize > 0);
  994. pllVolMgrName = (ULONG64 *)szVolumeManagerName;
  995. DebugPrint((4, "GetDriveNameString: VolMgrName %ws\n", pllVolMgrName));
  996. if ((pllVolMgrName[0] == LL_LOGIDISK_0) &&
  997. (pllVolMgrName[1] == LL_LOGIDISK_1) &&
  998. ((dwVolumeNumber == 0) || (dwVolumeNumber == (ULONG)-1))) {
  999. // no short cut exists so look up by matching
  1000. // the szDevicePath param to the wszInstanceName field
  1001. assert (DVE_DEV_NAME_LEN < (sizeof(szLocalDevicePath)/sizeof(szLocalDevicePath[0])));
  1002. szSrcPtr = (LPWSTR)szDevicePath;
  1003. dwBytesToCopy = lstrlenW (szSrcPtr); // length is really in chars
  1004. if (dwBytesToCopy >= DVE_DEV_NAME_LEN) {
  1005. // copy the last DVE_DEV_NAME_LEN chars
  1006. szSrcPtr += (dwBytesToCopy - DVE_DEV_NAME_LEN) + 1;
  1007. dwBytesToCopy = (DVE_DEV_NAME_LEN - 1) * sizeof(WCHAR);
  1008. } else {
  1009. dwBytesToCopy *= sizeof(WCHAR);
  1010. }
  1011. // now dwBytesToCopy is in bytes
  1012. memcpy (szLocalDevicePath, szSrcPtr, dwBytesToCopy);
  1013. // null terminate
  1014. assert ((dwBytesToCopy / sizeof(WCHAR)) < DVE_DEV_NAME_LEN);
  1015. szLocalDevicePath[dwBytesToCopy / sizeof(WCHAR)] = 0;
  1016. for (dwThisEntry = 0; dwThisEntry < dwNumEntries; dwThisEntry++) {
  1017. if (lstrcmpW(szLocalDevicePath, pList[dwThisEntry].wszInstanceName) == 0) {
  1018. break;
  1019. }
  1020. }
  1021. // continue to assign letter
  1022. } else {
  1023. // use the faster look up
  1024. for (dwThisEntry = 0; dwThisEntry < dwNumEntries; dwThisEntry++) {
  1025. if (((pList[dwThisEntry].llVolMgr[0] == pllVolMgrName[0]) &&
  1026. (pList[dwThisEntry].llVolMgr[1] == pllVolMgrName[1])) &&
  1027. (pList[dwThisEntry].dwVolumeNumber == dwVolumeNumber)) {
  1028. break;
  1029. }
  1030. }
  1031. }
  1032. DebugPrint((4, "GetDriveNameString: Trying long route %d %d\n", dwThisEntry, dwNumEntries));
  1033. if (dwThisEntry < dwNumEntries) {
  1034. // then a matching entry was found so copy the drive letter
  1035. //then this is the matching entry
  1036. if (pList[dwThisEntry].wcDriveLetter != 0) {
  1037. DebugPrint((4,
  1038. "GetDriveNameString: Found drive %c\n", pList[dwThisEntry].wcDriveLetter));
  1039. if (*pcchNameBufferSize > 3) {
  1040. szNameBuffer[0] = pList[dwThisEntry].wcDriveLetter;
  1041. szNameBuffer[1] = L':';
  1042. szNameBuffer[2] = 0;
  1043. pVolume = &pList[dwThisEntry];
  1044. } else {
  1045. dwReturnStatus = ERROR_INSUFFICIENT_BUFFER;
  1046. }
  1047. *pcchNameBufferSize = 3;
  1048. }
  1049. else {
  1050. DebugPrint((4,
  1051. "GetDriveNameString: Missing drive->%ws\n", szDevicePath));
  1052. // then this is a valid path, but doesn't match
  1053. // any assigned drive letters, so remove "\device\"
  1054. // and copy the remainder of the string
  1055. dwDestSize = cchDevicePathSize;
  1056. dwDestSize -= SIZE_OF_DEVICE; // subtract front of string not copied
  1057. if (dwDestSize < *pcchNameBufferSize) {
  1058. memcpy (szNameBuffer, &szDevicePath[SIZE_OF_DEVICE],
  1059. (dwDestSize * sizeof (WCHAR)));
  1060. szNameBuffer[dwDestSize] = 0;
  1061. pVolume = &pList[dwThisEntry];
  1062. } else {
  1063. dwReturnStatus = ERROR_INSUFFICIENT_BUFFER;
  1064. }
  1065. *pcchNameBufferSize = dwDestSize + 1;
  1066. }
  1067. } else {
  1068. DebugPrint((4,
  1069. "GetDriveNameString: New drive->%ws\n", szDevicePath));
  1070. // then this is a valid path, but doesn't match
  1071. // any assigned drive letters, so remove "\device\"
  1072. // and copy the remainder of the string
  1073. dwDestSize = cchDevicePathSize;
  1074. dwDestSize -= SIZE_OF_DEVICE; // subtract front of string not copied
  1075. if (dwDestSize < *pcchNameBufferSize) {
  1076. memcpy (szNameBuffer, &szDevicePath[SIZE_OF_DEVICE],
  1077. (dwDestSize * sizeof (WCHAR)));
  1078. szNameBuffer[dwDestSize] = 0;
  1079. } else {
  1080. dwReturnStatus = ERROR_INSUFFICIENT_BUFFER;
  1081. }
  1082. *pcchNameBufferSize = dwDestSize + 1;
  1083. }
  1084. DebugPrint((4, "GetDriveNameString: NameBufSize %d Entries %d\n",
  1085. *pcchNameBufferSize, dwNumEntries));
  1086. if (pVolume != NULL) {
  1087. RefreshVolume(pVolume);
  1088. *ppVolume = pVolume;
  1089. }
  1090. else {
  1091. *ppVolume = NULL;
  1092. }
  1093. return dwReturnStatus;
  1094. }
  1095. DWORD
  1096. MakePhysDiskInstanceNames (
  1097. PDRIVE_VOLUME_ENTRY pPhysDiskList,
  1098. DWORD dwNumPhysDiskListItems,
  1099. LPDWORD pdwMaxDriveNo,
  1100. PDRIVE_VOLUME_ENTRY pVolumeList,
  1101. DWORD dwNumVolumeListItems
  1102. )
  1103. {
  1104. DWORD dwPDItem;
  1105. DWORD dwVLItem;
  1106. WCHAR szLocalInstanceName[MAX_PATH];
  1107. WCHAR *pszNextChar;
  1108. DWORD dwMaxDriveNo = 0;
  1109. // for each HD in the PhysDisk List,
  1110. // find matching Volumes in the Volume list
  1111. DebugPrint((3, "MakePhysDiskInstanceNames: maxdriveno %d\n",
  1112. *pdwMaxDriveNo));
  1113. DebugPrint((3, "Dumping final physical disk list\n"));
  1114. #if DBG
  1115. DumpDiskList(pPhysDiskList, dwNumPhysDiskListItems);
  1116. #endif
  1117. for (dwPDItem = 0; dwPDItem < dwNumPhysDiskListItems; dwPDItem++) {
  1118. if (pPhysDiskList[dwPDItem].wPartNo != 0) {
  1119. //only do partitions that might have logical volumes first
  1120. // initialize the instance name for this HD
  1121. for (dwVLItem = 0; dwVLItem < dwNumVolumeListItems; dwVLItem++) {
  1122. DebugPrint((6,
  1123. "Phys Disk -- Comparing '%ws' to '%ws'\n",
  1124. pPhysDiskList[dwPDItem].wszInstanceName,
  1125. pVolumeList[dwVLItem].wszInstanceName));
  1126. if (lstrcmpiW(pPhysDiskList[dwPDItem].wszInstanceName,
  1127. pVolumeList[dwVLItem].wszInstanceName) == 0) {
  1128. DebugPrint ((4,
  1129. "Phys Disk: Drive/Part %d/%d (%s) is Logical Drive %c\n",
  1130. pPhysDiskList[dwPDItem].wDriveNo,
  1131. pPhysDiskList[dwPDItem].wPartNo,
  1132. pPhysDiskList[dwPDItem].wszInstanceName,
  1133. pVolumeList[dwVLItem].wcDriveLetter));
  1134. // then this partition matches so copy the volume information
  1135. pPhysDiskList[dwPDItem].wcDriveLetter =
  1136. pVolumeList[dwVLItem].wcDriveLetter;
  1137. pPhysDiskList[dwPDItem].llVolMgr[0] =
  1138. pVolumeList[dwVLItem].llVolMgr[0];
  1139. pPhysDiskList[dwPDItem].llVolMgr[1] =
  1140. pVolumeList[dwVLItem].llVolMgr[1];
  1141. pPhysDiskList[dwPDItem].dwVolumeNumber =
  1142. pVolumeList[dwVLItem].dwVolumeNumber;
  1143. // there should only one match so bail out and go to the next item
  1144. break;
  1145. }
  1146. }
  1147. }
  1148. }
  1149. // all the partitions with volumes now have drive letters so build the physical
  1150. // drive instance strings
  1151. for (dwPDItem = 0; dwPDItem < dwNumPhysDiskListItems; dwPDItem++) {
  1152. if (pPhysDiskList[dwPDItem].wPartNo == 0) {
  1153. // only do the physical partitions
  1154. // save the \Device\HarddiskVolume path here
  1155. lstrcpyW (szLocalInstanceName, pPhysDiskList[dwPDItem].wszInstanceName);
  1156. // initialize the instance name for this HD
  1157. memset(&pPhysDiskList[dwPDItem].wszInstanceName[0], 0, (DVE_DEV_NAME_LEN * sizeof(WCHAR)));
  1158. _ltow ((LONG)pPhysDiskList[dwPDItem].wDriveNo, pPhysDiskList[dwPDItem].wszInstanceName, 10);
  1159. pPhysDiskList[dwPDItem].wReserved = (WORD)(lstrlenW (pPhysDiskList[dwPDItem].wszInstanceName));
  1160. // search the entries that are logical partitions of this drive
  1161. for (dwVLItem = 0; dwVLItem < dwNumPhysDiskListItems; dwVLItem++) {
  1162. if (pPhysDiskList[dwVLItem].wPartNo != 0) {
  1163. DebugPrint ((6, "Phys Disk: Comparing %d/%d (%s) to %d/%d\n",
  1164. pPhysDiskList[dwPDItem].wDriveNo,
  1165. pPhysDiskList[dwPDItem].wPartNo,
  1166. szLocalInstanceName,
  1167. pPhysDiskList[dwVLItem].wDriveNo,
  1168. pPhysDiskList[dwVLItem].wPartNo));
  1169. if ((pPhysDiskList[dwVLItem].wDriveNo == pPhysDiskList[dwPDItem].wDriveNo) &&
  1170. (pPhysDiskList[dwVLItem].wcDriveLetter >= L'A')) { // only allow letters to be added
  1171. // then this logical drive is on the physical disk
  1172. pszNextChar = &pPhysDiskList[dwPDItem].wszInstanceName[0];
  1173. pszNextChar += pPhysDiskList[dwPDItem].wReserved;
  1174. *pszNextChar++ = L' ';
  1175. *pszNextChar++ = (WCHAR)(pPhysDiskList[dwVLItem].wcDriveLetter);
  1176. *pszNextChar++ = L':';
  1177. *pszNextChar = L'\0';
  1178. pPhysDiskList[dwPDItem].wReserved += 3;
  1179. DebugPrint ((4, " -- Drive %c added.\n",
  1180. pPhysDiskList[dwVLItem].wcDriveLetter));
  1181. if ((DWORD)pPhysDiskList[dwPDItem].wDriveNo > dwMaxDriveNo) {
  1182. dwMaxDriveNo = (DWORD)pPhysDiskList[dwPDItem].wDriveNo;
  1183. DebugPrint((2,
  1184. "Phys Disk: Drive count now = %d\n",
  1185. dwMaxDriveNo));
  1186. }
  1187. }
  1188. }
  1189. }
  1190. DebugPrint((2,
  1191. "Mapped Phys Disk: '%ws'\n",
  1192. pPhysDiskList[dwPDItem].wszInstanceName));
  1193. } // else not a physical partition
  1194. } //end of loop
  1195. // return max drive number
  1196. *pdwMaxDriveNo = dwMaxDriveNo;
  1197. DebugPrint((3, "MakePhysDiskInstanceNames: return maxdriveno %d\n",
  1198. *pdwMaxDriveNo));
  1199. return ERROR_SUCCESS;
  1200. }
  1201. DWORD
  1202. CompressPhysDiskTable (
  1203. PDRIVE_VOLUME_ENTRY pOrigTable,
  1204. DWORD dwOrigCount,
  1205. PDRIVE_VOLUME_ENTRY pNewTable,
  1206. DWORD dwNewCount
  1207. )
  1208. {
  1209. DWORD dwPDItem;
  1210. DWORD dwVLItem;
  1211. DWORD dwDriveId;
  1212. for (dwPDItem = 0; dwPDItem < dwNewCount; dwPDItem++) {
  1213. // for each drive entry in the new table find the matching
  1214. // harddisk entry in the original table
  1215. dwDriveId = (WORD)dwPDItem;
  1216. dwDriveId <<= 16;
  1217. dwDriveId &= 0xFFFF0000;
  1218. for (dwVLItem = 0; dwVLItem < dwOrigCount; dwVLItem++) {
  1219. if (pOrigTable[dwVLItem].dwDriveId == dwDriveId) {
  1220. DebugPrint((2,
  1221. "CompressPhysDiskTable:Phys Disk: phys drive %d is mapped as %s\n",
  1222. dwPDItem, pOrigTable[dwVLItem].wszInstanceName));
  1223. // copy this entry
  1224. memcpy (&pNewTable[dwPDItem], &pOrigTable[dwVLItem],
  1225. sizeof(DRIVE_VOLUME_ENTRY));
  1226. break;
  1227. }
  1228. }
  1229. }
  1230. return ERROR_SUCCESS;
  1231. }
  1232. BOOL
  1233. GetPhysicalDriveNameString (
  1234. DWORD dwDriveNumber,
  1235. PDRIVE_VOLUME_ENTRY pList,
  1236. DWORD dwNumEntries,
  1237. LPWSTR szNameBuffer
  1238. )
  1239. {
  1240. LPWSTR szNewString = NULL;
  1241. // see if the indexed entry matches
  1242. if (dwNumEntries > 0) {
  1243. if ((dwDriveNumber < dwNumEntries) && (!bUseNT4InstanceNames)) {
  1244. if ((DWORD)(pList[dwDriveNumber].wDriveNo) == dwDriveNumber) {
  1245. // this matches so we'll get the address of the instance string
  1246. szNewString = &pList[dwDriveNumber].wszInstanceName[0];
  1247. } else {
  1248. // this drive number doesn't match the one in the table
  1249. }
  1250. } else {
  1251. // this is an unknown drive no or we don't want to use
  1252. // the fancy ones
  1253. }
  1254. } else {
  1255. // no entries to look up
  1256. }
  1257. if (szNewString == NULL) {
  1258. // then we have to make one
  1259. _ltow ((LONG)dwDriveNumber, szNameBuffer, 10);
  1260. } else {
  1261. lstrcpyW (szNameBuffer, szNewString);
  1262. }
  1263. return TRUE;
  1264. }
  1265. NTSTATUS
  1266. OpenDevice(
  1267. IN PUNICODE_STRING DeviceName,
  1268. OUT PHANDLE Handle
  1269. )
  1270. {
  1271. NTSTATUS status;
  1272. OBJECT_ATTRIBUTES objectAttributes;
  1273. IO_STATUS_BLOCK status_block;
  1274. InitializeObjectAttributes(&objectAttributes,
  1275. DeviceName,
  1276. OBJ_CASE_INSENSITIVE,
  1277. NULL,
  1278. NULL);
  1279. status = NtOpenFile(Handle,
  1280. // (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1281. (ACCESS_MASK) FILE_GENERIC_READ,
  1282. &objectAttributes,
  1283. &status_block,
  1284. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1285. FILE_SYNCHRONOUS_IO_NONALERT // | FILE_DIRECTORY_FILE
  1286. );
  1287. return status;
  1288. }
  1289. NTSTATUS
  1290. GetDeviceName(
  1291. PMOUNTMGR_MOUNT_POINTS pMountPoints,
  1292. IN PMOUNTMGR_MOUNT_POINT Point,
  1293. OUT PUNICODE_STRING DeviceName
  1294. )
  1295. {
  1296. PWCHAR pThisChar;
  1297. DeviceName->Length = (WORD)(Point->SymbolicLinkNameLength + (WORD)sizeof(WCHAR));
  1298. DeviceName->MaximumLength = (WORD)(DeviceName->Length + (WORD)sizeof(WCHAR));
  1299. DeviceName->Buffer = (PWCHAR) ALLOCMEM(hLibHeap, HEAP_FLAGS, DeviceName->MaximumLength);
  1300. if (DeviceName->Buffer == NULL)
  1301. return STATUS_NO_MEMORY;
  1302. memcpy(DeviceName->Buffer,
  1303. (LPVOID)((PCHAR) pMountPoints + Point->SymbolicLinkNameOffset),
  1304. Point->SymbolicLinkNameLength);
  1305. DebugPrint((4, "GetDeviceName: %ws\n", DeviceName->Buffer));
  1306. pThisChar = &DeviceName->Buffer[Point->SymbolicLinkNameLength / sizeof(WCHAR)];
  1307. *pThisChar++ = L'\\';
  1308. *pThisChar = 0;
  1309. return STATUS_SUCCESS;
  1310. }
  1311. VOID
  1312. RefreshVolume(
  1313. PDRIVE_VOLUME_ENTRY pVolume
  1314. )
  1315. {
  1316. LONGLONG CurrentTime, Interval;
  1317. HANDLE hVolume;
  1318. NTSTATUS NtStatus;
  1319. IO_STATUS_BLOCK status_block;
  1320. FILE_FS_SIZE_INFORMATION FsSizeInformation;
  1321. ULONG AllocationUnitBytes;
  1322. GetSystemTimeAsFileTime((LPFILETIME) &CurrentTime);
  1323. Interval = (CurrentTime - pVolume->LastRefreshTime) / 10000000;
  1324. if (Interval > g_lRefreshInterval) {
  1325. pVolume->LastRefreshTime = CurrentTime;
  1326. hVolume = pVolume->hVolume;
  1327. if (hVolume == NULL) {
  1328. NtStatus = OpenDevice(&pVolume->DeviceName, &hVolume);
  1329. if (!NT_SUCCESS(NtStatus)) {
  1330. hVolume = NULL;
  1331. }
  1332. else {
  1333. pVolume->hVolume = hVolume;
  1334. }
  1335. }
  1336. if (hVolume != NULL) {
  1337. NtStatus = NtQueryVolumeInformationFile(hVolume,
  1338. &status_block,
  1339. &FsSizeInformation,
  1340. sizeof(FILE_FS_SIZE_INFORMATION),
  1341. FileFsSizeInformation);
  1342. }
  1343. if ( hVolume && NT_SUCCESS(NtStatus) ) {
  1344. AllocationUnitBytes =
  1345. FsSizeInformation.BytesPerSector *
  1346. FsSizeInformation.SectorsPerAllocationUnit;
  1347. pVolume->TotalBytes = FsSizeInformation.TotalAllocationUnits.QuadPart *
  1348. AllocationUnitBytes;
  1349. pVolume->FreeBytes = FsSizeInformation.AvailableAllocationUnits.QuadPart *
  1350. AllocationUnitBytes;
  1351. // Express in megabytes, truncated
  1352. pVolume->TotalBytes /= (1024*1024);
  1353. pVolume->FreeBytes /= (1024*1024);
  1354. }
  1355. if (g_lRefreshInterval > 0) {
  1356. if (pVolume->hVolume != NULL) {
  1357. NtClose(pVolume->hVolume);
  1358. }
  1359. pVolume->hVolume = NULL;
  1360. }
  1361. }
  1362. }
  1363. ULONG
  1364. GetDiskExtent(
  1365. IN HANDLE hVol,
  1366. IN OUT PVOLUME_DISK_EXTENTS *pVolExtents,
  1367. IN OUT PULONG ReturnedSize
  1368. )
  1369. {
  1370. ULONG Size, nDisks = 10;
  1371. NTSTATUS Status;
  1372. IO_STATUS_BLOCK IoStatus;
  1373. PVOLUME_DISK_EXTENTS Buffer;
  1374. Size = *ReturnedSize;
  1375. Buffer = *pVolExtents;
  1376. *ReturnedSize = Size;
  1377. Status = STATUS_BUFFER_OVERFLOW;
  1378. while (Status == STATUS_BUFFER_OVERFLOW) {
  1379. if (Buffer == NULL) {
  1380. Size = sizeof(VOLUME_DISK_EXTENTS) + (nDisks * sizeof(DISK_EXTENT));
  1381. Buffer = (PVOLUME_DISK_EXTENTS)
  1382. ALLOCMEM(hLibHeap, HEAP_FLAGS, Size);
  1383. if (Buffer == NULL) {
  1384. *pVolExtents = NULL;
  1385. *ReturnedSize = 0;
  1386. return 0;
  1387. }
  1388. }
  1389. IoStatus.Status = 0;
  1390. IoStatus.Information = 0;
  1391. Status = NtDeviceIoControlFile(hVol,
  1392. NULL,
  1393. NULL,
  1394. NULL,
  1395. &IoStatus,
  1396. IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
  1397. NULL,
  1398. 0,
  1399. (PVOID) Buffer,
  1400. Size);
  1401. if (Status == STATUS_BUFFER_OVERFLOW) {
  1402. nDisks = Buffer->NumberOfDiskExtents;
  1403. FREEMEM(hLibHeap, 0, Buffer);
  1404. Buffer = NULL;
  1405. }
  1406. }
  1407. *pVolExtents = Buffer;
  1408. *ReturnedSize = Size;
  1409. if (!NT_SUCCESS(Status)) {
  1410. DebugPrint((2, "GetDiskExtent: IOCTL Failure %X\n", Status));
  1411. return 0;
  1412. }
  1413. return Buffer->NumberOfDiskExtents;
  1414. }
  1415. DWORD
  1416. FindNewVolumes (
  1417. PDRIVE_VOLUME_ENTRY *ppPhysDiskList,
  1418. LPDWORD pdwNumPhysDiskListEntries,
  1419. PDRIVE_VOLUME_ENTRY pVolumeList,
  1420. DWORD dwNumVolumeListItems
  1421. )
  1422. {
  1423. DWORD dwVLItem;
  1424. PVOLUME_DISK_EXTENTS pVolExtents = NULL;
  1425. ULONG ReturnedSize = 0;
  1426. PDRIVE_VOLUME_ENTRY pPhysDiskList, pDisk, pVolume;
  1427. LIST_ENTRY NewVolumes, *pEntry;
  1428. PDRIVE_LIST pNewDisk;
  1429. DWORD dwNumPhysDiskListItems = *pdwNumPhysDiskListEntries;
  1430. DWORD dwNewDisks = 0;
  1431. UNICODE_STRING VolumeName;
  1432. // for each HD in the PhysDisk List,
  1433. // find matching Volumes in the Volume list
  1434. DebugPrint((3, "FindNewVolumes: NumPhysDisk %d NumVol %d\n",
  1435. *pdwNumPhysDiskListEntries, dwNumVolumeListItems));
  1436. pPhysDiskList = *ppPhysDiskList;
  1437. InitializeListHead(&NewVolumes);
  1438. for (dwVLItem=0; dwVLItem < dwNumVolumeListItems; dwVLItem++) {
  1439. ULONG nCount;
  1440. HANDLE hVol;
  1441. PDISK_EXTENT pDiskExtent;
  1442. PWCHAR wszVolume;
  1443. NTSTATUS status;
  1444. pVolume = &pVolumeList[dwVLItem];
  1445. if (LookupInstanceName(
  1446. pVolume->wszInstanceName,
  1447. pPhysDiskList,
  1448. dwNumPhysDiskListItems,
  1449. dwNumPhysDiskListItems) >= 0) {
  1450. continue;
  1451. }
  1452. pEntry = NewVolumes.Flink;
  1453. while (pEntry != &NewVolumes) {
  1454. pDisk = &((PDRIVE_LIST)pEntry)->DiskEntry;
  1455. if (!wcscmp(pDisk->wszInstanceName,
  1456. pVolume->wszInstanceName)) {
  1457. continue;
  1458. }
  1459. pEntry = pEntry->Flink;
  1460. }
  1461. wszVolume = &pVolume->wszInstanceName[0];
  1462. RtlInitUnicodeString(&VolumeName, pVolume->wszInstanceName);
  1463. nCount = VolumeName.Length / sizeof(WCHAR);
  1464. if (nCount > 0) {
  1465. if (wszVolume[nCount-1] == L'\\') {
  1466. wszVolume[nCount-1] = 0;
  1467. nCount--;
  1468. VolumeName.Length -= sizeof(WCHAR);
  1469. }
  1470. }
  1471. if (wszVolume != NULL && nCount > 0) {
  1472. status = OpenDevice(&VolumeName, &hVol);
  1473. DebugPrint((3, "Opening '%ws' with status %x\n", wszVolume, status));
  1474. if (NT_SUCCESS(status) && (hVol != NULL)) {
  1475. PDISK_EXTENT pExtent;
  1476. nCount = GetDiskExtent(hVol, &pVolExtents, &ReturnedSize);
  1477. DebugPrint((3, "nDisks = %d\n", nCount));
  1478. if (nCount > 0) {
  1479. pExtent = &pVolExtents->Extents[0];
  1480. while (nCount-- > 0) {
  1481. if (dwNumPhysDiskListItems < INITIAL_NUM_VOL_LIST_ENTRIES) {
  1482. pDisk = &pPhysDiskList[dwNumPhysDiskListItems];
  1483. dwNumPhysDiskListItems++;
  1484. }
  1485. else {
  1486. pNewDisk = (PDRIVE_LIST)
  1487. ALLOCMEM(hLibHeap, HEAP_ZERO_MEMORY, sizeof(DRIVE_LIST));
  1488. if (pNewDisk != NULL) {
  1489. dwNewDisks++;
  1490. pDisk = &pNewDisk->DiskEntry;
  1491. InsertTailList(&NewVolumes, &pNewDisk->Entry);
  1492. }
  1493. else {
  1494. pDisk = NULL;
  1495. }
  1496. }
  1497. if (pDisk == NULL) {
  1498. continue;
  1499. }
  1500. pDisk->wDriveNo = (WORD) pExtent->DiskNumber;
  1501. pDisk->wPartNo = 0xFF;
  1502. memcpy(pDisk->szVolumeManager, L"Partmgr ", sizeof(WCHAR) * 8);
  1503. wcscpy(pDisk->wszInstanceName, pVolume->wszInstanceName);
  1504. DebugPrint((3, "Extent %d Disk %d Start %I64u Size %I64u\n",
  1505. nCount, pExtent->DiskNumber,
  1506. pExtent->StartingOffset, pExtent->ExtentLength));
  1507. pExtent++;
  1508. }
  1509. }
  1510. NtClose(hVol);
  1511. }
  1512. }
  1513. }
  1514. if (pVolExtents != NULL) {
  1515. FREEMEM(hLibHeap, 0, pVolExtents);
  1516. }
  1517. if ((!IsListEmpty(&NewVolumes)) && (dwNewDisks > 0)) {
  1518. PDRIVE_VOLUME_ENTRY pOldBuffer;
  1519. PDRIVE_LIST pOldDisk;
  1520. pOldBuffer = pPhysDiskList;
  1521. pPhysDiskList = (PDRIVE_VOLUME_ENTRY) REALLOCMEM(
  1522. hLibHeap, HEAP_ZERO_MEMORY,
  1523. pPhysDiskList, (dwNumPhysDiskListItems + dwNewDisks) * sizeof (DRIVE_VOLUME_ENTRY));
  1524. if (pPhysDiskList == NULL) {
  1525. DebugPrint((3, "MakePhysDiskInstance realloc failure"));
  1526. FREEMEM(hLibHeap, 0, pOldBuffer);
  1527. *ppPhysDiskList = NULL;
  1528. return ERROR_OUTOFMEMORY;
  1529. }
  1530. //
  1531. // NOTE: Below assumes Entry is the first thing in DRIVE_LIST!!
  1532. //
  1533. pEntry = NewVolumes.Flink;
  1534. while (pEntry != &NewVolumes) {
  1535. pNewDisk = (PDRIVE_LIST) pEntry;
  1536. RtlCopyMemory(
  1537. &pPhysDiskList[dwNumPhysDiskListItems],
  1538. &pNewDisk->DiskEntry,
  1539. sizeof(DRIVE_VOLUME_ENTRY));
  1540. dwNumPhysDiskListItems++;
  1541. pOldDisk = pNewDisk;
  1542. pEntry = pEntry->Flink;
  1543. FREEMEM(hLibHeap, 0, pOldDisk);
  1544. }
  1545. }
  1546. *ppPhysDiskList = pPhysDiskList;
  1547. *pdwNumPhysDiskListEntries = dwNumPhysDiskListItems;
  1548. return ERROR_SUCCESS;
  1549. }
  1550. #if DBG
  1551. VOID
  1552. DumpDiskList(
  1553. IN PDRIVE_VOLUME_ENTRY pList,
  1554. IN ULONG nCount
  1555. )
  1556. {
  1557. ULONG i;
  1558. for (i=0; i<nCount; i++) {
  1559. DebugPrint((4, "\nEntry count = %d\n", i));
  1560. DebugPrint((4, "dwDriveId = %X\n", pList[i].dwDriveId));
  1561. DebugPrint((4, "DriveLetter = %c\n",
  1562. pList[i].wcDriveLetter == 0 ? ' ' : pList[i].wcDriveLetter));
  1563. DebugPrint((4, "VolMgr = %c%c%c%c%c%c%c%c\n",
  1564. pList[i].szVolumeManager[0],
  1565. pList[i].szVolumeManager[1],
  1566. pList[i].szVolumeManager[2],
  1567. pList[i].szVolumeManager[3],
  1568. pList[i].szVolumeManager[4],
  1569. pList[i].szVolumeManager[5],
  1570. pList[i].szVolumeManager[6],
  1571. pList[i].szVolumeManager[7]));
  1572. DebugPrint((4, "VolumeNumber = %d\n", pList[i].dwVolumeNumber));
  1573. DebugPrint((4, "Handle = %X\n", pList[i].hVolume));
  1574. DebugPrint((4, "InstanceName = %ws\n",
  1575. pList[i].wszInstanceName));
  1576. DebugPrint((4, "DeviceName = %ws\n",
  1577. pList[i].DeviceName.Buffer ? pList[i].DeviceName.Buffer : L""));
  1578. }
  1579. }
  1580. #endif