Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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