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.

479 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. config.c
  5. Abstract:
  6. This module provides the configuration information to the
  7. cluster disk device driver.
  8. Author:
  9. Rod Gamache (rodga) 7-Dec-1996
  10. Steal as much code as possible from FTDISK's config.c
  11. Charlie Wickham (charlwi) 20-Oct-1997
  12. NT5: stolen from ntos\fstub\drivesup.c
  13. Environment:
  14. kernel mode only
  15. Revision History:
  16. --*/
  17. #include "clusdskp.h"
  18. #include "mountmgr.h"
  19. //
  20. // Size of default work area allocated when getting information from
  21. // the registry.
  22. //
  23. #define WORK_AREA 4096
  24. typedef struct _DRIVE_LETTER_ENTRY {
  25. struct _DRIVE_LETTER_ENTRY *Next;
  26. UCHAR DriveLetter;
  27. UCHAR Fill3[3];
  28. } DRIVE_LETTER_ENTRY, *PDRIVE_LETTER_ENTRY;
  29. //
  30. // Global data
  31. //
  32. PDRIVE_LETTER_ENTRY ClusDiskDriveLetters = NULL;
  33. //
  34. // Forwards
  35. //
  36. NTSTATUS
  37. GetDriveLetterFromMountMgr(
  38. IN LPWSTR PartitionString,
  39. OUT PUCHAR DriveLetter
  40. );
  41. #pragma alloc_text(PAGE, GetDriveLetterFromMountMgr)
  42. NTSTATUS
  43. GetDriveLetterFromMountMgr(
  44. IN LPWSTR PartitionString,
  45. OUT PUCHAR DriveLetter
  46. )
  47. /*++
  48. Routine Description:
  49. This routine queries the mount mgr for the drive letter
  50. of the specified device.
  51. Arguments:
  52. DeviceName - Supplies the device name.
  53. DriveLetter - Returns the drive letter or 0 for none.
  54. Return Value:
  55. NTSTATUS
  56. --*/
  57. {
  58. ULONG partitionStringLength;
  59. ULONG mountPointSize;
  60. PMOUNTMGR_MOUNT_POINT mountPoint;
  61. UNICODE_STRING name;
  62. NTSTATUS status;
  63. PFILE_OBJECT fileObject;
  64. PDEVICE_OBJECT deviceObject;
  65. KEVENT event;
  66. PIRP irp;
  67. MOUNTMGR_MOUNT_POINTS points;
  68. IO_STATUS_BLOCK ioStatus;
  69. ULONG mountPointsSize;
  70. PMOUNTMGR_MOUNT_POINTS mountPoints;
  71. BOOLEAN freeMountPoints;
  72. UNICODE_STRING dosDevices;
  73. UCHAR driveLetter;
  74. ULONG i;
  75. UNICODE_STRING subString;
  76. WCHAR c;
  77. PAGED_CODE();
  78. partitionStringLength = wcslen( PartitionString ) * sizeof(WCHAR);
  79. //
  80. // allocate a MOUNT_POINT structure plus enough space for the
  81. // device name to follow
  82. //
  83. mountPointSize = sizeof( MOUNTMGR_MOUNT_POINT ) + partitionStringLength;
  84. mountPoint = (PMOUNTMGR_MOUNT_POINT)ExAllocatePool( PagedPool, mountPointSize );
  85. if (!mountPoint) {
  86. return STATUS_INSUFFICIENT_RESOURCES;
  87. }
  88. RtlZeroMemory( mountPoint, sizeof( MOUNTMGR_MOUNT_POINT ));
  89. mountPoint->DeviceNameOffset = (USHORT) sizeof(MOUNTMGR_MOUNT_POINT);
  90. mountPoint->DeviceNameLength = (USHORT) partitionStringLength;
  91. RtlCopyMemory( mountPoint + 1, PartitionString, partitionStringLength );
  92. //
  93. // get a pointer to the mount mgr device object and issue the first
  94. // query to get the size of the data
  95. //
  96. RtlInitUnicodeString( &name, MOUNTMGR_DEVICE_NAME );
  97. status = IoGetDeviceObjectPointer(&name,
  98. FILE_READ_ATTRIBUTES,
  99. &fileObject,
  100. &deviceObject);
  101. if (!NT_SUCCESS(status)) {
  102. ExFreePool(mountPoint);
  103. return status;
  104. }
  105. KeInitializeEvent(&event, NotificationEvent, FALSE);
  106. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_POINTS,
  107. deviceObject,
  108. mountPoint,
  109. mountPointSize,
  110. &points,
  111. sizeof(points),
  112. FALSE,
  113. &event,
  114. &ioStatus);
  115. if (!irp) {
  116. ObDereferenceObject(fileObject);
  117. ExFreePool(mountPoint);
  118. return STATUS_INSUFFICIENT_RESOURCES;
  119. }
  120. status = IoCallDriver(deviceObject, irp);
  121. if (status == STATUS_PENDING) {
  122. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  123. status = ioStatus.Status;
  124. }
  125. //
  126. // allocate enough space to get all the mount point info
  127. //
  128. if (status == STATUS_BUFFER_OVERFLOW) {
  129. mountPointsSize = points.Size;
  130. mountPoints = (PMOUNTMGR_MOUNT_POINTS)
  131. ExAllocatePool(PagedPool, mountPointsSize);
  132. if (!mountPoints) {
  133. ObDereferenceObject(fileObject);
  134. ExFreePool(mountPoint);
  135. return STATUS_INSUFFICIENT_RESOURCES;
  136. }
  137. KeInitializeEvent(&event, NotificationEvent, FALSE);
  138. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_POINTS,
  139. deviceObject,
  140. mountPoint,
  141. mountPointSize,
  142. mountPoints,
  143. mountPointsSize,
  144. FALSE,
  145. &event,
  146. &ioStatus);
  147. if (!irp) {
  148. ExFreePool(mountPoints);
  149. ObDereferenceObject(fileObject);
  150. ExFreePool(mountPoint);
  151. return STATUS_INSUFFICIENT_RESOURCES;
  152. }
  153. status = IoCallDriver(deviceObject, irp);
  154. if (status == STATUS_PENDING) {
  155. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  156. status = ioStatus.Status;
  157. } else if ( !NT_SUCCESS( status )) {
  158. ClusDiskPrint((1,"[ClusDisk] GetDLFromMM: 2nd IRP failed %08X\n",
  159. status));
  160. }
  161. freeMountPoints = TRUE;
  162. } else {
  163. mountPoints = &points;
  164. freeMountPoints = FALSE;
  165. if ( !NT_SUCCESS( status )) {
  166. ClusDiskPrint((1,"[ClusDisk] GetDLFromMM: 1st IRP failed %08X\n",
  167. status));
  168. }
  169. }
  170. ExFreePool(mountPoint);
  171. ObDereferenceObject(fileObject);
  172. if (!NT_SUCCESS(status)) {
  173. if (freeMountPoints) {
  174. ExFreePool(mountPoints);
  175. }
  176. return status;
  177. }
  178. //
  179. // run through the list of mount points, matching the
  180. // supplied devicename against the mount point symname.
  181. //
  182. RtlInitUnicodeString(&dosDevices, L"\\DosDevices\\");
  183. driveLetter = 0;
  184. for (i = 0; i < mountPoints->NumberOfMountPoints; i++) {
  185. if (mountPoints->MountPoints[i].SymbolicLinkNameLength !=
  186. dosDevices.Length + 2*sizeof(WCHAR)) {
  187. continue;
  188. }
  189. subString.Length = subString.MaximumLength = dosDevices.Length;
  190. subString.Buffer = (PWSTR) ((PCHAR) mountPoints +
  191. mountPoints->MountPoints[i].SymbolicLinkNameOffset);
  192. if (RtlCompareUnicodeString(&dosDevices, &subString, TRUE)) {
  193. continue;
  194. }
  195. c = subString.Buffer[subString.Length/sizeof(WCHAR) + 1];
  196. if (c != ':') {
  197. continue;
  198. }
  199. c = subString.Buffer[subString.Length/sizeof(WCHAR)];
  200. if (c < 'C' || c > 'Z') {
  201. continue;
  202. }
  203. driveLetter = (UCHAR) c;
  204. break;
  205. }
  206. if (freeMountPoints) {
  207. ExFreePool(mountPoints);
  208. }
  209. if ( driveLetter != 0 ) {
  210. *DriveLetter = driveLetter;
  211. status = STATUS_SUCCESS;
  212. } else {
  213. status = STATUS_NOT_FOUND;
  214. }
  215. return status;
  216. } // ClusDiskQueryMountLetter
  217. VOID
  218. ClusDiskAssignLetter(
  219. IN UCHAR DriveLetter,
  220. IN LPWSTR AssignDevice
  221. )
  222. /*++
  223. Routine Description:
  224. For all of the disks signatures that are supposed to be attached, we
  225. assign their drive letters to the specified device.
  226. Arguments:
  227. DriveLetter - the driver letter to assign to ClusDisk0.
  228. AssignDevice - NULL if we are not to assign any device letters,
  229. NON-NULL if we are.
  230. Return Value:
  231. None.
  232. --*/
  233. {
  234. } // ClusDiskAssignLetter
  235. VOID
  236. ClusDiskReleaseDriveLetters(
  237. VOID
  238. )
  239. /*++
  240. Routine Description:
  241. This routine is called only when the driver is being unloaded. This
  242. routine releases all of the drive letters that were assigned to ClusDisk0.
  243. Arguments:
  244. None.
  245. Return Value:
  246. None.
  247. Notes:
  248. This routine is only called when UnLoading ClusDisk.
  249. 2000/02/05: stevedz - This routine appears to be unnecessary.
  250. This routine should check if the drive letter is already assigned
  251. to ClusDisk0 before removing the assignment. Furthermore, it should
  252. probably reassign the letters back to the original drive, but since
  253. unload is not really supported, we won't worry about it now.
  254. --*/
  255. {
  256. } // ClusDiskReleaseDriveLetters
  257. NTSTATUS
  258. ClusDiskDismount(
  259. IN ULONG Signature
  260. )
  261. /*++
  262. Routine Description:
  263. Dismount all partitions on a spindle, using the registry to grovel
  264. for the drive letters.
  265. Arguments:
  266. Signature - the signature of the device to grovel for.
  267. Return Value:
  268. STATUS_SUCCESS if successful.
  269. An NTSTATUS error code on failure.
  270. --*/
  271. {
  272. NTSTATUS status;
  273. ULONG diskNumber;
  274. ULONG partIndex;
  275. UNICODE_STRING DeviceName;
  276. WCHAR NameBuffer[sizeof(L"\\Device\\Harddisk999\\Partition999")/sizeof(WCHAR)];
  277. UCHAR driveLetter;
  278. PCONFIGURATION_INFORMATION configurationInformation;
  279. PDRIVE_LAYOUT_INFORMATION DriveLayoutData;
  280. PPARTITION_INFORMATION partitionInfo;
  281. //
  282. // Get the system configuration information and take a
  283. // peek at each disk
  284. //
  285. configurationInformation = IoGetConfigurationInformation();
  286. for (diskNumber = 0;
  287. diskNumber < configurationInformation->DiskCount;
  288. diskNumber++)
  289. {
  290. //
  291. // get the device name for the physical disk and its
  292. // partition information
  293. //
  294. status = ClusDiskGetTargetDevice(diskNumber,
  295. 0,
  296. NULL,
  297. &DeviceName,
  298. &DriveLayoutData,
  299. NULL,
  300. FALSE);
  301. if ( !NT_SUCCESS(status) ) {
  302. ClusDiskPrint((1, "[Clusdisk] Dismount: Can't get target device info - %08X\n",
  303. status));
  304. continue;
  305. }
  306. if ( DriveLayoutData == NULL ) {
  307. ClusDiskPrint((1, "[Clusdisk] Dismount: Can't get partition info for disk %u\n",
  308. diskNumber));
  309. RtlFreeUnicodeString(&DeviceName);
  310. continue;
  311. }
  312. //
  313. // Skip till we find our device!
  314. //
  315. if ( DriveLayoutData->Signature == Signature ) {
  316. for ( partIndex = 0;
  317. partIndex < DriveLayoutData->PartitionCount;
  318. partIndex++ )
  319. {
  320. partitionInfo = &DriveLayoutData->PartitionEntry[partIndex];
  321. //
  322. // Make sure this is a valid partition, i.e., it's recognized by
  323. // a FS and it has a non-zero starting offset and length
  324. //
  325. if (!partitionInfo->RecognizedPartition &&
  326. !partitionInfo->StartingOffset.QuadPart &&
  327. !partitionInfo->PartitionLength.QuadPart)
  328. {
  329. continue;
  330. }
  331. swprintf(NameBuffer,
  332. L"\\Device\\Harddisk%u\\Partition%u",
  333. diskNumber,
  334. partitionInfo->PartitionNumber);
  335. RtlInitUnicodeString(&DeviceName, NameBuffer);
  336. status = GetDriveLetterFromMountMgr( NameBuffer, &driveLetter );
  337. if (NT_SUCCESS(status) && IsAlpha(driveLetter) ) {
  338. status = DismountPartitionDevice( driveLetter );
  339. } else {
  340. ClusDiskPrint((1,
  341. "[ClusDisk] Dismount: couldn't dismount drive. "
  342. "status %08X driveLetter %c (%02X)\n",
  343. status, driveLetter, driveLetter));
  344. }
  345. }
  346. break;
  347. }
  348. ExFreePool( DriveLayoutData );
  349. RtlFreeUnicodeString( &DeviceName );
  350. }
  351. return(STATUS_SUCCESS);
  352. } // ClusDiskDismount