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.

12947 lines
354 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. ftdisk.c
  5. Abstract:
  6. This driver provides fault tolerance through disk mirroring and striping.
  7. This module contains routines that support calls from the NT I/O system.
  8. Author:
  9. Bob Rinne (bobri) 2-Feb-1992
  10. Mike Glass (mglass)
  11. Norbert Kusters 2-Feb-1995
  12. Environment:
  13. kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. extern "C" {
  18. #include <ntosp.h>
  19. #include <ntddscsi.h>
  20. #include <initguid.h>
  21. #include <mountmgr.h>
  22. #include <ioevent.h>
  23. #include <partmgrp.h>
  24. #include <zwapi.h>
  25. #include <ntioapi.h>
  26. }
  27. #include <ftdisk.h>
  28. extern "C" {
  29. #include "wmiguid.h"
  30. #include "ntdddisk.h"
  31. #include "ftwmireg.h"
  32. }
  33. //
  34. // Global Sequence number for error log.
  35. //
  36. ULONG FtErrorLogSequence = 0;
  37. extern "C" {
  38. NTSTATUS
  39. DriverEntry(
  40. IN PDRIVER_OBJECT DriverObject,
  41. IN PUNICODE_STRING RegistryPath
  42. );
  43. NTSTATUS
  44. FtDiskAddDevice(
  45. IN PDRIVER_OBJECT DriverObject,
  46. IN PDEVICE_OBJECT PhysicalDeviceObject
  47. );
  48. }
  49. NTSTATUS
  50. FtpCreateLogicalDiskHelper(
  51. IN OUT PROOT_EXTENSION RootExtension,
  52. IN FT_LOGICAL_DISK_TYPE LogicalDiskType,
  53. IN USHORT NumberOfMembers,
  54. IN PFT_LOGICAL_DISK_ID ArrayOfMembers,
  55. IN USHORT ConfigurationInformationSize,
  56. IN PVOID ConfigurationInformation,
  57. IN USHORT StateInformationSize,
  58. IN PVOID StateInformation,
  59. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  60. );
  61. NTSTATUS
  62. FtpBreakLogicalDiskHelper(
  63. IN OUT PROOT_EXTENSION RootExtension,
  64. IN FT_LOGICAL_DISK_ID RootLogicalDiskId
  65. );
  66. NTSTATUS
  67. FtpCreatePartitionLogicalDiskHelper(
  68. IN OUT PVOLUME_EXTENSION Extension,
  69. IN LONGLONG PartitionSize,
  70. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  71. );
  72. NTSTATUS
  73. FtpAddPartition(
  74. IN PVOLUME_EXTENSION Extension,
  75. IN PDEVICE_OBJECT Partition,
  76. IN PDEVICE_OBJECT WholeDiskPdo
  77. );
  78. NTSTATUS
  79. FtpPartitionRemovedHelper(
  80. IN OUT PROOT_EXTENSION RootExtension,
  81. IN PDEVICE_OBJECT Partition,
  82. IN PDEVICE_OBJECT WholeDiskPdo
  83. );
  84. NTSTATUS
  85. FtpSignalCompletion(
  86. IN PDEVICE_OBJECT DeviceObject,
  87. IN PIRP Irp,
  88. IN PVOID Event
  89. );
  90. VOID
  91. FtpRefCountCompletion(
  92. IN PVOID Extension,
  93. IN NTSTATUS Status
  94. );
  95. VOID
  96. FtpDecrementRefCount(
  97. IN OUT PVOLUME_EXTENSION Extension
  98. );
  99. NTSTATUS
  100. FtpAllSystemsGo(
  101. IN PVOLUME_EXTENSION Extension,
  102. IN PIRP Irp,
  103. IN BOOLEAN MustBeComplete,
  104. IN BOOLEAN MustHaveVolume,
  105. IN BOOLEAN MustBeOnline
  106. );
  107. NTSTATUS
  108. FtpSetGptAttributesOnDisk(
  109. IN PDEVICE_OBJECT Partition,
  110. IN ULONGLONG GptAttributes
  111. );
  112. typedef struct _SET_TARGET_CONTEXT {
  113. KEVENT Event;
  114. PDEVICE_OBJECT TargetObject;
  115. PFT_VOLUME FtVolume;
  116. PDEVICE_OBJECT WholeDiskPdo;
  117. } SET_TARGET_CONTEXT, *PSET_TARGET_CONTEXT;
  118. VOID
  119. FtpSetTargetCallback(
  120. IN PVOLUME_EXTENSION Extension
  121. );
  122. VOID
  123. FtpVolumeReadOnlyCallback(
  124. IN PVOLUME_EXTENSION Extension
  125. );
  126. VOID
  127. FtpZeroRefCallback(
  128. IN PVOLUME_EXTENSION Extension,
  129. IN ZERO_REF_CALLBACK ZeroRefCallback,
  130. IN PVOID ZeroRefContext,
  131. IN BOOLEAN AcquireSemaphore
  132. );
  133. NTSTATUS
  134. FtpRefCountCompletionRoutine(
  135. IN PDEVICE_OBJECT DeviceObject,
  136. IN PIRP Irp,
  137. IN PVOID Extension
  138. );
  139. VOID
  140. FtDiskShutdownFlushCompletionRoutine(
  141. IN PVOID Irp,
  142. IN NTSTATUS Status
  143. );
  144. typedef struct _FT_PARTITION_OFFLINE_CONTEXT {
  145. PFT_VOLUME Root;
  146. PFT_VOLUME Parent;
  147. PFT_VOLUME Child;
  148. PKEVENT Event;
  149. } FT_PARTITION_OFFLINE_CONTEXT, *PFT_PARTITION_OFFLINE_CONTEXT;
  150. VOID
  151. FtpMemberOfflineCallback(
  152. IN PVOLUME_EXTENSION Extension
  153. );
  154. NTSTATUS
  155. FtpChangeNotify(
  156. IN OUT PROOT_EXTENSION RootExtension,
  157. IN OUT PIRP Irp
  158. );
  159. VOID
  160. FtpReadWriteCompletionRoutine(
  161. IN PTRANSFER_PACKET TransferPacket
  162. );
  163. typedef struct _INSERT_MEMBER_CONTEXT {
  164. KEVENT Event;
  165. PFT_VOLUME Parent;
  166. USHORT MemberNumber;
  167. PFT_VOLUME Member;
  168. } INSERT_MEMBER_CONTEXT, *PINSERT_MEMBER_CONTEXT;
  169. VOID
  170. FtpInsertMemberCallback(
  171. IN PVOLUME_EXTENSION Extension
  172. );
  173. VOID
  174. FtpVolumeOnlineCallback(
  175. IN PVOLUME_EXTENSION Extension
  176. );
  177. VOID
  178. FtpVolumeOfflineCallback(
  179. IN PVOLUME_EXTENSION Extension
  180. );
  181. VOID
  182. FtpPropogateRegistryState(
  183. IN PVOLUME_EXTENSION Extension,
  184. IN PFT_VOLUME Volume
  185. );
  186. VOID
  187. FtpQueryRemoveCallback(
  188. IN PVOLUME_EXTENSION Extension
  189. );
  190. VOID
  191. FtDiskShutdownCompletionRoutine(
  192. IN PVOID Context,
  193. IN NTSTATUS Status
  194. );
  195. NTSTATUS
  196. FtpCheckForQueryRemove(
  197. IN OUT PVOLUME_EXTENSION Extension
  198. );
  199. BOOLEAN
  200. FtpCheckForCancelRemove(
  201. IN OUT PVOLUME_EXTENSION Extension
  202. );
  203. VOID
  204. FtpRemoveHelper(
  205. IN OUT PVOLUME_EXTENSION Extension
  206. );
  207. VOID
  208. FtpStartCallback(
  209. IN PVOLUME_EXTENSION Extension
  210. );
  211. VOID
  212. FtpWorkerThread(
  213. IN PVOID RootExtension
  214. );
  215. VOID
  216. FtpEventSignalCompletion(
  217. IN PVOID Event,
  218. IN NTSTATUS Status
  219. );
  220. NTSTATUS
  221. FtWmi(
  222. IN PDEVICE_OBJECT DeviceObject,
  223. IN PIRP Irp
  224. );
  225. NTSTATUS
  226. FtWmiFunctionControl(
  227. IN PDEVICE_OBJECT DeviceObject,
  228. IN PIRP Irp,
  229. IN ULONG GuidIndex,
  230. IN WMIENABLEDISABLECONTROL Function,
  231. IN BOOLEAN Enable
  232. );
  233. NTSTATUS
  234. FtpPmWmiCounterLibContext(
  235. IN OUT PROOT_EXTENSION RootExtension,
  236. IN PIRP Irp
  237. );
  238. NTSTATUS
  239. FtpCheckForCompleteVolume(
  240. IN PVOLUME_EXTENSION Extension,
  241. IN PFT_VOLUME FtVolume
  242. );
  243. VOID
  244. FtpCancelChangeNotify(
  245. IN PDEVICE_OBJECT DeviceObject,
  246. IN PIRP Irp
  247. );
  248. PVOLUME_EXTENSION
  249. FtpFindExtensionCoveringPartition(
  250. IN PROOT_EXTENSION RootExtension,
  251. IN PDEVICE_OBJECT Partition
  252. );
  253. VOID
  254. FtpCleanupVolumeExtension(
  255. IN OUT PVOLUME_EXTENSION Extension
  256. );
  257. #ifdef ALLOC_PRAGMA
  258. #pragma alloc_text(INIT, DriverEntry)
  259. #pragma alloc_text(INIT, FtDiskAddDevice)
  260. #endif
  261. #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN CTL_CODE(IOCTL_VOLUME_BASE, 0, METHOD_BUFFERED, FILE_READ_ACCESS)
  262. #define UNIQUE_ID_MAX_BUFFER_SIZE 50
  263. #define REVERT_GPT_ATTRIBUTES_REGISTRY_NAME (L"GptAttributeRevertEntries")
  264. #ifdef ALLOC_PRAGMA
  265. #pragma code_seg("PAGE")
  266. #endif
  267. NTSTATUS
  268. FtpAcquireWithTimeout(
  269. IN OUT PROOT_EXTENSION RootExtension
  270. )
  271. /*++
  272. Routine Description:
  273. This routine grabs the root semaphore. This routine will timeout
  274. after 10 seconds.
  275. Arguments:
  276. RootExtension - Supplies the root extension.
  277. Return Value:
  278. None.
  279. --*/
  280. {
  281. LARGE_INTEGER timeout;
  282. NTSTATUS status;
  283. timeout.QuadPart = -10*(10*1000*1000);
  284. status = KeWaitForSingleObject(&RootExtension->Mutex, Executive,
  285. KernelMode, FALSE, &timeout);
  286. if (status == STATUS_TIMEOUT) {
  287. status = STATUS_UNSUCCESSFUL;
  288. }
  289. return status;
  290. }
  291. VOID
  292. FtpDeleteVolume(
  293. IN PFT_VOLUME Volume
  294. )
  295. {
  296. USHORT n, i;
  297. PFT_VOLUME vol;
  298. n = Volume->QueryNumberOfMembers();
  299. for (i = 0; i < n; i++) {
  300. vol = Volume->GetMember(i);
  301. if (vol) {
  302. FtpDeleteVolume(vol);
  303. }
  304. }
  305. if (!InterlockedDecrement(&Volume->_refCount)) {
  306. delete Volume;
  307. }
  308. }
  309. PFT_VOLUME
  310. FtpBuildFtVolume(
  311. IN OUT PROOT_EXTENSION RootExtension,
  312. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  313. IN OUT PDEVICE_OBJECT Partition,
  314. IN OUT PDEVICE_OBJECT WholeDiskPdo
  315. )
  316. /*++
  317. Routine Description:
  318. This routine builds up an FT volume object for the given logical
  319. disk id.
  320. Arguments:
  321. RootExtension - Supplies the root device extension.
  322. LogicalDiskId - Supplies the logical disk id.
  323. Partition - Supplies the first partition for this volume.
  324. WholeDiskPdo - Supplies the whole disk PDO.
  325. Return Value:
  326. A new FT volume object or NULL.
  327. --*/
  328. {
  329. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet = RootExtension->DiskInfoSet;
  330. FT_LOGICAL_DISK_TYPE diskType;
  331. LONGLONG offset;
  332. ULONG sectorSize;
  333. PPARTITION partition;
  334. NTSTATUS status;
  335. USHORT numMembers, i;
  336. PFT_VOLUME* volArray;
  337. PCOMPOSITE_FT_VOLUME comp;
  338. if (!LogicalDiskId) {
  339. return NULL;
  340. }
  341. diskType = diskInfoSet->QueryLogicalDiskType(LogicalDiskId);
  342. if (diskType == FtPartition) {
  343. partition = new PARTITION;
  344. if (!partition) {
  345. return NULL;
  346. }
  347. status = partition->Initialize(RootExtension, LogicalDiskId,
  348. Partition, WholeDiskPdo);
  349. if (!NT_SUCCESS(status)) {
  350. delete partition;
  351. return NULL;
  352. }
  353. return partition;
  354. }
  355. switch (diskType) {
  356. case FtVolumeSet:
  357. comp = new VOLUME_SET;
  358. break;
  359. case FtStripeSet:
  360. comp = new STRIPE;
  361. break;
  362. case FtMirrorSet:
  363. comp = new MIRROR;
  364. break;
  365. case FtStripeSetWithParity:
  366. comp = new STRIPE_WP;
  367. break;
  368. case FtRedistribution:
  369. comp = new REDISTRIBUTION;
  370. break;
  371. default:
  372. comp = NULL;
  373. break;
  374. }
  375. if (!comp) {
  376. return comp;
  377. }
  378. numMembers = diskInfoSet->QueryNumberOfMembersInLogicalDisk(LogicalDiskId);
  379. ASSERT(numMembers);
  380. volArray = (PFT_VOLUME*)
  381. ExAllocatePool(NonPagedPool, numMembers*sizeof(PFT_VOLUME));
  382. if (!volArray) {
  383. delete comp;
  384. return NULL;
  385. }
  386. for (i = 0; i < numMembers; i++) {
  387. volArray[i] = FtpBuildFtVolume(RootExtension,
  388. diskInfoSet->QueryMemberLogicalDiskId(LogicalDiskId, i),
  389. Partition, WholeDiskPdo);
  390. }
  391. status = comp->Initialize(RootExtension, LogicalDiskId, volArray,
  392. numMembers, diskInfoSet->
  393. GetConfigurationInformation(LogicalDiskId),
  394. diskInfoSet->GetStateInformation(LogicalDiskId));
  395. if (!NT_SUCCESS(status)) {
  396. for (i = 0; i < numMembers; i++) {
  397. if (volArray[i]) {
  398. FtpDeleteVolume(volArray[i]);
  399. }
  400. }
  401. delete comp;
  402. return NULL;
  403. }
  404. return comp;
  405. }
  406. VOID
  407. FtpCheckForRevertGptAttributes(
  408. IN PROOT_EXTENSION RootExtension,
  409. IN PDEVICE_OBJECT Partition,
  410. IN ULONG MbrSignature,
  411. IN GUID* GptPartitionGuid,
  412. IN PFT_LOGICAL_DISK_INFORMATION DiskInfo
  413. )
  414. {
  415. ULONG i, n;
  416. PFTP_GPT_ATTRIBUTE_REVERT_ENTRY p;
  417. n = RootExtension->NumberOfAttributeRevertEntries;
  418. p = RootExtension->GptAttributeRevertEntries;
  419. for (i = 0; i < n; i++) {
  420. if (MbrSignature) {
  421. if (MbrSignature == p[i].MbrSignature) {
  422. break;
  423. }
  424. } else {
  425. if (IsEqualGUID(p[i].PartitionUniqueId, *GptPartitionGuid)) {
  426. break;
  427. }
  428. }
  429. }
  430. if (i == n) {
  431. return;
  432. }
  433. if (MbrSignature) {
  434. DiskInfo->SetGptAttributes(p[i].GptAttributes);
  435. } else {
  436. FtpSetGptAttributesOnDisk(Partition, p[i].GptAttributes);
  437. }
  438. RootExtension->NumberOfAttributeRevertEntries--;
  439. if (i + 1 == n) {
  440. if (!RootExtension->NumberOfAttributeRevertEntries) {
  441. ExFreePool(RootExtension->GptAttributeRevertEntries);
  442. RootExtension->GptAttributeRevertEntries = NULL;
  443. }
  444. return;
  445. }
  446. RtlMoveMemory(&p[i], &p[i + 1],
  447. (n - i - 1)*sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY));
  448. }
  449. NTSTATUS
  450. FtpQueryPartitionInformation(
  451. IN PROOT_EXTENSION RootExtension,
  452. IN PDEVICE_OBJECT Partition,
  453. OUT PULONG DiskNumber,
  454. OUT PLONGLONG Offset,
  455. OUT PULONG PartitionNumber,
  456. OUT PUCHAR PartitionType,
  457. OUT PLONGLONG PartitionLength,
  458. OUT GUID* PartitionTypeGuid,
  459. OUT GUID* PartitionUniqueIdGuid,
  460. OUT PBOOLEAN IsGpt,
  461. OUT PULONGLONG GptAttributes
  462. )
  463. /*++
  464. Routine Description:
  465. This routine returns the disk number and offset for the given partition.
  466. Arguments:
  467. Partition - Supplies the partition.
  468. DiskNumber - Returns the disk number.
  469. Offset - Returns the offset.
  470. PartitionNumber - Returns the partition number.
  471. PartitionType - Returns the partition type.
  472. PartitionLength - Returns the partition length.
  473. Return Value:
  474. NTSTATUS
  475. --*/
  476. {
  477. KEVENT event;
  478. PIRP irp;
  479. IO_STATUS_BLOCK ioStatus;
  480. NTSTATUS status;
  481. STORAGE_DEVICE_NUMBER number;
  482. PLIST_ENTRY l;
  483. PARTITION_INFORMATION_EX partInfo;
  484. if (DiskNumber || PartitionNumber) {
  485. KeInitializeEvent(&event, NotificationEvent, FALSE);
  486. irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
  487. Partition, NULL, 0, &number,
  488. sizeof(number), FALSE, &event,
  489. &ioStatus);
  490. if (!irp) {
  491. return STATUS_INSUFFICIENT_RESOURCES;
  492. }
  493. status = IoCallDriver(Partition, irp);
  494. if (status == STATUS_PENDING) {
  495. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  496. status = ioStatus.Status;
  497. }
  498. if (!NT_SUCCESS(status)) {
  499. return status;
  500. }
  501. if (DiskNumber) {
  502. *DiskNumber = number.DeviceNumber;
  503. }
  504. if (PartitionNumber) {
  505. *PartitionNumber = number.PartitionNumber;
  506. }
  507. }
  508. if (Offset || PartitionType || PartitionLength || PartitionTypeGuid ||
  509. PartitionUniqueIdGuid || IsGpt || GptAttributes) {
  510. KeInitializeEvent(&event, NotificationEvent, FALSE);
  511. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
  512. Partition, NULL, 0, &partInfo,
  513. sizeof(partInfo), FALSE, &event,
  514. &ioStatus);
  515. if (!irp) {
  516. return STATUS_INSUFFICIENT_RESOURCES;
  517. }
  518. status = IoCallDriver(Partition, irp);
  519. if (status == STATUS_PENDING) {
  520. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  521. status = ioStatus.Status;
  522. }
  523. if (!NT_SUCCESS(status)) {
  524. return status;
  525. }
  526. if (Offset) {
  527. *Offset = partInfo.StartingOffset.QuadPart;
  528. }
  529. if (PartitionType) {
  530. if (partInfo.PartitionStyle == PARTITION_STYLE_MBR) {
  531. *PartitionType = partInfo.Mbr.PartitionType;
  532. } else {
  533. *PartitionType = 0;
  534. }
  535. }
  536. if (PartitionLength) {
  537. *PartitionLength = partInfo.PartitionLength.QuadPart;
  538. }
  539. if (PartitionTypeGuid) {
  540. if (partInfo.PartitionStyle == PARTITION_STYLE_GPT) {
  541. *PartitionTypeGuid = partInfo.Gpt.PartitionType;
  542. }
  543. }
  544. if (PartitionUniqueIdGuid) {
  545. if (partInfo.PartitionStyle == PARTITION_STYLE_GPT) {
  546. *PartitionUniqueIdGuid = partInfo.Gpt.PartitionId;
  547. }
  548. }
  549. if (IsGpt) {
  550. if (partInfo.PartitionStyle == PARTITION_STYLE_GPT) {
  551. *IsGpt = TRUE;
  552. } else {
  553. *IsGpt = FALSE;
  554. }
  555. }
  556. if (GptAttributes) {
  557. if (partInfo.PartitionStyle == PARTITION_STYLE_GPT) {
  558. *GptAttributes = partInfo.Gpt.Attributes;
  559. } else {
  560. *GptAttributes = 0;
  561. }
  562. }
  563. }
  564. return STATUS_SUCCESS;
  565. }
  566. PVOLUME_EXTENSION
  567. FtpFindExtensionCoveringDiskId(
  568. IN PROOT_EXTENSION RootExtension,
  569. IN FT_LOGICAL_DISK_ID LogicalDiskId
  570. )
  571. /*++
  572. Routine Description:
  573. This routine finds the device extension for the given root logical
  574. disk id.
  575. Arguments:
  576. RootExtension - Supplies the root device extension.
  577. LogicalDiskId - Supplies the logical disk id.
  578. Return Value:
  579. A volume extension or NULL.
  580. --*/
  581. {
  582. PLIST_ENTRY l;
  583. PVOLUME_EXTENSION extension;
  584. for (l = RootExtension->VolumeList.Flink; l != &RootExtension->VolumeList;
  585. l = l->Flink) {
  586. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  587. if (extension->FtVolume &&
  588. extension->FtVolume->GetContainedLogicalDisk(LogicalDiskId)) {
  589. return extension;
  590. }
  591. }
  592. return NULL;
  593. }
  594. PVOLUME_EXTENSION
  595. FtpFindExtension(
  596. IN PROOT_EXTENSION RootExtension,
  597. IN FT_LOGICAL_DISK_ID LogicalDiskId
  598. )
  599. /*++
  600. Routine Description:
  601. This routine finds the device extension for the given root logical
  602. disk id.
  603. Arguments:
  604. RootExtension - Supplies the root device extension.
  605. LogicalDiskId - Supplies the logical disk id.
  606. Return Value:
  607. A volume extension or NULL.
  608. --*/
  609. {
  610. PLIST_ENTRY l;
  611. PVOLUME_EXTENSION extension;
  612. for (l = RootExtension->VolumeList.Flink; l != &RootExtension->VolumeList;
  613. l = l->Flink) {
  614. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  615. if (extension->FtVolume &&
  616. extension->FtVolume->QueryLogicalDiskId() == LogicalDiskId) {
  617. return extension;
  618. }
  619. }
  620. return NULL;
  621. }
  622. class EMPTY_IRP_QUEUE_WORK_ITEM : public WORK_QUEUE_ITEM {
  623. public:
  624. LIST_ENTRY IrpQueue;
  625. PVOLUME_EXTENSION Extension;
  626. };
  627. typedef EMPTY_IRP_QUEUE_WORK_ITEM *PEMPTY_IRP_QUEUE_WORK_ITEM;
  628. VOID
  629. FtpEmptyQueueWorkerRoutine(
  630. IN PVOID WorkItem
  631. )
  632. /*++
  633. Routine Description:
  634. This routine empties the given queue of irps by calling their respective
  635. dispatch routines.
  636. Arguments:
  637. WorkItem - Supplies the work item.
  638. Return Value:
  639. None.
  640. --*/
  641. {
  642. PEMPTY_IRP_QUEUE_WORK_ITEM workItem = (PEMPTY_IRP_QUEUE_WORK_ITEM) WorkItem;
  643. PLIST_ENTRY q, l;
  644. PDRIVER_OBJECT driverObject;
  645. PDEVICE_OBJECT deviceObject;
  646. PIRP irp;
  647. PIO_STACK_LOCATION irpSp;
  648. q = &workItem->IrpQueue;
  649. driverObject = workItem->Extension->Root->DriverObject;
  650. deviceObject = workItem->Extension->DeviceObject;
  651. while (!IsListEmpty(q)) {
  652. l = RemoveHeadList(q);
  653. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  654. irpSp = IoGetCurrentIrpStackLocation(irp);
  655. driverObject->MajorFunction[irpSp->MajorFunction](deviceObject, irp);
  656. }
  657. ExFreePool(WorkItem);
  658. }
  659. ULONG
  660. FtpQueryDiskSignature(
  661. IN PDEVICE_OBJECT WholeDiskPdo
  662. )
  663. /*++
  664. Routine Description:
  665. This routine queries the disk signature for the given disk.
  666. Arguments:
  667. WholeDisk - Supplies the whole disk.
  668. Return Value:
  669. The disk signature.
  670. --*/
  671. {
  672. PDEVICE_OBJECT wholeDisk;
  673. KEVENT event;
  674. PIRP irp;
  675. PARTMGR_DISK_SIGNATURE partSig;
  676. IO_STATUS_BLOCK ioStatus;
  677. NTSTATUS status;
  678. wholeDisk = IoGetAttachedDeviceReference(WholeDiskPdo);
  679. if (!wholeDisk) {
  680. return 0;
  681. }
  682. KeInitializeEvent(&event, NotificationEvent, FALSE);
  683. irp = IoBuildDeviceIoControlRequest(IOCTL_PARTMGR_QUERY_DISK_SIGNATURE,
  684. wholeDisk, NULL, 0, &partSig,
  685. sizeof(partSig), FALSE, &event,
  686. &ioStatus);
  687. if (!irp) {
  688. ObDereferenceObject(wholeDisk);
  689. return 0;
  690. }
  691. status = IoCallDriver(wholeDisk, irp);
  692. if (status == STATUS_PENDING) {
  693. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  694. status = ioStatus.Status;
  695. }
  696. if (!NT_SUCCESS(status)) {
  697. ObDereferenceObject(wholeDisk);
  698. return 0;
  699. }
  700. ObDereferenceObject(wholeDisk);
  701. return partSig.Signature;
  702. }
  703. BOOLEAN
  704. FtpQueryUniqueIdBuffer(
  705. IN PVOLUME_EXTENSION Extension,
  706. OUT PUCHAR UniqueId,
  707. OUT PUSHORT UniqueIdLength
  708. )
  709. {
  710. GUID uniqueGuid;
  711. ULONG signature;
  712. NTSTATUS status;
  713. LONGLONG offset;
  714. FT_LOGICAL_DISK_ID diskId;
  715. if (Extension->IsGpt) {
  716. *UniqueIdLength = sizeof(GUID) + 8;
  717. } else if (Extension->TargetObject) {
  718. *UniqueIdLength = sizeof(ULONG) + sizeof(LONGLONG);
  719. } else if (Extension->FtVolume) {
  720. *UniqueIdLength = sizeof(FT_LOGICAL_DISK_ID);
  721. } else {
  722. return FALSE;
  723. }
  724. if (!UniqueId) {
  725. return TRUE;
  726. }
  727. if (Extension->IsGpt) {
  728. RtlCopyMemory(UniqueId, "DMIO:ID:", 8);
  729. RtlCopyMemory(UniqueId + 8, &Extension->UniqueIdGuid, sizeof(GUID));
  730. } else if (Extension->TargetObject) {
  731. ASSERT(Extension->WholeDiskPdo);
  732. signature = FtpQueryDiskSignature(Extension->WholeDiskPdo);
  733. if (!signature) {
  734. return FALSE;
  735. }
  736. status = FtpQueryPartitionInformation(Extension->Root,
  737. Extension->TargetObject,
  738. NULL, &offset, NULL, NULL, NULL,
  739. NULL, NULL, NULL, NULL);
  740. if (!NT_SUCCESS(status)) {
  741. return FALSE;
  742. }
  743. RtlCopyMemory(UniqueId, &signature, sizeof(signature));
  744. RtlCopyMemory(UniqueId + sizeof(signature), &offset, sizeof(offset));
  745. } else {
  746. diskId = Extension->FtVolume->QueryLogicalDiskId();
  747. RtlCopyMemory(UniqueId, &diskId, sizeof(diskId));
  748. }
  749. return TRUE;
  750. }
  751. UCHAR
  752. FtpQueryMountLetter(
  753. IN PVOLUME_EXTENSION Extension
  754. )
  755. /*++
  756. Routine Description:
  757. This routine queries the drive letter from the mount point manager.
  758. Arguments:
  759. Extension - Supplies the volume extension.
  760. Delete - Supplies whether or not to delete the drive letter.
  761. Return Value:
  762. A mount point drive letter or 0.
  763. --*/
  764. {
  765. USHORT uniqueIdLength;
  766. ULONG mountPointSize;
  767. PMOUNTMGR_MOUNT_POINT mountPoint;
  768. UNICODE_STRING name;
  769. NTSTATUS status;
  770. PFILE_OBJECT fileObject;
  771. PDEVICE_OBJECT deviceObject;
  772. KEVENT event;
  773. PIRP irp;
  774. MOUNTMGR_MOUNT_POINTS points;
  775. IO_STATUS_BLOCK ioStatus;
  776. ULONG mountPointsSize;
  777. PMOUNTMGR_MOUNT_POINTS mountPoints;
  778. BOOLEAN freeMountPoints;
  779. UNICODE_STRING dosDevices;
  780. UCHAR driveLetter;
  781. ULONG i;
  782. UNICODE_STRING subString;
  783. WCHAR c;
  784. if (!FtpQueryUniqueIdBuffer(Extension, NULL, &uniqueIdLength)) {
  785. return 0;
  786. }
  787. mountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) + uniqueIdLength;
  788. mountPoint = (PMOUNTMGR_MOUNT_POINT)
  789. ExAllocatePool(PagedPool, mountPointSize);
  790. if (!mountPoint) {
  791. return 0;
  792. }
  793. if (!FtpQueryUniqueIdBuffer(Extension, (PUCHAR) (mountPoint + 1),
  794. &uniqueIdLength)) {
  795. ExFreePool(mountPoint);
  796. return 0;
  797. }
  798. RtlZeroMemory(mountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
  799. mountPoint->UniqueIdOffset = (USHORT) sizeof(MOUNTMGR_MOUNT_POINT);
  800. mountPoint->UniqueIdLength = uniqueIdLength;
  801. RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
  802. status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &fileObject,
  803. &deviceObject);
  804. if (!NT_SUCCESS(status)) {
  805. ExFreePool(mountPoint);
  806. return 0;
  807. }
  808. KeInitializeEvent(&event, NotificationEvent, FALSE);
  809. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_POINTS,
  810. deviceObject, mountPoint,
  811. mountPointSize, &points,
  812. sizeof(points), FALSE, &event,
  813. &ioStatus);
  814. if (!irp) {
  815. ObDereferenceObject(fileObject);
  816. ExFreePool(mountPoint);
  817. return 0;
  818. }
  819. status = IoCallDriver(deviceObject, irp);
  820. if (status == STATUS_PENDING) {
  821. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  822. status = ioStatus.Status;
  823. }
  824. if (status == STATUS_BUFFER_OVERFLOW) {
  825. mountPointsSize = points.Size;
  826. mountPoints = (PMOUNTMGR_MOUNT_POINTS)
  827. ExAllocatePool(PagedPool, mountPointsSize);
  828. if (!mountPoints) {
  829. ObDereferenceObject(fileObject);
  830. ExFreePool(mountPoint);
  831. return 0;
  832. }
  833. KeInitializeEvent(&event, NotificationEvent, FALSE);
  834. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_QUERY_POINTS,
  835. deviceObject, mountPoint,
  836. mountPointSize, mountPoints,
  837. mountPointsSize, FALSE, &event,
  838. &ioStatus);
  839. if (!irp) {
  840. ExFreePool(mountPoints);
  841. ObDereferenceObject(fileObject);
  842. ExFreePool(mountPoint);
  843. return 0;
  844. }
  845. status = IoCallDriver(deviceObject, irp);
  846. if (status == STATUS_PENDING) {
  847. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  848. status = ioStatus.Status;
  849. }
  850. freeMountPoints = TRUE;
  851. } else {
  852. mountPoints = &points;
  853. freeMountPoints = FALSE;
  854. }
  855. ExFreePool(mountPoint);
  856. ObDereferenceObject(fileObject);
  857. if (!NT_SUCCESS(status)) {
  858. if (freeMountPoints) {
  859. ExFreePool(mountPoints);
  860. }
  861. return 0;
  862. }
  863. RtlInitUnicodeString(&dosDevices, L"\\DosDevices\\");
  864. driveLetter = 0;
  865. for (i = 0; i < mountPoints->NumberOfMountPoints; i++) {
  866. if (mountPoints->MountPoints[i].SymbolicLinkNameLength !=
  867. dosDevices.Length + 2*sizeof(WCHAR)) {
  868. continue;
  869. }
  870. subString.Length = subString.MaximumLength = dosDevices.Length;
  871. subString.Buffer = (PWSTR) ((PCHAR) mountPoints +
  872. mountPoints->MountPoints[i].SymbolicLinkNameOffset);
  873. if (RtlCompareUnicodeString(&dosDevices, &subString, TRUE)) {
  874. continue;
  875. }
  876. c = subString.Buffer[subString.Length/sizeof(WCHAR) + 1];
  877. if (c != ':') {
  878. continue;
  879. }
  880. c = subString.Buffer[subString.Length/sizeof(WCHAR)];
  881. if (c < FirstDriveLetter || c > LastDriveLetter) {
  882. continue;
  883. }
  884. driveLetter = (UCHAR) c;
  885. break;
  886. }
  887. if (freeMountPoints) {
  888. ExFreePool(mountPoints);
  889. }
  890. return driveLetter;
  891. }
  892. NTSTATUS
  893. FtpDiskRegistryQueryRoutine(
  894. IN PWSTR ValueName,
  895. IN ULONG ValueType,
  896. IN PVOID ValueData,
  897. IN ULONG ValueLength,
  898. IN PVOID Context,
  899. IN PVOID EntryContext
  900. )
  901. /*++
  902. Routine Description:
  903. This routine is a query routine for the disk registry entry. It allocates
  904. space for the disk registry and copies it to the given context.
  905. Arguments:
  906. ValueName - Supplies the name of the registry value.
  907. ValueType - Supplies the type of the registry value.
  908. ValueData - Supplies the data of the registry value.
  909. ValueLength - Supplies the length of the registry value.
  910. Context - Returns the disk registry entry.
  911. EntryContext - Returns the disk registry size.
  912. Return Value:
  913. NTSTATUS
  914. --*/
  915. {
  916. PVOID p;
  917. PDISK_CONFIG_HEADER* reg;
  918. PULONG size;
  919. p = ExAllocatePool(PagedPool, ValueLength);
  920. if (!p) {
  921. return STATUS_INSUFFICIENT_RESOURCES;
  922. }
  923. RtlCopyMemory(p, ValueData, ValueLength);
  924. reg = (PDISK_CONFIG_HEADER*) Context;
  925. *reg = (PDISK_CONFIG_HEADER) p;
  926. size = (PULONG) EntryContext;
  927. if (size) {
  928. *size = ValueLength;
  929. }
  930. return STATUS_SUCCESS;
  931. }
  932. PDISK_PARTITION
  933. FtpFindDiskPartition(
  934. IN PDISK_REGISTRY DiskRegistry,
  935. IN ULONG Signature,
  936. IN LONGLONG Offset
  937. )
  938. {
  939. PDISK_DESCRIPTION diskDescription;
  940. USHORT i, j;
  941. PDISK_PARTITION diskPartition;
  942. LONGLONG tmp;
  943. diskDescription = &DiskRegistry->Disks[0];
  944. for (i = 0; i < DiskRegistry->NumberOfDisks; i++) {
  945. if (diskDescription->Signature == Signature) {
  946. for (j = 0; j < diskDescription->NumberOfPartitions; j++) {
  947. diskPartition = &diskDescription->Partitions[j];
  948. RtlCopyMemory(&tmp, &diskPartition->StartingOffset.QuadPart,
  949. sizeof(LONGLONG));
  950. if (tmp == Offset) {
  951. return diskPartition;
  952. }
  953. }
  954. }
  955. diskDescription = (PDISK_DESCRIPTION) &diskDescription->
  956. Partitions[diskDescription->NumberOfPartitions];
  957. }
  958. return NULL;
  959. }
  960. UCHAR
  961. FtpQueryDriveLetterFromRegistry(
  962. IN PROOT_EXTENSION RootExtension,
  963. IN PDEVICE_OBJECT TargetObject,
  964. IN PDEVICE_OBJECT WholeDiskPdo,
  965. IN BOOLEAN DeleteLetter
  966. )
  967. /*++
  968. Routine Description:
  969. This routine queries the sticky drive letter from the old registry.
  970. Arguments:
  971. RootExtension - Supplies the root extension.
  972. TargetObject - Supplies the device object for the partition.
  973. WholeDiskPdo - Supplies the whole disk PDO.
  974. DeleteLetter - Supplies whether or not to delete the drive letter.
  975. Return Value:
  976. A sticky drive letter.
  977. 0 to represent no drive letter.
  978. --*/
  979. {
  980. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  981. ULONG registrySize;
  982. NTSTATUS status;
  983. PDISK_CONFIG_HEADER registry;
  984. PDISK_REGISTRY diskRegistry;
  985. ULONG signature;
  986. LONGLONG offset;
  987. PDISK_PARTITION diskPartition;
  988. UCHAR driveLetter;
  989. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  990. queryTable[0].QueryRoutine = FtpDiskRegistryQueryRoutine;
  991. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  992. queryTable[0].Name = L"Information";
  993. queryTable[0].EntryContext = &registrySize;
  994. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
  995. queryTable, &registry, NULL);
  996. if (!NT_SUCCESS(status)) {
  997. return 0;
  998. }
  999. diskRegistry = (PDISK_REGISTRY)
  1000. ((PUCHAR) registry + registry->DiskInformationOffset);
  1001. signature = FtpQueryDiskSignature(WholeDiskPdo);
  1002. if (!signature) {
  1003. ExFreePool(registry);
  1004. return 0;
  1005. }
  1006. status = FtpQueryPartitionInformation(RootExtension, TargetObject,
  1007. NULL, &offset, NULL, NULL, NULL,
  1008. NULL, NULL, NULL, NULL);
  1009. if (!NT_SUCCESS(status)) {
  1010. ExFreePool(registry);
  1011. return 0;
  1012. }
  1013. diskPartition = FtpFindDiskPartition(diskRegistry, signature, offset);
  1014. if (!diskPartition) {
  1015. ExFreePool(registry);
  1016. return 0;
  1017. }
  1018. if (diskPartition->AssignDriveLetter) {
  1019. driveLetter = diskPartition->DriveLetter;
  1020. } else {
  1021. driveLetter = 0xFF;
  1022. }
  1023. if (DeleteLetter) {
  1024. diskPartition->DriveLetter = 0;
  1025. diskPartition->AssignDriveLetter = TRUE;
  1026. RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, DISK_REGISTRY_KEY_W,
  1027. L"Information", REG_BINARY, registry,
  1028. registrySize);
  1029. }
  1030. ExFreePool(registry);
  1031. return driveLetter;
  1032. }
  1033. UCHAR
  1034. FtpQueryDriveLetterFromRegistry(
  1035. IN PVOLUME_EXTENSION Extension,
  1036. IN BOOLEAN DeleteLetter
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine queries the sticky drive letter from the old registry.
  1041. Arguments:
  1042. Extension - Supplies the volume extension.
  1043. Return Value:
  1044. A sticky drive letter.
  1045. 0 to represent no drive letter.
  1046. --*/
  1047. {
  1048. if (Extension->TargetObject) {
  1049. return FtpQueryDriveLetterFromRegistry(Extension->Root,
  1050. Extension->TargetObject,
  1051. Extension->WholeDiskPdo,
  1052. DeleteLetter);
  1053. }
  1054. return 0;
  1055. }
  1056. BOOLEAN
  1057. FtpSetMountLetter(
  1058. IN PVOLUME_EXTENSION Extension,
  1059. IN UCHAR DriveLetter
  1060. )
  1061. /*++
  1062. Routine Description:
  1063. This routine sets a drive letter to the given device in the mount table.
  1064. Arguments:
  1065. Extension - Supplies the volume extension.
  1066. DriveLetter - Supplies the drive letter.
  1067. Return Value:
  1068. FALSE - Failure.
  1069. TRUE - Success.
  1070. --*/
  1071. {
  1072. WCHAR dosBuffer[30];
  1073. UNICODE_STRING dosName;
  1074. WCHAR ntBuffer[40];
  1075. UNICODE_STRING ntName;
  1076. ULONG createPointSize;
  1077. PMOUNTMGR_CREATE_POINT_INPUT createPoint;
  1078. UNICODE_STRING name;
  1079. NTSTATUS status;
  1080. PFILE_OBJECT fileObject;
  1081. PDEVICE_OBJECT deviceObject;
  1082. KEVENT event;
  1083. PIRP irp;
  1084. IO_STATUS_BLOCK ioStatus;
  1085. swprintf(dosBuffer, L"\\DosDevices\\%c:", DriveLetter);
  1086. RtlInitUnicodeString(&dosName, dosBuffer);
  1087. swprintf(ntBuffer, L"\\Device\\HarddiskVolume%d", Extension->VolumeNumber);
  1088. RtlInitUnicodeString(&ntName, ntBuffer);
  1089. createPointSize = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
  1090. dosName.Length + ntName.Length;
  1091. createPoint = (PMOUNTMGR_CREATE_POINT_INPUT)
  1092. ExAllocatePool(PagedPool, createPointSize);
  1093. if (!createPoint) {
  1094. return FALSE;
  1095. }
  1096. createPoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  1097. createPoint->SymbolicLinkNameLength = dosName.Length;
  1098. createPoint->DeviceNameOffset = createPoint->SymbolicLinkNameOffset +
  1099. createPoint->SymbolicLinkNameLength;
  1100. createPoint->DeviceNameLength = ntName.Length;
  1101. RtlCopyMemory((PCHAR) createPoint + createPoint->SymbolicLinkNameOffset,
  1102. dosName.Buffer, dosName.Length);
  1103. RtlCopyMemory((PCHAR) createPoint + createPoint->DeviceNameOffset,
  1104. ntName.Buffer, ntName.Length);
  1105. RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
  1106. status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &fileObject,
  1107. &deviceObject);
  1108. if (!NT_SUCCESS(status)) {
  1109. ExFreePool(createPoint);
  1110. return 0;
  1111. }
  1112. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1113. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CREATE_POINT,
  1114. deviceObject, createPoint,
  1115. createPointSize, NULL, 0, FALSE,
  1116. &event, &ioStatus);
  1117. if (!irp) {
  1118. ObDereferenceObject(fileObject);
  1119. ExFreePool(createPoint);
  1120. return FALSE;
  1121. }
  1122. status = IoCallDriver(deviceObject, irp);
  1123. if (status == STATUS_PENDING) {
  1124. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1125. status = ioStatus.Status;
  1126. }
  1127. ObDereferenceObject(fileObject);
  1128. ExFreePool(createPoint);
  1129. if (!NT_SUCCESS(status)) {
  1130. return FALSE;
  1131. }
  1132. return TRUE;
  1133. }
  1134. VOID
  1135. FtpCreateOldNameLinks(
  1136. IN PVOLUME_EXTENSION Extension
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. This routine creates a \Device\Harddisk%d\Partition%d name for the
  1141. given target device for legacy devices. If successful, it stores the
  1142. name in the device extension.
  1143. Arguments:
  1144. Extension - Supplies the volume extension.
  1145. Return Value:
  1146. None.
  1147. --*/
  1148. {
  1149. WCHAR deviceNameBuffer[64];
  1150. UNICODE_STRING deviceName;
  1151. NTSTATUS status;
  1152. ULONG diskNumber, partitionNumber, i;
  1153. WCHAR oldNameBuffer[80];
  1154. UNICODE_STRING oldName;
  1155. swprintf(deviceNameBuffer, L"\\Device\\HarddiskVolume%d", Extension->VolumeNumber);
  1156. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1157. if (Extension->TargetObject) {
  1158. status = FtpQueryPartitionInformation(Extension->Root,
  1159. Extension->TargetObject,
  1160. &diskNumber, NULL,
  1161. &partitionNumber, NULL, NULL,
  1162. NULL, NULL, NULL, NULL);
  1163. if (!NT_SUCCESS(status)) {
  1164. return;
  1165. }
  1166. swprintf(oldNameBuffer, L"\\Device\\Harddisk%d\\Partition%d",
  1167. diskNumber, partitionNumber);
  1168. RtlInitUnicodeString(&oldName, oldNameBuffer);
  1169. IoDeleteSymbolicLink(&oldName);
  1170. for (i = 0; i < 1000; i++) {
  1171. status = IoCreateSymbolicLink(&oldName, &deviceName);
  1172. if (NT_SUCCESS(status)) {
  1173. break;
  1174. }
  1175. }
  1176. } else {
  1177. Extension->FtVolume->CreateLegacyNameLinks(&deviceName);
  1178. }
  1179. }
  1180. NTSTATUS
  1181. FtpQuerySuperFloppyDevnodeName(
  1182. IN PVOLUME_EXTENSION Extension,
  1183. OUT PWCHAR* DevnodeName
  1184. )
  1185. {
  1186. NTSTATUS status;
  1187. UNICODE_STRING string;
  1188. PWCHAR result;
  1189. ULONG n, i;
  1190. WCHAR c;
  1191. status = IoRegisterDeviceInterface(Extension->WholeDiskPdo, &DiskClassGuid,
  1192. NULL, &string);
  1193. if (!NT_SUCCESS(status)) {
  1194. return status;
  1195. }
  1196. result = (PWCHAR) ExAllocatePool(PagedPool, string.Length + sizeof(WCHAR));
  1197. if (!result) {
  1198. ExFreePool(string.Buffer);
  1199. return STATUS_INSUFFICIENT_RESOURCES;
  1200. }
  1201. n = string.Length/sizeof(WCHAR);
  1202. for (i = 0; i < n; i++) {
  1203. c = string.Buffer[i];
  1204. if (c <= ' ' || c >= 0x80 || c == ',' || c == '\\') {
  1205. c = '_';
  1206. }
  1207. result[i] = c;
  1208. }
  1209. result[n] = 0;
  1210. ExFreePool(string.Buffer);
  1211. *DevnodeName = result;
  1212. return STATUS_SUCCESS;
  1213. }
  1214. BOOLEAN
  1215. FtpCreateNewDevice(
  1216. IN PROOT_EXTENSION RootExtension,
  1217. IN PDEVICE_OBJECT TargetObject,
  1218. IN PFT_VOLUME FtVolume,
  1219. IN PDEVICE_OBJECT WholeDiskPdo,
  1220. IN ULONG AlignmentRequirement,
  1221. IN BOOLEAN IsPreExposure,
  1222. IN BOOLEAN IsHidden,
  1223. IN BOOLEAN IsReadOnly,
  1224. IN BOOLEAN IsEspType,
  1225. IN ULONGLONG MbrGptAttributes
  1226. )
  1227. /*++
  1228. Routine Description:
  1229. This routine creates a new device object with the next available
  1230. device name using the given target object of ft volume.
  1231. Arguments:
  1232. RootExtension - Supplies the root extension.
  1233. TargetObject - Supplies the partition.
  1234. FtVolume - Supplies the FT volume.
  1235. WholeDiskPdo - Supplies the whole disk PDO.
  1236. Return Value:
  1237. FALSE - Failure.
  1238. TRUE - Success.
  1239. --*/
  1240. {
  1241. WCHAR volumeName[30];
  1242. UNICODE_STRING volumeString;
  1243. NTSTATUS status;
  1244. PDEVICE_OBJECT deviceObject;
  1245. PVOLUME_EXTENSION extension, e;
  1246. PWCHAR buf;
  1247. ULONG signature;
  1248. LONGLONG offset, size;
  1249. PLIST_ENTRY l;
  1250. LONG r;
  1251. GUID uniqueGuid;
  1252. UNICODE_STRING guidString;
  1253. BOOLEAN IsGpt;
  1254. ASSERT(TargetObject || FtVolume);
  1255. ASSERT(!(TargetObject && FtVolume));
  1256. ASSERT(!TargetObject || WholeDiskPdo);
  1257. swprintf(volumeName, L"\\Device\\HarddiskVolume%d",
  1258. RootExtension->NextVolumeNumber);
  1259. RtlInitUnicodeString(&volumeString, volumeName);
  1260. status = IoCreateDevice(RootExtension->DriverObject,
  1261. sizeof(VOLUME_EXTENSION),
  1262. &volumeString, FILE_DEVICE_DISK, 0,
  1263. FALSE, &deviceObject);
  1264. if (!NT_SUCCESS(status)) {
  1265. return FALSE;
  1266. }
  1267. extension = (PVOLUME_EXTENSION) deviceObject->DeviceExtension;
  1268. RtlZeroMemory(extension, sizeof(VOLUME_EXTENSION));
  1269. extension->DeviceObject = deviceObject;
  1270. extension->Root = RootExtension;
  1271. extension->DeviceExtensionType = DEVICE_EXTENSION_VOLUME;
  1272. KeInitializeSpinLock(&extension->SpinLock);
  1273. extension->TargetObject = TargetObject;
  1274. extension->FtVolume = FtVolume;
  1275. extension->RefCount = 1;
  1276. InitializeListHead(&extension->ZeroRefHoldQueue);
  1277. extension->IsStarted = FALSE;
  1278. extension->IsOffline = TRUE;
  1279. extension->IsHidden = IsHidden;
  1280. extension->IsReadOnly = IsReadOnly;
  1281. extension->IsEspType = IsEspType;
  1282. extension->VolumeNumber = RootExtension->NextVolumeNumber++;
  1283. extension->EmergencyTransferPacket = new DISPATCH_TP;
  1284. InitializeListHead(&extension->EmergencyTransferPacketQueue);
  1285. extension->MbrGptAttributes = MbrGptAttributes;
  1286. if (!extension->EmergencyTransferPacket) {
  1287. IoDeleteDevice(deviceObject);
  1288. return FALSE;
  1289. }
  1290. InitializeListHead(&extension->ChangeNotifyIrps);
  1291. buf = (PWCHAR) ExAllocatePool(PagedPool, 80*sizeof(WCHAR));
  1292. if (!buf) {
  1293. delete extension->EmergencyTransferPacket;
  1294. IoDeleteDevice(deviceObject);
  1295. return FALSE;
  1296. }
  1297. if (TargetObject) {
  1298. extension->WholeDiskPdo = WholeDiskPdo;
  1299. extension->WholeDisk = IoGetAttachedDeviceReference(WholeDiskPdo);
  1300. ObDereferenceObject(extension->WholeDisk);
  1301. status = FtpQueryPartitionInformation(RootExtension, TargetObject,
  1302. NULL, &offset, NULL, NULL,
  1303. &size, NULL, &uniqueGuid,
  1304. &IsGpt, NULL);
  1305. if (!NT_SUCCESS(status)) {
  1306. delete extension->EmergencyTransferPacket;
  1307. IoDeleteDevice(deviceObject);
  1308. return FALSE;
  1309. }
  1310. extension->PartitionOffset = offset;
  1311. extension->PartitionLength = size;
  1312. if (IsGpt) {
  1313. extension->IsGpt = TRUE;
  1314. extension->UniqueIdGuid = uniqueGuid;
  1315. if (IsEspType &&
  1316. IsEqualGUID(uniqueGuid,
  1317. RootExtension->ESPUniquePartitionGUID)) {
  1318. IoSetSystemPartition(&volumeString);
  1319. }
  1320. status = RtlStringFromGUID(uniqueGuid, &guidString);
  1321. if (!NT_SUCCESS(status)) {
  1322. delete extension->EmergencyTransferPacket;
  1323. IoDeleteDevice(deviceObject);
  1324. return FALSE;
  1325. }
  1326. swprintf(buf, L"GptPartition%s", guidString.Buffer);
  1327. ExFreePool(guidString.Buffer);
  1328. } else if (offset == 0) {
  1329. extension->IsSuperFloppy = TRUE;
  1330. ExFreePool(buf);
  1331. status = FtpQuerySuperFloppyDevnodeName(extension, &buf);
  1332. if (!NT_SUCCESS(status)) {
  1333. delete extension->EmergencyTransferPacket;
  1334. IoDeleteDevice(deviceObject);
  1335. return FALSE;
  1336. }
  1337. } else {
  1338. signature = FtpQueryDiskSignature(extension->WholeDiskPdo);
  1339. if (!signature) {
  1340. delete extension->EmergencyTransferPacket;
  1341. IoDeleteDevice(deviceObject);
  1342. return FALSE;
  1343. }
  1344. swprintf(buf, L"Signature%XOffset%I64XLength%I64X", signature,
  1345. offset, size);
  1346. }
  1347. } else {
  1348. swprintf(buf, L"Ft%I64X", FtVolume->QueryLogicalDiskId());
  1349. }
  1350. RtlInitUnicodeString(&extension->DeviceNodeName, buf);
  1351. KeInitializeSemaphore(&extension->Semaphore, 1, 1);
  1352. InsertTailList(&RootExtension->VolumeList, &extension->ListEntry);
  1353. deviceObject->Flags |= DO_DIRECT_IO;
  1354. deviceObject->AlignmentRequirement = AlignmentRequirement;
  1355. if (FtVolume) {
  1356. deviceObject->StackSize = FtVolume->QueryStackSize() + 1;
  1357. } else {
  1358. deviceObject->StackSize = TargetObject->StackSize + 1;
  1359. }
  1360. if (IsPreExposure) {
  1361. extension->TargetObject = NULL;
  1362. extension->FtVolume = NULL;
  1363. extension->IsPreExposure = TRUE;
  1364. extension->WholeDiskPdo = NULL;
  1365. extension->WholeDisk = NULL;
  1366. extension->PartitionOffset = 0;
  1367. extension->PartitionLength = 0;
  1368. r = 1;
  1369. for (l = RootExtension->VolumeList.Flink;
  1370. l != &RootExtension->VolumeList; l = l->Flink) {
  1371. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  1372. if (e == extension) {
  1373. continue;
  1374. }
  1375. r = RtlCompareUnicodeString(&e->DeviceNodeName,
  1376. &extension->DeviceNodeName, TRUE);
  1377. if (!r) {
  1378. break;
  1379. }
  1380. }
  1381. if (!r) {
  1382. RemoveEntryList(&extension->ListEntry);
  1383. ExFreePool(extension->DeviceNodeName.Buffer);
  1384. delete extension->EmergencyTransferPacket;
  1385. IoDeleteDevice(deviceObject);
  1386. return FALSE;
  1387. }
  1388. RootExtension->PreExposureCount++;
  1389. } else {
  1390. FtpCreateOldNameLinks(extension);
  1391. }
  1392. if (!IsPreExposure && RootExtension->PreExposureCount) {
  1393. r = 1;
  1394. for (l = RootExtension->VolumeList.Flink;
  1395. l != &RootExtension->VolumeList; l = l->Flink) {
  1396. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  1397. if (e == extension) {
  1398. continue;
  1399. }
  1400. if (!e->IsPreExposure) {
  1401. continue;
  1402. }
  1403. r = RtlCompareUnicodeString(&e->DeviceNodeName,
  1404. &extension->DeviceNodeName, TRUE);
  1405. if (!r) {
  1406. break;
  1407. }
  1408. }
  1409. if (!r) {
  1410. RootExtension->PreExposureCount--;
  1411. RemoveEntryList(&e->ListEntry);
  1412. InsertTailList(&RootExtension->DeadVolumeList, &e->ListEntry);
  1413. FtpCleanupVolumeExtension(e);
  1414. }
  1415. }
  1416. // Allocate WMI library context
  1417. extension->WmilibContext = (PWMILIB_CONTEXT)
  1418. ExAllocatePool(PagedPool, sizeof(WMILIB_CONTEXT));
  1419. if (extension->WmilibContext != NULL) {
  1420. RtlZeroMemory(extension->WmilibContext, sizeof(WMILIB_CONTEXT));
  1421. extension->WmilibContext->GuidCount = DiskperfGuidCount;
  1422. extension->WmilibContext->GuidList = DiskperfGuidList;
  1423. extension->WmilibContext->QueryWmiRegInfo = FtQueryWmiRegInfo;
  1424. extension->WmilibContext->QueryWmiDataBlock = FtQueryWmiDataBlock;
  1425. extension->WmilibContext->WmiFunctionControl = FtWmiFunctionControl;
  1426. }
  1427. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  1428. return TRUE;
  1429. }
  1430. PVOLUME_EXTENSION
  1431. FtpFindExtension(
  1432. IN PROOT_EXTENSION RootExtension,
  1433. IN ULONG Signature,
  1434. IN LONGLONG Offset
  1435. )
  1436. /*++
  1437. Routine Description:
  1438. This routine finds the device extension for the given partition.
  1439. Arguments:
  1440. RootExtension - Supplies the root device extension.
  1441. Signature - Supplies the partition's disk signature.
  1442. Offset - Supplies the partition's offset.
  1443. Return Value:
  1444. A volume extension or NULL.
  1445. --*/
  1446. {
  1447. PLIST_ENTRY l;
  1448. PVOLUME_EXTENSION extension;
  1449. ULONG signature;
  1450. NTSTATUS status;
  1451. LONGLONG offset;
  1452. for (l = RootExtension->VolumeList.Flink; l != &RootExtension->VolumeList;
  1453. l = l->Flink) {
  1454. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  1455. if (!extension->TargetObject) {
  1456. continue;
  1457. }
  1458. signature = FtpQueryDiskSignature(extension->WholeDiskPdo);
  1459. if (Signature != signature) {
  1460. continue;
  1461. }
  1462. status = FtpQueryPartitionInformation(RootExtension,
  1463. extension->TargetObject,
  1464. NULL, &offset, NULL, NULL, NULL,
  1465. NULL, NULL, NULL, NULL);
  1466. if (!NT_SUCCESS(status)) {
  1467. continue;
  1468. }
  1469. if (offset != Offset) {
  1470. continue;
  1471. }
  1472. return extension;
  1473. }
  1474. return NULL;
  1475. }
  1476. BOOLEAN
  1477. FtpQueryNtDeviceNameString(
  1478. IN PROOT_EXTENSION RootExtension,
  1479. IN ULONG Signature,
  1480. IN LONGLONG Offset,
  1481. OUT PUNICODE_STRING String
  1482. )
  1483. {
  1484. PVOLUME_EXTENSION extension;
  1485. PWSTR stringBuffer;
  1486. extension = FtpFindExtension(RootExtension, Signature, Offset);
  1487. if (!extension) {
  1488. return FALSE;
  1489. }
  1490. stringBuffer = (PWSTR) ExAllocatePool(PagedPool, 128);
  1491. if (!stringBuffer) {
  1492. return FALSE;
  1493. }
  1494. swprintf(stringBuffer, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  1495. RtlInitUnicodeString(String, stringBuffer);
  1496. return TRUE;
  1497. }
  1498. BOOLEAN
  1499. FtpQueryNtDeviceNameString(
  1500. IN PROOT_EXTENSION RootExtension,
  1501. IN FT_LOGICAL_DISK_ID RootLogicalDiskId,
  1502. OUT PUNICODE_STRING String
  1503. )
  1504. {
  1505. PVOLUME_EXTENSION extension;
  1506. PWSTR stringBuffer;
  1507. extension = FtpFindExtension(RootExtension, RootLogicalDiskId);
  1508. if (!extension) {
  1509. return FALSE;
  1510. }
  1511. stringBuffer = (PWSTR) ExAllocatePool(PagedPool, 128);
  1512. if (!stringBuffer) {
  1513. return FALSE;
  1514. }
  1515. swprintf(stringBuffer, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  1516. RtlInitUnicodeString(String, stringBuffer);
  1517. return TRUE;
  1518. }
  1519. BOOLEAN
  1520. FtpLockLogicalDisk(
  1521. IN PROOT_EXTENSION RootExtension,
  1522. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1523. OUT PHANDLE Handle
  1524. )
  1525. /*++
  1526. Routine Description:
  1527. This routine attempts to lock the given logical disk id by going through
  1528. the file system. If it is successful then it returns the handle to the
  1529. locked volume.
  1530. Arguments:
  1531. RootExtension - Supplies the root extension.
  1532. LogicalDiskId - Supplies the logical disk id.
  1533. Handle - Returns a handle to the locked volume.
  1534. Return Value:
  1535. FALSE - Failure.
  1536. TRUE - Success.
  1537. --*/
  1538. {
  1539. UNICODE_STRING string;
  1540. OBJECT_ATTRIBUTES oa;
  1541. NTSTATUS status;
  1542. IO_STATUS_BLOCK ioStatus;
  1543. if (!FtpQueryNtDeviceNameString(RootExtension, LogicalDiskId, &string)) {
  1544. return FALSE;
  1545. }
  1546. FtpRelease(RootExtension);
  1547. InitializeObjectAttributes(&oa, &string, OBJ_CASE_INSENSITIVE, 0, 0);
  1548. status = ZwOpenFile(Handle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  1549. &oa, &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1550. FILE_SYNCHRONOUS_IO_ALERT);
  1551. ExFreePool(string.Buffer);
  1552. if (!NT_SUCCESS(status)) {
  1553. FtpAcquire(RootExtension);
  1554. return FALSE;
  1555. }
  1556. status = ZwFsControlFile(*Handle, 0, NULL, NULL, &ioStatus,
  1557. FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);
  1558. if (!NT_SUCCESS(status)) {
  1559. ZwClose(*Handle);
  1560. FtpAcquire(RootExtension);
  1561. return FALSE;
  1562. }
  1563. FtpAcquire(RootExtension);
  1564. return TRUE;
  1565. }
  1566. VOID
  1567. FtpUniqueIdNotify(
  1568. IN PVOLUME_EXTENSION Extension,
  1569. IN PMOUNTDEV_UNIQUE_ID NewUniqueId
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. This routine goes through all of the mount manager clients that
  1574. have registered to be aware of unique id changes to devices.
  1575. Arguments:
  1576. Extension - Supplies the volume extension.
  1577. NewUniqueId - Supplies the new unique id.
  1578. Return Value:
  1579. None.
  1580. --*/
  1581. {
  1582. PMOUNTDEV_UNIQUE_ID oldUniqueId;
  1583. UCHAR oldUniqueIdBuffer[UNIQUE_ID_MAX_BUFFER_SIZE];
  1584. PLIST_ENTRY l;
  1585. PIRP irp;
  1586. PIO_STACK_LOCATION irpSp;
  1587. PMOUNTDEV_UNIQUE_ID input;
  1588. ULONG inputLength, outputLength;
  1589. PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT output;
  1590. oldUniqueId = (PMOUNTDEV_UNIQUE_ID) oldUniqueIdBuffer;
  1591. while (!IsListEmpty(&Extension->ChangeNotifyIrps)) {
  1592. l = RemoveHeadList(&Extension->ChangeNotifyIrps);
  1593. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  1594. //
  1595. // Remove cancel routine. If cancel is active let it complete this IRP.
  1596. //
  1597. if (IoSetCancelRoutine (irp, NULL) == NULL) {
  1598. InitializeListHead (&irp->Tail.Overlay.ListEntry);
  1599. continue;
  1600. }
  1601. irpSp = IoGetCurrentIrpStackLocation(irp);
  1602. input = (PMOUNTDEV_UNIQUE_ID) irp->AssociatedIrp.SystemBuffer;
  1603. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  1604. sizeof(MOUNTDEV_UNIQUE_ID)) {
  1605. irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1606. irp->IoStatus.Information = 0;
  1607. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1608. continue;
  1609. }
  1610. inputLength = FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) +
  1611. input->UniqueIdLength;
  1612. if (inputLength >
  1613. irpSp->Parameters.DeviceIoControl.InputBufferLength) {
  1614. irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1615. irp->IoStatus.Information = 0;
  1616. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1617. continue;
  1618. }
  1619. if (inputLength > 20) {
  1620. irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1621. irp->IoStatus.Information = 0;
  1622. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1623. continue;
  1624. }
  1625. RtlCopyMemory(oldUniqueId, input, inputLength);
  1626. outputLength = sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) +
  1627. oldUniqueId->UniqueIdLength +
  1628. NewUniqueId->UniqueIdLength;
  1629. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1630. sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT)) {
  1631. irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1632. irp->IoStatus.Information = 0;
  1633. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1634. continue;
  1635. }
  1636. output = (PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT)
  1637. irp->AssociatedIrp.SystemBuffer;
  1638. output->Size = outputLength;
  1639. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1640. outputLength) {
  1641. irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  1642. irp->IoStatus.Information =
  1643. sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT);
  1644. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1645. continue;
  1646. }
  1647. output->OldUniqueIdOffset =
  1648. sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT);
  1649. output->OldUniqueIdLength = oldUniqueId->UniqueIdLength;
  1650. output->NewUniqueIdOffset = output->OldUniqueIdOffset +
  1651. output->OldUniqueIdLength;
  1652. output->NewUniqueIdLength = NewUniqueId->UniqueIdLength;
  1653. RtlCopyMemory((PCHAR) output + output->OldUniqueIdOffset,
  1654. oldUniqueId->UniqueId, output->OldUniqueIdLength);
  1655. RtlCopyMemory((PCHAR) output + output->NewUniqueIdOffset,
  1656. NewUniqueId->UniqueId, output->NewUniqueIdLength);
  1657. irp->IoStatus.Status = STATUS_SUCCESS;
  1658. irp->IoStatus.Information = output->Size;
  1659. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1660. }
  1661. // Perform a pre-exposure of the new devnode to avoid the PNP reboot
  1662. // pop-up.
  1663. if (FtpCreateNewDevice(Extension->Root, Extension->TargetObject,
  1664. Extension->FtVolume, Extension->WholeDiskPdo,
  1665. Extension->DeviceObject->AlignmentRequirement,
  1666. TRUE, TRUE, FALSE, FALSE, 0)) {
  1667. IoInvalidateDeviceRelations(Extension->Root->Pdo, BusRelations);
  1668. }
  1669. }
  1670. NTSTATUS
  1671. FtpDeleteMountPoints(
  1672. IN PVOLUME_EXTENSION Extension
  1673. )
  1674. /*++
  1675. Routine Description:
  1676. This routine deletes the all of the entries in the mount table that
  1677. are pointing to the given unique id.
  1678. Arguments:
  1679. Extension - Supplies the volume extension.
  1680. Return Value:
  1681. NTSTATUS
  1682. --*/
  1683. {
  1684. UNICODE_STRING name;
  1685. NTSTATUS status;
  1686. PFILE_OBJECT fileObject;
  1687. PDEVICE_OBJECT deviceObject;
  1688. WCHAR deviceNameBuffer[30];
  1689. UNICODE_STRING deviceName;
  1690. PMOUNTMGR_MOUNT_POINT point;
  1691. UCHAR buffer[sizeof(MOUNTMGR_MOUNT_POINT) + 60];
  1692. PVOID mountPoints;
  1693. KEVENT event;
  1694. PIRP irp;
  1695. IO_STATUS_BLOCK ioStatus;
  1696. RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
  1697. status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &fileObject,
  1698. &deviceObject);
  1699. if (!NT_SUCCESS(status)) {
  1700. return status;
  1701. }
  1702. swprintf(deviceNameBuffer, L"\\Device\\HarddiskVolume%d", Extension->VolumeNumber);
  1703. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  1704. point = (PMOUNTMGR_MOUNT_POINT) buffer;
  1705. RtlZeroMemory(point, sizeof(MOUNTMGR_MOUNT_POINT));
  1706. point->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1707. point->DeviceNameLength = deviceName.Length;
  1708. RtlCopyMemory((PCHAR) point + point->DeviceNameOffset, deviceName.Buffer,
  1709. point->DeviceNameLength);
  1710. mountPoints = ExAllocatePool(PagedPool, PAGE_SIZE);
  1711. if (!mountPoints) {
  1712. ObDereferenceObject(fileObject);
  1713. return STATUS_INSUFFICIENT_RESOURCES;
  1714. }
  1715. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1716. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
  1717. deviceObject, point,
  1718. sizeof(MOUNTMGR_MOUNT_POINT) +
  1719. point->DeviceNameLength, mountPoints,
  1720. PAGE_SIZE, FALSE, &event, &ioStatus);
  1721. if (!irp) {
  1722. ExFreePool(mountPoints);
  1723. ObDereferenceObject(fileObject);
  1724. return STATUS_INSUFFICIENT_RESOURCES;
  1725. }
  1726. status = IoCallDriver(deviceObject, irp);
  1727. if (status == STATUS_PENDING) {
  1728. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1729. status = ioStatus.Status;
  1730. }
  1731. ExFreePool(mountPoints);
  1732. ObDereferenceObject(fileObject);
  1733. return status;
  1734. }
  1735. VOID
  1736. FtpCleanupVolumeExtension(
  1737. IN OUT PVOLUME_EXTENSION Extension
  1738. )
  1739. {
  1740. PLIST_ENTRY l;
  1741. PIRP irp;
  1742. PPMWMICOUNTERLIB_CONTEXT counterLib;
  1743. if (Extension->EmergencyTransferPacket) {
  1744. delete Extension->EmergencyTransferPacket;
  1745. Extension->EmergencyTransferPacket = NULL;
  1746. }
  1747. while (!IsListEmpty(&Extension->ChangeNotifyIrps)) {
  1748. l = RemoveHeadList(&Extension->ChangeNotifyIrps);
  1749. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  1750. //
  1751. // Remove cancel routine. If cancel is active let it complete this IRP.
  1752. //
  1753. if (IoSetCancelRoutine (irp, NULL) == NULL) {
  1754. InitializeListHead (&irp->Tail.Overlay.ListEntry);
  1755. continue;
  1756. }
  1757. irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1758. irp->IoStatus.Information = 0;
  1759. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1760. }
  1761. if (Extension->WmilibContext != NULL) {
  1762. IoWMIRegistrationControl(Extension->DeviceObject,
  1763. WMIREG_ACTION_DEREGISTER);
  1764. ExFreePool(Extension->WmilibContext);
  1765. Extension->WmilibContext = NULL;
  1766. counterLib = &Extension->Root->PmWmiCounterLibContext;
  1767. counterLib->PmWmiCounterDisable(&Extension->PmWmiCounterContext,
  1768. TRUE, TRUE);
  1769. Extension->CountersEnabled = FALSE;
  1770. }
  1771. }
  1772. NTSTATUS
  1773. FtpStartSystemThread(
  1774. IN PROOT_EXTENSION RootExtension
  1775. )
  1776. {
  1777. OBJECT_ATTRIBUTES oa;
  1778. NTSTATUS status;
  1779. HANDLE handle;
  1780. if (!RootExtension->TerminateThread) {
  1781. return STATUS_SUCCESS;
  1782. }
  1783. InterlockedExchange(&RootExtension->TerminateThread, FALSE);
  1784. InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
  1785. status = PsCreateSystemThread(&handle, 0, &oa, 0, NULL, FtpWorkerThread,
  1786. RootExtension);
  1787. if (!NT_SUCCESS(status)) {
  1788. return status;
  1789. }
  1790. status = ObReferenceObjectByHandle(handle, THREAD_ALL_ACCESS, NULL,
  1791. KernelMode,
  1792. &RootExtension->WorkerThread, NULL);
  1793. ZwClose(handle);
  1794. if (!NT_SUCCESS(status)) {
  1795. InterlockedExchange(&RootExtension->TerminateThread, TRUE);
  1796. }
  1797. return status;
  1798. }
  1799. NTSTATUS
  1800. FtpCreateLogicalDisk(
  1801. IN OUT PROOT_EXTENSION RootExtension,
  1802. IN OUT PIRP Irp
  1803. )
  1804. /*++
  1805. Routine Description:
  1806. This routine creates the given logical disk.
  1807. Arguments:
  1808. RootExtension - Supplies the root extension.
  1809. Irp - Supplies the I/O request packet.
  1810. Return Value:
  1811. NTSTATUS
  1812. --*/
  1813. {
  1814. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1815. PFT_CREATE_LOGICAL_DISK_INPUT createDisk;
  1816. ULONG inputSize;
  1817. PVOID configInfo;
  1818. NTSTATUS status;
  1819. FT_LOGICAL_DISK_ID newLogicalDiskId;
  1820. PFT_CREATE_LOGICAL_DISK_OUTPUT createDiskOutput;
  1821. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  1822. sizeof(FT_CREATE_LOGICAL_DISK_INPUT) ||
  1823. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1824. sizeof(FT_CREATE_LOGICAL_DISK_OUTPUT)) {
  1825. return STATUS_INVALID_PARAMETER;
  1826. }
  1827. createDisk = (PFT_CREATE_LOGICAL_DISK_INPUT)
  1828. Irp->AssociatedIrp.SystemBuffer;
  1829. inputSize = FIELD_OFFSET(FT_CREATE_LOGICAL_DISK_INPUT, MemberArray) +
  1830. createDisk->NumberOfMembers*sizeof(FT_LOGICAL_DISK_ID) +
  1831. createDisk->ConfigurationInformationSize;
  1832. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < inputSize) {
  1833. return STATUS_INVALID_PARAMETER;
  1834. }
  1835. configInfo = &createDisk->MemberArray[createDisk->NumberOfMembers];
  1836. if (!RootExtension->FtCodeLocked) {
  1837. MmLockPagableCodeSection(FtpComputeParity);
  1838. status = FtpStartSystemThread(RootExtension);
  1839. if (!NT_SUCCESS(status)) {
  1840. return status;
  1841. }
  1842. RootExtension->FtCodeLocked = TRUE;
  1843. }
  1844. status = FtpCreateLogicalDiskHelper(RootExtension,
  1845. createDisk->LogicalDiskType,
  1846. createDisk->NumberOfMembers,
  1847. createDisk->MemberArray,
  1848. createDisk->ConfigurationInformationSize,
  1849. configInfo, 0, NULL, &newLogicalDiskId);
  1850. if (!NT_SUCCESS(status)) {
  1851. return status;
  1852. }
  1853. createDiskOutput = (PFT_CREATE_LOGICAL_DISK_OUTPUT)
  1854. Irp->AssociatedIrp.SystemBuffer;
  1855. createDiskOutput->NewLogicalDiskId = newLogicalDiskId;
  1856. Irp->IoStatus.Information = sizeof(FT_CREATE_LOGICAL_DISK_OUTPUT);
  1857. return status;
  1858. }
  1859. VOID
  1860. FtpResetPartitionType(
  1861. IN PVOLUME_EXTENSION Extension
  1862. )
  1863. /*++
  1864. Routine Description:
  1865. This routine resets the FT bit in the partition type.
  1866. Arguments:
  1867. Extension - Supplies the volume extension.
  1868. Return Value:
  1869. None.
  1870. --*/
  1871. {
  1872. PDEVICE_OBJECT targetObject;
  1873. KEVENT event;
  1874. PIRP irp;
  1875. PARTITION_INFORMATION partInfo;
  1876. IO_STATUS_BLOCK ioStatus;
  1877. NTSTATUS status;
  1878. SET_PARTITION_INFORMATION setPartInfo;
  1879. targetObject = Extension->TargetObject;
  1880. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1881. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
  1882. targetObject, NULL, 0, &partInfo,
  1883. sizeof(partInfo), FALSE, &event,
  1884. &ioStatus);
  1885. if (!irp) {
  1886. return;
  1887. }
  1888. status = IoCallDriver(targetObject, irp);
  1889. if (status == STATUS_PENDING) {
  1890. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1891. status = ioStatus.Status;
  1892. }
  1893. if (!NT_SUCCESS(status)) {
  1894. return;
  1895. }
  1896. setPartInfo.PartitionType = (partInfo.PartitionType & ~(0x80));
  1897. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1898. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_PARTITION_INFO,
  1899. targetObject, &setPartInfo,
  1900. sizeof(setPartInfo), NULL, 0, FALSE,
  1901. &event, &ioStatus);
  1902. if (!irp) {
  1903. return;
  1904. }
  1905. status = IoCallDriver(targetObject, irp);
  1906. if (status == STATUS_PENDING) {
  1907. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1908. }
  1909. }
  1910. NTSTATUS
  1911. FtpBreakLogicalDisk(
  1912. IN OUT PROOT_EXTENSION RootExtension,
  1913. IN OUT PIRP Irp
  1914. )
  1915. /*++
  1916. Routine Description:
  1917. This routine breaks a given logical disk.
  1918. Arguments:
  1919. RootExtension - Supplies the root extension.
  1920. Irp - Supplies the I/O request packet.
  1921. Return Value:
  1922. NTSTATUS
  1923. --*/
  1924. {
  1925. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1926. PFT_BREAK_LOGICAL_DISK_INPUT input;
  1927. FT_LOGICAL_DISK_ID diskId;
  1928. NTSTATUS status;
  1929. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  1930. sizeof(FT_BREAK_LOGICAL_DISK_INPUT)) {
  1931. return STATUS_INVALID_PARAMETER;
  1932. }
  1933. input = (PFT_BREAK_LOGICAL_DISK_INPUT) Irp->AssociatedIrp.SystemBuffer;
  1934. diskId = input->RootLogicalDiskId;
  1935. status = FtpBreakLogicalDiskHelper(RootExtension, diskId);
  1936. return status;
  1937. }
  1938. NTSTATUS
  1939. FtpEnumerateLogicalDisks(
  1940. IN OUT PROOT_EXTENSION RootExtension,
  1941. IN OUT PIRP Irp
  1942. )
  1943. /*++
  1944. Routine Description:
  1945. This routine enumerates all of the logical disks in the system.
  1946. Arguments:
  1947. RootExtension - Supplies the root extension.
  1948. Irp - Supplies the I/O request packet.
  1949. Return Value:
  1950. NTSTATUS
  1951. --*/
  1952. {
  1953. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1954. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  1955. PFT_ENUMERATE_LOGICAL_DISKS_OUTPUT output;
  1956. ULONG i;
  1957. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1958. sizeof(FT_ENUMERATE_LOGICAL_DISKS_OUTPUT)) {
  1959. return STATUS_INVALID_PARAMETER;
  1960. }
  1961. diskInfoSet = RootExtension->DiskInfoSet;
  1962. output = (PFT_ENUMERATE_LOGICAL_DISKS_OUTPUT)
  1963. Irp->AssociatedIrp.SystemBuffer;
  1964. output->NumberOfRootLogicalDisks =
  1965. diskInfoSet->QueryNumberOfRootLogicalDiskIds();
  1966. Irp->IoStatus.Information = FIELD_OFFSET(FT_ENUMERATE_LOGICAL_DISKS_OUTPUT,
  1967. RootLogicalDiskIds) +
  1968. output->NumberOfRootLogicalDisks*
  1969. sizeof(FT_LOGICAL_DISK_ID);
  1970. if (Irp->IoStatus.Information >
  1971. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  1972. Irp->IoStatus.Information =
  1973. FIELD_OFFSET(FT_ENUMERATE_LOGICAL_DISKS_OUTPUT,
  1974. RootLogicalDiskIds);
  1975. return STATUS_BUFFER_OVERFLOW;
  1976. }
  1977. for (i = 0; i < output->NumberOfRootLogicalDisks; i++) {
  1978. output->RootLogicalDiskIds[i] = diskInfoSet->QueryRootLogicalDiskId(i);
  1979. }
  1980. return STATUS_SUCCESS;
  1981. }
  1982. NTSTATUS
  1983. FtpQueryLogicalDiskInformation(
  1984. IN OUT PROOT_EXTENSION RootExtension,
  1985. IN OUT PIRP Irp
  1986. )
  1987. /*++
  1988. Routine Description:
  1989. This routine returns the logical disk information.
  1990. Arguments:
  1991. RootExtension - Supplies the root extension.
  1992. Irp - Supplies the I/O request packet.
  1993. Return Value:
  1994. NTSTATUS
  1995. --*/
  1996. {
  1997. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1998. PFT_QUERY_LOGICAL_DISK_INFORMATION_INPUT input;
  1999. PFT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT output;
  2000. FT_LOGICAL_DISK_ID diskId;
  2001. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  2002. PVOLUME_EXTENSION extension;
  2003. PFT_VOLUME topVol, vol;
  2004. PFT_LOGICAL_DISK_DESCRIPTION diskDescription;
  2005. PFT_PARTITION_CONFIGURATION_INFORMATION partInfo;
  2006. LONGLONG offset;
  2007. PDEVICE_OBJECT wholeDisk;
  2008. ULONG diskNumber, sectorSize;
  2009. PDRIVE_LAYOUT_INFORMATION_EX layout;
  2010. NTSTATUS status;
  2011. USHORT i;
  2012. PCHAR p, q;
  2013. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2014. sizeof(FT_QUERY_LOGICAL_DISK_INFORMATION_INPUT) ||
  2015. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2016. sizeof(FT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT)) {
  2017. return STATUS_INVALID_PARAMETER;
  2018. }
  2019. input = (PFT_QUERY_LOGICAL_DISK_INFORMATION_INPUT)
  2020. Irp->AssociatedIrp.SystemBuffer;
  2021. output = (PFT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT)
  2022. Irp->AssociatedIrp.SystemBuffer;
  2023. diskId = input->LogicalDiskId;
  2024. diskInfoSet = RootExtension->DiskInfoSet;
  2025. diskDescription = diskInfoSet->GetLogicalDiskDescription(diskId, 0);
  2026. if (!diskDescription) {
  2027. return STATUS_INVALID_PARAMETER;
  2028. }
  2029. output->LogicalDiskType = diskDescription->LogicalDiskType;
  2030. output->VolumeSize = 0;
  2031. extension = FtpFindExtensionCoveringDiskId(RootExtension, diskId);
  2032. if (extension) {
  2033. topVol = extension->FtVolume;
  2034. vol = topVol->GetContainedLogicalDisk(diskId);
  2035. output->VolumeSize = vol->QueryVolumeSize();
  2036. }
  2037. if (output->LogicalDiskType == FtPartition) {
  2038. if (!diskInfoSet->QueryFtPartitionInformation(diskId, &offset,
  2039. &wholeDisk, &diskNumber,
  2040. &sectorSize, NULL)) {
  2041. Irp->IoStatus.Information = 0;
  2042. return STATUS_INVALID_PARAMETER;
  2043. }
  2044. status = FtpReadPartitionTableEx(wholeDisk, &layout);
  2045. if (!NT_SUCCESS(status)) {
  2046. Irp->IoStatus.Information = 0;
  2047. return status;
  2048. }
  2049. output->NumberOfMembers = 0;
  2050. output->ConfigurationInformationSize =
  2051. sizeof(FT_PARTITION_CONFIGURATION_INFORMATION);
  2052. output->StateInformationSize = 0;
  2053. output->Reserved = 0;
  2054. Irp->IoStatus.Information =
  2055. FIELD_OFFSET(FT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT,
  2056. MemberArray) +
  2057. output->ConfigurationInformationSize;
  2058. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2059. Irp->IoStatus.Information) {
  2060. Irp->IoStatus.Information =
  2061. FIELD_OFFSET(FT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT,
  2062. MemberArray);
  2063. ExFreePool(layout);
  2064. return STATUS_BUFFER_OVERFLOW;
  2065. }
  2066. partInfo = (PFT_PARTITION_CONFIGURATION_INFORMATION)
  2067. ((PCHAR) output +
  2068. FIELD_OFFSET(FT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT,
  2069. MemberArray));
  2070. partInfo->Signature = layout->Mbr.Signature;
  2071. partInfo->DiskNumber = diskNumber;
  2072. partInfo->ByteOffset = offset;
  2073. ExFreePool(layout);
  2074. } else {
  2075. output->NumberOfMembers = diskDescription->u.Other.NumberOfMembers;
  2076. if (diskDescription->u.Other.ByteOffsetToConfigurationInformation) {
  2077. if (diskDescription->u.Other.ByteOffsetToStateInformation) {
  2078. output->ConfigurationInformationSize =
  2079. diskDescription->u.Other.ByteOffsetToStateInformation -
  2080. diskDescription->u.Other.ByteOffsetToConfigurationInformation;
  2081. } else {
  2082. output->ConfigurationInformationSize =
  2083. diskDescription->DiskDescriptionSize -
  2084. diskDescription->u.Other.ByteOffsetToConfigurationInformation;
  2085. }
  2086. } else {
  2087. output->ConfigurationInformationSize = 0;
  2088. }
  2089. if (diskDescription->u.Other.ByteOffsetToStateInformation) {
  2090. output->StateInformationSize =
  2091. diskDescription->DiskDescriptionSize -
  2092. diskDescription->u.Other.ByteOffsetToStateInformation;
  2093. } else {
  2094. output->StateInformationSize = 0;
  2095. }
  2096. diskDescription->Reserved = 0;
  2097. Irp->IoStatus.Information =
  2098. FIELD_OFFSET(FT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT,
  2099. MemberArray) +
  2100. output->NumberOfMembers*sizeof(FT_LOGICAL_DISK_ID) +
  2101. output->ConfigurationInformationSize +
  2102. output->StateInformationSize;
  2103. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2104. Irp->IoStatus.Information) {
  2105. Irp->IoStatus.Information =
  2106. FIELD_OFFSET(FT_QUERY_LOGICAL_DISK_INFORMATION_OUTPUT,
  2107. MemberArray);
  2108. return STATUS_BUFFER_OVERFLOW;
  2109. }
  2110. for (i = 0; i < output->NumberOfMembers; i++) {
  2111. output->MemberArray[i] =
  2112. diskInfoSet->QueryMemberLogicalDiskId(diskId, i);
  2113. }
  2114. if (output->ConfigurationInformationSize) {
  2115. p = (PCHAR) &output->MemberArray[output->NumberOfMembers];
  2116. q = (PCHAR) diskDescription +
  2117. diskDescription->u.Other.ByteOffsetToConfigurationInformation;
  2118. RtlCopyMemory(p, q, output->ConfigurationInformationSize);
  2119. }
  2120. if (output->StateInformationSize) {
  2121. p = (PCHAR) &output->MemberArray[output->NumberOfMembers] +
  2122. output->ConfigurationInformationSize;
  2123. q = (PCHAR) diskDescription +
  2124. diskDescription->u.Other.ByteOffsetToStateInformation;
  2125. RtlCopyMemory(p, q, output->StateInformationSize);
  2126. vol->ModifyStateForUser(p);
  2127. }
  2128. }
  2129. return STATUS_SUCCESS;
  2130. }
  2131. NTSTATUS
  2132. FtpOrphanLogicalDiskMember(
  2133. IN OUT PROOT_EXTENSION RootExtension,
  2134. IN OUT PIRP Irp
  2135. )
  2136. /*++
  2137. Routine Description:
  2138. This routine orphans the given logical disk member.
  2139. Arguments:
  2140. RootExtension - Supplies the root extension.
  2141. Irp - Supplies the I/O request packet.
  2142. Return Value:
  2143. NTSTATUS
  2144. --*/
  2145. {
  2146. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2147. PFT_ORPHAN_LOGICAL_DISK_MEMBER_INPUT input;
  2148. FT_LOGICAL_DISK_ID diskId;
  2149. USHORT member;
  2150. PVOLUME_EXTENSION extension;
  2151. PFT_VOLUME vol;
  2152. NTSTATUS status;
  2153. KEVENT event;
  2154. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2155. sizeof(FT_ORPHAN_LOGICAL_DISK_MEMBER_INPUT)) {
  2156. return STATUS_INVALID_PARAMETER;
  2157. }
  2158. input = (PFT_ORPHAN_LOGICAL_DISK_MEMBER_INPUT)
  2159. Irp->AssociatedIrp.SystemBuffer;
  2160. diskId = input->LogicalDiskId;
  2161. member = input->MemberNumberToOrphan;
  2162. extension = FtpFindExtensionCoveringDiskId(RootExtension, diskId);
  2163. if (!extension || !extension->FtVolume) {
  2164. return STATUS_INVALID_PARAMETER;
  2165. }
  2166. vol = extension->FtVolume->GetContainedLogicalDisk(diskId);
  2167. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2168. status = vol->OrphanMember(member, FtpEventSignalCompletion, &event);
  2169. if (NT_SUCCESS(status)) {
  2170. FtpRelease(RootExtension);
  2171. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2172. FtpAcquire(RootExtension);
  2173. }
  2174. return status;
  2175. }
  2176. NTSTATUS
  2177. FtpQueryNtDeviceNameForLogicalDisk(
  2178. IN OUT PROOT_EXTENSION RootExtension,
  2179. IN OUT PIRP Irp
  2180. )
  2181. /*++
  2182. Routine Description:
  2183. This routine returns the nt device name for the given logical partition.
  2184. Arguments:
  2185. RootExtension - Supplies the root extension.
  2186. Irp - Supplies the I/O request packet.
  2187. Return Value:
  2188. NTSTATUS
  2189. --*/
  2190. {
  2191. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2192. PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_INPUT input;
  2193. PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT output;
  2194. FT_LOGICAL_DISK_ID diskId;
  2195. UNICODE_STRING targetName;
  2196. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2197. sizeof(FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_INPUT) ||
  2198. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2199. sizeof(FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT)) {
  2200. return STATUS_INVALID_PARAMETER;
  2201. }
  2202. input = (PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_INPUT)
  2203. Irp->AssociatedIrp.SystemBuffer;
  2204. output = (PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT)
  2205. Irp->AssociatedIrp.SystemBuffer;
  2206. diskId = input->RootLogicalDiskId;
  2207. if (!FtpQueryNtDeviceNameString(RootExtension, diskId, &targetName)) {
  2208. return STATUS_INVALID_PARAMETER;
  2209. }
  2210. output->NumberOfCharactersInNtDeviceName = targetName.Length/sizeof(WCHAR);
  2211. Irp->IoStatus.Information =
  2212. FIELD_OFFSET(FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT,
  2213. NtDeviceName) +
  2214. output->NumberOfCharactersInNtDeviceName*sizeof(WCHAR);
  2215. if (Irp->IoStatus.Information >
  2216. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  2217. Irp->IoStatus.Information =
  2218. FIELD_OFFSET(FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT,
  2219. NtDeviceName);
  2220. ExFreePool(targetName.Buffer);
  2221. return STATUS_BUFFER_OVERFLOW;
  2222. }
  2223. RtlCopyMemory(output->NtDeviceName, targetName.Buffer,
  2224. targetName.Length);
  2225. ExFreePool(targetName.Buffer);
  2226. return STATUS_SUCCESS;
  2227. }
  2228. NTSTATUS
  2229. FtpQueryDriveLetterForLogicalDisk(
  2230. IN OUT PROOT_EXTENSION RootExtension,
  2231. IN OUT PIRP Irp
  2232. )
  2233. /*++
  2234. Routine Description:
  2235. This routine queries the drive letter for the given root logical disk.
  2236. Arguments:
  2237. Extension - Supplies the root extension.
  2238. Irp - Supplies the I/O request packet.
  2239. Return Value:
  2240. NTSTATUS
  2241. --*/
  2242. {
  2243. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2244. PFT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK_INPUT input;
  2245. PFT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK_OUTPUT output;
  2246. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  2247. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2248. sizeof(FT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK_INPUT) ||
  2249. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2250. sizeof(FT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK_OUTPUT)) {
  2251. return STATUS_INVALID_PARAMETER;
  2252. }
  2253. input = (PFT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK_INPUT)
  2254. Irp->AssociatedIrp.SystemBuffer;
  2255. output = (PFT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK_OUTPUT)
  2256. Irp->AssociatedIrp.SystemBuffer;
  2257. diskInfoSet = RootExtension->DiskInfoSet;
  2258. output->DriveLetter = diskInfoSet->QueryDriveLetter(
  2259. input->RootLogicalDiskId);
  2260. if (output->DriveLetter == 0xFF) {
  2261. output->DriveLetter = 0;
  2262. }
  2263. Irp->IoStatus.Information =
  2264. sizeof(FT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK_OUTPUT);
  2265. return STATUS_SUCCESS;
  2266. }
  2267. NTSTATUS
  2268. FtpDeleteMountLetter(
  2269. IN UCHAR DriveLetter
  2270. )
  2271. /*++
  2272. Routine Description:
  2273. This routine deletes the given drive letter from the mount point
  2274. manager.
  2275. Arguments:
  2276. DriveLetter - Supplies the drive letter.
  2277. Return Value:
  2278. NTSTATUS
  2279. --*/
  2280. {
  2281. UNICODE_STRING name;
  2282. NTSTATUS status;
  2283. PFILE_OBJECT fileObject;
  2284. PDEVICE_OBJECT deviceObject;
  2285. PMOUNTMGR_MOUNT_POINT point;
  2286. UCHAR buffer[sizeof(MOUNTMGR_MOUNT_POINT) + 50];
  2287. PWSTR s;
  2288. UNICODE_STRING symName;
  2289. PVOID mountPoints;
  2290. KEVENT event;
  2291. PIRP irp;
  2292. IO_STATUS_BLOCK ioStatus;
  2293. RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME);
  2294. status = IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &fileObject,
  2295. &deviceObject);
  2296. if (!NT_SUCCESS(status)) {
  2297. return status;
  2298. }
  2299. point = (PMOUNTMGR_MOUNT_POINT) buffer;
  2300. RtlZeroMemory(point, sizeof(MOUNTMGR_MOUNT_POINT));
  2301. s = (PWSTR) ((PCHAR) point + sizeof(MOUNTMGR_MOUNT_POINT));
  2302. swprintf(s, L"\\DosDevices\\%c:", DriveLetter);
  2303. RtlInitUnicodeString(&symName, s);
  2304. point->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  2305. point->SymbolicLinkNameLength = symName.Length;
  2306. mountPoints = ExAllocatePool(PagedPool, PAGE_SIZE);
  2307. if (!mountPoints) {
  2308. ObDereferenceObject(fileObject);
  2309. return STATUS_INSUFFICIENT_RESOURCES;
  2310. }
  2311. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2312. irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
  2313. deviceObject, point,
  2314. sizeof(MOUNTMGR_MOUNT_POINT) +
  2315. symName.Length, mountPoints, PAGE_SIZE,
  2316. FALSE, &event, &ioStatus);
  2317. if (!irp) {
  2318. ExFreePool(mountPoints);
  2319. ObDereferenceObject(fileObject);
  2320. return STATUS_INSUFFICIENT_RESOURCES;
  2321. }
  2322. status = IoCallDriver(deviceObject, irp);
  2323. if (status == STATUS_PENDING) {
  2324. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2325. status = ioStatus.Status;
  2326. }
  2327. ExFreePool(mountPoints);
  2328. ObDereferenceObject(fileObject);
  2329. return status;
  2330. }
  2331. NTSTATUS
  2332. FtpSetDriveLetterForLogicalDisk(
  2333. IN OUT PROOT_EXTENSION RootExtension,
  2334. IN OUT PIRP Irp
  2335. )
  2336. /*++
  2337. Routine Description:
  2338. This routine sets the drive letter for the given root logical disk.
  2339. Arguments:
  2340. Extension - Supplies the root extension.
  2341. Irp - Supplies the I/O request packet.
  2342. Return Value:
  2343. NTSTATUS
  2344. --*/
  2345. {
  2346. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2347. PFT_SET_DRIVE_LETTER_FOR_LOGICAL_DISK_INPUT input;
  2348. FT_LOGICAL_DISK_ID diskId;
  2349. UCHAR driveLetter, currentLetter;
  2350. PVOLUME_EXTENSION extension;
  2351. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  2352. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2353. sizeof(FT_SET_DRIVE_LETTER_FOR_LOGICAL_DISK_INPUT)) {
  2354. return STATUS_INVALID_PARAMETER;
  2355. }
  2356. input = (PFT_SET_DRIVE_LETTER_FOR_LOGICAL_DISK_INPUT)
  2357. Irp->AssociatedIrp.SystemBuffer;
  2358. diskId = input->RootLogicalDiskId;
  2359. driveLetter = input->DriveLetter;
  2360. if (driveLetter < FirstDriveLetter || driveLetter > LastDriveLetter) {
  2361. if (driveLetter) {
  2362. return STATUS_INVALID_PARAMETER;
  2363. }
  2364. }
  2365. extension = FtpFindExtension(RootExtension, diskId);
  2366. if (!extension) {
  2367. return STATUS_INVALID_PARAMETER;
  2368. }
  2369. currentLetter = FtpQueryMountLetter(extension);
  2370. if (currentLetter) {
  2371. FtpDeleteMountLetter(currentLetter);
  2372. }
  2373. if (driveLetter && !FtpSetMountLetter(extension, driveLetter)) {
  2374. return STATUS_INVALID_PARAMETER;
  2375. }
  2376. diskInfoSet = RootExtension->DiskInfoSet;
  2377. diskInfoSet->SetDriveLetter(diskId, driveLetter);
  2378. return STATUS_SUCCESS;
  2379. }
  2380. NTSTATUS
  2381. FtpQueryNtDeviceNameForPartition(
  2382. IN OUT PROOT_EXTENSION RootExtension,
  2383. IN OUT PIRP Irp
  2384. )
  2385. /*++
  2386. Routine Description:
  2387. This routine returns the nt device name for the given partition.
  2388. Arguments:
  2389. RootExtension - Supplies the root extension.
  2390. Irp - Supplies the I/O request packet.
  2391. Return Value:
  2392. NTSTATUS
  2393. --*/
  2394. {
  2395. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2396. PFT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_INPUT input;
  2397. PFT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_OUTPUT output;
  2398. UNICODE_STRING targetName;
  2399. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2400. sizeof(FT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_INPUT) ||
  2401. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2402. sizeof(FT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_OUTPUT)) {
  2403. return STATUS_INVALID_PARAMETER;
  2404. }
  2405. input = (PFT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_INPUT)
  2406. Irp->AssociatedIrp.SystemBuffer;
  2407. output = (PFT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_OUTPUT)
  2408. Irp->AssociatedIrp.SystemBuffer;
  2409. if (!FtpQueryNtDeviceNameString(RootExtension, input->Signature,
  2410. input->Offset, &targetName)) {
  2411. return STATUS_INVALID_PARAMETER;
  2412. }
  2413. output->NumberOfCharactersInNtDeviceName = targetName.Length/sizeof(WCHAR);
  2414. Irp->IoStatus.Information =
  2415. FIELD_OFFSET(FT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_OUTPUT,
  2416. NtDeviceName) +
  2417. output->NumberOfCharactersInNtDeviceName*sizeof(WCHAR);
  2418. if (Irp->IoStatus.Information >
  2419. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  2420. Irp->IoStatus.Information =
  2421. FIELD_OFFSET(FT_QUERY_NT_DEVICE_NAME_FOR_PARTITION_OUTPUT,
  2422. NtDeviceName);
  2423. ExFreePool(targetName.Buffer);
  2424. return STATUS_BUFFER_OVERFLOW;
  2425. }
  2426. RtlCopyMemory(output->NtDeviceName, targetName.Buffer,
  2427. targetName.Length);
  2428. ExFreePool(targetName.Buffer);
  2429. return STATUS_SUCCESS;
  2430. }
  2431. NTSTATUS
  2432. FtpStopSyncOperations(
  2433. IN OUT PROOT_EXTENSION RootExtension,
  2434. IN OUT PIRP Irp
  2435. )
  2436. /*++
  2437. Routine Description:
  2438. This routine stops all sync operations on the given root logical disk.
  2439. Arguments:
  2440. Extension - Supplies the root extension.
  2441. Irp - Supplies the I/O request packet.
  2442. Return Value:
  2443. NTSTATUS
  2444. --*/
  2445. {
  2446. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2447. PFT_STOP_SYNC_OPERATIONS_INPUT input;
  2448. FT_LOGICAL_DISK_ID diskId;
  2449. PVOLUME_EXTENSION extension;
  2450. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2451. sizeof(FT_STOP_SYNC_OPERATIONS_INPUT)) {
  2452. return STATUS_INVALID_PARAMETER;
  2453. }
  2454. input = (PFT_STOP_SYNC_OPERATIONS_INPUT) Irp->AssociatedIrp.SystemBuffer;
  2455. diskId = input->RootLogicalDiskId;
  2456. extension = FtpFindExtension(RootExtension, diskId);
  2457. if (!extension || !extension->FtVolume) {
  2458. return STATUS_INVALID_PARAMETER;
  2459. }
  2460. extension->FtVolume->StopSyncOperations();
  2461. return STATUS_SUCCESS;
  2462. }
  2463. NTSTATUS
  2464. FtpQueryStableGuid(
  2465. IN OUT PVOLUME_EXTENSION Extension,
  2466. IN OUT PIRP Irp
  2467. )
  2468. /*++
  2469. Routine Description:
  2470. This routine is called to query the stable guid for this volume.
  2471. Arguments:
  2472. Extension - Supplies the volume extension.
  2473. Irp - Supplies the IO request packet.
  2474. Return Value:
  2475. NTSTATUS
  2476. --*/
  2477. {
  2478. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2479. PMOUNTDEV_STABLE_GUID output;
  2480. if (!Extension->IsGpt) {
  2481. return STATUS_UNSUCCESSFUL;
  2482. }
  2483. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2484. sizeof(MOUNTDEV_STABLE_GUID)) {
  2485. return STATUS_INVALID_PARAMETER;
  2486. }
  2487. output = (PMOUNTDEV_STABLE_GUID) Irp->AssociatedIrp.SystemBuffer;
  2488. output->StableGuid = Extension->UniqueIdGuid;
  2489. Irp->IoStatus.Information = sizeof(MOUNTDEV_STABLE_GUID);
  2490. return STATUS_SUCCESS;
  2491. }
  2492. NTSTATUS
  2493. FtpQueryUniqueId(
  2494. IN OUT PVOLUME_EXTENSION Extension,
  2495. IN OUT PIRP Irp
  2496. )
  2497. /*++
  2498. Routine Description:
  2499. This routine is called to query the unique id for this volume.
  2500. Arguments:
  2501. Extension - Supplies the volume extension.
  2502. Irp - Supplies the IO request packet.
  2503. Return Value:
  2504. NTSTATUS
  2505. --*/
  2506. {
  2507. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2508. PMOUNTDEV_UNIQUE_ID output;
  2509. NTSTATUS status;
  2510. ULONG diskNumber;
  2511. LONGLONG offset;
  2512. FT_LOGICAL_DISK_ID diskId;
  2513. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2514. sizeof(MOUNTDEV_UNIQUE_ID)) {
  2515. return STATUS_INVALID_PARAMETER;
  2516. }
  2517. output = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer;
  2518. if (Extension->IsSuperFloppy) {
  2519. output->UniqueIdLength = Extension->DeviceNodeName.Length;
  2520. } else {
  2521. if (!FtpQueryUniqueIdBuffer(Extension, NULL,
  2522. &output->UniqueIdLength)) {
  2523. return STATUS_INVALID_PARAMETER;
  2524. }
  2525. }
  2526. Irp->IoStatus.Information = sizeof(USHORT) + output->UniqueIdLength;
  2527. if (Irp->IoStatus.Information >
  2528. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  2529. Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
  2530. return STATUS_BUFFER_OVERFLOW;
  2531. }
  2532. if (Extension->IsSuperFloppy) {
  2533. RtlCopyMemory(output->UniqueId, Extension->DeviceNodeName.Buffer,
  2534. output->UniqueIdLength);
  2535. } else {
  2536. if (!FtpQueryUniqueIdBuffer(Extension, output->UniqueId,
  2537. &output->UniqueIdLength)) {
  2538. return STATUS_INVALID_DEVICE_REQUEST;
  2539. }
  2540. }
  2541. return STATUS_SUCCESS;
  2542. }
  2543. NTSTATUS
  2544. FtpUniqueIdChangeNotify(
  2545. IN OUT PVOLUME_EXTENSION Extension,
  2546. IN OUT PIRP Irp
  2547. )
  2548. /*++
  2549. Routine Description:
  2550. This routine is to give a notify callback routine.
  2551. Arguments:
  2552. Extension - Supplies the volume extension.
  2553. Irp - Supplies the IO request packet.
  2554. Return Value:
  2555. NTSTATUS
  2556. --*/
  2557. {
  2558. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2559. PMOUNTDEV_UNIQUE_ID input;
  2560. ULONG len;
  2561. PMOUNTDEV_UNIQUE_ID currentId;
  2562. UCHAR idBuffer[UNIQUE_ID_MAX_BUFFER_SIZE];
  2563. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2564. sizeof(MOUNTDEV_UNIQUE_ID)) {
  2565. return STATUS_INVALID_PARAMETER;
  2566. }
  2567. if (!Extension->TargetObject && !Extension->FtVolume) {
  2568. return STATUS_INVALID_PARAMETER;
  2569. }
  2570. if (Extension->IsSuperFloppy) {
  2571. return STATUS_INVALID_PARAMETER;
  2572. }
  2573. input = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer;
  2574. len = FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) +
  2575. input->UniqueIdLength;
  2576. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < len) {
  2577. return STATUS_INVALID_PARAMETER;
  2578. }
  2579. if (!IsListEmpty(&Extension->ChangeNotifyIrps)) {
  2580. return STATUS_INVALID_PARAMETER;
  2581. }
  2582. Irp->Tail.Overlay.DriverContext[0] = Extension;
  2583. IoSetCancelRoutine (Irp, FtpCancelChangeNotify);
  2584. if (Irp->Cancel && IoSetCancelRoutine (Irp, NULL) == NULL) {
  2585. return STATUS_CANCELLED;
  2586. }
  2587. IoMarkIrpPending(Irp);
  2588. InsertTailList(&Extension->ChangeNotifyIrps, &Irp->Tail.Overlay.ListEntry);
  2589. currentId = (PMOUNTDEV_UNIQUE_ID) idBuffer;
  2590. FtpQueryUniqueIdBuffer(Extension, currentId->UniqueId,
  2591. &currentId->UniqueIdLength);
  2592. if (input->UniqueIdLength != currentId->UniqueIdLength ||
  2593. RtlCompareMemory(input->UniqueId, currentId->UniqueId,
  2594. input->UniqueIdLength) != input->UniqueIdLength) {
  2595. FtpUniqueIdNotify(Extension, currentId);
  2596. }
  2597. return STATUS_PENDING;
  2598. }
  2599. NTSTATUS
  2600. FtpCreatePartitionLogicalDisk(
  2601. IN OUT PVOLUME_EXTENSION Extension,
  2602. IN OUT PIRP Irp
  2603. )
  2604. /*++
  2605. Routine Description:
  2606. This routine creates assigns a logical disk id to a partition.
  2607. Arguments:
  2608. Extension - Supplies the partition extension.
  2609. Irp - Supplies the I/O request packet.
  2610. Return Value:
  2611. NTSTATUS
  2612. --*/
  2613. {
  2614. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2615. LONGLONG partitionSize;
  2616. NTSTATUS status;
  2617. FT_LOGICAL_DISK_ID diskId;
  2618. PFT_CREATE_PARTITION_LOGICAL_DISK_OUTPUT output;
  2619. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2620. sizeof(FT_CREATE_PARTITION_LOGICAL_DISK_OUTPUT)) {
  2621. return STATUS_INVALID_PARAMETER;
  2622. }
  2623. if (irpSp->Parameters.DeviceIoControl.InputBufferLength >=
  2624. sizeof(LONGLONG)) {
  2625. partitionSize = *((PLONGLONG) Irp->AssociatedIrp.SystemBuffer);
  2626. } else {
  2627. partitionSize = 0;
  2628. }
  2629. status = FtpCreatePartitionLogicalDiskHelper(Extension, partitionSize,
  2630. &diskId);
  2631. if (!NT_SUCCESS(status)) {
  2632. return status;
  2633. }
  2634. Irp->IoStatus.Information =
  2635. sizeof(FT_CREATE_PARTITION_LOGICAL_DISK_OUTPUT);
  2636. output = (PFT_CREATE_PARTITION_LOGICAL_DISK_OUTPUT)
  2637. Irp->AssociatedIrp.SystemBuffer;
  2638. output->NewLogicalDiskId = diskId;
  2639. return status;
  2640. }
  2641. NTSTATUS
  2642. FtpQueryDeviceName(
  2643. IN OUT PVOLUME_EXTENSION Extension,
  2644. IN OUT PIRP Irp
  2645. )
  2646. /*++
  2647. Routine Description:
  2648. This routine returns the device name for the given device.
  2649. Arguments:
  2650. Extension - Supplies the volume extension.
  2651. Irp - Supplies the IO request packet.
  2652. Return Value:
  2653. NTSTATUS
  2654. --*/
  2655. {
  2656. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2657. WCHAR nameBuffer[100];
  2658. UNICODE_STRING nameString;
  2659. PMOUNTDEV_NAME name;
  2660. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2661. sizeof(MOUNTDEV_NAME)) {
  2662. return STATUS_INVALID_PARAMETER;
  2663. }
  2664. swprintf(nameBuffer, L"\\Device\\HarddiskVolume%d", Extension->VolumeNumber);
  2665. RtlInitUnicodeString(&nameString, nameBuffer);
  2666. name = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer;
  2667. name->NameLength = nameString.Length;
  2668. Irp->IoStatus.Information = name->NameLength + sizeof(USHORT);
  2669. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2670. Irp->IoStatus.Information) {
  2671. Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
  2672. return STATUS_BUFFER_OVERFLOW;
  2673. }
  2674. RtlCopyMemory(name->Name, nameString.Buffer, name->NameLength);
  2675. return STATUS_SUCCESS;
  2676. }
  2677. NTSTATUS
  2678. FtpQuerySuggestedLinkName(
  2679. IN OUT PVOLUME_EXTENSION Extension,
  2680. IN OUT PIRP Irp
  2681. )
  2682. /*++
  2683. Routine Description:
  2684. This routine returns the suggested link name for the given device.
  2685. Arguments:
  2686. Extension - Supplies the volume extension.
  2687. Irp - Supplies the IO request packet.
  2688. Return Value:
  2689. NTSTATUS
  2690. --*/
  2691. {
  2692. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2693. BOOLEAN deleteLetter;
  2694. UCHAR driveLetter;
  2695. PFT_VOLUME vol;
  2696. FT_LOGICAL_DISK_ID diskId;
  2697. WCHAR nameBuffer[30];
  2698. UNICODE_STRING nameString;
  2699. PMOUNTDEV_SUGGESTED_LINK_NAME name;
  2700. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2701. sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
  2702. return STATUS_INVALID_PARAMETER;
  2703. }
  2704. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  2705. FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28) {
  2706. deleteLetter = TRUE;
  2707. } else {
  2708. deleteLetter = FALSE;
  2709. }
  2710. driveLetter = FtpQueryDriveLetterFromRegistry(Extension, deleteLetter);
  2711. vol = Extension->FtVolume;
  2712. if (vol) {
  2713. diskId = vol->QueryLogicalDiskId();
  2714. driveLetter = Extension->Root->DiskInfoSet->QueryDriveLetter(diskId);
  2715. }
  2716. if (!driveLetter) {
  2717. return STATUS_NOT_FOUND;
  2718. }
  2719. swprintf(nameBuffer, L"\\DosDevices\\%c:", driveLetter);
  2720. RtlInitUnicodeString(&nameString, nameBuffer);
  2721. name = (PMOUNTDEV_SUGGESTED_LINK_NAME) Irp->AssociatedIrp.SystemBuffer;
  2722. name->UseOnlyIfThereAreNoOtherLinks = TRUE;
  2723. name->NameLength = nameString.Length;
  2724. Irp->IoStatus.Information =
  2725. name->NameLength + FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name);
  2726. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  2727. Irp->IoStatus.Information) {
  2728. Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
  2729. return STATUS_BUFFER_OVERFLOW;
  2730. }
  2731. RtlCopyMemory(name->Name, nameString.Buffer, name->NameLength);
  2732. return STATUS_SUCCESS;
  2733. }
  2734. class CHANGE_DRIVE_LETTER_WORK_ITEM : public WORK_QUEUE_ITEM {
  2735. public:
  2736. PROOT_EXTENSION RootExtension;
  2737. FT_LOGICAL_DISK_ID LogicalDiskId;
  2738. UCHAR OldDriveLetter;
  2739. UCHAR NewDriveLetter;
  2740. };
  2741. typedef CHANGE_DRIVE_LETTER_WORK_ITEM *PCHANGE_DRIVE_LETTER_WORK_ITEM;
  2742. VOID
  2743. FtpChangeDriveLetterWorkerRoutine(
  2744. IN PVOID WorkItem
  2745. )
  2746. /*++
  2747. Routine Description:
  2748. This routine changes the drive letter.
  2749. Arguments:
  2750. WorkItem - Supplies the work item.
  2751. Return Value:
  2752. None.
  2753. --*/
  2754. {
  2755. PCHANGE_DRIVE_LETTER_WORK_ITEM workItem = (PCHANGE_DRIVE_LETTER_WORK_ITEM) WorkItem;
  2756. PROOT_EXTENSION rootExtension = workItem->RootExtension;
  2757. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet = rootExtension->DiskInfoSet;
  2758. FtpAcquire(rootExtension);
  2759. if (workItem->OldDriveLetter &&
  2760. diskInfoSet->QueryDriveLetter(workItem->LogicalDiskId) !=
  2761. workItem->OldDriveLetter) {
  2762. FtpRelease(rootExtension);
  2763. ExFreePool(WorkItem);
  2764. return;
  2765. }
  2766. diskInfoSet->SetDriveLetter(workItem->LogicalDiskId,
  2767. workItem->NewDriveLetter);
  2768. FtpRelease(rootExtension);
  2769. ExFreePool(WorkItem);
  2770. }
  2771. NTSTATUS
  2772. FtpLinkCreated(
  2773. IN OUT PVOLUME_EXTENSION Extension,
  2774. IN OUT PIRP Irp
  2775. )
  2776. /*++
  2777. Routine Description:
  2778. This routine is called when the mount manager changes the link.
  2779. Arguments:
  2780. Extension - Supplies the volume extension.
  2781. Irp - Supplies the IO request packet.
  2782. Return Value:
  2783. NTSTATUS
  2784. --*/
  2785. {
  2786. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2787. PFT_VOLUME vol;
  2788. PMOUNTDEV_NAME name;
  2789. ULONG nameLen;
  2790. UNICODE_STRING nameString;
  2791. UNICODE_STRING dosDevices;
  2792. UCHAR driveLetter;
  2793. PCHANGE_DRIVE_LETTER_WORK_ITEM workItem;
  2794. vol = Extension->FtVolume;
  2795. if (!vol) {
  2796. return STATUS_SUCCESS;
  2797. }
  2798. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2799. sizeof(MOUNTDEV_NAME)) {
  2800. return STATUS_INVALID_PARAMETER;
  2801. }
  2802. name = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer;
  2803. nameLen = name->NameLength + sizeof(USHORT);
  2804. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < nameLen) {
  2805. return STATUS_INVALID_PARAMETER;
  2806. }
  2807. nameString.Buffer = name->Name;
  2808. nameString.Length = nameString.MaximumLength = name->NameLength;
  2809. if (nameString.Length != 28 || nameString.Buffer[13] != ':' ||
  2810. nameString.Buffer[12] < FirstDriveLetter || nameString.Buffer[12] > LastDriveLetter) {
  2811. return STATUS_SUCCESS;
  2812. }
  2813. nameString.Length -= 2*sizeof(WCHAR);
  2814. RtlInitUnicodeString(&dosDevices, L"\\DosDevices\\");
  2815. if (!RtlEqualUnicodeString(&dosDevices, &nameString, TRUE)) {
  2816. return STATUS_SUCCESS;
  2817. }
  2818. driveLetter = (UCHAR) nameString.Buffer[12];
  2819. workItem = (PCHANGE_DRIVE_LETTER_WORK_ITEM)
  2820. ExAllocatePool(NonPagedPool, sizeof(CHANGE_DRIVE_LETTER_WORK_ITEM));
  2821. if (!workItem) {
  2822. return STATUS_INSUFFICIENT_RESOURCES;
  2823. }
  2824. ExInitializeWorkItem(workItem, FtpChangeDriveLetterWorkerRoutine, workItem);
  2825. workItem->RootExtension = Extension->Root;
  2826. workItem->LogicalDiskId = vol->QueryLogicalDiskId();
  2827. workItem->OldDriveLetter = 0;
  2828. workItem->NewDriveLetter = driveLetter;
  2829. ExQueueWorkItem(workItem, DelayedWorkQueue);
  2830. return STATUS_SUCCESS;
  2831. }
  2832. NTSTATUS
  2833. FtpLinkDeleted(
  2834. IN OUT PVOLUME_EXTENSION Extension,
  2835. IN OUT PIRP Irp
  2836. )
  2837. /*++
  2838. Routine Description:
  2839. This routine is called when the mount manager deletes a link.
  2840. Arguments:
  2841. Extension - Supplies the volume extension.
  2842. Irp - Supplies the IO request packet.
  2843. Return Value:
  2844. NTSTATUS
  2845. --*/
  2846. {
  2847. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  2848. PFT_VOLUME vol;
  2849. PMOUNTDEV_NAME name;
  2850. ULONG nameLen;
  2851. UNICODE_STRING nameString;
  2852. UNICODE_STRING dosDevices;
  2853. UCHAR driveLetter;
  2854. PCHANGE_DRIVE_LETTER_WORK_ITEM workItem;
  2855. vol = Extension->FtVolume;
  2856. if (!vol) {
  2857. return STATUS_SUCCESS;
  2858. }
  2859. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  2860. sizeof(MOUNTDEV_NAME)) {
  2861. return STATUS_INVALID_PARAMETER;
  2862. }
  2863. name = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer;
  2864. nameLen = name->NameLength + sizeof(USHORT);
  2865. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < nameLen) {
  2866. return STATUS_INVALID_PARAMETER;
  2867. }
  2868. nameString.Buffer = name->Name;
  2869. nameString.Length = nameString.MaximumLength = name->NameLength;
  2870. if (nameString.Length != 28 || nameString.Buffer[13] != ':' ||
  2871. nameString.Buffer[12] < FirstDriveLetter || nameString.Buffer[12] > LastDriveLetter) {
  2872. return STATUS_SUCCESS;
  2873. }
  2874. nameString.Length -= 2*sizeof(WCHAR);
  2875. RtlInitUnicodeString(&dosDevices, L"\\DosDevices\\");
  2876. if (!RtlEqualUnicodeString(&dosDevices, &nameString, TRUE)) {
  2877. return STATUS_SUCCESS;
  2878. }
  2879. driveLetter = (UCHAR) nameString.Buffer[12];
  2880. workItem = (PCHANGE_DRIVE_LETTER_WORK_ITEM)
  2881. ExAllocatePool(NonPagedPool, sizeof(CHANGE_DRIVE_LETTER_WORK_ITEM));
  2882. if (!workItem) {
  2883. return STATUS_INSUFFICIENT_RESOURCES;
  2884. }
  2885. ExInitializeWorkItem(workItem, FtpChangeDriveLetterWorkerRoutine, workItem);
  2886. workItem->RootExtension = Extension->Root;
  2887. workItem->LogicalDiskId = vol->QueryLogicalDiskId();
  2888. workItem->OldDriveLetter = driveLetter;
  2889. workItem->NewDriveLetter = 0;
  2890. ExQueueWorkItem(workItem, DelayedWorkQueue);
  2891. return STATUS_SUCCESS;
  2892. }
  2893. VOID
  2894. FtpSyncLogicalDiskIds(
  2895. IN PFT_LOGICAL_DISK_INFORMATION_SET DiskInfoSet,
  2896. IN OUT PFT_VOLUME RootVolume,
  2897. IN OUT PFT_VOLUME Volume
  2898. )
  2899. /*++
  2900. Routine Description:
  2901. This routine syncs up the logical disk ids in the given FT_VOLUME object
  2902. with the on disk logical disk ids.
  2903. Arguments:
  2904. DiskInfoSet - Supplies the disk info set.
  2905. RootVolume - Supplies the root volume.
  2906. Volume - Supplies the volume.
  2907. Return Value:
  2908. None.
  2909. --*/
  2910. {
  2911. FT_LOGICAL_DISK_ID diskId;
  2912. PFT_LOGICAL_DISK_DESCRIPTION p;
  2913. USHORT n, i;
  2914. PFT_VOLUME vol;
  2915. if (Volume->QueryLogicalDiskType() == FtPartition) {
  2916. for (;;) {
  2917. diskId = Volume->QueryLogicalDiskId();
  2918. p = DiskInfoSet->GetParentLogicalDiskDescription(diskId);
  2919. if (!p) {
  2920. break;
  2921. }
  2922. Volume = RootVolume->GetParentLogicalDisk(Volume);
  2923. if (!Volume) {
  2924. break;
  2925. }
  2926. Volume->SetLogicalDiskId(p->LogicalDiskId);
  2927. }
  2928. return;
  2929. }
  2930. n = Volume->QueryNumberOfMembers();
  2931. for (i = 0; i < n; i++) {
  2932. vol = Volume->GetMember(i);
  2933. if (vol) {
  2934. FtpSyncLogicalDiskIds(DiskInfoSet, RootVolume, vol);
  2935. }
  2936. }
  2937. }
  2938. VOID
  2939. FtpSyncLogicalDiskIds(
  2940. IN PROOT_EXTENSION RootExtension
  2941. )
  2942. /*++
  2943. Routine Description:
  2944. This routine syncs up the logical disk ids in the FT_VOLUME objects
  2945. with the on disk logical disk ids.
  2946. Arguments:
  2947. RootExtension - Supplies the root extension.
  2948. Return Value:
  2949. None.
  2950. --*/
  2951. {
  2952. PLIST_ENTRY l;
  2953. PVOLUME_EXTENSION extension;
  2954. PFT_VOLUME vol;
  2955. for (l = RootExtension->VolumeList.Flink;
  2956. l != &RootExtension->VolumeList; l = l->Flink) {
  2957. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  2958. vol = extension->FtVolume;
  2959. if (!vol) {
  2960. continue;
  2961. }
  2962. FtpSyncLogicalDiskIds(RootExtension->DiskInfoSet, vol, vol);
  2963. }
  2964. }
  2965. NTSTATUS
  2966. FtpPartitionArrivedHelper(
  2967. IN OUT PROOT_EXTENSION RootExtension,
  2968. IN PDEVICE_OBJECT Partition,
  2969. IN PDEVICE_OBJECT WholeDiskPdo
  2970. )
  2971. {
  2972. ULONG diskNumber;
  2973. LONGLONG offset;
  2974. UCHAR partitionType;
  2975. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  2976. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  2977. NTSTATUS status;
  2978. BOOLEAN changedLogicalDiskIds;
  2979. FT_LOGICAL_DISK_ID diskId, partitionDiskId;
  2980. PVOLUME_EXTENSION extension;
  2981. PFT_VOLUME vol, c;
  2982. PFT_LOGICAL_DISK_DESCRIPTION parentDesc;
  2983. ULONG n;
  2984. UCHAR registryState[100];
  2985. USHORT registryStateSize;
  2986. BOOLEAN IsGpt, isHidden, isReadOnly, isEspType;
  2987. GUID partitionTypeGuid, partitionUniqueId;
  2988. ULONGLONG gptAttributes;
  2989. ULONG signature;
  2990. status = FtpQueryPartitionInformation(RootExtension, Partition,
  2991. &diskNumber, &offset, NULL,
  2992. &partitionType, NULL,
  2993. &partitionTypeGuid,
  2994. &partitionUniqueId, &IsGpt,
  2995. &gptAttributes);
  2996. if (!NT_SUCCESS(status)) {
  2997. return status;
  2998. }
  2999. isHidden = FALSE;
  3000. isReadOnly = FALSE;
  3001. isEspType = FALSE;
  3002. if (IsGpt) {
  3003. if (IsEqualGUID(partitionTypeGuid, PARTITION_LDM_DATA_GUID)) {
  3004. return STATUS_INVALID_PARAMETER;
  3005. }
  3006. if (RootExtension->GptAttributeRevertEntries) {
  3007. FtpCheckForRevertGptAttributes(RootExtension, Partition, 0,
  3008. &partitionUniqueId, NULL);
  3009. status = FtpQueryPartitionInformation(
  3010. RootExtension, Partition, NULL, NULL, NULL, NULL, NULL,
  3011. NULL, NULL, NULL, &gptAttributes);
  3012. if (!NT_SUCCESS(status)) {
  3013. return status;
  3014. }
  3015. }
  3016. if (IsEqualGUID(partitionTypeGuid, PARTITION_BASIC_DATA_GUID)) {
  3017. if (gptAttributes&GPT_BASIC_DATA_ATTRIBUTE_HIDDEN) {
  3018. isHidden = TRUE;
  3019. }
  3020. if (gptAttributes&GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY) {
  3021. isReadOnly = TRUE;
  3022. }
  3023. } else {
  3024. if (IsEqualGUID(partitionTypeGuid, PARTITION_SYSTEM_GUID)) {
  3025. isEspType = TRUE;
  3026. }
  3027. isHidden = TRUE;
  3028. }
  3029. if (!FtpCreateNewDevice(RootExtension, Partition, NULL, WholeDiskPdo,
  3030. Partition->AlignmentRequirement, FALSE,
  3031. isHidden, isReadOnly, isEspType, 0)) {
  3032. return STATUS_INSUFFICIENT_RESOURCES;
  3033. }
  3034. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  3035. return STATUS_SUCCESS;
  3036. }
  3037. if (partitionType == PARTITION_LDM) {
  3038. return STATUS_INVALID_PARAMETER;
  3039. }
  3040. if (!IsRecognizedPartition(partitionType)) {
  3041. isHidden = TRUE;
  3042. }
  3043. diskInfoSet = RootExtension->DiskInfoSet;
  3044. if (!diskInfoSet->IsDiskInSet(WholeDiskPdo)) {
  3045. diskInfo = new FT_LOGICAL_DISK_INFORMATION;
  3046. if (!diskInfo) {
  3047. return STATUS_INSUFFICIENT_RESOURCES;
  3048. }
  3049. status = diskInfo->Initialize(RootExtension, WholeDiskPdo);
  3050. if (!NT_SUCCESS(status)) {
  3051. delete diskInfo;
  3052. return status;
  3053. }
  3054. status = diskInfoSet->AddLogicalDiskInformation(diskInfo,
  3055. &changedLogicalDiskIds);
  3056. if (!NT_SUCCESS(status)) {
  3057. delete diskInfo;
  3058. return status;
  3059. }
  3060. if (changedLogicalDiskIds) {
  3061. FtpSyncLogicalDiskIds(RootExtension);
  3062. }
  3063. if (RootExtension->GptAttributeRevertEntries) {
  3064. signature = FtpQueryDiskSignature(WholeDiskPdo);
  3065. if (signature) {
  3066. FtpCheckForRevertGptAttributes(RootExtension, Partition,
  3067. signature, NULL, diskInfo);
  3068. }
  3069. }
  3070. } else {
  3071. diskInfo = diskInfoSet->FindLogicalDiskInformation(WholeDiskPdo);
  3072. }
  3073. if (diskInfo) {
  3074. if (IsRecognizedPartition(partitionType)) {
  3075. gptAttributes = diskInfo->GetGptAttributes();
  3076. if (gptAttributes&GPT_BASIC_DATA_ATTRIBUTE_HIDDEN) {
  3077. isHidden = TRUE;
  3078. }
  3079. if (gptAttributes&GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY) {
  3080. isReadOnly = TRUE;
  3081. }
  3082. } else {
  3083. gptAttributes = 0;
  3084. }
  3085. }
  3086. // Make sure that the on disk reflects the state of the registry.
  3087. diskInfoSet->MigrateRegistryInformation(Partition, diskNumber, offset);
  3088. diskId = diskInfoSet->QueryRootLogicalDiskIdForContainedPartition(
  3089. diskNumber, offset);
  3090. if (diskId) {
  3091. if (!RootExtension->FtCodeLocked) {
  3092. MmLockPagableCodeSection(FtpComputeParity);
  3093. status = FtpStartSystemThread(RootExtension);
  3094. if (!NT_SUCCESS(status)) {
  3095. return status;
  3096. }
  3097. RootExtension->FtCodeLocked = TRUE;
  3098. }
  3099. extension = FtpFindExtension(RootExtension, diskId);
  3100. if (extension) {
  3101. status = FtpAddPartition(extension, Partition, WholeDiskPdo);
  3102. if (!NT_SUCCESS(status)) {
  3103. return status;
  3104. }
  3105. FtpNotify(RootExtension, extension);
  3106. } else {
  3107. vol = FtpBuildFtVolume(RootExtension, diskId, Partition,
  3108. WholeDiskPdo);
  3109. if (!vol) {
  3110. return STATUS_INSUFFICIENT_RESOURCES;
  3111. }
  3112. partitionDiskId = diskInfoSet->QueryPartitionLogicalDiskId(
  3113. diskNumber, offset);
  3114. parentDesc = diskInfoSet->GetParentLogicalDiskDescription(
  3115. partitionDiskId, &n);
  3116. while (parentDesc) {
  3117. if (parentDesc->u.Other.ByteOffsetToStateInformation &&
  3118. (c = vol->GetContainedLogicalDisk(
  3119. parentDesc->LogicalDiskId))) {
  3120. c->NewStateArrival((PCHAR) parentDesc +
  3121. parentDesc->u.Other.ByteOffsetToStateInformation);
  3122. }
  3123. parentDesc = diskInfoSet->GetParentLogicalDiskDescription(
  3124. parentDesc, n);
  3125. }
  3126. if (!FtpCreateNewDevice(RootExtension, NULL, vol, NULL,
  3127. Partition->AlignmentRequirement, FALSE,
  3128. isHidden, isReadOnly, FALSE, 0)) {
  3129. FtpDeleteVolume(vol);
  3130. return STATUS_INSUFFICIENT_RESOURCES;
  3131. }
  3132. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  3133. }
  3134. } else {
  3135. if (!FtpCreateNewDevice(RootExtension, Partition, NULL, WholeDiskPdo,
  3136. Partition->AlignmentRequirement, FALSE,
  3137. isHidden, isReadOnly, FALSE, gptAttributes)) {
  3138. return STATUS_INSUFFICIENT_RESOURCES;
  3139. }
  3140. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  3141. }
  3142. return STATUS_SUCCESS;
  3143. }
  3144. NTSTATUS
  3145. FtpPartitionArrived(
  3146. IN OUT PROOT_EXTENSION RootExtension,
  3147. IN OUT PIRP Irp
  3148. )
  3149. /*++
  3150. Routine Description:
  3151. This routine is called when a new partition is introduced into the
  3152. system.
  3153. Arguments:
  3154. Extension - Supplies the device extension.
  3155. Irp - Supplies the IO request packet.
  3156. Return Value:
  3157. NTSTATUS
  3158. --*/
  3159. {
  3160. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3161. PVOLMGR_PARTITION_INFORMATION input;
  3162. PDEVICE_OBJECT partition, wholeDiskPdo;
  3163. NTSTATUS status;
  3164. ULONG diskNumber;
  3165. LONGLONG offset;
  3166. UCHAR partitionType;
  3167. PVOLUME_EXTENSION extension;
  3168. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3169. sizeof(VOLMGR_PARTITION_INFORMATION)) {
  3170. return STATUS_INVALID_PARAMETER;
  3171. }
  3172. input = (PVOLMGR_PARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  3173. partition = input->PartitionDeviceObject;
  3174. wholeDiskPdo = input->WholeDiskPdo;
  3175. status = FtpPartitionArrivedHelper(RootExtension, partition, wholeDiskPdo);
  3176. return status;
  3177. }
  3178. VOID
  3179. FtpTotalBreakUp(
  3180. IN OUT PROOT_EXTENSION RootExtension,
  3181. IN FT_LOGICAL_DISK_ID LogicalDiskId
  3182. )
  3183. {
  3184. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet = RootExtension->DiskInfoSet;
  3185. USHORT numDiskIds, i;
  3186. PFT_LOGICAL_DISK_ID diskIds;
  3187. if (!LogicalDiskId) {
  3188. return;
  3189. }
  3190. numDiskIds = diskInfoSet->QueryNumberOfMembersInLogicalDisk(LogicalDiskId);
  3191. if (numDiskIds) {
  3192. diskIds = (PFT_LOGICAL_DISK_ID)
  3193. ExAllocatePool(PagedPool, numDiskIds*sizeof(FT_LOGICAL_DISK_ID));
  3194. if (!diskIds) {
  3195. return;
  3196. }
  3197. for (i = 0; i < numDiskIds; i++) {
  3198. diskIds[i] = diskInfoSet->QueryMemberLogicalDiskId(LogicalDiskId, i);
  3199. }
  3200. }
  3201. diskInfoSet->BreakLogicalDisk(LogicalDiskId);
  3202. if (numDiskIds) {
  3203. for (i = 0; i < numDiskIds; i++) {
  3204. FtpTotalBreakUp(RootExtension, diskIds[i]);
  3205. }
  3206. ExFreePool(diskIds);
  3207. }
  3208. }
  3209. NTSTATUS
  3210. FtpWholeDiskRemoved(
  3211. IN OUT PROOT_EXTENSION RootExtension,
  3212. IN OUT PIRP Irp
  3213. )
  3214. /*++
  3215. Routine Description:
  3216. This routine is called when a whole disk is removed from the system.
  3217. Arguments:
  3218. Extension - Supplies the device extension.
  3219. Irp - Supplies the IO request packet.
  3220. Return Value:
  3221. NTSTATUS
  3222. --*/
  3223. {
  3224. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3225. PVOLMGR_WHOLE_DISK_INFORMATION input;
  3226. PDEVICE_OBJECT pdo, wholeDisk;
  3227. NTSTATUS status;
  3228. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3229. sizeof(VOLMGR_WHOLE_DISK_INFORMATION)) {
  3230. return STATUS_INVALID_PARAMETER;
  3231. }
  3232. input = (PVOLMGR_WHOLE_DISK_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  3233. pdo = input->WholeDiskPdo;
  3234. status = RootExtension->DiskInfoSet->RemoveLogicalDiskInformation(pdo);
  3235. return status;
  3236. }
  3237. NTSTATUS
  3238. FtpReferenceDependantVolume(
  3239. IN OUT PROOT_EXTENSION RootExtension,
  3240. IN OUT PIRP Irp
  3241. )
  3242. /*++
  3243. Routine Description:
  3244. This routine references the volume dependant to the given partition.
  3245. Arguments:
  3246. Extension - Supplies the device extension.
  3247. Irp - Supplies the IO request packet.
  3248. Return Value:
  3249. NTSTATUS
  3250. --*/
  3251. {
  3252. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3253. PVOLMGR_PARTITION_INFORMATION input;
  3254. PDEVICE_OBJECT partition;
  3255. PVOLUME_EXTENSION extension;
  3256. PVOLMGR_DEPENDANT_VOLUMES_INFORMATION output;
  3257. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3258. sizeof(VOLMGR_PARTITION_INFORMATION) ||
  3259. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  3260. sizeof(VOLMGR_DEPENDANT_VOLUMES_INFORMATION)) {
  3261. return STATUS_INVALID_PARAMETER;
  3262. }
  3263. input = (PVOLMGR_PARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  3264. partition = input->PartitionDeviceObject;
  3265. output = (PVOLMGR_DEPENDANT_VOLUMES_INFORMATION)
  3266. Irp->AssociatedIrp.SystemBuffer;
  3267. output->DependantVolumeReferences = (PDEVICE_RELATIONS)
  3268. ExAllocatePool(PagedPool,
  3269. sizeof(DEVICE_RELATIONS));
  3270. if (!output->DependantVolumeReferences) {
  3271. return STATUS_INSUFFICIENT_RESOURCES;
  3272. }
  3273. extension = FtpFindExtensionCoveringPartition(RootExtension, partition);
  3274. if (!extension) {
  3275. ExFreePool(output->DependantVolumeReferences);
  3276. return STATUS_INSUFFICIENT_RESOURCES;
  3277. }
  3278. if (extension->IsStarted) {
  3279. output->DependantVolumeReferences->Count = 1;
  3280. output->DependantVolumeReferences->Objects[0] =
  3281. extension->DeviceObject;
  3282. ObReferenceObject(extension->DeviceObject);
  3283. } else {
  3284. output->DependantVolumeReferences->Count = 0;
  3285. }
  3286. Irp->IoStatus.Information = sizeof(VOLMGR_DEPENDANT_VOLUMES_INFORMATION);
  3287. return STATUS_SUCCESS;
  3288. }
  3289. NTSTATUS
  3290. FtpPartitionRemoved(
  3291. IN OUT PROOT_EXTENSION RootExtension,
  3292. IN OUT PIRP Irp
  3293. )
  3294. /*++
  3295. Routine Description:
  3296. This routine is called when a partition is removed from the system.
  3297. Arguments:
  3298. Extension - Supplies the device extension.
  3299. Irp - Supplies the IO request packet.
  3300. Return Value:
  3301. NTSTATUS
  3302. --*/
  3303. {
  3304. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3305. PVOLMGR_PARTITION_INFORMATION input;
  3306. PDEVICE_OBJECT partition;
  3307. PDEVICE_OBJECT wholeDiskPdo;
  3308. NTSTATUS status;
  3309. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3310. sizeof(VOLMGR_PARTITION_INFORMATION)) {
  3311. return STATUS_INVALID_PARAMETER;
  3312. }
  3313. input = (PVOLMGR_PARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  3314. partition = input->PartitionDeviceObject;
  3315. wholeDiskPdo = input->WholeDiskPdo;
  3316. status = FtpPartitionRemovedHelper(RootExtension, partition, wholeDiskPdo);
  3317. return status;
  3318. }
  3319. NTSTATUS
  3320. FtpQueryChangePartition(
  3321. IN OUT PROOT_EXTENSION RootExtension,
  3322. IN OUT PIRP Irp
  3323. )
  3324. /*++
  3325. Routine Description:
  3326. This routine checks to see if the given partition can be grown.
  3327. Arguments:
  3328. Extension - Supplies the device extension.
  3329. Irp - Supplies the IO request packet.
  3330. Return Value:
  3331. NTSTATUS
  3332. --*/
  3333. {
  3334. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3335. PVOLMGR_PARTITION_INFORMATION input;
  3336. PVOLUME_EXTENSION extension;
  3337. NTSTATUS status;
  3338. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3339. sizeof(VOLMGR_PARTITION_INFORMATION)) {
  3340. return STATUS_INVALID_PARAMETER;
  3341. }
  3342. input = (PVOLMGR_PARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  3343. extension = FtpFindExtensionCoveringPartition(
  3344. RootExtension, input->PartitionDeviceObject);
  3345. if (!extension) {
  3346. return STATUS_INVALID_PARAMETER;
  3347. }
  3348. if (extension->TargetObject) {
  3349. status = STATUS_SUCCESS;
  3350. } else {
  3351. status = STATUS_INVALID_DEVICE_REQUEST;
  3352. }
  3353. return status;
  3354. }
  3355. NTSTATUS
  3356. FtpPartitionChanged(
  3357. IN OUT PROOT_EXTENSION RootExtension,
  3358. IN OUT PIRP Irp
  3359. )
  3360. /*++
  3361. Routine Description:
  3362. This routine does a notification because the given partition has
  3363. changed.
  3364. Arguments:
  3365. Extension - Supplies the device extension.
  3366. Irp - Supplies the IO request packet.
  3367. Return Value:
  3368. NTSTATUS
  3369. --*/
  3370. {
  3371. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3372. PVOLMGR_PARTITION_INFORMATION input;
  3373. PVOLUME_EXTENSION extension;
  3374. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3375. sizeof(VOLMGR_PARTITION_INFORMATION)) {
  3376. return STATUS_INVALID_PARAMETER;
  3377. }
  3378. input = (PVOLMGR_PARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  3379. extension = FtpFindExtensionCoveringPartition(
  3380. RootExtension, input->PartitionDeviceObject);
  3381. if (!extension) {
  3382. return STATUS_INVALID_PARAMETER;
  3383. }
  3384. extension->WholeDisk = NULL;
  3385. extension->PartitionOffset = 0;
  3386. extension->PartitionLength = 0;
  3387. FtpNotify(RootExtension, extension);
  3388. // Perform a pre-exposure of the new devnode to avoid the PNP reboot
  3389. // pop-up.
  3390. if (!extension->IsGpt &&
  3391. FtpCreateNewDevice(extension->Root, extension->TargetObject,
  3392. extension->FtVolume, extension->WholeDiskPdo,
  3393. extension->DeviceObject->AlignmentRequirement,
  3394. TRUE, TRUE, FALSE, FALSE, 0)) {
  3395. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  3396. }
  3397. return STATUS_SUCCESS;
  3398. }
  3399. NTSTATUS
  3400. FtpQueryRootId(
  3401. IN PROOT_EXTENSION Extension,
  3402. IN PIRP Irp
  3403. )
  3404. /*++
  3405. Routine Description:
  3406. This routine queries the ID for the given PDO.
  3407. Arguments:
  3408. Extension - Supplies the root extension.
  3409. Irp - Supplies the IO request packet.
  3410. Return Value:
  3411. NTSTATUS
  3412. --*/
  3413. {
  3414. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3415. UNICODE_STRING string;
  3416. NTSTATUS status;
  3417. ULONG diskNumber;
  3418. LONGLONG offset;
  3419. WCHAR buffer[100];
  3420. FT_LOGICAL_DISK_ID diskId;
  3421. PWSTR id;
  3422. switch (irpSp->Parameters.QueryId.IdType) {
  3423. case BusQueryDeviceID:
  3424. RtlInitUnicodeString(&string, L"ROOT\\FTDISK");
  3425. break;
  3426. case BusQueryHardwareIDs:
  3427. RtlInitUnicodeString(&string, L"ROOT\\FTDISK");
  3428. break;
  3429. case BusQueryInstanceID:
  3430. RtlInitUnicodeString(&string, L"0000");
  3431. break;
  3432. default:
  3433. return STATUS_NOT_SUPPORTED ;
  3434. }
  3435. id = (PWSTR) ExAllocatePool(PagedPool, string.Length + 2*sizeof(WCHAR));
  3436. if (!id) {
  3437. return STATUS_INSUFFICIENT_RESOURCES;
  3438. }
  3439. RtlCopyMemory(id, string.Buffer, string.Length);
  3440. id[string.Length/sizeof(WCHAR)] = 0;
  3441. id[string.Length/sizeof(WCHAR) + 1] = 0;
  3442. Irp->IoStatus.Information = (ULONG_PTR) id;
  3443. return STATUS_SUCCESS;
  3444. }
  3445. NTSTATUS
  3446. FtpQueryId(
  3447. IN PVOLUME_EXTENSION Extension,
  3448. IN PIRP Irp
  3449. )
  3450. /*++
  3451. Routine Description:
  3452. This routine queries the ID for the given PDO.
  3453. Arguments:
  3454. Extension - Supplies the volume extension.
  3455. Irp - Supplies the IO request packet.
  3456. Return Value:
  3457. NTSTATUS
  3458. --*/
  3459. {
  3460. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3461. UNICODE_STRING string;
  3462. NTSTATUS status;
  3463. PWSTR id;
  3464. switch (irpSp->Parameters.QueryId.IdType) {
  3465. case BusQueryDeviceID:
  3466. RtlInitUnicodeString(&string, L"STORAGE\\Volume");
  3467. break;
  3468. case BusQueryHardwareIDs:
  3469. RtlInitUnicodeString(&string, L"STORAGE\\Volume");
  3470. break;
  3471. case BusQueryInstanceID:
  3472. string = Extension->DeviceNodeName;
  3473. break;
  3474. default:
  3475. return STATUS_NOT_SUPPORTED ;
  3476. }
  3477. id = (PWSTR) ExAllocatePool(PagedPool, string.Length + 2*sizeof(WCHAR));
  3478. if (!id) {
  3479. return STATUS_INSUFFICIENT_RESOURCES;
  3480. }
  3481. RtlCopyMemory(id, string.Buffer, string.Length);
  3482. id[string.Length/sizeof(WCHAR)] = 0;
  3483. id[string.Length/sizeof(WCHAR) + 1] = 0;
  3484. Irp->IoStatus.Information = (ULONG_PTR) id;
  3485. return STATUS_SUCCESS;
  3486. }
  3487. class FTP_LOG_ERROR_CONTEXT : public WORK_QUEUE_ITEM {
  3488. public:
  3489. PDEVICE_EXTENSION Extension;
  3490. FT_LOGICAL_DISK_ID LogicalDiskId;
  3491. NTSTATUS SpecificIoStatus;
  3492. NTSTATUS FinalStatus;
  3493. ULONG UniqueErrorValue;
  3494. };
  3495. typedef FTP_LOG_ERROR_CONTEXT *PFTP_LOG_ERROR_CONTEXT;
  3496. VOID
  3497. FtpLogErrorWorker(
  3498. IN PVOID Context
  3499. )
  3500. {
  3501. PFTP_LOG_ERROR_CONTEXT context = (PFTP_LOG_ERROR_CONTEXT) Context;
  3502. PDEVICE_EXTENSION Extension;
  3503. PDEVICE_OBJECT deviceObject;
  3504. ULONG volumeNumber;
  3505. FT_LOGICAL_DISK_ID LogicalDiskId;
  3506. NTSTATUS SpecificIoStatus;
  3507. NTSTATUS FinalStatus;
  3508. ULONG UniqueErrorValue;
  3509. PDEVICE_EXTENSION extension;
  3510. NTSTATUS status;
  3511. UNICODE_STRING dosName;
  3512. ULONG extraSpace;
  3513. PIO_ERROR_LOG_PACKET errorLogPacket;
  3514. PWCHAR p;
  3515. Extension = context->Extension;
  3516. LogicalDiskId = context->LogicalDiskId;
  3517. SpecificIoStatus = context->SpecificIoStatus;
  3518. FinalStatus = context->FinalStatus;
  3519. UniqueErrorValue = context->UniqueErrorValue;
  3520. if (LogicalDiskId) {
  3521. FtpAcquire(Extension->Root);
  3522. extension = FtpFindExtensionCoveringDiskId(Extension->Root,
  3523. LogicalDiskId);
  3524. if (extension) {
  3525. deviceObject = extension->DeviceObject;
  3526. volumeNumber = ((PVOLUME_EXTENSION) extension)->VolumeNumber;
  3527. ObReferenceObject(deviceObject);
  3528. } else {
  3529. deviceObject = NULL;
  3530. }
  3531. FtpRelease(Extension->Root);
  3532. if (!extension) {
  3533. extension = Extension->Root;
  3534. }
  3535. } else {
  3536. extension = Extension;
  3537. deviceObject = NULL;
  3538. }
  3539. DebugPrint((2, "FtpLogError: DE %x:%x, unique %x, status %x\n",
  3540. extension,
  3541. extension->DeviceObject,
  3542. UniqueErrorValue,
  3543. SpecificIoStatus));
  3544. if (deviceObject) {
  3545. status = RtlVolumeDeviceToDosName(deviceObject, &dosName);
  3546. ObDereferenceObject(deviceObject);
  3547. if (!NT_SUCCESS(status)) {
  3548. dosName.Buffer = (PWCHAR) ExAllocatePool(PagedPool, 100*sizeof(WCHAR));
  3549. if (dosName.Buffer) {
  3550. swprintf(dosName.Buffer, L"\\Device\\HarddiskVolume%d",
  3551. volumeNumber);
  3552. RtlInitUnicodeString(&dosName, dosName.Buffer);
  3553. }
  3554. }
  3555. } else {
  3556. dosName.Buffer = NULL;
  3557. }
  3558. if (dosName.Buffer) {
  3559. extraSpace = dosName.Length + sizeof(WCHAR);
  3560. } else {
  3561. extraSpace = 34;
  3562. }
  3563. errorLogPacket = (PIO_ERROR_LOG_PACKET)
  3564. IoAllocateErrorLogEntry(extension->DeviceObject,
  3565. sizeof(IO_ERROR_LOG_PACKET) +
  3566. (UCHAR)extraSpace);
  3567. if (!errorLogPacket) {
  3568. DebugPrint((1, "FtpLogError: unable to allocate error log packet\n"));
  3569. if (dosName.Buffer) {
  3570. ExFreePool(dosName.Buffer);
  3571. }
  3572. return;
  3573. }
  3574. errorLogPacket->ErrorCode = SpecificIoStatus;
  3575. errorLogPacket->SequenceNumber = FtErrorLogSequence++;
  3576. errorLogPacket->FinalStatus = FinalStatus;
  3577. errorLogPacket->UniqueErrorValue = UniqueErrorValue;
  3578. errorLogPacket->DumpDataSize = 0;
  3579. errorLogPacket->RetryCount = 0;
  3580. errorLogPacket->NumberOfStrings = 1;
  3581. errorLogPacket->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
  3582. p = (PWCHAR) ((PCHAR) errorLogPacket + sizeof(IO_ERROR_LOG_PACKET));
  3583. if (dosName.Buffer) {
  3584. RtlCopyMemory(p, dosName.Buffer, dosName.Length);
  3585. p[dosName.Length/sizeof(WCHAR)] = 0;
  3586. ExFreePool(dosName.Buffer);
  3587. } else if (LogicalDiskId <= 0xFFFF && LogicalDiskId >= 0) {
  3588. swprintf(p, L"%d", LogicalDiskId);
  3589. } else {
  3590. swprintf(p, L"%I64X", LogicalDiskId);
  3591. }
  3592. IoWriteErrorLogEntry(errorLogPacket);
  3593. ExFreePool(Context);
  3594. }
  3595. VOID
  3596. FtpSendPagingNotification(
  3597. IN PDEVICE_OBJECT Partition
  3598. )
  3599. /*++
  3600. Routine Description:
  3601. This routine sends a paging path IRP to the given partition.
  3602. Arguments:
  3603. Partition - Supplies the partition.
  3604. Return Value:
  3605. None.
  3606. --*/
  3607. {
  3608. KEVENT event;
  3609. PIRP irp;
  3610. IO_STATUS_BLOCK ioStatus;
  3611. PIO_STACK_LOCATION irpSp;
  3612. NTSTATUS status;
  3613. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3614. irp = IoBuildDeviceIoControlRequest(0, Partition, NULL, 0, NULL, 0,
  3615. FALSE, &event, &ioStatus);
  3616. if (!irp) {
  3617. return;
  3618. }
  3619. irpSp = IoGetNextIrpStackLocation(irp);
  3620. irpSp->MajorFunction = IRP_MJ_PNP;
  3621. irpSp->MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
  3622. irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
  3623. irpSp->Parameters.UsageNotification.InPath = TRUE;
  3624. irpSp->Parameters.UsageNotification.Type = DeviceUsageTypePaging;
  3625. status = IoCallDriver(Partition, irp);
  3626. if (status == STATUS_PENDING) {
  3627. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3628. status = ioStatus.Status;
  3629. }
  3630. }
  3631. NTSTATUS
  3632. FtpInitializeLogicalDisk(
  3633. IN OUT PROOT_EXTENSION RootExtension,
  3634. IN OUT PIRP Irp
  3635. )
  3636. /*++
  3637. Routine Description:
  3638. This routine initializes a given logical disk.
  3639. Arguments:
  3640. RootExtension - Supplies the root extension.
  3641. Irp - Supplies the I/O request packet.
  3642. Return Value:
  3643. NTSTATUS
  3644. --*/
  3645. {
  3646. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3647. PFT_INITIALIZE_LOGICAL_DISK_INPUT input;
  3648. FT_LOGICAL_DISK_ID diskId;
  3649. PVOLUME_EXTENSION extension;
  3650. PFT_VOLUME vol;
  3651. NTSTATUS status;
  3652. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3653. sizeof(FT_INITIALIZE_LOGICAL_DISK_INPUT)) {
  3654. return STATUS_INVALID_PARAMETER;
  3655. }
  3656. input = (PFT_INITIALIZE_LOGICAL_DISK_INPUT) Irp->AssociatedIrp.SystemBuffer;
  3657. diskId = input->RootLogicalDiskId;
  3658. extension = FtpFindExtension(RootExtension, diskId);
  3659. if (!extension || !extension->FtVolume) {
  3660. return STATUS_INVALID_PARAMETER;
  3661. }
  3662. vol = extension->FtVolume;
  3663. ASSERT(vol);
  3664. status = FtpAllSystemsGo(extension, NULL, TRUE, TRUE, TRUE);
  3665. if (!NT_SUCCESS(status)) {
  3666. return status;
  3667. }
  3668. vol->StartSyncOperations(input->RegenerateOrphans,
  3669. FtpRefCountCompletion, extension);
  3670. return STATUS_SUCCESS;
  3671. }
  3672. NTSTATUS
  3673. FtpCheckIo(
  3674. IN OUT PROOT_EXTENSION RootExtension,
  3675. IN OUT PIRP Irp
  3676. )
  3677. /*++
  3678. Routine Description:
  3679. This routine checks the io path for the given logical disk.
  3680. Arguments:
  3681. Extension - Supplies the root extension.
  3682. Irp - Supplies the I/O request packet.
  3683. Return Value:
  3684. NTSTATUS
  3685. --*/
  3686. {
  3687. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3688. PFT_CHECK_IO_INPUT input;
  3689. PFT_CHECK_IO_OUTPUT output;
  3690. FT_LOGICAL_DISK_ID diskId;
  3691. PVOLUME_EXTENSION extension;
  3692. PFT_VOLUME vol;
  3693. NTSTATUS status;
  3694. BOOLEAN ok;
  3695. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3696. sizeof(FT_CHECK_IO_INPUT) ||
  3697. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  3698. sizeof(FT_CHECK_IO_OUTPUT)) {
  3699. return STATUS_INVALID_PARAMETER;
  3700. }
  3701. input = (PFT_CHECK_IO_INPUT) Irp->AssociatedIrp.SystemBuffer;
  3702. output = (PFT_CHECK_IO_OUTPUT) Irp->AssociatedIrp.SystemBuffer;
  3703. diskId = input->LogicalDiskId;
  3704. extension = FtpFindExtensionCoveringDiskId(RootExtension, diskId);
  3705. if (!extension || !extension->FtVolume) {
  3706. return STATUS_INVALID_PARAMETER;
  3707. }
  3708. status = FtpAllSystemsGo(extension, NULL, FALSE, TRUE, TRUE);
  3709. if (!NT_SUCCESS(status)) {
  3710. output->IsIoOk = FALSE;
  3711. Irp->IoStatus.Information = sizeof(FT_CHECK_IO_OUTPUT);
  3712. return STATUS_SUCCESS;
  3713. }
  3714. vol = extension->FtVolume->GetContainedLogicalDisk(diskId);
  3715. status = vol->CheckIo(&ok);
  3716. FtpDecrementRefCount(extension);
  3717. if (NT_SUCCESS(status)) {
  3718. output->IsIoOk = ok;
  3719. Irp->IoStatus.Information = sizeof(FT_CHECK_IO_OUTPUT);
  3720. }
  3721. return status;
  3722. }
  3723. NTSTATUS
  3724. FtpBreakLogicalDiskHelper(
  3725. IN OUT PROOT_EXTENSION RootExtension,
  3726. IN FT_LOGICAL_DISK_ID RootLogicalDiskId
  3727. )
  3728. /*++
  3729. Routine Description:
  3730. This routine breaks a given logical disk.
  3731. Arguments:
  3732. RootExtension - Supplies the root extension.
  3733. RootLogicalDiskId - Supplies the root logical disk id.
  3734. Return Value:
  3735. NTSTATUS
  3736. --*/
  3737. {
  3738. FT_LOGICAL_DISK_ID diskId;
  3739. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  3740. PVOLUME_EXTENSION extension;
  3741. FT_LOGICAL_DISK_TYPE diskType;
  3742. UCHAR newUniqueIdBuffer[UNIQUE_ID_MAX_BUFFER_SIZE];
  3743. PMOUNTDEV_UNIQUE_ID newUniqueId;
  3744. PPARTITION partition;
  3745. BOOLEAN closeHandle;
  3746. PFT_VOLUME vol, member, m;
  3747. HANDLE handle;
  3748. PFT_MIRROR_AND_SWP_STATE_INFORMATION state;
  3749. USHORT n, i;
  3750. NTSTATUS status;
  3751. KEVENT event;
  3752. SET_TARGET_CONTEXT context;
  3753. ULONG alignment;
  3754. diskId = RootLogicalDiskId;
  3755. diskInfoSet = RootExtension->DiskInfoSet;
  3756. extension = FtpFindExtension(RootExtension, diskId);
  3757. if (!extension) {
  3758. return STATUS_INVALID_PARAMETER;
  3759. }
  3760. alignment = extension->DeviceObject->AlignmentRequirement;
  3761. diskType = diskInfoSet->QueryLogicalDiskType(diskId);
  3762. newUniqueId = (PMOUNTDEV_UNIQUE_ID) newUniqueIdBuffer;
  3763. vol = extension->FtVolume;
  3764. if (diskType == FtPartition) {
  3765. partition = (PPARTITION) vol;
  3766. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  3767. context.TargetObject = partition->GetTargetObject();
  3768. context.FtVolume = NULL;
  3769. context.WholeDiskPdo = partition->GetWholeDiskPdo();
  3770. FtpZeroRefCallback(extension, FtpSetTargetCallback, &context, TRUE);
  3771. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  3772. NULL);
  3773. member = NULL;
  3774. closeHandle = FALSE;
  3775. FtpResetPartitionType(extension);
  3776. FtpQueryUniqueIdBuffer(extension, newUniqueId->UniqueId,
  3777. &newUniqueId->UniqueIdLength);
  3778. FtpUniqueIdNotify(extension, newUniqueId);
  3779. } else if (diskType == FtMirrorSet) {
  3780. state = (PFT_MIRROR_AND_SWP_STATE_INFORMATION)
  3781. diskInfoSet->GetStateInformation(diskId);
  3782. if (!state) {
  3783. return STATUS_INVALID_PARAMETER;
  3784. }
  3785. if (state->UnhealthyMemberState == FtMemberHealthy ||
  3786. state->UnhealthyMemberNumber != 0) {
  3787. member = vol->GetMember(0);
  3788. if (!member) {
  3789. member = vol->GetMember(1);
  3790. }
  3791. } else {
  3792. member = vol->GetMember(1);
  3793. if (!member) {
  3794. member = vol->GetMember(0);
  3795. }
  3796. }
  3797. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  3798. context.TargetObject = NULL;
  3799. context.FtVolume = member;
  3800. context.WholeDiskPdo = NULL;
  3801. FtpZeroRefCallback(extension, FtpSetTargetCallback, &context, TRUE);
  3802. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  3803. NULL);
  3804. closeHandle = FALSE;
  3805. FtpQueryUniqueIdBuffer(extension, newUniqueId->UniqueId,
  3806. &newUniqueId->UniqueIdLength);
  3807. FtpUniqueIdNotify(extension, newUniqueId);
  3808. } else {
  3809. if (!FtpLockLogicalDisk(RootExtension, diskId, &handle)) {
  3810. return STATUS_ACCESS_DENIED;
  3811. }
  3812. closeHandle = TRUE;
  3813. member = NULL;
  3814. }
  3815. status = diskInfoSet->BreakLogicalDisk(diskId);
  3816. if (!NT_SUCCESS(status)) {
  3817. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  3818. context.TargetObject = NULL;
  3819. context.FtVolume = vol;
  3820. context.WholeDiskPdo = NULL;
  3821. FtpZeroRefCallback(extension, FtpSetTargetCallback, &context, TRUE);
  3822. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  3823. NULL);
  3824. if (closeHandle) {
  3825. ZwClose(handle);
  3826. }
  3827. return status;
  3828. }
  3829. if (closeHandle) {
  3830. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  3831. context.TargetObject = NULL;
  3832. context.FtVolume = NULL;
  3833. context.WholeDiskPdo = NULL;
  3834. FtpZeroRefCallback(extension, FtpSetTargetCallback, &context, TRUE);
  3835. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  3836. NULL);
  3837. RemoveEntryList(&extension->ListEntry);
  3838. InsertTailList(&RootExtension->DeadVolumeList, &extension->ListEntry);
  3839. FtpDeleteMountPoints(extension);
  3840. FtpCleanupVolumeExtension(extension);
  3841. }
  3842. n = vol->QueryNumberOfMembers();
  3843. for (i = 0; i < n; i++) {
  3844. m = vol->GetMember(i);
  3845. if (!m || m == member) {
  3846. continue;
  3847. }
  3848. FtpCreateNewDevice(RootExtension, NULL, m, NULL, alignment, FALSE,
  3849. FALSE, FALSE, FALSE, 0);
  3850. }
  3851. if (!InterlockedDecrement(&vol->_refCount)) {
  3852. delete vol;
  3853. }
  3854. if (member) {
  3855. FtpNotify(RootExtension, extension);
  3856. } else if (!closeHandle) {
  3857. FtpNotify(RootExtension, extension);
  3858. }
  3859. if (closeHandle) {
  3860. ZwClose(handle);
  3861. }
  3862. if (diskType != FtPartition) {
  3863. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  3864. }
  3865. return STATUS_SUCCESS;
  3866. }
  3867. NTSTATUS
  3868. FtpReplaceLogicalDiskMember(
  3869. IN OUT PROOT_EXTENSION RootExtension,
  3870. IN OUT PIRP Irp
  3871. )
  3872. /*++
  3873. Routine Description:
  3874. This routine replaces the given logical disk member.
  3875. Arguments:
  3876. RootExtension - Supplies the root extension.
  3877. Irp - Supplies the I/O request packet.
  3878. Return Value:
  3879. NTSTATUS
  3880. --*/
  3881. {
  3882. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  3883. PFT_REPLACE_LOGICAL_DISK_MEMBER_INPUT input;
  3884. PFT_REPLACE_LOGICAL_DISK_MEMBER_OUTPUT output;
  3885. FT_LOGICAL_DISK_ID diskId, newMemberDiskId, newDiskId;
  3886. USHORT member;
  3887. HANDLE handle;
  3888. PVOLUME_EXTENSION replacementExtension, extension;
  3889. PFT_VOLUME replacementVolume, vol, oldVol, root;
  3890. NTSTATUS status;
  3891. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  3892. PVOLUME_EXTENSION oldVolExtension;
  3893. PFT_LOGICAL_DISK_DESCRIPTION p;
  3894. WCHAR deviceNameBuffer[64];
  3895. UNICODE_STRING deviceName;
  3896. UCHAR newUniqueIdBuffer[UNIQUE_ID_MAX_BUFFER_SIZE];
  3897. PMOUNTDEV_UNIQUE_ID newUniqueId;
  3898. KEVENT event;
  3899. SET_TARGET_CONTEXT context;
  3900. ULONG alignment;
  3901. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  3902. sizeof(FT_REPLACE_LOGICAL_DISK_MEMBER_INPUT) ||
  3903. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  3904. sizeof(FT_REPLACE_LOGICAL_DISK_MEMBER_OUTPUT)) {
  3905. return STATUS_INVALID_PARAMETER;
  3906. }
  3907. input = (PFT_REPLACE_LOGICAL_DISK_MEMBER_INPUT)
  3908. Irp->AssociatedIrp.SystemBuffer;
  3909. output = (PFT_REPLACE_LOGICAL_DISK_MEMBER_OUTPUT)
  3910. Irp->AssociatedIrp.SystemBuffer;
  3911. diskId = input->LogicalDiskId;
  3912. member = input->MemberNumberToReplace;
  3913. newMemberDiskId = input->NewMemberLogicalDiskId;
  3914. if (!FtpLockLogicalDisk(RootExtension, newMemberDiskId, &handle)) {
  3915. return STATUS_ACCESS_DENIED;
  3916. }
  3917. replacementExtension = FtpFindExtension(RootExtension, newMemberDiskId);
  3918. extension = FtpFindExtensionCoveringDiskId(RootExtension, diskId);
  3919. if (!extension || !extension->FtVolume || !replacementExtension ||
  3920. !replacementExtension->FtVolume) {
  3921. ZwClose(handle);
  3922. return STATUS_INVALID_PARAMETER;
  3923. }
  3924. alignment = extension->DeviceObject->AlignmentRequirement;
  3925. extension->DeviceObject->AlignmentRequirement |=
  3926. replacementExtension->DeviceObject->AlignmentRequirement;
  3927. newUniqueId = (PMOUNTDEV_UNIQUE_ID) newUniqueIdBuffer;
  3928. replacementVolume = replacementExtension->FtVolume;
  3929. root = extension->FtVolume;
  3930. vol = root->GetContainedLogicalDisk(diskId);
  3931. // Flush the QUEUE so that no IRPs in transit have incorrect alignment.
  3932. KeInitializeEvent(&event, NotificationEvent, FALSE);
  3933. FtpZeroRefCallback(extension, FtpQueryRemoveCallback, &event,
  3934. TRUE);
  3935. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  3936. NULL);
  3937. status = FtpAllSystemsGo(extension, NULL, FALSE, TRUE, TRUE);
  3938. if (!NT_SUCCESS(status)) {
  3939. ZwClose(handle);
  3940. return status;
  3941. }
  3942. status = FtpCheckForCompleteVolume(extension, vol);
  3943. if (!NT_SUCCESS(status)) {
  3944. FtpDecrementRefCount(extension);
  3945. ZwClose(handle);
  3946. return status;
  3947. }
  3948. status = FtpAllSystemsGo(replacementExtension, NULL, TRUE, TRUE, TRUE);
  3949. if (!NT_SUCCESS(status)) {
  3950. FtpDecrementRefCount(extension);
  3951. ZwClose(handle);
  3952. return status;
  3953. }
  3954. FtpDecrementRefCount(replacementExtension);
  3955. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  3956. context.TargetObject = NULL;
  3957. context.FtVolume = NULL;
  3958. context.WholeDiskPdo = NULL;
  3959. FtpZeroRefCallback(replacementExtension, FtpSetTargetCallback, &context,
  3960. TRUE);
  3961. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL);
  3962. oldVol = vol->GetMember(member);
  3963. if (!vol->IsVolumeSuitableForRegenerate(member, replacementVolume)) {
  3964. FtpDecrementRefCount(extension);
  3965. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  3966. context.TargetObject = NULL;
  3967. context.FtVolume = replacementVolume;
  3968. context.WholeDiskPdo = NULL;
  3969. FtpZeroRefCallback(replacementExtension, FtpSetTargetCallback,
  3970. &context, TRUE);
  3971. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  3972. NULL);
  3973. ZwClose(handle);
  3974. return STATUS_INVALID_PARAMETER;
  3975. }
  3976. diskInfoSet = RootExtension->DiskInfoSet;
  3977. status = diskInfoSet->ReplaceLogicalDiskMember(diskId, member,
  3978. newMemberDiskId,
  3979. &newDiskId);
  3980. if (!NT_SUCCESS(status)) {
  3981. FtpDecrementRefCount(extension);
  3982. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  3983. context.TargetObject = NULL;
  3984. context.FtVolume = replacementVolume;
  3985. context.WholeDiskPdo = NULL;
  3986. FtpZeroRefCallback(replacementExtension, FtpSetTargetCallback,
  3987. &context, TRUE);
  3988. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  3989. NULL);
  3990. ZwClose(handle);
  3991. return status;
  3992. }
  3993. InterlockedIncrement(&extension->RefCount);
  3994. vol->RegenerateMember(member, replacementVolume,
  3995. FtpRefCountCompletion, extension);
  3996. vol->StartSyncOperations(FALSE, FtpRefCountCompletion, extension);
  3997. RemoveEntryList(&replacementExtension->ListEntry);
  3998. InsertTailList(&RootExtension->DeadVolumeList,
  3999. &replacementExtension->ListEntry);
  4000. FtpDeleteMountPoints(replacementExtension);
  4001. FtpCleanupVolumeExtension(replacementExtension);
  4002. Irp->IoStatus.Information =
  4003. sizeof(FT_REPLACE_LOGICAL_DISK_MEMBER_OUTPUT);
  4004. output->NewLogicalDiskId = newDiskId;
  4005. vol->SetLogicalDiskId(newDiskId);
  4006. while (p = diskInfoSet->GetParentLogicalDiskDescription(
  4007. vol->QueryLogicalDiskId())) {
  4008. if (vol = root->GetParentLogicalDisk(vol)) {
  4009. vol->SetLogicalDiskId(p->LogicalDiskId);
  4010. }
  4011. }
  4012. if (oldVol) {
  4013. FtpCreateNewDevice(RootExtension, NULL, oldVol, NULL, alignment, FALSE,
  4014. FALSE, FALSE, FALSE, 0);
  4015. }
  4016. swprintf(deviceNameBuffer, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  4017. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  4018. replacementVolume->CreateLegacyNameLinks(&deviceName);
  4019. FtpQueryUniqueIdBuffer(extension, newUniqueId->UniqueId,
  4020. &newUniqueId->UniqueIdLength);
  4021. FtpUniqueIdNotify(extension, newUniqueId);
  4022. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  4023. ZwClose(handle);
  4024. return status;
  4025. }
  4026. NTSTATUS
  4027. FtDiskPagingNotification(
  4028. IN PDEVICE_OBJECT DeviceObject,
  4029. IN PIRP Irp
  4030. )
  4031. /*++
  4032. Routine Description:
  4033. This routine handles the PnP paging notification IRP.
  4034. Arguments:
  4035. DeviceObject - Supplies the device object.
  4036. Irp - Supplies the IO request packet.
  4037. Return Value:
  4038. NTSTATUS
  4039. --*/
  4040. {
  4041. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  4042. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  4043. NTSTATUS status;
  4044. PFT_VOLUME vol;
  4045. ASSERT(extension->DeviceExtensionType != DEVICE_EXTENSION_ROOT);
  4046. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  4047. if (status == STATUS_PENDING) {
  4048. return status;
  4049. }
  4050. if (!NT_SUCCESS(status)) {
  4051. Irp->IoStatus.Information = 0;
  4052. Irp->IoStatus.Status = status;
  4053. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  4054. return status;
  4055. }
  4056. if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
  4057. extension->InPagingPath = irpSp->Parameters.UsageNotification.InPath;
  4058. IoInvalidateDeviceState(extension->DeviceObject);
  4059. }
  4060. if (extension->TargetObject) {
  4061. IoCopyCurrentIrpStackLocationToNext(Irp);
  4062. IoSetCompletionRoutine(Irp, FtpRefCountCompletionRoutine,
  4063. extension, TRUE, TRUE, TRUE);
  4064. IoMarkIrpPending(Irp);
  4065. IoCallDriver(extension->TargetObject, Irp);
  4066. return STATUS_PENDING;
  4067. }
  4068. vol = extension->FtVolume;
  4069. ASSERT(vol);
  4070. IoMarkIrpPending(Irp);
  4071. irpSp->DeviceObject = DeviceObject;
  4072. vol->BroadcastIrp(Irp, FtDiskShutdownFlushCompletionRoutine, Irp);
  4073. return STATUS_PENDING;
  4074. }
  4075. VOID
  4076. FtpDereferenceMbrGptAttributes(
  4077. IN PVOLUME_EXTENSION Extension,
  4078. IN PDEVICE_OBJECT WholeDiskPdo
  4079. )
  4080. {
  4081. PLIST_ENTRY l;
  4082. PVOLUME_EXTENSION extension;
  4083. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  4084. for (l = Extension->Root->VolumeList.Flink;
  4085. l != &Extension->Root->VolumeList; l = l->Flink) {
  4086. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  4087. if (extension == Extension ||
  4088. extension->WholeDiskPdo != WholeDiskPdo ||
  4089. !extension->MbrGptAttributes) {
  4090. continue;
  4091. }
  4092. return;
  4093. }
  4094. diskInfo = Extension->Root->DiskInfoSet->FindLogicalDiskInformation(
  4095. WholeDiskPdo);
  4096. if (diskInfo) {
  4097. diskInfo->SetGptAttributes(0);
  4098. }
  4099. }
  4100. NTSTATUS
  4101. FtpPartitionRemovedHelper(
  4102. IN OUT PROOT_EXTENSION RootExtension,
  4103. IN PDEVICE_OBJECT Partition,
  4104. IN PDEVICE_OBJECT WholeDiskPdo
  4105. )
  4106. {
  4107. PVOLUME_EXTENSION extension;
  4108. KEVENT event;
  4109. PFT_VOLUME vol, part, parent;
  4110. FT_PARTITION_OFFLINE_CONTEXT offlineContext;
  4111. USHORT n, i;
  4112. SET_TARGET_CONTEXT context;
  4113. extension = FtpFindExtensionCoveringPartition(RootExtension, Partition);
  4114. if (!extension) {
  4115. return STATUS_INVALID_PARAMETER;
  4116. }
  4117. if (extension->TargetObject) {
  4118. ASSERT(extension->TargetObject == Partition);
  4119. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  4120. context.TargetObject = NULL;
  4121. context.FtVolume = NULL;
  4122. context.WholeDiskPdo = NULL;
  4123. FtpZeroRefCallback(extension, FtpSetTargetCallback, &context, TRUE);
  4124. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  4125. NULL);
  4126. if (WholeDiskPdo) {
  4127. FtpDeleteMountPoints(extension);
  4128. if (!extension->IsGpt && extension->MbrGptAttributes) {
  4129. FtpDereferenceMbrGptAttributes(extension, WholeDiskPdo);
  4130. }
  4131. }
  4132. RemoveEntryList(&extension->ListEntry);
  4133. InsertTailList(&RootExtension->DeadVolumeList, &extension->ListEntry);
  4134. FtpCleanupVolumeExtension(extension);
  4135. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  4136. } else {
  4137. vol = extension->FtVolume;
  4138. ASSERT(vol);
  4139. part = vol->GetContainedLogicalDisk(Partition);
  4140. parent = vol->GetParentLogicalDisk(part);
  4141. KeInitializeEvent(&event, NotificationEvent, FALSE);
  4142. offlineContext.Root = vol;
  4143. offlineContext.Parent = parent;
  4144. offlineContext.Child = part;
  4145. offlineContext.Event = &event;
  4146. FtpZeroRefCallback(extension, FtpMemberOfflineCallback,
  4147. &offlineContext, TRUE);
  4148. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  4149. if (extension->FtVolume) {
  4150. FtpNotify(RootExtension, extension);
  4151. } else {
  4152. if (WholeDiskPdo) {
  4153. FtpDeleteMountPoints(extension);
  4154. FtpTotalBreakUp(RootExtension, vol->QueryLogicalDiskId());
  4155. }
  4156. FtpDeleteVolume(vol);
  4157. RemoveEntryList(&extension->ListEntry);
  4158. InsertTailList(&RootExtension->DeadVolumeList, &extension->ListEntry);
  4159. FtpCleanupVolumeExtension(extension);
  4160. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  4161. }
  4162. if (parent) {
  4163. if (!InterlockedDecrement(&part->_refCount)) {
  4164. delete part;
  4165. }
  4166. }
  4167. }
  4168. return STATUS_SUCCESS;
  4169. }
  4170. NTSTATUS
  4171. FtpGetVolumeDiskExtents(
  4172. IN PVOLUME_EXTENSION Extension,
  4173. IN PIRP Irp
  4174. )
  4175. /*++
  4176. Routine Description:
  4177. This routine returns the disk extents for the given volume.
  4178. Arguments:
  4179. Extension - Supplies the volume extension.
  4180. Irp - Supplies the IO request packet.
  4181. Return Value:
  4182. NTSTATUS
  4183. --*/
  4184. {
  4185. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  4186. PVOLUME_DISK_EXTENTS output = (PVOLUME_DISK_EXTENTS) Irp->AssociatedIrp.SystemBuffer;
  4187. NTSTATUS status;
  4188. ULONG diskNumber, numExtents;
  4189. LONGLONG offset, length;
  4190. PDISK_EXTENT extents;
  4191. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4192. sizeof(VOLUME_DISK_EXTENTS)) {
  4193. return STATUS_INVALID_PARAMETER;
  4194. }
  4195. if (Extension->TargetObject) {
  4196. status = FtpQueryPartitionInformation(Extension->Root,
  4197. Extension->TargetObject,
  4198. &diskNumber, &offset, NULL,
  4199. NULL, &length, NULL, NULL, NULL,
  4200. NULL);
  4201. if (!NT_SUCCESS(status)) {
  4202. return status;
  4203. }
  4204. Irp->IoStatus.Information = sizeof(VOLUME_DISK_EXTENTS);
  4205. output->NumberOfDiskExtents = 1;
  4206. output->Extents[0].DiskNumber = diskNumber;
  4207. output->Extents[0].StartingOffset.QuadPart = offset;
  4208. output->Extents[0].ExtentLength.QuadPart = length;
  4209. return STATUS_SUCCESS;
  4210. }
  4211. status = Extension->FtVolume->QueryDiskExtents(&extents, &numExtents);
  4212. if (!NT_SUCCESS(status)) {
  4213. return status;
  4214. }
  4215. output->NumberOfDiskExtents = numExtents;
  4216. Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_DISK_EXTENTS, Extents) +
  4217. numExtents*sizeof(DISK_EXTENT);
  4218. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4219. Irp->IoStatus.Information) {
  4220. Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_DISK_EXTENTS, Extents);
  4221. ExFreePool(extents);
  4222. return STATUS_BUFFER_OVERFLOW;
  4223. }
  4224. RtlCopyMemory(output->Extents, extents, numExtents*sizeof(DISK_EXTENT));
  4225. ExFreePool(extents);
  4226. return status;
  4227. }
  4228. NTSTATUS
  4229. FtpDisksFromFtVolume(
  4230. IN PFT_VOLUME FtVolume,
  4231. OUT PDEVICE_OBJECT** DiskPdos,
  4232. OUT PULONG NumDiskPdos
  4233. )
  4234. {
  4235. PDEVICE_OBJECT* diskPdos;
  4236. ULONG numDisks, nd, j, k;
  4237. USHORT n, i;
  4238. PFT_VOLUME vol;
  4239. PDEVICE_OBJECT* dp;
  4240. NTSTATUS status;
  4241. PDEVICE_OBJECT* diskPdos2;
  4242. if (FtVolume->QueryLogicalDiskType() == FtPartition) {
  4243. numDisks = 1;
  4244. diskPdos = (PDEVICE_OBJECT*)
  4245. ExAllocatePool(PagedPool, numDisks*sizeof(PDEVICE_OBJECT));
  4246. if (!diskPdos) {
  4247. return STATUS_INSUFFICIENT_RESOURCES;
  4248. }
  4249. diskPdos[0] = ((PPARTITION) FtVolume)->GetWholeDiskPdo();
  4250. *DiskPdos = diskPdos;
  4251. *NumDiskPdos = numDisks;
  4252. return STATUS_SUCCESS;
  4253. }
  4254. diskPdos = NULL;
  4255. numDisks = 0;
  4256. n = FtVolume->QueryNumberOfMembers();
  4257. for (i = 0; i < n; i++) {
  4258. vol = FtVolume->GetMember(i);
  4259. if (!vol) {
  4260. continue;
  4261. }
  4262. status = FtpDisksFromFtVolume(vol, &dp, &nd);
  4263. if (!NT_SUCCESS(status)) {
  4264. if (diskPdos) {
  4265. ExFreePool(diskPdos);
  4266. }
  4267. return status;
  4268. }
  4269. diskPdos2 = diskPdos;
  4270. diskPdos = (PDEVICE_OBJECT*) ExAllocatePool(PagedPool,
  4271. (numDisks + nd)*sizeof(PDEVICE_OBJECT));
  4272. if (!diskPdos) {
  4273. ExFreePool(dp);
  4274. if (diskPdos2) {
  4275. ExFreePool(diskPdos2);
  4276. }
  4277. return STATUS_INSUFFICIENT_RESOURCES;
  4278. }
  4279. if (diskPdos2) {
  4280. RtlCopyMemory(diskPdos, diskPdos2,
  4281. numDisks*sizeof(PDEVICE_OBJECT));
  4282. ExFreePool(diskPdos2);
  4283. }
  4284. for (j = 0; j < nd; j++) {
  4285. for (k = 0; k < numDisks; k++) {
  4286. if (dp[j] == diskPdos[k]) {
  4287. break;
  4288. }
  4289. }
  4290. if (k == numDisks) {
  4291. diskPdos[numDisks++] = dp[j];
  4292. }
  4293. }
  4294. ExFreePool(dp);
  4295. }
  4296. *DiskPdos = diskPdos;
  4297. *NumDiskPdos = numDisks;
  4298. return STATUS_SUCCESS;
  4299. }
  4300. NTSTATUS
  4301. FtpDisksFromVolumes(
  4302. IN PVOLUME_EXTENSION* Extensions,
  4303. IN ULONG NumVolumes,
  4304. OUT PDEVICE_OBJECT** WholeDiskPdos,
  4305. OUT PULONG NumDisks
  4306. )
  4307. /*++
  4308. Routine Description:
  4309. This routine computes the disks that are used by the given volumes
  4310. and returns the list of whole disk pdos.
  4311. Arguments:
  4312. Extensions - Supplies the list of volumes.
  4313. NumVolumes - Supplies the number of volumes.
  4314. WholeDiskPdos - Returns the list of disks.
  4315. NumDisks - Returns the number of disks.
  4316. Return Value:
  4317. NTSTATUS
  4318. --*/
  4319. {
  4320. ULONG numDisks, i, j, k;
  4321. PDEVICE_OBJECT* diskPdos;
  4322. PDEVICE_OBJECT* diskPdos2;
  4323. NTSTATUS status;
  4324. PDEVICE_OBJECT* volumeDiskPdos;
  4325. ULONG numVolumeDisks;
  4326. numDisks = 0;
  4327. diskPdos = NULL;
  4328. for (i = 0; i < NumVolumes; i++) {
  4329. if (Extensions[i]->TargetObject) {
  4330. for (j = 0; j < numDisks; j++) {
  4331. if (Extensions[i]->WholeDiskPdo == diskPdos[j]) {
  4332. break;
  4333. }
  4334. }
  4335. if (j == numDisks) {
  4336. diskPdos2 = diskPdos;
  4337. numDisks++;
  4338. diskPdos = (PDEVICE_OBJECT*)
  4339. ExAllocatePool(PagedPool,
  4340. numDisks*sizeof(PDEVICE_OBJECT));
  4341. if (!diskPdos) {
  4342. if (diskPdos2) {
  4343. ExFreePool(diskPdos2);
  4344. }
  4345. return STATUS_INSUFFICIENT_RESOURCES;
  4346. }
  4347. if (diskPdos2) {
  4348. RtlCopyMemory(diskPdos, diskPdos2,
  4349. (numDisks - 1)*sizeof(PDEVICE_OBJECT));
  4350. ExFreePool(diskPdos2);
  4351. }
  4352. diskPdos[numDisks - 1] = Extensions[i]->WholeDiskPdo;
  4353. }
  4354. } else if (Extensions[i]->FtVolume) {
  4355. status = FtpDisksFromFtVolume(Extensions[i]->FtVolume,
  4356. &volumeDiskPdos, &numVolumeDisks);
  4357. if (!NT_SUCCESS(status)) {
  4358. if (diskPdos) {
  4359. ExFreePool(diskPdos);
  4360. }
  4361. return status;
  4362. }
  4363. diskPdos2 = diskPdos;
  4364. diskPdos = (PDEVICE_OBJECT*) ExAllocatePool(PagedPool,
  4365. (numDisks + numVolumeDisks)*sizeof(PDEVICE_OBJECT));
  4366. if (!diskPdos) {
  4367. ExFreePool(volumeDiskPdos);
  4368. if (diskPdos2) {
  4369. ExFreePool(diskPdos2);
  4370. }
  4371. return STATUS_INSUFFICIENT_RESOURCES;
  4372. }
  4373. if (diskPdos2) {
  4374. RtlCopyMemory(diskPdos, diskPdos2,
  4375. numDisks*sizeof(PDEVICE_OBJECT));
  4376. ExFreePool(diskPdos2);
  4377. }
  4378. for (j = 0; j < numVolumeDisks; j++) {
  4379. for (k = 0; k < numDisks; k++) {
  4380. if (volumeDiskPdos[j] == diskPdos[k]) {
  4381. break;
  4382. }
  4383. }
  4384. if (k == numDisks) {
  4385. diskPdos[numDisks++] = volumeDiskPdos[j];
  4386. }
  4387. }
  4388. ExFreePool(volumeDiskPdos);
  4389. }
  4390. }
  4391. *WholeDiskPdos = diskPdos;
  4392. *NumDisks = numDisks;
  4393. return STATUS_SUCCESS;
  4394. }
  4395. BOOLEAN
  4396. FtpVolumeContainsDisks(
  4397. IN PFT_VOLUME FtVolume,
  4398. IN PDEVICE_OBJECT* WholeDiskPdos,
  4399. IN ULONG NumDisks
  4400. )
  4401. /*++
  4402. Routine Description:
  4403. This routine determines whether or not the given volume contains
  4404. any of the given disks.
  4405. Arguments:
  4406. FtVolume - Supplies the FT volumes.
  4407. WholeDiskPdos - Supplies the list of disks.
  4408. NumDisks - Supplies the number of disks.
  4409. Return Value:
  4410. FALSE - The given volume does not contain any of the given disks.
  4411. TRUE - The given volume contains at least one of the given disks.
  4412. --*/
  4413. {
  4414. PDEVICE_OBJECT wholeDiskPdo;
  4415. ULONG i;
  4416. USHORT n, j;
  4417. PFT_VOLUME vol;
  4418. if (FtVolume->QueryLogicalDiskType() == FtPartition) {
  4419. wholeDiskPdo = ((PPARTITION) FtVolume)->GetWholeDiskPdo();
  4420. for (i = 0; i < NumDisks; i++) {
  4421. if (wholeDiskPdo == WholeDiskPdos[i]) {
  4422. return TRUE;
  4423. }
  4424. }
  4425. return FALSE;
  4426. }
  4427. n = FtVolume->QueryNumberOfMembers();
  4428. for (j = 0; j < n; j++) {
  4429. vol = FtVolume->GetMember(j);
  4430. if (!vol) {
  4431. continue;
  4432. }
  4433. if (FtpVolumeContainsDisks(vol, WholeDiskPdos, NumDisks)) {
  4434. return TRUE;
  4435. }
  4436. }
  4437. return FALSE;
  4438. }
  4439. NTSTATUS
  4440. FtpVolumesFromDisks(
  4441. IN PROOT_EXTENSION RootExtension,
  4442. IN PDEVICE_OBJECT* WholeDiskPdos,
  4443. IN ULONG NumDisks,
  4444. OUT PVOLUME_EXTENSION** Extensions,
  4445. OUT PULONG NumVolumes
  4446. )
  4447. /*++
  4448. Routine Description:
  4449. This routine computes the volumes that use the given set of disks
  4450. and returns the list of volume device extensions.
  4451. Arguments:
  4452. RootExtension - Supplies the root extension.
  4453. WholeDiskPdos - Supplies the list of disks.
  4454. NumDisks - Supplies the number of disks.
  4455. Extensions - Returns the list of volumes.
  4456. NumVolumes - Returns the number of volumes.
  4457. Return Value:
  4458. NTSTATUS
  4459. --*/
  4460. {
  4461. PVOLUME_EXTENSION* extensions;
  4462. ULONG numVolumes;
  4463. PLIST_ENTRY l;
  4464. PVOLUME_EXTENSION extension;
  4465. ULONG i;
  4466. extensions = (PVOLUME_EXTENSION*)
  4467. ExAllocatePool(PagedPool, RootExtension->NextVolumeNumber*
  4468. sizeof(PVOLUME_EXTENSION));
  4469. if (!extensions) {
  4470. return STATUS_INSUFFICIENT_RESOURCES;
  4471. }
  4472. numVolumes = 0;
  4473. for (l = RootExtension->VolumeList.Flink;
  4474. l != &RootExtension->VolumeList; l = l->Flink) {
  4475. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  4476. if (extension->TargetObject) {
  4477. for (i = 0; i < NumDisks; i++) {
  4478. if (WholeDiskPdos[i] == extension->WholeDiskPdo) {
  4479. break;
  4480. }
  4481. }
  4482. if (i == NumDisks) {
  4483. continue;
  4484. }
  4485. } else if (extension->FtVolume) {
  4486. if (!FtpVolumeContainsDisks(extension->FtVolume, WholeDiskPdos,
  4487. NumDisks)) {
  4488. continue;
  4489. }
  4490. } else {
  4491. continue;
  4492. }
  4493. extensions[numVolumes++] = extension;
  4494. }
  4495. *Extensions = extensions;
  4496. *NumVolumes = numVolumes;
  4497. return STATUS_SUCCESS;
  4498. }
  4499. NTSTATUS
  4500. FtpQueryFailoverSet(
  4501. IN PVOLUME_EXTENSION Extension,
  4502. IN PIRP Irp
  4503. )
  4504. /*++
  4505. Routine Description:
  4506. This routine returns the list of disks which include the given volume
  4507. and which make up a failover set.
  4508. Arguments:
  4509. Extension - Supplies the volume extension.
  4510. Irp - Supplies the IO request packet.
  4511. Return Value:
  4512. NTSTATUS
  4513. --*/
  4514. {
  4515. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  4516. ULONG numVolumes, numVolumes2, numDisks, numDisks2;
  4517. PVOLUME_EXTENSION* extensions;
  4518. PDEVICE_OBJECT* diskPdos;
  4519. NTSTATUS status;
  4520. PVOLUME_FAILOVER_SET output;
  4521. ULONG i;
  4522. PDEVICE_OBJECT deviceObject;
  4523. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4524. sizeof(VOLUME_FAILOVER_SET)) {
  4525. return STATUS_INVALID_PARAMETER;
  4526. }
  4527. numVolumes = 1;
  4528. extensions = (PVOLUME_EXTENSION*)
  4529. ExAllocatePool(PagedPool,
  4530. numVolumes*sizeof(PVOLUME_EXTENSION));
  4531. if (!extensions) {
  4532. return STATUS_INSUFFICIENT_RESOURCES;
  4533. }
  4534. extensions[0] = Extension;
  4535. diskPdos = NULL;
  4536. numDisks = 0;
  4537. for (;;) {
  4538. numDisks2 = numDisks;
  4539. if (diskPdos) {
  4540. ExFreePool(diskPdos);
  4541. diskPdos = NULL;
  4542. }
  4543. status = FtpDisksFromVolumes(extensions, numVolumes, &diskPdos,
  4544. &numDisks);
  4545. if (!NT_SUCCESS(status)) {
  4546. break;
  4547. }
  4548. if (numDisks == numDisks2) {
  4549. status = STATUS_SUCCESS;
  4550. break;
  4551. }
  4552. numVolumes2 = numVolumes;
  4553. if (extensions) {
  4554. ExFreePool(extensions);
  4555. extensions = NULL;
  4556. }
  4557. status = FtpVolumesFromDisks(Extension->Root, diskPdos, numDisks,
  4558. &extensions, &numVolumes);
  4559. if (!NT_SUCCESS(status)) {
  4560. break;
  4561. }
  4562. if (numVolumes == numVolumes2) {
  4563. status = STATUS_SUCCESS;
  4564. break;
  4565. }
  4566. }
  4567. if (extensions) {
  4568. ExFreePool(extensions);
  4569. }
  4570. if (!NT_SUCCESS(status)) {
  4571. if (diskPdos) {
  4572. ExFreePool(diskPdos);
  4573. }
  4574. return status;
  4575. }
  4576. output = (PVOLUME_FAILOVER_SET) Irp->AssociatedIrp.SystemBuffer;
  4577. output->NumberOfDisks = numDisks;
  4578. Irp->IoStatus.Information =
  4579. FIELD_OFFSET(VOLUME_FAILOVER_SET, DiskNumbers) +
  4580. numDisks*sizeof(ULONG);
  4581. if (Irp->IoStatus.Information >
  4582. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  4583. Irp->IoStatus.Information = sizeof(VOLUME_FAILOVER_SET);
  4584. if (diskPdos) {
  4585. ExFreePool(diskPdos);
  4586. }
  4587. return STATUS_BUFFER_OVERFLOW;
  4588. }
  4589. for (i = 0; i < numDisks; i++) {
  4590. deviceObject = IoGetAttachedDeviceReference(diskPdos[i]);
  4591. status = FtpQueryPartitionInformation(Extension->Root, deviceObject,
  4592. &output->DiskNumbers[i],
  4593. NULL, NULL, NULL, NULL, NULL,
  4594. NULL, NULL, NULL);
  4595. ObDereferenceObject(deviceObject);
  4596. if (!NT_SUCCESS(status)) {
  4597. Irp->IoStatus.Information = 0;
  4598. if (diskPdos) {
  4599. ExFreePool(diskPdos);
  4600. }
  4601. return status;
  4602. }
  4603. }
  4604. if (diskPdos) {
  4605. ExFreePool(diskPdos);
  4606. }
  4607. return STATUS_SUCCESS;
  4608. }
  4609. NTSTATUS
  4610. FtpQueryVolumeNumber(
  4611. IN PVOLUME_EXTENSION Extension,
  4612. IN PIRP Irp
  4613. )
  4614. /*++
  4615. Routine Description:
  4616. This routine returns the volume number for the given volume.
  4617. Arguments:
  4618. Extension - Supplies the volume extension.
  4619. Irp - Supplies the IO request packet.
  4620. Return Value:
  4621. NTSTATUS
  4622. --*/
  4623. {
  4624. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  4625. PVOLUME_NUMBER output;
  4626. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4627. sizeof(VOLUME_NUMBER)) {
  4628. return STATUS_INVALID_PARAMETER;
  4629. }
  4630. output = (PVOLUME_NUMBER) Irp->AssociatedIrp.SystemBuffer;
  4631. output->VolumeNumber = Extension->VolumeNumber;
  4632. RtlCopyMemory(output->VolumeManagerName, L"FTDISK ", 16);
  4633. Irp->IoStatus.Information = sizeof(VOLUME_NUMBER);
  4634. return STATUS_SUCCESS;
  4635. }
  4636. NTSTATUS
  4637. FtpLogicalToPhysical(
  4638. IN PVOLUME_EXTENSION Extension,
  4639. IN PIRP Irp
  4640. )
  4641. /*++
  4642. Routine Description:
  4643. This routine returns physical disk and offset for a given volume
  4644. logical offset.
  4645. Arguments:
  4646. Extension - Supplies the volume extension.
  4647. Irp - Supplies the IO request packet.
  4648. Return Value:
  4649. NTSTATUS
  4650. --*/
  4651. {
  4652. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  4653. PVOLUME_LOGICAL_OFFSET input;
  4654. LONGLONG logicalOffset;
  4655. PVOLUME_PHYSICAL_OFFSETS output;
  4656. NTSTATUS status;
  4657. ULONG diskNumber;
  4658. LONGLONG partitionOffset, partitionLength;
  4659. PFT_VOLUME vol;
  4660. PVOLUME_PHYSICAL_OFFSET physicalOffsets;
  4661. ULONG numPhysicalOffsets;
  4662. ULONG i;
  4663. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  4664. sizeof(VOLUME_LOGICAL_OFFSET) ||
  4665. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4666. sizeof(VOLUME_PHYSICAL_OFFSETS)) {
  4667. return STATUS_INVALID_PARAMETER;
  4668. }
  4669. input = (PVOLUME_LOGICAL_OFFSET) Irp->AssociatedIrp.SystemBuffer;
  4670. logicalOffset = input->LogicalOffset;
  4671. output = (PVOLUME_PHYSICAL_OFFSETS) Irp->AssociatedIrp.SystemBuffer;
  4672. if (Extension->TargetObject) {
  4673. status = FtpQueryPartitionInformation(Extension->Root,
  4674. Extension->TargetObject,
  4675. &diskNumber,
  4676. &partitionOffset, NULL, NULL,
  4677. &partitionLength, NULL, NULL,
  4678. NULL, NULL);
  4679. if (!NT_SUCCESS(status)) {
  4680. return status;
  4681. }
  4682. if (logicalOffset < 0 ||
  4683. partitionLength <= logicalOffset) {
  4684. return STATUS_INVALID_PARAMETER;
  4685. }
  4686. output->NumberOfPhysicalOffsets = 1;
  4687. output->PhysicalOffset[0].DiskNumber = diskNumber;
  4688. output->PhysicalOffset[0].Offset = partitionOffset + logicalOffset;
  4689. Irp->IoStatus.Information = sizeof(VOLUME_PHYSICAL_OFFSETS);
  4690. return status;
  4691. }
  4692. vol = Extension->FtVolume;
  4693. ASSERT(vol);
  4694. status = vol->QueryPhysicalOffsets(logicalOffset, &physicalOffsets,
  4695. &numPhysicalOffsets);
  4696. if (!NT_SUCCESS(status)) {
  4697. return status;
  4698. }
  4699. Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_PHYSICAL_OFFSETS,
  4700. PhysicalOffset) +
  4701. numPhysicalOffsets*
  4702. sizeof(VOLUME_PHYSICAL_OFFSET);
  4703. output->NumberOfPhysicalOffsets = numPhysicalOffsets;
  4704. if (Irp->IoStatus.Information >
  4705. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  4706. Irp->IoStatus.Information = FIELD_OFFSET(VOLUME_PHYSICAL_OFFSETS,
  4707. PhysicalOffset);
  4708. ExFreePool(physicalOffsets);
  4709. return STATUS_BUFFER_OVERFLOW;
  4710. }
  4711. for (i = 0; i < numPhysicalOffsets; i++) {
  4712. output->PhysicalOffset[i] = physicalOffsets[i];
  4713. }
  4714. ExFreePool(physicalOffsets);
  4715. return STATUS_SUCCESS;
  4716. }
  4717. NTSTATUS
  4718. FtpPhysicalToLogical(
  4719. IN PVOLUME_EXTENSION Extension,
  4720. IN PIRP Irp
  4721. )
  4722. /*++
  4723. Routine Description:
  4724. This routine returns the volume logical offset for a given disk number
  4725. and physical offset.
  4726. Arguments:
  4727. Extension - Supplies the volume extension.
  4728. Irp - Supplies the IO request packet.
  4729. Return Value:
  4730. NTSTATUS
  4731. --*/
  4732. {
  4733. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  4734. PVOLUME_PHYSICAL_OFFSET input;
  4735. ULONG diskNumber, otherDiskNumber;
  4736. LONGLONG physicalOffset;
  4737. PVOLUME_LOGICAL_OFFSET output;
  4738. NTSTATUS status;
  4739. LONGLONG partitionOffset, partitionLength;
  4740. PFT_VOLUME vol;
  4741. LONGLONG logicalOffset;
  4742. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  4743. sizeof(VOLUME_PHYSICAL_OFFSET) ||
  4744. irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  4745. sizeof(VOLUME_LOGICAL_OFFSET)) {
  4746. return STATUS_INVALID_PARAMETER;
  4747. }
  4748. input = (PVOLUME_PHYSICAL_OFFSET) Irp->AssociatedIrp.SystemBuffer;
  4749. diskNumber = input->DiskNumber;
  4750. physicalOffset = input->Offset;
  4751. output = (PVOLUME_LOGICAL_OFFSET) Irp->AssociatedIrp.SystemBuffer;
  4752. if (Extension->TargetObject) {
  4753. status = FtpQueryPartitionInformation(Extension->Root,
  4754. Extension->TargetObject,
  4755. &otherDiskNumber,
  4756. &partitionOffset, NULL, NULL,
  4757. &partitionLength, NULL, NULL,
  4758. NULL, NULL);
  4759. if (!NT_SUCCESS(status)) {
  4760. return status;
  4761. }
  4762. if (diskNumber != otherDiskNumber ||
  4763. physicalOffset < partitionOffset ||
  4764. partitionOffset + partitionLength <= physicalOffset) {
  4765. return STATUS_INVALID_PARAMETER;
  4766. }
  4767. output->LogicalOffset = physicalOffset - partitionOffset;
  4768. Irp->IoStatus.Information = sizeof(VOLUME_LOGICAL_OFFSET);
  4769. return status;
  4770. }
  4771. vol = Extension->FtVolume;
  4772. ASSERT(vol);
  4773. status = vol->QueryLogicalOffset(input, &logicalOffset);
  4774. if (!NT_SUCCESS(status)) {
  4775. return status;
  4776. }
  4777. output->LogicalOffset = logicalOffset;
  4778. Irp->IoStatus.Information = sizeof(VOLUME_LOGICAL_OFFSET);
  4779. return status;
  4780. }
  4781. BOOLEAN
  4782. FtpIsReplicatedPartition(
  4783. IN PFT_VOLUME FtVolume
  4784. )
  4785. {
  4786. PFT_VOLUME m0, m1;
  4787. if (FtVolume->QueryLogicalDiskType() == FtPartition) {
  4788. return TRUE;
  4789. }
  4790. if (FtVolume->QueryLogicalDiskType() != FtMirrorSet) {
  4791. return FALSE;
  4792. }
  4793. m0 = FtVolume->GetMember(0);
  4794. m1 = FtVolume->GetMember(1);
  4795. if (m0 && !FtpIsReplicatedPartition(m0)) {
  4796. return FALSE;
  4797. }
  4798. if (m1 && !FtpIsReplicatedPartition(m1)) {
  4799. return FALSE;
  4800. }
  4801. if (!m0 && !m1) {
  4802. return FALSE;
  4803. }
  4804. return TRUE;
  4805. }
  4806. NTSTATUS
  4807. FtpIsPartition(
  4808. IN PVOLUME_EXTENSION Extension,
  4809. IN PIRP Irp
  4810. )
  4811. /*++
  4812. Routine Description:
  4813. This routine determines whether the given volume is installable.
  4814. To be an installable volume on Whistler, the volume must be a basic
  4815. partition.
  4816. We will disallow installing to Ft mirrors on Whistler, because we will
  4817. offline Ft volumes after a Whistler install\upgrade.
  4818. This call will return STATUS_UNSUCCESSFUL for all volumes that are
  4819. not a simple basic partition, e.g., mirrors, RAID5, stripe sets
  4820. and volume sets.
  4821. Arguments:
  4822. Extension - Supplies the volume extension.
  4823. Irp - Supplies the IO request packet.
  4824. Return Value:
  4825. NTSTATUS
  4826. --*/
  4827. {
  4828. NTSTATUS status;
  4829. if (Extension->TargetObject) {
  4830. status = STATUS_SUCCESS;
  4831. }
  4832. else if (Extension->FtVolume && FtpIsReplicatedPartition(Extension->FtVolume)) {
  4833. status = STATUS_SUCCESS;
  4834. }
  4835. else {
  4836. status = STATUS_UNSUCCESSFUL;
  4837. }
  4838. return status;
  4839. }
  4840. NTSTATUS
  4841. FtpSetGptAttributesOnDisk(
  4842. IN PDEVICE_OBJECT Partition,
  4843. IN ULONGLONG GptAttributes
  4844. )
  4845. {
  4846. KEVENT event;
  4847. PIRP irp;
  4848. PARTITION_INFORMATION_EX partInfo;
  4849. IO_STATUS_BLOCK ioStatus;
  4850. NTSTATUS status;
  4851. SET_PARTITION_INFORMATION_EX setPartInfo;
  4852. KeInitializeEvent(&event, NotificationEvent, FALSE);
  4853. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
  4854. Partition, NULL, 0, &partInfo,
  4855. sizeof(partInfo), FALSE, &event,
  4856. &ioStatus);
  4857. if (!irp) {
  4858. return STATUS_INSUFFICIENT_RESOURCES;
  4859. }
  4860. status = IoCallDriver(Partition, irp);
  4861. if (status == STATUS_PENDING) {
  4862. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  4863. status = ioStatus.Status;
  4864. }
  4865. if (!NT_SUCCESS(status)) {
  4866. return status;
  4867. }
  4868. ASSERT(partInfo.PartitionStyle == PARTITION_STYLE_GPT);
  4869. setPartInfo.PartitionStyle = partInfo.PartitionStyle;
  4870. setPartInfo.Gpt = partInfo.Gpt;
  4871. setPartInfo.Gpt.Attributes = GptAttributes;
  4872. irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_SET_PARTITION_INFO_EX,
  4873. Partition, &setPartInfo,
  4874. sizeof(setPartInfo), NULL, 0, FALSE,
  4875. &event, &ioStatus);
  4876. if (!irp) {
  4877. return STATUS_INSUFFICIENT_RESOURCES;
  4878. }
  4879. status = IoCallDriver(Partition, irp);
  4880. if (status == STATUS_PENDING) {
  4881. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  4882. status = ioStatus.Status;
  4883. }
  4884. if (!NT_SUCCESS(status)) {
  4885. return status;
  4886. }
  4887. return STATUS_SUCCESS;
  4888. }
  4889. NTSTATUS
  4890. FtpCheckSecurity(
  4891. IN PVOLUME_EXTENSION Extension,
  4892. IN PIRP Irp
  4893. )
  4894. {
  4895. SECURITY_SUBJECT_CONTEXT securityContext;
  4896. BOOLEAN accessGranted;
  4897. NTSTATUS status;
  4898. ACCESS_MASK grantedAccess;
  4899. SeCaptureSubjectContext(&securityContext);
  4900. SeLockSubjectContext(&securityContext);
  4901. accessGranted = FALSE;
  4902. status = STATUS_ACCESS_DENIED;
  4903. _try {
  4904. accessGranted = SeAccessCheck(
  4905. Extension->DeviceObject->SecurityDescriptor,
  4906. &securityContext, TRUE, FILE_READ_DATA, 0, NULL,
  4907. IoGetFileObjectGenericMapping(), Irp->RequestorMode,
  4908. &grantedAccess, &status);
  4909. } _finally {
  4910. SeUnlockSubjectContext(&securityContext);
  4911. SeReleaseSubjectContext(&securityContext);
  4912. }
  4913. if (!accessGranted) {
  4914. return status;
  4915. }
  4916. return STATUS_SUCCESS;
  4917. }
  4918. NTSTATUS
  4919. FtpQueryRegistryRevertEntriesCallback(
  4920. IN PWSTR ValueName,
  4921. IN ULONG ValueType,
  4922. IN PVOID ValueData,
  4923. IN ULONG ValueLength,
  4924. IN PVOID RevertEntries,
  4925. IN PVOID NumberOfRevertEntries
  4926. )
  4927. {
  4928. PFTP_GPT_ATTRIBUTE_REVERT_ENTRY* revertEntries = (PFTP_GPT_ATTRIBUTE_REVERT_ENTRY*) RevertEntries;
  4929. PULONG pn = (PULONG) NumberOfRevertEntries;
  4930. if (ValueType != REG_BINARY) {
  4931. return STATUS_SUCCESS;
  4932. }
  4933. (*revertEntries) = (PFTP_GPT_ATTRIBUTE_REVERT_ENTRY)
  4934. ExAllocatePool(PagedPool, ValueLength);
  4935. if (!(*revertEntries)) {
  4936. return STATUS_SUCCESS;
  4937. }
  4938. RtlCopyMemory((*revertEntries), ValueData, ValueLength);
  4939. *pn = ValueLength/sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY);
  4940. return STATUS_SUCCESS;
  4941. }
  4942. NTSTATUS
  4943. FtpQueryRegistryRevertEntries(
  4944. IN PROOT_EXTENSION RootExtension,
  4945. OUT PFTP_GPT_ATTRIBUTE_REVERT_ENTRY* RevertEntries,
  4946. OUT PULONG NumberOfRevertEntries
  4947. )
  4948. {
  4949. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  4950. PFTP_GPT_ATTRIBUTE_REVERT_ENTRY revertEntries;
  4951. ULONG n;
  4952. revertEntries = NULL;
  4953. n = 0;
  4954. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  4955. queryTable[0].QueryRoutine = FtpQueryRegistryRevertEntriesCallback;
  4956. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  4957. queryTable[0].Name = REVERT_GPT_ATTRIBUTES_REGISTRY_NAME;
  4958. queryTable[0].EntryContext = &n;
  4959. if (!RootExtension->DiskPerfRegistryPath.Buffer) {
  4960. return STATUS_INSUFFICIENT_RESOURCES;
  4961. }
  4962. RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  4963. RootExtension->DiskPerfRegistryPath.Buffer,
  4964. queryTable, &revertEntries, NULL);
  4965. if (!revertEntries) {
  4966. return STATUS_INSUFFICIENT_RESOURCES;
  4967. }
  4968. *RevertEntries = revertEntries;
  4969. *NumberOfRevertEntries = n;
  4970. return STATUS_SUCCESS;
  4971. }
  4972. NTSTATUS
  4973. FtpStoreGptAttributeRevertRecord(
  4974. IN PROOT_EXTENSION RootExtension,
  4975. IN ULONG MbrSignature,
  4976. IN GUID* GptPartitionGuid,
  4977. IN ULONGLONG GptAttributes
  4978. )
  4979. {
  4980. NTSTATUS status;
  4981. PFTP_GPT_ATTRIBUTE_REVERT_ENTRY p, q;
  4982. ULONG n, i;
  4983. status = FtpQueryRegistryRevertEntries(RootExtension, &p, &n);
  4984. if (!NT_SUCCESS(status)) {
  4985. p = NULL;
  4986. n = 0;
  4987. }
  4988. for (i = 0; i < n; i++) {
  4989. if (MbrSignature) {
  4990. if (MbrSignature == p[i].MbrSignature) {
  4991. break;
  4992. }
  4993. } else {
  4994. if (IsEqualGUID(*GptPartitionGuid, p[i].PartitionUniqueId)) {
  4995. break;
  4996. }
  4997. }
  4998. }
  4999. if (i == n) {
  5000. q = (PFTP_GPT_ATTRIBUTE_REVERT_ENTRY)
  5001. ExAllocatePool(PagedPool,
  5002. (n + 1)*sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY));
  5003. if (!q) {
  5004. if (p) {
  5005. ExFreePool(p);
  5006. }
  5007. return STATUS_INSUFFICIENT_RESOURCES;
  5008. }
  5009. if (n) {
  5010. RtlCopyMemory(q, p, n*sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY));
  5011. }
  5012. if (p) {
  5013. ExFreePool(p);
  5014. }
  5015. p = q;
  5016. n++;
  5017. }
  5018. RtlZeroMemory(&p[i], sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY));
  5019. if (GptPartitionGuid) {
  5020. p[i].PartitionUniqueId = *GptPartitionGuid;
  5021. }
  5022. p[i].GptAttributes = GptAttributes;
  5023. p[i].MbrSignature = MbrSignature;
  5024. status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  5025. RootExtension->DiskPerfRegistryPath.Buffer,
  5026. REVERT_GPT_ATTRIBUTES_REGISTRY_NAME,
  5027. REG_BINARY, p,
  5028. n*sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY));
  5029. ExFreePool(p);
  5030. return status;
  5031. }
  5032. VOID
  5033. FtpDeleteGptAttributeRevertRecord(
  5034. IN PROOT_EXTENSION RootExtension,
  5035. IN ULONG MbrSignature,
  5036. IN GUID* GptPartitionGuid
  5037. )
  5038. {
  5039. NTSTATUS status;
  5040. PFTP_GPT_ATTRIBUTE_REVERT_ENTRY p, q;
  5041. ULONG n, i;
  5042. status = FtpQueryRegistryRevertEntries(RootExtension, &p, &n);
  5043. if (!NT_SUCCESS(status)) {
  5044. return;
  5045. }
  5046. for (i = 0; i < n; i++) {
  5047. if (MbrSignature) {
  5048. if (MbrSignature == p[i].MbrSignature) {
  5049. break;
  5050. }
  5051. } else {
  5052. if (IsEqualGUID(*GptPartitionGuid, p[i].PartitionUniqueId)) {
  5053. break;
  5054. }
  5055. }
  5056. }
  5057. if (i == n) {
  5058. return;
  5059. }
  5060. if (i + 1 < n) {
  5061. RtlMoveMemory(&p[i], &p[i + 1],
  5062. (n - i - 1)*sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY));
  5063. }
  5064. n--;
  5065. if (n) {
  5066. RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  5067. RootExtension->DiskPerfRegistryPath.Buffer,
  5068. REVERT_GPT_ATTRIBUTES_REGISTRY_NAME,
  5069. REG_BINARY, p,
  5070. n*sizeof(FTP_GPT_ATTRIBUTE_REVERT_ENTRY));
  5071. } else {
  5072. RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  5073. RootExtension->DiskPerfRegistryPath.Buffer,
  5074. REVERT_GPT_ATTRIBUTES_REGISTRY_NAME);
  5075. }
  5076. ExFreePool(p);
  5077. return;
  5078. }
  5079. VOID
  5080. FtpApplyGptAttributes(
  5081. IN PVOLUME_EXTENSION Extension,
  5082. IN ULONGLONG GptAttributes
  5083. )
  5084. {
  5085. NTSTATUS status;
  5086. if (GptAttributes&GPT_BASIC_DATA_ATTRIBUTE_READ_ONLY) {
  5087. if (!Extension->IsReadOnly) {
  5088. FtpZeroRefCallback(Extension, FtpVolumeReadOnlyCallback,
  5089. (PVOID) TRUE, TRUE);
  5090. }
  5091. } else {
  5092. if (Extension->IsReadOnly) {
  5093. FtpZeroRefCallback(Extension, FtpVolumeReadOnlyCallback,
  5094. (PVOID) FALSE, TRUE);
  5095. }
  5096. }
  5097. if (GptAttributes&GPT_BASIC_DATA_ATTRIBUTE_HIDDEN) {
  5098. if (!Extension->IsHidden) {
  5099. Extension->IsHidden = TRUE;
  5100. if (Extension->MountedDeviceInterfaceName.Buffer) {
  5101. IoSetDeviceInterfaceState(
  5102. &Extension->MountedDeviceInterfaceName, FALSE);
  5103. }
  5104. }
  5105. } else {
  5106. if (Extension->IsHidden) {
  5107. Extension->IsHidden = FALSE;
  5108. if (!Extension->MountedDeviceInterfaceName.Buffer) {
  5109. if (!Extension->IsStarted) {
  5110. return;
  5111. }
  5112. status = IoRegisterDeviceInterface(
  5113. Extension->DeviceObject,
  5114. &MOUNTDEV_MOUNTED_DEVICE_GUID, NULL,
  5115. &Extension->MountedDeviceInterfaceName);
  5116. if (!NT_SUCCESS(status)) {
  5117. return;
  5118. }
  5119. }
  5120. IoSetDeviceInterfaceState(
  5121. &Extension->MountedDeviceInterfaceName, TRUE);
  5122. }
  5123. }
  5124. }
  5125. VOID
  5126. FtpRevertGptAttributes(
  5127. IN PVOLUME_EXTENSION Extension
  5128. )
  5129. {
  5130. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  5131. ULONG signature;
  5132. PLIST_ENTRY l;
  5133. PVOLUME_EXTENSION extension;
  5134. Extension->RevertOnCloseFileObject = NULL;
  5135. if (!Extension->IsGpt) {
  5136. diskInfo = Extension->Root->DiskInfoSet->FindLogicalDiskInformation(
  5137. Extension->WholeDiskPdo);
  5138. if (diskInfo) {
  5139. diskInfo->SetGptAttributes(Extension->GptAttributesToRevertTo);
  5140. }
  5141. signature = FtpQueryDiskSignature(Extension->WholeDiskPdo);
  5142. if (signature) {
  5143. FtpDeleteGptAttributeRevertRecord(Extension->Root, signature,
  5144. NULL);
  5145. }
  5146. return;
  5147. }
  5148. l = &Extension->Root->VolumeList;
  5149. extension = Extension;
  5150. for (;;) {
  5151. FtpSetGptAttributesOnDisk(extension->TargetObject,
  5152. Extension->GptAttributesToRevertTo);
  5153. FtpDeleteGptAttributeRevertRecord(Extension->Root, 0,
  5154. &extension->UniqueIdGuid);
  5155. if (!Extension->ApplyToAllConnectedVolumes) {
  5156. break;
  5157. }
  5158. for (l = l->Flink; l != &Extension->Root->VolumeList; l = l->Flink) {
  5159. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5160. if (extension == Extension ||
  5161. extension->WholeDiskPdo != Extension->WholeDiskPdo) {
  5162. continue;
  5163. }
  5164. }
  5165. if (l == &Extension->Root->VolumeList) {
  5166. break;
  5167. }
  5168. }
  5169. }
  5170. NTSTATUS
  5171. FtpSetGptAttributes(
  5172. IN PVOLUME_EXTENSION Extension,
  5173. IN PIRP Irp
  5174. )
  5175. /*++
  5176. Routine Description:
  5177. This routine sets the given GPT attributes on the given volume. If the
  5178. 'RevertOnClose' bit is set then the GPT attributes will go back to
  5179. their original state when the handle that this IOCTL was sent using
  5180. gets an IRP_MJ_CLEANUP. In order for this driver to get the CLEANUP, the
  5181. handle must not be opened with read or write access but just
  5182. read_attributes. If the 'RevertOnClose' bit is set then the effect of
  5183. the bit changes will not be applied to this volume and every effort will
  5184. be made so that if the system crashes, the bits will be properly reverted.
  5185. If the 'RevertOnClose' bit is clear then the effect of the bit changes will
  5186. be immediate. If READ_ONLY is set, for example, the volume will instantly
  5187. become read only and all writes will fail. The caller should normally
  5188. only issue READ_ONLY request after issueing an
  5189. IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES and before issueing the corresponding
  5190. IOCTL_VOLSNAP_RELEASE_WRITES. If HIDDEN is set, then the volume will
  5191. take itself out of the list of volumes used by the MOUNTMGR. Similarly,
  5192. if the HIDDEN bit is cleared then the volume will put itself back in
  5193. the list of volumes used by the MOUNTMGR.
  5194. If the 'ApplyToAllConnectedVolumes' bit is set then the GPT attributes
  5195. will be set for all volumes that are joined by a disk relation. In
  5196. the basic disk case, this means all partitions on the disk. In the
  5197. dynamic disk case, this means all volumes in the group. This IOCTL will
  5198. fail on MBR basic disks unless this is set because MBR basic disks do
  5199. not support the GPT attributes per partition but per disk.
  5200. Arguments:
  5201. Extension - Supplies the volume extension.
  5202. Irp - Supplies the I/O request packet.
  5203. Return Value:
  5204. NTSTATUS
  5205. --*/
  5206. {
  5207. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5208. PVOLUME_SET_GPT_ATTRIBUTES_INFORMATION input = (PVOLUME_SET_GPT_ATTRIBUTES_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  5209. NTSTATUS status;
  5210. UCHAR partitionType;
  5211. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  5212. ULONGLONG gptAttributes;
  5213. ULONG signature;
  5214. PLIST_ENTRY l;
  5215. PVOLUME_EXTENSION extension;
  5216. GUID partitionTypeGuid;
  5217. status = FtpCheckSecurity(Extension, Irp);
  5218. if (!NT_SUCCESS(status)) {
  5219. return status;
  5220. }
  5221. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5222. sizeof(VOLUME_SET_GPT_ATTRIBUTES_INFORMATION)) {
  5223. return STATUS_INVALID_PARAMETER;
  5224. }
  5225. if (input->Reserved1 || input->Reserved2 || !Extension->TargetObject) {
  5226. return STATUS_INVALID_PARAMETER;
  5227. }
  5228. if (!Extension->IsGpt) {
  5229. if (!input->ApplyToAllConnectedVolumes) {
  5230. return STATUS_INVALID_PARAMETER;
  5231. }
  5232. status = FtpQueryPartitionInformation(Extension->Root,
  5233. Extension->TargetObject,
  5234. NULL, NULL, NULL, &partitionType,
  5235. NULL, NULL, NULL, NULL, NULL);
  5236. if (!NT_SUCCESS(status)) {
  5237. return status;
  5238. }
  5239. if (!IsRecognizedPartition(partitionType)) {
  5240. return STATUS_INVALID_PARAMETER;
  5241. }
  5242. diskInfo = Extension->Root->DiskInfoSet->
  5243. FindLogicalDiskInformation(Extension->WholeDiskPdo);
  5244. if (!diskInfo) {
  5245. return STATUS_INVALID_PARAMETER;
  5246. }
  5247. if (input->RevertOnClose) {
  5248. gptAttributes = diskInfo->GetGptAttributes();
  5249. Extension->GptAttributesToRevertTo = gptAttributes;
  5250. Extension->RevertOnCloseFileObject = irpSp->FileObject;
  5251. Extension->ApplyToAllConnectedVolumes =
  5252. input->ApplyToAllConnectedVolumes;
  5253. signature = FtpQueryDiskSignature(Extension->WholeDiskPdo);
  5254. if (!signature) {
  5255. Extension->RevertOnCloseFileObject = NULL;
  5256. return STATUS_INSUFFICIENT_RESOURCES;
  5257. }
  5258. status = FtpStoreGptAttributeRevertRecord(Extension->Root,
  5259. signature, NULL,
  5260. gptAttributes);
  5261. if (!NT_SUCCESS(status)) {
  5262. Extension->RevertOnCloseFileObject = NULL;
  5263. return status;
  5264. }
  5265. }
  5266. status = diskInfo->SetGptAttributes(input->GptAttributes);
  5267. if (!NT_SUCCESS(status)) {
  5268. if (input->RevertOnClose) {
  5269. Extension->RevertOnCloseFileObject = NULL;
  5270. FtpDeleteGptAttributeRevertRecord(Extension->Root, signature,
  5271. NULL);
  5272. }
  5273. return status;
  5274. }
  5275. if (!input->RevertOnClose) {
  5276. FtpApplyGptAttributes(Extension, input->GptAttributes);
  5277. Extension->MbrGptAttributes = input->GptAttributes;
  5278. for (l = Extension->Root->VolumeList.Flink;
  5279. l != &Extension->Root->VolumeList; l = l->Flink) {
  5280. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5281. if (extension == Extension ||
  5282. extension->WholeDiskPdo != Extension->WholeDiskPdo) {
  5283. continue;
  5284. }
  5285. status = FtpQueryPartitionInformation(extension->Root,
  5286. extension->TargetObject,
  5287. NULL, NULL, NULL,
  5288. &partitionType, NULL,
  5289. NULL, NULL, NULL, NULL);
  5290. if (!NT_SUCCESS(status) ||
  5291. !IsRecognizedPartition(partitionType)) {
  5292. continue;
  5293. }
  5294. FtpApplyGptAttributes(extension, input->GptAttributes);
  5295. extension->MbrGptAttributes = input->GptAttributes;
  5296. }
  5297. }
  5298. return STATUS_SUCCESS;
  5299. }
  5300. l = &Extension->Root->VolumeList;
  5301. extension = Extension;
  5302. for (;;) {
  5303. status = FtpQueryPartitionInformation(Extension->Root,
  5304. extension->TargetObject,
  5305. NULL, NULL, NULL, NULL, NULL,
  5306. &partitionTypeGuid, NULL,
  5307. NULL, &gptAttributes);
  5308. if (!NT_SUCCESS(status)) {
  5309. return status;
  5310. }
  5311. if (!IsEqualGUID(partitionTypeGuid, PARTITION_BASIC_DATA_GUID)) {
  5312. if (extension == Extension) {
  5313. return STATUS_INVALID_PARAMETER;
  5314. }
  5315. goto NextVolume;
  5316. }
  5317. if (input->RevertOnClose) {
  5318. if (extension == Extension) {
  5319. Extension->RevertOnCloseFileObject = irpSp->FileObject;
  5320. Extension->GptAttributesToRevertTo = gptAttributes;
  5321. Extension->ApplyToAllConnectedVolumes =
  5322. input->ApplyToAllConnectedVolumes;
  5323. }
  5324. status = FtpStoreGptAttributeRevertRecord(
  5325. Extension->Root, 0, &extension->UniqueIdGuid,
  5326. gptAttributes);
  5327. if (!NT_SUCCESS(status)) {
  5328. if (input->RevertOnClose) {
  5329. FtpRevertGptAttributes(Extension);
  5330. }
  5331. return status;
  5332. }
  5333. }
  5334. status = FtpSetGptAttributesOnDisk(extension->TargetObject,
  5335. input->GptAttributes);
  5336. if (!NT_SUCCESS(status)) {
  5337. if (input->RevertOnClose) {
  5338. FtpRevertGptAttributes(Extension);
  5339. }
  5340. return status;
  5341. }
  5342. if (!input->RevertOnClose) {
  5343. FtpApplyGptAttributes(extension, input->GptAttributes);
  5344. }
  5345. NextVolume:
  5346. if (!input->ApplyToAllConnectedVolumes) {
  5347. break;
  5348. }
  5349. for (l = l->Flink; l != &Extension->Root->VolumeList; l = l->Flink) {
  5350. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5351. if (extension == Extension ||
  5352. extension->WholeDiskPdo != Extension->WholeDiskPdo) {
  5353. continue;
  5354. }
  5355. }
  5356. if (l == &Extension->Root->VolumeList) {
  5357. break;
  5358. }
  5359. }
  5360. return STATUS_SUCCESS;
  5361. }
  5362. NTSTATUS
  5363. FtpGetGptAttributes(
  5364. IN PVOLUME_EXTENSION Extension,
  5365. IN PIRP Irp
  5366. )
  5367. /*++
  5368. Routine Description:
  5369. This routine returns the current GPT attributes definitions for the volume.
  5370. Arguments:
  5371. Extension - Supplies the volume extension.
  5372. Irp - Supplies the I/O request packet.
  5373. Return Value:
  5374. NTSTATUS
  5375. --*/
  5376. {
  5377. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5378. PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION output = (PVOLUME_GET_GPT_ATTRIBUTES_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  5379. NTSTATUS status;
  5380. UCHAR partitionType;
  5381. GUID gptPartitionType;
  5382. ULONGLONG gptAttributes;
  5383. PFT_LOGICAL_DISK_INFORMATION diskInfo;
  5384. Irp->IoStatus.Information = sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION);
  5385. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5386. Irp->IoStatus.Information) {
  5387. Irp->IoStatus.Information = 0;
  5388. return STATUS_INVALID_PARAMETER;
  5389. }
  5390. if (!Extension->TargetObject) {
  5391. Irp->IoStatus.Information = 0;
  5392. return STATUS_INVALID_PARAMETER;
  5393. }
  5394. status = FtpQueryPartitionInformation(Extension->Root,
  5395. Extension->TargetObject, NULL, NULL,
  5396. NULL, &partitionType, NULL,
  5397. &gptPartitionType, NULL, NULL,
  5398. &gptAttributes);
  5399. if (!NT_SUCCESS(status)) {
  5400. Irp->IoStatus.Information = 0;
  5401. return status;
  5402. }
  5403. if (Extension->IsGpt) {
  5404. if (!IsEqualGUID(gptPartitionType, PARTITION_BASIC_DATA_GUID)) {
  5405. Irp->IoStatus.Information = 0;
  5406. return STATUS_INVALID_PARAMETER;
  5407. }
  5408. output->GptAttributes = gptAttributes;
  5409. return STATUS_SUCCESS;
  5410. }
  5411. if (!IsRecognizedPartition(partitionType)) {
  5412. Irp->IoStatus.Information = 0;
  5413. return STATUS_INVALID_PARAMETER;
  5414. }
  5415. diskInfo = Extension->Root->DiskInfoSet->
  5416. FindLogicalDiskInformation(Extension->WholeDiskPdo);
  5417. if (!diskInfo) {
  5418. Irp->IoStatus.Information = 0;
  5419. return STATUS_INVALID_PARAMETER;
  5420. }
  5421. gptAttributes = diskInfo->GetGptAttributes();
  5422. output->GptAttributes = gptAttributes;
  5423. return STATUS_SUCCESS;
  5424. }
  5425. NTSTATUS
  5426. FtpQueryHiddenVolumes(
  5427. IN PROOT_EXTENSION RootExtension,
  5428. IN PIRP Irp
  5429. )
  5430. /*++
  5431. Routine Description:
  5432. This routine returns a list of hidden volumes. Hidden volumes are those
  5433. that do not give PNP VolumeClassGuid notification.
  5434. Arguments:
  5435. RootExtension - Supplies the root extension.
  5436. Irp - Supplies the IO request packet.
  5437. Return Value:
  5438. NTSTATUS
  5439. -*/
  5440. {
  5441. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5442. PVOLMGR_HIDDEN_VOLUMES output;
  5443. PLIST_ENTRY l;
  5444. PVOLUME_EXTENSION extension;
  5445. WCHAR buffer[100];
  5446. UNICODE_STRING name;
  5447. PWCHAR buf;
  5448. Irp->IoStatus.Information = FIELD_OFFSET(VOLMGR_HIDDEN_VOLUMES, MultiSz);
  5449. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5450. Irp->IoStatus.Information) {
  5451. Irp->IoStatus.Information = 0;
  5452. return STATUS_INVALID_PARAMETER;
  5453. }
  5454. output = (PVOLMGR_HIDDEN_VOLUMES) Irp->AssociatedIrp.SystemBuffer;
  5455. output->MultiSzLength = sizeof(WCHAR);
  5456. for (l = RootExtension->VolumeList.Flink; l != &RootExtension->VolumeList;
  5457. l = l->Flink) {
  5458. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5459. if (!extension->IsHidden || !extension->IsInstalled) {
  5460. continue;
  5461. }
  5462. swprintf(buffer, L"\\Device\\HarddiskVolume%d",
  5463. extension->VolumeNumber);
  5464. RtlInitUnicodeString(&name, buffer);
  5465. output->MultiSzLength += name.Length + sizeof(WCHAR);
  5466. }
  5467. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5468. Irp->IoStatus.Information + output->MultiSzLength) {
  5469. return STATUS_BUFFER_OVERFLOW;
  5470. }
  5471. Irp->IoStatus.Information += output->MultiSzLength;
  5472. buf = output->MultiSz;
  5473. for (l = RootExtension->VolumeList.Flink; l != &RootExtension->VolumeList;
  5474. l = l->Flink) {
  5475. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  5476. if (!extension->IsHidden || !extension->IsInstalled) {
  5477. continue;
  5478. }
  5479. swprintf(buf, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  5480. RtlInitUnicodeString(&name, buf);
  5481. buf += name.Length/sizeof(WCHAR) + 1;
  5482. }
  5483. *buf = 0;
  5484. return STATUS_SUCCESS;
  5485. }
  5486. NTSTATUS
  5487. FtDiskDeviceControl(
  5488. IN PDEVICE_OBJECT DeviceObject,
  5489. IN PIRP Irp
  5490. )
  5491. /*++
  5492. Routine Description:
  5493. This routine is the dispatch for IRP_MJ_DEVICE_CONTROL.
  5494. Arguments:
  5495. DeviceObject - Supplies the device object.
  5496. Irp - Supplies the IO request packet.
  5497. Return Value:
  5498. NTSTATUS
  5499. --*/
  5500. {
  5501. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  5502. PROOT_EXTENSION rootExtension = extension->Root;
  5503. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  5504. NTSTATUS status;
  5505. PFT_VOLUME vol;
  5506. PDISPATCH_TP packet;
  5507. PVERIFY_INFORMATION verifyInfo;
  5508. PSET_PARTITION_INFORMATION setPartitionInfo;
  5509. PSET_PARTITION_INFORMATION_EX setPartitionInfoEx;
  5510. PDEVICE_OBJECT targetObject;
  5511. KEVENT event;
  5512. PPARTITION_INFORMATION partInfo;
  5513. PPARTITION_INFORMATION_EX partInfoEx;
  5514. PDISK_GEOMETRY diskGeometry;
  5515. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  5516. PFT_SET_INFORMATION setInfo;
  5517. FT_LOGICAL_DISK_ID diskId;
  5518. PFT_MIRROR_AND_SWP_STATE_INFORMATION stateInfo;
  5519. PFT_SPECIAL_READ specialRead;
  5520. PFT_QUERY_LOGICAL_DISK_ID_OUTPUT queryLogicalDiskIdOutput;
  5521. PGET_LENGTH_INFORMATION lengthInfo;
  5522. ULONG cylinderSize;
  5523. Irp->IoStatus.Information = 0;
  5524. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  5525. FtpAcquire(rootExtension);
  5526. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  5527. case FT_CONFIGURE:
  5528. status = STATUS_INVALID_PARAMETER;
  5529. break;
  5530. case FT_CREATE_LOGICAL_DISK:
  5531. status = FtpCreateLogicalDisk(rootExtension, Irp);
  5532. break;
  5533. case FT_BREAK_LOGICAL_DISK:
  5534. status = FtpBreakLogicalDisk(rootExtension, Irp);
  5535. break;
  5536. case FT_ENUMERATE_LOGICAL_DISKS:
  5537. status = FtpEnumerateLogicalDisks(rootExtension, Irp);
  5538. break;
  5539. case FT_QUERY_LOGICAL_DISK_INFORMATION:
  5540. status = FtpQueryLogicalDiskInformation(rootExtension, Irp);
  5541. break;
  5542. case FT_ORPHAN_LOGICAL_DISK_MEMBER:
  5543. status = FtpOrphanLogicalDiskMember(rootExtension, Irp);
  5544. break;
  5545. case FT_REPLACE_LOGICAL_DISK_MEMBER:
  5546. status = FtpReplaceLogicalDiskMember(rootExtension, Irp);
  5547. break;
  5548. case FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK:
  5549. status = FtpQueryNtDeviceNameForLogicalDisk(rootExtension, Irp);
  5550. break;
  5551. case FT_INITIALIZE_LOGICAL_DISK:
  5552. status = FtpInitializeLogicalDisk(rootExtension, Irp);
  5553. break;
  5554. case FT_QUERY_DRIVE_LETTER_FOR_LOGICAL_DISK:
  5555. status = FtpQueryDriveLetterForLogicalDisk(rootExtension, Irp);
  5556. break;
  5557. case FT_CHECK_IO:
  5558. status = FtpCheckIo(rootExtension, Irp);
  5559. break;
  5560. case FT_SET_DRIVE_LETTER_FOR_LOGICAL_DISK:
  5561. status = FtpSetDriveLetterForLogicalDisk(rootExtension, Irp);
  5562. break;
  5563. case FT_QUERY_NT_DEVICE_NAME_FOR_PARTITION:
  5564. status = FtpQueryNtDeviceNameForPartition(rootExtension, Irp);
  5565. break;
  5566. case FT_CHANGE_NOTIFY:
  5567. status = FtpChangeNotify(rootExtension, Irp);
  5568. break;
  5569. case FT_STOP_SYNC_OPERATIONS:
  5570. status = FtpStopSyncOperations(rootExtension, Irp);
  5571. break;
  5572. case IOCTL_VOLMGR_QUERY_HIDDEN_VOLUMES:
  5573. status = FtpQueryHiddenVolumes(rootExtension, Irp);
  5574. break;
  5575. default:
  5576. status = STATUS_INVALID_PARAMETER;
  5577. break;
  5578. }
  5579. FtpRelease(rootExtension);
  5580. if (status != STATUS_PENDING) {
  5581. Irp->IoStatus.Status = status;
  5582. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5583. }
  5584. return status;
  5585. }
  5586. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  5587. case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
  5588. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5589. if (status == STATUS_PENDING) {
  5590. return status;
  5591. }
  5592. if (NT_SUCCESS(status)) {
  5593. status = FtpQueryUniqueId(extension, Irp);
  5594. FtpDecrementRefCount(extension);
  5595. }
  5596. Irp->IoStatus.Status = status;
  5597. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5598. return status;
  5599. case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
  5600. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5601. if (status == STATUS_PENDING) {
  5602. return status;
  5603. }
  5604. if (NT_SUCCESS(status)) {
  5605. status = FtpQueryStableGuid(extension, Irp);
  5606. FtpDecrementRefCount(extension);
  5607. }
  5608. Irp->IoStatus.Status = status;
  5609. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5610. return status;
  5611. case IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY:
  5612. FtpAcquire(extension->Root);
  5613. status = FtpUniqueIdChangeNotify(extension, Irp);
  5614. FtpRelease(extension->Root);
  5615. if (status != STATUS_PENDING) {
  5616. Irp->IoStatus.Status = status;
  5617. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5618. }
  5619. return status;
  5620. case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
  5621. status = FtpAllSystemsGo(extension, Irp, FALSE, FALSE, FALSE);
  5622. if (status == STATUS_PENDING) {
  5623. return status;
  5624. }
  5625. if (NT_SUCCESS(status)) {
  5626. status = FtpQueryDeviceName(extension, Irp);
  5627. FtpDecrementRefCount(extension);
  5628. }
  5629. Irp->IoStatus.Status = status;
  5630. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5631. return status;
  5632. case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
  5633. FtpAcquire(extension->Root);
  5634. status = FtpQuerySuggestedLinkName(extension, Irp);
  5635. FtpRelease(extension->Root);
  5636. Irp->IoStatus.Status = status;
  5637. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5638. return status;
  5639. case IOCTL_MOUNTDEV_LINK_CREATED:
  5640. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, TRUE);
  5641. if (status == STATUS_PENDING) {
  5642. return status;
  5643. }
  5644. if (NT_SUCCESS(status)) {
  5645. status = FtpLinkCreated(extension, Irp);
  5646. FtpDecrementRefCount(extension);
  5647. }
  5648. Irp->IoStatus.Status = status;
  5649. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5650. return status;
  5651. case IOCTL_MOUNTDEV_LINK_DELETED:
  5652. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, TRUE);
  5653. if (status == STATUS_PENDING) {
  5654. return status;
  5655. }
  5656. if (NT_SUCCESS(status)) {
  5657. status = FtpLinkDeleted(extension, Irp);
  5658. FtpDecrementRefCount(extension);
  5659. }
  5660. Irp->IoStatus.Status = status;
  5661. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5662. return status;
  5663. case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
  5664. case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS_ADMIN:
  5665. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5666. if (status == STATUS_PENDING) {
  5667. return status;
  5668. }
  5669. if (NT_SUCCESS(status)) {
  5670. status = FtpGetVolumeDiskExtents(extension, Irp);
  5671. FtpDecrementRefCount(extension);
  5672. }
  5673. Irp->IoStatus.Status = status;
  5674. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5675. return status;
  5676. case IOCTL_VOLUME_SUPPORTS_ONLINE_OFFLINE:
  5677. Irp->IoStatus.Status = STATUS_SUCCESS;
  5678. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5679. return STATUS_SUCCESS;
  5680. case IOCTL_VOLUME_ONLINE:
  5681. FtpAcquire(extension->Root);
  5682. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5683. if (status == STATUS_PENDING) {
  5684. FtpRelease(extension->Root);
  5685. return status;
  5686. }
  5687. if (!NT_SUCCESS(status)) {
  5688. FtpRelease(extension->Root);
  5689. Irp->IoStatus.Status = status;
  5690. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5691. return status;
  5692. }
  5693. if (extension->FtVolume) {
  5694. FtpPropogateRegistryState(extension, extension->FtVolume);
  5695. }
  5696. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5697. FtpZeroRefCallback(extension, FtpVolumeOnlineCallback, &event,
  5698. TRUE);
  5699. FtpDecrementRefCount(extension);
  5700. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  5701. FtpRelease(extension->Root);
  5702. Irp->IoStatus.Status = STATUS_SUCCESS;
  5703. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5704. return STATUS_SUCCESS;
  5705. case IOCTL_VOLUME_OFFLINE:
  5706. FtpAcquire(extension->Root);
  5707. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5708. FtpZeroRefCallback(extension, FtpVolumeOfflineCallback, &event,
  5709. TRUE);
  5710. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  5711. FtpRelease(extension->Root);
  5712. Irp->IoStatus.Status = STATUS_SUCCESS;
  5713. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5714. return STATUS_SUCCESS;
  5715. case IOCTL_VOLUME_IS_OFFLINE:
  5716. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5717. if (status == STATUS_PENDING) {
  5718. return status;
  5719. }
  5720. if (NT_SUCCESS(status)) {
  5721. if (!extension->IsOffline) {
  5722. status = STATUS_UNSUCCESSFUL;
  5723. }
  5724. FtpDecrementRefCount(extension);
  5725. }
  5726. Irp->IoStatus.Status = status;
  5727. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5728. return status;
  5729. case IOCTL_VOLUME_IS_IO_CAPABLE:
  5730. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5731. if (status == STATUS_PENDING) {
  5732. return status;
  5733. }
  5734. if (NT_SUCCESS(status)) {
  5735. if (!extension->TargetObject &&
  5736. !extension->FtVolume->IsComplete(TRUE)) {
  5737. status = STATUS_UNSUCCESSFUL;
  5738. }
  5739. FtpDecrementRefCount(extension);
  5740. }
  5741. Irp->IoStatus.Status = status;
  5742. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5743. return status;
  5744. case IOCTL_VOLUME_QUERY_FAILOVER_SET:
  5745. FtpAcquire(extension->Root);
  5746. status = FtpQueryFailoverSet(extension, Irp);
  5747. FtpRelease(extension->Root);
  5748. Irp->IoStatus.Status = status;
  5749. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5750. return status;
  5751. case IOCTL_VOLUME_QUERY_VOLUME_NUMBER:
  5752. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5753. if (status == STATUS_PENDING) {
  5754. return status;
  5755. }
  5756. if (NT_SUCCESS(status)) {
  5757. status = FtpQueryVolumeNumber(extension, Irp);
  5758. FtpDecrementRefCount(extension);
  5759. }
  5760. Irp->IoStatus.Status = status;
  5761. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5762. return status;
  5763. case IOCTL_VOLUME_LOGICAL_TO_PHYSICAL:
  5764. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5765. if (status == STATUS_PENDING) {
  5766. return status;
  5767. }
  5768. if (NT_SUCCESS(status)) {
  5769. status = FtpLogicalToPhysical(extension, Irp);
  5770. FtpDecrementRefCount(extension);
  5771. }
  5772. Irp->IoStatus.Status = status;
  5773. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5774. return status;
  5775. case IOCTL_VOLUME_PHYSICAL_TO_LOGICAL:
  5776. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5777. if (status == STATUS_PENDING) {
  5778. return status;
  5779. }
  5780. if (NT_SUCCESS(status)) {
  5781. status = FtpPhysicalToLogical(extension, Irp);
  5782. FtpDecrementRefCount(extension);
  5783. }
  5784. Irp->IoStatus.Status = status;
  5785. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5786. return status;
  5787. case IOCTL_VOLUME_IS_PARTITION:
  5788. status = FtpAllSystemsGo(extension, Irp, TRUE, TRUE, TRUE);
  5789. if (status == STATUS_PENDING) {
  5790. return status;
  5791. }
  5792. if (NT_SUCCESS(status)) {
  5793. status = FtpIsPartition(extension, Irp);
  5794. FtpDecrementRefCount(extension);
  5795. }
  5796. Irp->IoStatus.Status = status;
  5797. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5798. return status;
  5799. case IOCTL_VOLUME_SET_GPT_ATTRIBUTES:
  5800. FtpAcquire(extension->Root);
  5801. status = FtpSetGptAttributes(extension, Irp);
  5802. FtpRelease(extension->Root);
  5803. Irp->IoStatus.Status = status;
  5804. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5805. return status;
  5806. case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
  5807. FtpAcquire(extension->Root);
  5808. status = FtpGetGptAttributes(extension, Irp);
  5809. FtpRelease(extension->Root);
  5810. Irp->IoStatus.Status = status;
  5811. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5812. return status;
  5813. case IOCTL_PARTMGR_EJECT_VOLUME_MANAGERS:
  5814. status = STATUS_INVALID_DEVICE_REQUEST;
  5815. Irp->IoStatus.Status = status;
  5816. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5817. return status;
  5818. case IOCTL_DISK_GET_PARTITION_INFO:
  5819. case IOCTL_DISK_GET_PARTITION_INFO_EX:
  5820. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, FALSE);
  5821. break;
  5822. case IOCTL_DISK_IS_WRITABLE:
  5823. if (extension->IsReadOnly) {
  5824. status = STATUS_MEDIA_WRITE_PROTECTED;
  5825. } else {
  5826. status = FtpAllSystemsGo(extension, Irp, TRUE, TRUE, TRUE);
  5827. }
  5828. break;
  5829. case IOCTL_DISK_PERFORMANCE:
  5830. //
  5831. // Verify user buffer is large enough for the performance data.
  5832. //
  5833. status = STATUS_SUCCESS;
  5834. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  5835. sizeof(DISK_PERFORMANCE)) {
  5836. //
  5837. // Indicate unsuccessful status and no data transferred.
  5838. //
  5839. status = STATUS_BUFFER_TOO_SMALL;
  5840. Irp->IoStatus.Information = 0;
  5841. }
  5842. else if (!(extension->CountersEnabled)) {
  5843. if (!FtQueryEnableAlways(DeviceObject)) {
  5844. status = STATUS_UNSUCCESSFUL;
  5845. Irp->IoStatus.Information = 0;
  5846. }
  5847. }
  5848. if (status == STATUS_SUCCESS) {
  5849. extension->Root->PmWmiCounterLibContext.
  5850. PmWmiCounterQuery(extension->PmWmiCounterContext,
  5851. (PDISK_PERFORMANCE) Irp->AssociatedIrp.SystemBuffer,
  5852. L"FTDISK ",
  5853. extension->VolumeNumber);
  5854. Irp->IoStatus.Information = sizeof(DISK_PERFORMANCE);
  5855. }
  5856. Irp->IoStatus.Status = status;
  5857. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5858. return status;
  5859. case IOCTL_DISK_PERFORMANCE_OFF:
  5860. //
  5861. // Turns off counting
  5862. //
  5863. if (extension->CountersEnabled) {
  5864. if (InterlockedCompareExchange(&extension->EnableAlways, 0, 1) == 1) {
  5865. if (!(extension->Root->PmWmiCounterLibContext.
  5866. PmWmiCounterDisable(&extension->PmWmiCounterContext, FALSE, FALSE))) {
  5867. extension->CountersEnabled = FALSE;
  5868. }
  5869. }
  5870. }
  5871. Irp->IoStatus.Information = 0;
  5872. status = STATUS_SUCCESS;
  5873. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5874. return status;
  5875. default:
  5876. status = FtpAllSystemsGo(extension, Irp, TRUE, TRUE, TRUE);
  5877. break;
  5878. }
  5879. if (status == STATUS_PENDING) {
  5880. return status;
  5881. }
  5882. if (!NT_SUCCESS(status)) {
  5883. Irp->IoStatus.Status = status;
  5884. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5885. return status;
  5886. }
  5887. if (extension->TargetObject) {
  5888. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  5889. FT_CREATE_PARTITION_LOGICAL_DISK) {
  5890. FtpDecrementRefCount(extension);
  5891. Irp->IoStatus.Information = 0;
  5892. FtpAcquire(extension->Root);
  5893. if (!extension->Root->FtCodeLocked) {
  5894. MmLockPagableCodeSection(FtpComputeParity);
  5895. status = FtpStartSystemThread(extension->Root);
  5896. if (!NT_SUCCESS(status)) {
  5897. FtpRelease(extension->Root);
  5898. Irp->IoStatus.Status = status;
  5899. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5900. return status;
  5901. }
  5902. extension->Root->FtCodeLocked = TRUE;
  5903. }
  5904. status = FtpCreatePartitionLogicalDisk(extension, Irp);
  5905. FtpRelease(extension->Root);
  5906. Irp->IoStatus.Status = status;
  5907. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  5908. return status;
  5909. }
  5910. IoCopyCurrentIrpStackLocationToNext(Irp);
  5911. IoSetCompletionRoutine(Irp, FtpRefCountCompletionRoutine,
  5912. extension, TRUE, TRUE, TRUE);
  5913. IoMarkIrpPending(Irp);
  5914. IoCallDriver(extension->TargetObject, Irp);
  5915. return STATUS_PENDING;
  5916. }
  5917. vol = extension->FtVolume;
  5918. ASSERT(vol);
  5919. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  5920. case IOCTL_DISK_GET_DRIVE_LAYOUT:
  5921. case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
  5922. case IOCTL_SCSI_GET_ADDRESS:
  5923. case IOCTL_SCSI_GET_DUMP_POINTERS:
  5924. case IOCTL_SCSI_FREE_DUMP_POINTERS:
  5925. if (FtpIsReplicatedPartition(vol)) {
  5926. targetObject = vol->GetLeftmostPartitionObject();
  5927. ASSERT(targetObject);
  5928. KeInitializeEvent(&event, NotificationEvent, FALSE);
  5929. IoCopyCurrentIrpStackLocationToNext(Irp);
  5930. IoSetCompletionRoutine(Irp, FtpSignalCompletion, &event, TRUE,
  5931. TRUE, TRUE);
  5932. IoCallDriver(targetObject, Irp);
  5933. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  5934. NULL);
  5935. status = Irp->IoStatus.Status;
  5936. } else {
  5937. status = STATUS_INVALID_DEVICE_REQUEST;
  5938. }
  5939. break;
  5940. case IOCTL_DISK_VERIFY:
  5941. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5942. sizeof(VERIFY_INFORMATION)) {
  5943. status = STATUS_INVALID_PARAMETER;
  5944. break;
  5945. }
  5946. packet = new DISPATCH_TP;
  5947. if (!packet) {
  5948. status = STATUS_INSUFFICIENT_RESOURCES;
  5949. break;
  5950. }
  5951. verifyInfo = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  5952. if (verifyInfo->StartingOffset.QuadPart < 0) {
  5953. delete packet;
  5954. status = STATUS_INVALID_PARAMETER;
  5955. break;
  5956. }
  5957. packet->Mdl = NULL;
  5958. packet->Offset = verifyInfo->StartingOffset.QuadPart;
  5959. packet->Length = verifyInfo->Length;
  5960. packet->CompletionRoutine = FtpReadWriteCompletionRoutine;
  5961. packet->TargetVolume = vol;
  5962. packet->Thread = Irp->Tail.Overlay.Thread;
  5963. packet->IrpFlags = irpSp->Flags;
  5964. packet->ReadPacket = TRUE;
  5965. packet->Irp = Irp;
  5966. packet->Extension = extension;
  5967. IoMarkIrpPending(Irp);
  5968. TRANSFER(packet);
  5969. return STATUS_PENDING;
  5970. case IOCTL_DISK_SET_PARTITION_INFO:
  5971. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5972. sizeof(SET_PARTITION_INFORMATION)) {
  5973. status = STATUS_INVALID_PARAMETER;
  5974. break;
  5975. }
  5976. setPartitionInfo = (PSET_PARTITION_INFORMATION)
  5977. Irp->AssociatedIrp.SystemBuffer;
  5978. status = vol->SetPartitionType(setPartitionInfo->PartitionType);
  5979. break;
  5980. case IOCTL_DISK_SET_PARTITION_INFO_EX:
  5981. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  5982. sizeof(SET_PARTITION_INFORMATION_EX)) {
  5983. status = STATUS_INVALID_PARAMETER;
  5984. break;
  5985. }
  5986. setPartitionInfoEx = (PSET_PARTITION_INFORMATION_EX)
  5987. Irp->AssociatedIrp.SystemBuffer;
  5988. if (setPartitionInfoEx->PartitionStyle != PARTITION_STYLE_MBR) {
  5989. status = STATUS_INVALID_PARAMETER;
  5990. break;
  5991. }
  5992. status = vol->SetPartitionType(
  5993. setPartitionInfoEx->Mbr.PartitionType);
  5994. break;
  5995. case IOCTL_DISK_GET_PARTITION_INFO_EX:
  5996. if (extension->IsGpt) {
  5997. status = STATUS_INVALID_PARAMETER;
  5998. break;
  5999. }
  6000. //
  6001. // Fall through.
  6002. //
  6003. case IOCTL_DISK_GET_PARTITION_INFO:
  6004. targetObject = vol->GetLeftmostPartitionObject();
  6005. if (!targetObject) {
  6006. status = STATUS_NO_SUCH_DEVICE;
  6007. break;
  6008. }
  6009. KeInitializeEvent(&event, NotificationEvent, FALSE);
  6010. IoCopyCurrentIrpStackLocationToNext(Irp);
  6011. IoSetCompletionRoutine(Irp, FtpSignalCompletion, &event, TRUE,
  6012. TRUE, TRUE);
  6013. IoCallDriver(targetObject, Irp);
  6014. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  6015. status = Irp->IoStatus.Status;
  6016. if (!NT_SUCCESS(status)) {
  6017. break;
  6018. }
  6019. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  6020. IOCTL_DISK_GET_PARTITION_INFO) {
  6021. partInfo = (PPARTITION_INFORMATION)
  6022. Irp->AssociatedIrp.SystemBuffer;
  6023. partInfo->PartitionLength.QuadPart = vol->QueryVolumeSize();
  6024. break;
  6025. }
  6026. partInfoEx = (PPARTITION_INFORMATION_EX)
  6027. Irp->AssociatedIrp.SystemBuffer;
  6028. if (partInfoEx->PartitionStyle != PARTITION_STYLE_MBR) {
  6029. ASSERT(FALSE);
  6030. status = STATUS_INVALID_PARAMETER;
  6031. break;
  6032. }
  6033. partInfoEx->PartitionLength.QuadPart = vol->QueryVolumeSize();
  6034. break;
  6035. case IOCTL_DISK_GET_LENGTH_INFO:
  6036. Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
  6037. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  6038. Irp->IoStatus.Information) {
  6039. Irp->IoStatus.Information = 0;
  6040. status = STATUS_INVALID_PARAMETER;
  6041. break;
  6042. }
  6043. lengthInfo = (PGET_LENGTH_INFORMATION)
  6044. Irp->AssociatedIrp.SystemBuffer;
  6045. lengthInfo->Length.QuadPart = vol->QueryVolumeSize();
  6046. status = STATUS_SUCCESS;
  6047. break;
  6048. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  6049. targetObject = vol->GetLeftmostPartitionObject();
  6050. if (!targetObject) {
  6051. status = STATUS_NO_SUCH_DEVICE;
  6052. break;
  6053. }
  6054. KeInitializeEvent(&event, NotificationEvent, FALSE);
  6055. IoCopyCurrentIrpStackLocationToNext(Irp);
  6056. IoSetCompletionRoutine(Irp, FtpSignalCompletion, &event, TRUE,
  6057. TRUE, TRUE);
  6058. IoCallDriver(targetObject, Irp);
  6059. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  6060. status = Irp->IoStatus.Status;
  6061. if (!NT_SUCCESS(status)) {
  6062. break;
  6063. }
  6064. diskGeometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
  6065. diskGeometry->BytesPerSector = vol->QuerySectorSize();
  6066. cylinderSize = diskGeometry->TracksPerCylinder*
  6067. diskGeometry->SectorsPerTrack*
  6068. diskGeometry->BytesPerSector;
  6069. if (cylinderSize) {
  6070. diskGeometry->Cylinders.QuadPart =
  6071. vol->QueryVolumeSize()/cylinderSize;
  6072. }
  6073. break;
  6074. case IOCTL_DISK_CHECK_VERIFY:
  6075. status = STATUS_SUCCESS;
  6076. break;
  6077. case FT_QUERY_SET_STATE:
  6078. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  6079. sizeof(FT_SET_INFORMATION)) {
  6080. status = STATUS_INVALID_PARAMETER;
  6081. break;
  6082. }
  6083. FtpAcquire(rootExtension);
  6084. diskInfoSet = rootExtension->DiskInfoSet;
  6085. setInfo = (PFT_SET_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  6086. diskId = vol->QueryLogicalDiskId();
  6087. setInfo->NumberOfMembers =
  6088. diskInfoSet->QueryNumberOfMembersInLogicalDisk(diskId);
  6089. switch (diskInfoSet->QueryLogicalDiskType(diskId)) {
  6090. case FtVolumeSet:
  6091. setInfo->Type = VolumeSet;
  6092. break;
  6093. case FtStripeSet:
  6094. setInfo->Type = Stripe;
  6095. break;
  6096. case FtMirrorSet:
  6097. setInfo->Type = Mirror;
  6098. break;
  6099. case FtStripeSetWithParity:
  6100. setInfo->Type = StripeWithParity;
  6101. break;
  6102. default:
  6103. setInfo->Type = NotAnFtMember;
  6104. break;
  6105. }
  6106. stateInfo = (PFT_MIRROR_AND_SWP_STATE_INFORMATION)
  6107. diskInfoSet->GetStateInformation(diskId);
  6108. if (stateInfo) {
  6109. if (stateInfo->IsInitializing) {
  6110. setInfo->SetState = FtInitializing;
  6111. } else {
  6112. switch (stateInfo->UnhealthyMemberState) {
  6113. case FtMemberHealthy:
  6114. setInfo->SetState = FtStateOk;
  6115. break;
  6116. case FtMemberRegenerating:
  6117. setInfo->SetState = FtRegenerating;
  6118. break;
  6119. case FtMemberOrphaned:
  6120. setInfo->SetState = FtHasOrphan;
  6121. break;
  6122. }
  6123. }
  6124. } else {
  6125. setInfo->SetState = FtStateOk;
  6126. }
  6127. FtpRelease(rootExtension);
  6128. Irp->IoStatus.Information = sizeof(FT_SET_INFORMATION);
  6129. status = STATUS_SUCCESS;
  6130. break;
  6131. case FT_SECONDARY_READ:
  6132. case FT_PRIMARY_READ:
  6133. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  6134. sizeof(FT_SPECIAL_READ)) {
  6135. status = STATUS_INVALID_PARAMETER;
  6136. break;
  6137. }
  6138. specialRead = (PFT_SPECIAL_READ) Irp->AssociatedIrp.SystemBuffer;
  6139. if (specialRead->ByteOffset.QuadPart <= 0) {
  6140. status = STATUS_INVALID_PARAMETER;
  6141. break;
  6142. }
  6143. if (specialRead->Length >
  6144. irpSp->Parameters.DeviceIoControl.OutputBufferLength) {
  6145. status = STATUS_INVALID_PARAMETER;
  6146. break;
  6147. }
  6148. packet = new DISPATCH_TP;
  6149. if (!packet) {
  6150. status = STATUS_INSUFFICIENT_RESOURCES;
  6151. break;
  6152. }
  6153. packet->Mdl = Irp->MdlAddress;
  6154. packet->Offset = specialRead->ByteOffset.QuadPart;
  6155. packet->Length = specialRead->Length;
  6156. packet->CompletionRoutine = FtpReadWriteCompletionRoutine;
  6157. packet->TargetVolume = vol;
  6158. packet->Thread = Irp->Tail.Overlay.Thread;
  6159. packet->IrpFlags = irpSp->Flags;
  6160. packet->ReadPacket = TRUE;
  6161. if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
  6162. FT_SECONDARY_READ) {
  6163. packet->SpecialRead = TP_SPECIAL_READ_SECONDARY;
  6164. } else {
  6165. packet->SpecialRead = TP_SPECIAL_READ_PRIMARY;
  6166. }
  6167. packet->Irp = Irp;
  6168. packet->Extension = extension;
  6169. IoMarkIrpPending(Irp);
  6170. TRANSFER(packet);
  6171. return STATUS_PENDING;
  6172. case FT_BALANCED_READ_MODE:
  6173. case FT_SEQUENTIAL_WRITE_MODE:
  6174. case FT_PARALLEL_WRITE_MODE:
  6175. status = STATUS_SUCCESS;
  6176. break;
  6177. case FT_QUERY_LOGICAL_DISK_ID:
  6178. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  6179. sizeof(FT_QUERY_LOGICAL_DISK_ID_OUTPUT)) {
  6180. status = STATUS_INVALID_PARAMETER;
  6181. break;
  6182. }
  6183. queryLogicalDiskIdOutput = (PFT_QUERY_LOGICAL_DISK_ID_OUTPUT)
  6184. Irp->AssociatedIrp.SystemBuffer;
  6185. queryLogicalDiskIdOutput->RootLogicalDiskId =
  6186. vol->QueryLogicalDiskId();
  6187. Irp->IoStatus.Information = sizeof(FT_QUERY_LOGICAL_DISK_ID_OUTPUT);
  6188. status = STATUS_SUCCESS;
  6189. break;
  6190. default:
  6191. status = STATUS_INVALID_DEVICE_REQUEST;
  6192. break;
  6193. }
  6194. FtpDecrementRefCount(extension);
  6195. Irp->IoStatus.Status = status;
  6196. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6197. return status;
  6198. }
  6199. NTSTATUS
  6200. FtpCreatePartitionLogicalDiskHelper(
  6201. IN OUT PVOLUME_EXTENSION Extension,
  6202. IN LONGLONG PartitionSize,
  6203. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  6204. )
  6205. {
  6206. PMOUNTDEV_UNIQUE_ID newUniqueId;
  6207. UCHAR newUniqueIdBuffer[UNIQUE_ID_MAX_BUFFER_SIZE];
  6208. NTSTATUS status;
  6209. ULONG diskNumber;
  6210. LONGLONG offset;
  6211. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  6212. FT_LOGICAL_DISK_ID diskId;
  6213. PPARTITION partition;
  6214. UCHAR type;
  6215. SET_TARGET_CONTEXT context;
  6216. if (Extension->IsGpt) {
  6217. return STATUS_INVALID_PARAMETER;
  6218. }
  6219. newUniqueId = (PMOUNTDEV_UNIQUE_ID) newUniqueIdBuffer;
  6220. status = FtpQueryPartitionInformation(Extension->Root,
  6221. Extension->TargetObject, &diskNumber,
  6222. &offset, NULL, NULL, NULL, NULL,
  6223. NULL, NULL, NULL);
  6224. if (!NT_SUCCESS(status)) {
  6225. return status;
  6226. }
  6227. diskInfoSet = Extension->Root->DiskInfoSet;
  6228. status = diskInfoSet->CreatePartitionLogicalDisk(diskNumber, offset,
  6229. PartitionSize, &diskId);
  6230. if (!NT_SUCCESS(status)) {
  6231. return status;
  6232. }
  6233. partition = new PARTITION;
  6234. if (!partition) {
  6235. diskInfoSet->BreakLogicalDisk(diskId);
  6236. return STATUS_INSUFFICIENT_RESOURCES;
  6237. }
  6238. status = partition->Initialize(Extension->Root, diskId,
  6239. Extension->TargetObject,
  6240. Extension->WholeDiskPdo);
  6241. if (!NT_SUCCESS(status)) {
  6242. if (!InterlockedDecrement(&partition->_refCount)) {
  6243. delete partition;
  6244. }
  6245. diskInfoSet->BreakLogicalDisk(diskId);
  6246. return status;
  6247. }
  6248. type = partition->QueryPartitionType();
  6249. if (!type) {
  6250. if (!InterlockedDecrement(&partition->_refCount)) {
  6251. delete partition;
  6252. }
  6253. diskInfoSet->BreakLogicalDisk(diskId);
  6254. return STATUS_INSUFFICIENT_RESOURCES;
  6255. }
  6256. status = partition->SetPartitionType(type);
  6257. if (!NT_SUCCESS(status)) {
  6258. if (!InterlockedDecrement(&partition->_refCount)) {
  6259. delete partition;
  6260. }
  6261. diskInfoSet->BreakLogicalDisk(diskId);
  6262. return status;
  6263. }
  6264. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  6265. context.TargetObject = NULL;
  6266. context.FtVolume = partition;
  6267. context.WholeDiskPdo = NULL;
  6268. FtpZeroRefCallback(Extension, FtpSetTargetCallback, &context, TRUE);
  6269. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  6270. NULL);
  6271. FtpQueryUniqueIdBuffer(Extension, newUniqueId->UniqueId,
  6272. &newUniqueId->UniqueIdLength);
  6273. FtpUniqueIdNotify(Extension, newUniqueId);
  6274. *NewLogicalDiskId = diskId;
  6275. FtpNotify(Extension->Root, Extension);
  6276. return status;
  6277. }
  6278. NTSTATUS
  6279. FtpInsertMirror(
  6280. IN OUT PROOT_EXTENSION RootExtension,
  6281. IN PFT_LOGICAL_DISK_ID ArrayOfMembers,
  6282. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  6283. )
  6284. {
  6285. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  6286. ULONG i;
  6287. NTSTATUS status;
  6288. PVOLUME_EXTENSION extension, shadowExtension;
  6289. PFT_VOLUME topVol, vol, shadowVol, parentVol;
  6290. FT_LOGICAL_DISK_ID fakeDiskId, mirrorDiskId, parentDiskId;
  6291. FT_LOGICAL_DISK_ID mirrorMembers[2];
  6292. FT_MIRROR_SET_CONFIGURATION_INFORMATION config;
  6293. FT_MIRROR_AND_SWP_STATE_INFORMATION state;
  6294. USHORT n, j;
  6295. PMIRROR mirror;
  6296. PFT_VOLUME* arrayOfVolumes;
  6297. KEVENT event;
  6298. INSERT_MEMBER_CONTEXT context;
  6299. UCHAR newUniqueIdBuffer[UNIQUE_ID_MAX_BUFFER_SIZE];
  6300. PMOUNTDEV_UNIQUE_ID newUniqueId;
  6301. PFT_LOGICAL_DISK_DESCRIPTION p;
  6302. WCHAR deviceNameBuffer[64];
  6303. UNICODE_STRING deviceName;
  6304. SET_TARGET_CONTEXT setContext;
  6305. diskInfoSet = RootExtension->DiskInfoSet;
  6306. for (i = 0; i < 100; i++) {
  6307. status = diskInfoSet->CreatePartitionLogicalDisk(i, 0, 0, &fakeDiskId);
  6308. if (NT_SUCCESS(status)) {
  6309. break;
  6310. }
  6311. }
  6312. if (i == 100) {
  6313. return status;
  6314. }
  6315. extension = FtpFindExtensionCoveringDiskId(RootExtension,
  6316. ArrayOfMembers[0]);
  6317. ASSERT(extension);
  6318. topVol = extension->FtVolume;
  6319. vol = topVol->GetContainedLogicalDisk(ArrayOfMembers[0]);
  6320. shadowExtension = FtpFindExtension(RootExtension, ArrayOfMembers[1]);
  6321. ASSERT(shadowExtension);
  6322. shadowVol = shadowExtension->FtVolume;
  6323. if (shadowVol->QueryVolumeSize() < vol->QueryVolumeSize()) {
  6324. return STATUS_INVALID_PARAMETER;
  6325. }
  6326. mirrorMembers[0] = fakeDiskId;
  6327. mirrorMembers[1] = ArrayOfMembers[1];
  6328. config.MemberSize = vol->QueryVolumeSize();
  6329. state.IsInitializing = FALSE;
  6330. state.IsDirty = TRUE;
  6331. state.UnhealthyMemberNumber = 1;
  6332. state.UnhealthyMemberState = FtMemberRegenerating;
  6333. status = diskInfoSet->AddNewLogicalDisk(FtMirrorSet, 2, mirrorMembers,
  6334. sizeof(config), &config,
  6335. sizeof(state), &state,
  6336. &mirrorDiskId);
  6337. if (!NT_SUCCESS(status)) {
  6338. diskInfoSet->BreakLogicalDisk(fakeDiskId);
  6339. return status;
  6340. }
  6341. parentVol = topVol->GetParentLogicalDisk(vol);
  6342. if (!parentVol) {
  6343. diskInfoSet->BreakLogicalDisk(mirrorDiskId);
  6344. diskInfoSet->BreakLogicalDisk(fakeDiskId);
  6345. return STATUS_INVALID_PARAMETER;
  6346. }
  6347. n = parentVol->QueryNumberOfMembers();
  6348. for (j = 0; j < n; j++) {
  6349. if (parentVol->GetMember(j) == vol) {
  6350. break;
  6351. }
  6352. }
  6353. status = diskInfoSet->ReplaceLogicalDiskMember(
  6354. parentVol->QueryLogicalDiskId(), j, mirrorDiskId, &parentDiskId);
  6355. if (!NT_SUCCESS(status)) {
  6356. diskInfoSet->BreakLogicalDisk(mirrorDiskId);
  6357. diskInfoSet->BreakLogicalDisk(fakeDiskId);
  6358. return status;
  6359. }
  6360. status = diskInfoSet->ReplaceLogicalDiskMember(
  6361. mirrorDiskId, 0, ArrayOfMembers[0], &mirrorDiskId);
  6362. if (!NT_SUCCESS(status)) {
  6363. diskInfoSet->ReplaceLogicalDiskMember(
  6364. parentDiskId, j, ArrayOfMembers[0], &parentDiskId);
  6365. diskInfoSet->BreakLogicalDisk(mirrorDiskId);
  6366. diskInfoSet->BreakLogicalDisk(fakeDiskId);
  6367. return status;
  6368. }
  6369. *NewLogicalDiskId = mirrorDiskId;
  6370. diskInfoSet->BreakLogicalDisk(fakeDiskId);
  6371. arrayOfVolumes = (PFT_VOLUME*) ExAllocatePool(NonPagedPool, 2*sizeof(PFT_VOLUME));
  6372. if (!arrayOfVolumes) {
  6373. return STATUS_INSUFFICIENT_RESOURCES;
  6374. }
  6375. mirror = new MIRROR;
  6376. if (!mirror) {
  6377. ExFreePool(arrayOfVolumes);
  6378. return STATUS_INSUFFICIENT_RESOURCES;
  6379. }
  6380. arrayOfVolumes[0] = vol;
  6381. arrayOfVolumes[1] = shadowVol;
  6382. status = mirror->Initialize(RootExtension, mirrorDiskId, arrayOfVolumes, 2,
  6383. &config, &state);
  6384. if (!NT_SUCCESS(status)) {
  6385. if (!InterlockedDecrement(&mirror->_refCount)) {
  6386. delete mirror;
  6387. }
  6388. return status;
  6389. }
  6390. KeInitializeEvent(&setContext.Event, NotificationEvent, FALSE);
  6391. setContext.TargetObject = NULL;
  6392. setContext.FtVolume = NULL;
  6393. setContext.WholeDiskPdo = NULL;
  6394. FtpZeroRefCallback(shadowExtension, FtpSetTargetCallback, &setContext,
  6395. TRUE);
  6396. KeWaitForSingleObject(&setContext.Event, Executive, KernelMode, FALSE,
  6397. NULL);
  6398. RemoveEntryList(&shadowExtension->ListEntry);
  6399. InsertTailList(&RootExtension->DeadVolumeList,
  6400. &shadowExtension->ListEntry);
  6401. FtpDeleteMountPoints(shadowExtension);
  6402. FtpCleanupVolumeExtension(shadowExtension);
  6403. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  6404. context.Parent = parentVol;
  6405. context.MemberNumber = j;
  6406. context.Member = mirror;
  6407. FtpZeroRefCallback(extension, FtpInsertMemberCallback, &context, TRUE);
  6408. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL);
  6409. parentVol = mirror;
  6410. while (p = diskInfoSet->GetParentLogicalDiskDescription(
  6411. parentVol->QueryLogicalDiskId())) {
  6412. if (parentVol = topVol->GetParentLogicalDisk(parentVol)) {
  6413. parentVol->SetLogicalDiskId(p->LogicalDiskId);
  6414. }
  6415. }
  6416. swprintf(deviceNameBuffer, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  6417. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  6418. mirror->CreateLegacyNameLinks(&deviceName);
  6419. newUniqueId = (PMOUNTDEV_UNIQUE_ID) newUniqueIdBuffer;
  6420. FtpQueryUniqueIdBuffer(extension, newUniqueId->UniqueId,
  6421. &newUniqueId->UniqueIdLength);
  6422. FtpUniqueIdNotify(extension, newUniqueId);
  6423. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  6424. FtpNotify(RootExtension, extension);
  6425. return STATUS_SUCCESS;
  6426. }
  6427. VOID
  6428. FtpBootDriverReinitialization(
  6429. IN PDRIVER_OBJECT DriverObject,
  6430. IN PVOID RootExtension,
  6431. IN ULONG Count
  6432. )
  6433. /*++
  6434. Routine Description:
  6435. This routine is called after all of the boot drivers are loaded and it
  6436. checks to make sure that we did not boot off of the stale half of a
  6437. mirror.
  6438. Arguments:
  6439. DriverObject - Supplies the drive object.
  6440. RootExtension - Supplies the root extension.
  6441. Count - Supplies the count.
  6442. Return Value:
  6443. None.
  6444. --*/
  6445. {
  6446. PROOT_EXTENSION rootExtension = (PROOT_EXTENSION) RootExtension;
  6447. NTSTATUS status;
  6448. BOOTDISK_INFORMATION bootInfo;
  6449. BOOLEAN onlyOne, skipBoot, skipSystem;
  6450. PLIST_ENTRY l;
  6451. PVOLUME_EXTENSION extension;
  6452. PFT_VOLUME vol, partition;
  6453. FT_MEMBER_STATE state;
  6454. status = IoGetBootDiskInformation(&bootInfo, sizeof(bootInfo));
  6455. if (!NT_SUCCESS(status)) {
  6456. return;
  6457. }
  6458. if (bootInfo.BootDeviceSignature == bootInfo.SystemDeviceSignature &&
  6459. bootInfo.BootPartitionOffset == bootInfo.SystemPartitionOffset) {
  6460. onlyOne = TRUE;
  6461. } else {
  6462. onlyOne = FALSE;
  6463. }
  6464. if (!bootInfo.BootDeviceSignature || !bootInfo.BootPartitionOffset) {
  6465. skipBoot = TRUE;
  6466. } else {
  6467. skipBoot = FALSE;
  6468. }
  6469. if (!bootInfo.SystemDeviceSignature || !bootInfo.SystemPartitionOffset) {
  6470. skipSystem = TRUE;
  6471. } else {
  6472. skipSystem = FALSE;
  6473. }
  6474. if (skipBoot && skipSystem) {
  6475. return;
  6476. }
  6477. FtpAcquire(rootExtension);
  6478. for (l = rootExtension->VolumeList.Flink;
  6479. l != &rootExtension->VolumeList; l = l->Flink) {
  6480. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6481. vol = extension->FtVolume;
  6482. if (!vol) {
  6483. continue;
  6484. }
  6485. if (!skipBoot) {
  6486. partition = vol->GetContainedLogicalDisk(
  6487. bootInfo.BootDeviceSignature,
  6488. bootInfo.BootPartitionOffset);
  6489. if (partition) {
  6490. if (vol->QueryVolumeState(partition, &state) &&
  6491. state != FtMemberHealthy) {
  6492. KeBugCheckEx(FTDISK_INTERNAL_ERROR,
  6493. (ULONG_PTR) extension,
  6494. bootInfo.BootDeviceSignature,
  6495. (ULONG_PTR) bootInfo.BootPartitionOffset,
  6496. state);
  6497. }
  6498. }
  6499. }
  6500. if (onlyOne) {
  6501. continue;
  6502. }
  6503. if (!skipSystem) {
  6504. partition = vol->GetContainedLogicalDisk(
  6505. bootInfo.SystemDeviceSignature,
  6506. bootInfo.SystemPartitionOffset);
  6507. if (partition) {
  6508. if (vol->QueryVolumeState(partition, &state) &&
  6509. state != FtMemberHealthy) {
  6510. KeBugCheckEx(FTDISK_INTERNAL_ERROR,
  6511. (ULONG_PTR) extension,
  6512. bootInfo.BootDeviceSignature,
  6513. (ULONG_PTR) bootInfo.BootPartitionOffset,
  6514. state);
  6515. }
  6516. }
  6517. }
  6518. }
  6519. rootExtension->PastBootReinitialize = TRUE;
  6520. FtpRelease(rootExtension);
  6521. }
  6522. NTSTATUS
  6523. FtpQuerySystemVolumeNameQueryRoutine(
  6524. IN PWSTR ValueName,
  6525. IN ULONG ValueType,
  6526. IN PVOID ValueData,
  6527. IN ULONG ValueLength,
  6528. IN PVOID Context,
  6529. IN PVOID EntryContext
  6530. )
  6531. /*++
  6532. Routine Description:
  6533. This routine queries the unique id for the given value.
  6534. Arguments:
  6535. ValueName - Supplies the name of the registry value.
  6536. ValueType - Supplies the type of the registry value.
  6537. ValueData - Supplies the data of the registry value.
  6538. ValueLength - Supplies the length of the registry value.
  6539. Context - Returns the system volume name.
  6540. EntryContext - Not used.
  6541. Return Value:
  6542. NTSTATUS
  6543. --*/
  6544. {
  6545. PUNICODE_STRING systemVolumeName = (PUNICODE_STRING) Context;
  6546. UNICODE_STRING string;
  6547. if (ValueType != REG_SZ) {
  6548. return STATUS_SUCCESS;
  6549. }
  6550. RtlInitUnicodeString(&string, (PWSTR) ValueData);
  6551. systemVolumeName->Length = string.Length;
  6552. systemVolumeName->MaximumLength = systemVolumeName->Length + sizeof(WCHAR);
  6553. systemVolumeName->Buffer = (PWSTR) ExAllocatePool(PagedPool,
  6554. systemVolumeName->MaximumLength);
  6555. if (!systemVolumeName->Buffer) {
  6556. return STATUS_SUCCESS;
  6557. }
  6558. RtlCopyMemory(systemVolumeName->Buffer, ValueData,
  6559. systemVolumeName->Length);
  6560. systemVolumeName->Buffer[systemVolumeName->Length/sizeof(WCHAR)] = 0;
  6561. return STATUS_SUCCESS;
  6562. }
  6563. VOID
  6564. FtpDriverReinitialization(
  6565. IN PDRIVER_OBJECT DriverObject,
  6566. IN PVOID RootExtension,
  6567. IN ULONG Count
  6568. )
  6569. /*++
  6570. Routine Description:
  6571. This routine is called after all of the disk drivers are loaded
  6572. Arguments:
  6573. DriverObject - Supplies the drive object.
  6574. RootExtension - Supplies the root extension.
  6575. Count - Supplies the count.
  6576. Return Value:
  6577. None.
  6578. --*/
  6579. {
  6580. PROOT_EXTENSION rootExtension = (PROOT_EXTENSION) RootExtension;
  6581. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  6582. UNICODE_STRING systemVolumeName, s;
  6583. PLIST_ENTRY l;
  6584. PVOLUME_EXTENSION extension;
  6585. WCHAR buffer[100];
  6586. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  6587. queryTable[0].QueryRoutine = FtpQuerySystemVolumeNameQueryRoutine;
  6588. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  6589. queryTable[0].Name = L"SystemPartition";
  6590. systemVolumeName.Buffer = NULL;
  6591. RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  6592. L"\\Registry\\Machine\\System\\Setup",
  6593. queryTable, &systemVolumeName, NULL);
  6594. FtpAcquire(rootExtension);
  6595. for (l = rootExtension->VolumeList.Flink;
  6596. l != &rootExtension->VolumeList; l = l->Flink) {
  6597. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6598. if (!extension->IsEspType) {
  6599. continue;
  6600. }
  6601. swprintf(buffer, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  6602. RtlInitUnicodeString(&s, buffer);
  6603. if (systemVolumeName.Buffer &&
  6604. RtlEqualUnicodeString(&s, &systemVolumeName, TRUE)) {
  6605. rootExtension->ESPUniquePartitionGUID = extension->UniqueIdGuid;
  6606. }
  6607. FtpApplyESPProtection(&s);
  6608. }
  6609. rootExtension->PastReinitialize = TRUE;
  6610. FtpRelease(rootExtension);
  6611. if (systemVolumeName.Buffer) {
  6612. ExFreePool(systemVolumeName.Buffer);
  6613. }
  6614. }
  6615. VOID
  6616. FtpCopyStateToRegistry(
  6617. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  6618. IN PVOID LogicalDiskState,
  6619. IN USHORT LogicalDiskStateSize
  6620. )
  6621. /*++
  6622. Routine Description:
  6623. This routine writes the given state to the registry so that it can
  6624. be retrieved to solve some of the so called split brain problems.
  6625. Arguments:
  6626. LogicalDiskId - Supplies the logical disk id.
  6627. LogicalDiskState - Supplies the logical disk state.
  6628. LogicalDiskStateSize - Supplies the logical disk state size.
  6629. Return Value:
  6630. None.
  6631. --*/
  6632. {
  6633. WCHAR registryName[50];
  6634. RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, FT_STATE_REGISTRY_KEY);
  6635. swprintf(registryName, L"%I64X", LogicalDiskId);
  6636. RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, FT_STATE_REGISTRY_KEY,
  6637. registryName, REG_BINARY, LogicalDiskState,
  6638. LogicalDiskStateSize);
  6639. }
  6640. NTSTATUS
  6641. FtpQueryStateFromRegistryRoutine(
  6642. IN PWSTR ValueName,
  6643. IN ULONG ValueType,
  6644. IN PVOID ValueData,
  6645. IN ULONG ValueLength,
  6646. IN PVOID Context,
  6647. IN PVOID EntryContext
  6648. )
  6649. /*++
  6650. Routine Description:
  6651. This routine fetches the binary data for the given regitry entry.
  6652. Arguments:
  6653. ValueName - Supplies the name of the registry value.
  6654. ValueType - Supplies the type of the registry value.
  6655. ValueData - Supplies the data of the registry value.
  6656. ValueLength - Supplies the length of the registry value.
  6657. Context - Returns the registry data.
  6658. EntryContext - Supplies the length of the registry data buffer.
  6659. Return Value:
  6660. NTSTATUS
  6661. --*/
  6662. {
  6663. if (ValueLength > *((PUSHORT) EntryContext)) {
  6664. return STATUS_INVALID_PARAMETER;
  6665. }
  6666. *((PUSHORT) EntryContext) = (USHORT) ValueLength;
  6667. RtlCopyMemory(Context, ValueData, ValueLength);
  6668. return STATUS_SUCCESS;
  6669. }
  6670. BOOLEAN
  6671. FtpQueryStateFromRegistry(
  6672. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  6673. IN PVOID LogicalDiskState,
  6674. IN USHORT BufferSize,
  6675. OUT PUSHORT LogicalDiskStateSize
  6676. )
  6677. /*++
  6678. Routine Description:
  6679. This routine queries the given state from the registry so that it can
  6680. be retrieved to solve some of the so called split brain problems.
  6681. Arguments:
  6682. LogicalDiskId - Supplies the logical disk id.
  6683. LogicalDiskState - Supplies the logical disk state.
  6684. LogicalDiskStateSize - Supplie the logical disk state size.
  6685. Return Value:
  6686. None.
  6687. --*/
  6688. {
  6689. WCHAR registryName[50];
  6690. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  6691. NTSTATUS status;
  6692. *LogicalDiskStateSize = BufferSize;
  6693. swprintf(registryName, L"%I64X", LogicalDiskId);
  6694. RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE));
  6695. queryTable[0].QueryRoutine = FtpQueryStateFromRegistryRoutine;
  6696. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  6697. queryTable[0].Name = registryName;
  6698. queryTable[0].EntryContext = LogicalDiskStateSize;
  6699. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  6700. FT_STATE_REGISTRY_KEY, queryTable,
  6701. LogicalDiskState, NULL);
  6702. if (!NT_SUCCESS(status)) {
  6703. return FALSE;
  6704. }
  6705. return TRUE;
  6706. }
  6707. VOID
  6708. FtpDeleteStateInRegistry(
  6709. IN FT_LOGICAL_DISK_ID LogicalDiskId
  6710. )
  6711. /*++
  6712. Routine Description:
  6713. This routine deletes the given registry state in the registry.
  6714. Arguments:
  6715. LogicalDiskId - Supplies the logical disk id.
  6716. Return Value:
  6717. None.
  6718. --*/
  6719. {
  6720. WCHAR registryName[50];
  6721. swprintf(registryName, L"%I64X", LogicalDiskId);
  6722. RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, FT_STATE_REGISTRY_KEY,
  6723. registryName);
  6724. }
  6725. NTSTATUS
  6726. FtWmi(
  6727. IN PDEVICE_OBJECT DeviceObject,
  6728. IN PIRP Irp
  6729. )
  6730. /*++
  6731. Routine Description:
  6732. This routine handles any WMI requests for information.
  6733. Arguments:
  6734. DeviceObject - Context for the activity.
  6735. Irp - The device control argument block.
  6736. Return Value:
  6737. Status is returned.
  6738. --*/
  6739. {
  6740. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  6741. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6742. NTSTATUS status;
  6743. SYSCTL_IRP_DISPOSITION disposition;
  6744. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  6745. IoSkipCurrentIrpStackLocation(Irp);
  6746. return IoCallDriver(extension->Root->TargetObject, Irp);
  6747. }
  6748. ASSERT(extension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  6749. status = WmiSystemControl(extension->WmilibContext, DeviceObject,
  6750. Irp, &disposition);
  6751. switch (disposition) {
  6752. case IrpProcessed:
  6753. break;
  6754. case IrpNotCompleted:
  6755. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6756. break;
  6757. default:
  6758. status = Irp->IoStatus.Status;
  6759. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  6760. break;
  6761. }
  6762. return status;
  6763. }
  6764. NTSTATUS
  6765. FtWmiFunctionControl(
  6766. IN PDEVICE_OBJECT DeviceObject,
  6767. IN PIRP Irp,
  6768. IN ULONG GuidIndex,
  6769. IN WMIENABLEDISABLECONTROL Function,
  6770. IN BOOLEAN Enable
  6771. )
  6772. /*++
  6773. Routine Description:
  6774. This routine is a callback into the driver to query for enabling or
  6775. disabling events and data collection. When the driver has finished it
  6776. must call WmiCompleteRequest to complete the irp. The driver can return
  6777. STATUS_PENDING if the irp cannot be completed immediately.
  6778. Arguments:
  6779. DeviceObject is the device whose events or data collection are being
  6780. enabled or disabled
  6781. Irp is the Irp that makes this request
  6782. GuidIndex is the index into the list of guids provided when the
  6783. device registered
  6784. Function differentiates between event and data collection operations
  6785. Enable indicates whether to enable or disable
  6786. Return Value:
  6787. status
  6788. --*/
  6789. {
  6790. NTSTATUS status;
  6791. PVOLUME_EXTENSION extension;
  6792. PPMWMICOUNTERLIB_CONTEXT counterLib;
  6793. extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  6794. counterLib = &extension->Root->PmWmiCounterLibContext;
  6795. if (GuidIndex == 0)
  6796. {
  6797. status = STATUS_SUCCESS;
  6798. if (Function == WmiDataBlockControl) {
  6799. if (!Enable) {
  6800. extension->CountersEnabled =
  6801. counterLib->PmWmiCounterDisable(
  6802. &extension->PmWmiCounterContext,FALSE,FALSE);
  6803. } else {
  6804. status = counterLib->PmWmiCounterEnable(
  6805. &extension->PmWmiCounterContext);
  6806. if (NT_SUCCESS(status)) {
  6807. extension->CountersEnabled = TRUE;
  6808. }
  6809. }
  6810. }
  6811. } else {
  6812. status = STATUS_WMI_GUID_NOT_FOUND;
  6813. }
  6814. status = WmiCompleteRequest(
  6815. DeviceObject,
  6816. Irp,
  6817. status,
  6818. 0,
  6819. IO_NO_INCREMENT);
  6820. return(status);
  6821. }
  6822. NTSTATUS
  6823. FtpPmWmiCounterLibContext(
  6824. IN OUT PROOT_EXTENSION RootExtension,
  6825. IN PIRP Irp
  6826. )
  6827. /*++
  6828. Routine Description:
  6829. This routine is called from the partition manager to enable access to
  6830. the performance counter maintenance routines.
  6831. Arguments:
  6832. RootExtension - Supplies the device extension.
  6833. Irp - Supplies the IO request packet.
  6834. Return Value:
  6835. NTSTATUS
  6836. --*/
  6837. {
  6838. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6839. PPMWMICOUNTERLIB_CONTEXT input;
  6840. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  6841. sizeof(PMWMICOUNTERLIB_CONTEXT)) {
  6842. return STATUS_INVALID_PARAMETER;
  6843. }
  6844. input = (PPMWMICOUNTERLIB_CONTEXT) Irp->AssociatedIrp.SystemBuffer;
  6845. RootExtension->PmWmiCounterLibContext = *input;
  6846. return STATUS_SUCCESS;
  6847. }
  6848. VOID
  6849. FtDiskUnload(
  6850. IN PDRIVER_OBJECT DriverObject
  6851. )
  6852. /*++
  6853. Routine Description:
  6854. This routine unloads.
  6855. Arguments:
  6856. DriverObject - Supplies the driver object.
  6857. Return Value:
  6858. None.
  6859. --*/
  6860. {
  6861. ObDereferenceObject(DriverObject);
  6862. }
  6863. VOID
  6864. FtpApplyESPSecurityWorker(
  6865. IN PDEVICE_OBJECT DeviceObject,
  6866. IN PVOID WorkItem
  6867. )
  6868. {
  6869. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  6870. PIO_WORKITEM workItem = (PIO_WORKITEM) WorkItem;
  6871. WCHAR buffer[100];
  6872. UNICODE_STRING s;
  6873. swprintf(buffer, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  6874. RtlInitUnicodeString(&s, buffer);
  6875. FtpApplyESPProtection(&s);
  6876. IoFreeWorkItem(workItem);
  6877. }
  6878. VOID
  6879. FtpPostApplyESPSecurity(
  6880. IN PVOLUME_EXTENSION Extension
  6881. )
  6882. {
  6883. PIO_WORKITEM workItem;
  6884. workItem = IoAllocateWorkItem(Extension->DeviceObject);
  6885. if (!workItem) {
  6886. return;
  6887. }
  6888. IoQueueWorkItem(workItem, FtpApplyESPSecurityWorker, DelayedWorkQueue,
  6889. workItem);
  6890. }
  6891. NTSTATUS
  6892. FtDiskPnp(
  6893. IN PDEVICE_OBJECT DeviceObject,
  6894. IN PIRP Irp
  6895. )
  6896. /*++
  6897. Routine Description:
  6898. This routine is the dispatch for IRP_MJ_PNP.
  6899. Arguments:
  6900. DeviceObject - Supplies the device object.
  6901. Irp - Supplies the IO request packet.
  6902. Return Value:
  6903. NTSTATUS
  6904. --*/
  6905. {
  6906. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  6907. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  6908. PROOT_EXTENSION rootExtension;
  6909. PDEVICE_OBJECT targetObject;
  6910. NTSTATUS status;
  6911. UNICODE_STRING interfaceName;
  6912. PLIST_ENTRY l;
  6913. PVOLUME_EXTENSION e;
  6914. UNICODE_STRING dosName;
  6915. KEVENT event;
  6916. ULONG n, size;
  6917. PDEVICE_RELATIONS deviceRelations;
  6918. PDEVICE_CAPABILITIES capabilities;
  6919. DEVICE_INSTALL_STATE deviceInstallState;
  6920. ULONG bytes;
  6921. BOOLEAN deletePdo;
  6922. BOOLEAN dontAssertGuid;
  6923. BOOLEAN removeInProgress;
  6924. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  6925. rootExtension = (PROOT_EXTENSION) extension;
  6926. targetObject = rootExtension->TargetObject;
  6927. switch (irpSp->MinorFunction) {
  6928. case IRP_MN_START_DEVICE:
  6929. case IRP_MN_CANCEL_REMOVE_DEVICE:
  6930. case IRP_MN_CANCEL_STOP_DEVICE:
  6931. case IRP_MN_QUERY_RESOURCES:
  6932. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  6933. Irp->IoStatus.Status = STATUS_SUCCESS ;
  6934. IoSkipCurrentIrpStackLocation(Irp);
  6935. return IoCallDriver(targetObject, Irp);
  6936. case IRP_MN_QUERY_DEVICE_RELATIONS:
  6937. if (irpSp->Parameters.QueryDeviceRelations.Type != BusRelations) {
  6938. IoSkipCurrentIrpStackLocation(Irp);
  6939. return IoCallDriver(targetObject, Irp);
  6940. }
  6941. FtpAcquire(rootExtension);
  6942. n = 0;
  6943. for (l = rootExtension->VolumeList.Flink;
  6944. l != &rootExtension->VolumeList; l = l->Flink) {
  6945. n++;
  6946. }
  6947. size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) +
  6948. n*sizeof(PDEVICE_OBJECT);
  6949. deviceRelations = (PDEVICE_RELATIONS)
  6950. ExAllocatePool(PagedPool, size);
  6951. if (!deviceRelations) {
  6952. FtpRelease(rootExtension);
  6953. status = STATUS_INSUFFICIENT_RESOURCES;
  6954. Irp->IoStatus.Information = 0;
  6955. break;
  6956. }
  6957. deviceRelations->Count = n;
  6958. n = 0;
  6959. for (l = rootExtension->VolumeList.Flink;
  6960. l != &rootExtension->VolumeList; l = l->Flink) {
  6961. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6962. deviceRelations->Objects[n++] = e->DeviceObject;
  6963. ObReferenceObject(e->DeviceObject);
  6964. }
  6965. while (!IsListEmpty(&rootExtension->DeadVolumeList)) {
  6966. l = RemoveHeadList(&rootExtension->DeadVolumeList);
  6967. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6968. e->DeadToPnp = TRUE;
  6969. }
  6970. FtpRelease(rootExtension);
  6971. Irp->IoStatus.Status = STATUS_SUCCESS;
  6972. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  6973. IoSkipCurrentIrpStackLocation(Irp);
  6974. return IoCallDriver(targetObject, Irp);
  6975. case IRP_MN_QUERY_ID:
  6976. status = FtpQueryRootId(rootExtension, Irp);
  6977. if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
  6978. if (NT_SUCCESS(status)) {
  6979. Irp->IoStatus.Status = status;
  6980. }
  6981. IoSkipCurrentIrpStackLocation(Irp);
  6982. return IoCallDriver(targetObject, Irp);
  6983. }
  6984. break;
  6985. case IRP_MN_REMOVE_DEVICE:
  6986. case IRP_MN_SURPRISE_REMOVAL:
  6987. FtpAcquire(rootExtension);
  6988. if (rootExtension->VolumeManagerInterfaceName.Buffer) {
  6989. IoSetDeviceInterfaceState(
  6990. &rootExtension->VolumeManagerInterfaceName, FALSE);
  6991. ExFreePool(rootExtension->VolumeManagerInterfaceName.Buffer);
  6992. rootExtension->VolumeManagerInterfaceName.Buffer = NULL;
  6993. }
  6994. if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  6995. ASSERT(IsListEmpty(&rootExtension->VolumeList));
  6996. while (!IsListEmpty(&rootExtension->VolumeList)) {
  6997. l = RemoveHeadList(&rootExtension->VolumeList);
  6998. e = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  6999. FtpCleanupVolumeExtension(e);
  7000. ExFreePool(e->DeviceNodeName.Buffer);
  7001. IoDeleteDevice(e->DeviceObject);
  7002. }
  7003. delete rootExtension->DiskInfoSet;
  7004. rootExtension->DiskInfoSet = NULL;
  7005. FtpRelease(rootExtension);
  7006. InterlockedExchange(&rootExtension->TerminateThread, TRUE);
  7007. KeReleaseSemaphore(&rootExtension->WorkerSemaphore,
  7008. IO_NO_INCREMENT, 1, FALSE);
  7009. KeWaitForSingleObject(rootExtension->WorkerThread, Executive,
  7010. KernelMode, FALSE, NULL);
  7011. ObDereferenceObject(rootExtension->WorkerThread);
  7012. ASSERT(IsListEmpty(&rootExtension->ChangeNotifyIrpList));
  7013. IoDetachDevice(targetObject);
  7014. IoUnregisterShutdownNotification(rootExtension->DeviceObject);
  7015. IoDeleteDevice(rootExtension->DeviceObject);
  7016. } else {
  7017. FtpRelease(rootExtension);
  7018. }
  7019. Irp->IoStatus.Status = STATUS_SUCCESS;
  7020. IoSkipCurrentIrpStackLocation(Irp);
  7021. return IoCallDriver(targetObject, Irp);
  7022. case IRP_MN_QUERY_REMOVE_DEVICE:
  7023. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  7024. status = STATUS_INVALID_DEVICE_REQUEST;
  7025. break;
  7026. case IRP_MN_QUERY_CAPABILITIES:
  7027. KeInitializeEvent(&event, NotificationEvent, FALSE);
  7028. IoCopyCurrentIrpStackLocationToNext(Irp);
  7029. IoSetCompletionRoutine(Irp, FtpSignalCompletion,
  7030. &event, TRUE, TRUE, TRUE);
  7031. IoCallDriver(targetObject, Irp);
  7032. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  7033. NULL);
  7034. capabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
  7035. capabilities->SilentInstall = 1;
  7036. capabilities->RawDeviceOK = 1;
  7037. status = Irp->IoStatus.Status;
  7038. break;
  7039. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  7040. KeInitializeEvent(&event, NotificationEvent, FALSE);
  7041. IoCopyCurrentIrpStackLocationToNext(Irp);
  7042. IoSetCompletionRoutine(Irp, FtpSignalCompletion,
  7043. &event, TRUE, TRUE, TRUE);
  7044. IoCallDriver(targetObject, Irp);
  7045. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  7046. NULL);
  7047. status = Irp->IoStatus.Status;
  7048. if (NT_SUCCESS(status)) {
  7049. Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE |
  7050. PNP_DEVICE_DONT_DISPLAY_IN_UI;
  7051. } else {
  7052. status = STATUS_SUCCESS;
  7053. Irp->IoStatus.Information = PNP_DEVICE_NOT_DISABLEABLE |
  7054. PNP_DEVICE_DONT_DISPLAY_IN_UI;
  7055. }
  7056. break;
  7057. default:
  7058. IoSkipCurrentIrpStackLocation(Irp);
  7059. return IoCallDriver(targetObject, Irp);
  7060. }
  7061. } else if (extension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME) {
  7062. switch (irpSp->MinorFunction) {
  7063. case IRP_MN_START_DEVICE:
  7064. FtpAcquire(extension->Root);
  7065. KeInitializeEvent(&event, NotificationEvent, FALSE);
  7066. FtpZeroRefCallback(extension, FtpStartCallback, &event, TRUE);
  7067. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  7068. NULL);
  7069. dontAssertGuid = FALSE;
  7070. if (extension->Root->PastBootReinitialize) {
  7071. status = IoGetDeviceProperty(extension->DeviceObject,
  7072. DevicePropertyInstallState,
  7073. sizeof(deviceInstallState),
  7074. &deviceInstallState, &bytes);
  7075. if (NT_SUCCESS(status)) {
  7076. if (deviceInstallState == InstallStateInstalled) {
  7077. extension->IsInstalled = TRUE;
  7078. if (extension->IsPreExposure) {
  7079. extension->Root->PreExposureCount--;
  7080. RemoveEntryList(&extension->ListEntry);
  7081. InsertTailList(
  7082. &extension->Root->DeadVolumeList,
  7083. &extension->ListEntry);
  7084. FtpCleanupVolumeExtension(extension);
  7085. status = STATUS_UNSUCCESSFUL;
  7086. dontAssertGuid = TRUE;
  7087. } else if (extension->IsHidden) {
  7088. status = STATUS_UNSUCCESSFUL;
  7089. dontAssertGuid = TRUE;
  7090. if (extension->IsEspType &&
  7091. extension->Root->PastReinitialize) {
  7092. FtpPostApplyESPSecurity(extension);
  7093. }
  7094. } else {
  7095. status = IoRegisterDeviceInterface(
  7096. extension->DeviceObject,
  7097. &MOUNTDEV_MOUNTED_DEVICE_GUID, NULL,
  7098. &extension->MountedDeviceInterfaceName);
  7099. }
  7100. } else {
  7101. status = STATUS_UNSUCCESSFUL;
  7102. dontAssertGuid = TRUE;
  7103. }
  7104. } else {
  7105. dontAssertGuid = TRUE;
  7106. }
  7107. } else {
  7108. extension->IsInstalled = TRUE;
  7109. if (extension->IsPreExposure || extension->IsHidden) {
  7110. status = STATUS_UNSUCCESSFUL;
  7111. dontAssertGuid = TRUE;
  7112. } else {
  7113. status = IoRegisterDeviceInterface(
  7114. extension->DeviceObject,
  7115. &MOUNTDEV_MOUNTED_DEVICE_GUID, NULL,
  7116. &extension->MountedDeviceInterfaceName);
  7117. }
  7118. }
  7119. if (NT_SUCCESS(status)) {
  7120. status = IoSetDeviceInterfaceState(
  7121. &extension->MountedDeviceInterfaceName, TRUE);
  7122. }
  7123. if (!NT_SUCCESS(status)) {
  7124. if (extension->MountedDeviceInterfaceName.Buffer) {
  7125. ExFreePool(extension->MountedDeviceInterfaceName.Buffer);
  7126. extension->MountedDeviceInterfaceName.Buffer = NULL;
  7127. }
  7128. KeInitializeEvent(&event, NotificationEvent, FALSE);
  7129. FtpZeroRefCallback(extension, FtpVolumeOnlineCallback,
  7130. &event, TRUE);
  7131. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  7132. NULL);
  7133. }
  7134. if (!extension->IsHidden) {
  7135. FtRegisterDevice(DeviceObject);
  7136. }
  7137. FtpRelease(extension->Root);
  7138. if (dontAssertGuid) {
  7139. status = STATUS_SUCCESS;
  7140. }
  7141. break;
  7142. case IRP_MN_QUERY_REMOVE_DEVICE:
  7143. if (extension->DeviceObject->Flags&DO_SYSTEM_BOOT_PARTITION) {
  7144. status = STATUS_INVALID_DEVICE_REQUEST;
  7145. break;
  7146. }
  7147. status = FtpCheckForQueryRemove(extension);
  7148. break;
  7149. case IRP_MN_CANCEL_REMOVE_DEVICE:
  7150. removeInProgress = FtpCheckForCancelRemove(extension);
  7151. if (removeInProgress) {
  7152. KeInitializeEvent(&event, NotificationEvent, FALSE);
  7153. FtpZeroRefCallback(extension, FtpQueryRemoveCallback, &event,
  7154. TRUE);
  7155. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  7156. NULL);
  7157. }
  7158. status = STATUS_SUCCESS;
  7159. break;
  7160. case IRP_MN_QUERY_STOP_DEVICE:
  7161. status = STATUS_UNSUCCESSFUL;
  7162. break;
  7163. case IRP_MN_CANCEL_STOP_DEVICE:
  7164. case IRP_MN_QUERY_RESOURCES:
  7165. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  7166. status = STATUS_SUCCESS;
  7167. break;
  7168. case IRP_MN_REMOVE_DEVICE:
  7169. case IRP_MN_SURPRISE_REMOVAL:
  7170. FtpAcquire(extension->Root);
  7171. FtpRemoveHelper(extension);
  7172. KeInitializeEvent(&event, NotificationEvent, FALSE);
  7173. FtpZeroRefCallback(extension, FtpQueryRemoveCallback, &event,
  7174. TRUE);
  7175. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE,
  7176. NULL);
  7177. if (extension->MountedDeviceInterfaceName.Buffer) {
  7178. IoSetDeviceInterfaceState(
  7179. &extension->MountedDeviceInterfaceName, FALSE);
  7180. ExFreePool(extension->MountedDeviceInterfaceName.Buffer);
  7181. extension->MountedDeviceInterfaceName.Buffer = NULL;
  7182. }
  7183. if (irpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  7184. if (extension->DeadToPnp && !extension->DeviceDeleted) {
  7185. extension->DeviceDeleted = TRUE;
  7186. ExFreePool(extension->DeviceNodeName.Buffer);
  7187. deletePdo = TRUE;
  7188. } else {
  7189. deletePdo = FALSE;
  7190. }
  7191. } else {
  7192. deletePdo = FALSE;
  7193. }
  7194. FtpRelease(extension->Root);
  7195. // If this device is still being enumerated then don't
  7196. // delete it and wait for a start instead. If it is not
  7197. // being enumerated then blow it away.
  7198. if (deletePdo) {
  7199. IoDeleteDevice(extension->DeviceObject);
  7200. }
  7201. status = STATUS_SUCCESS;
  7202. break;
  7203. case IRP_MN_QUERY_DEVICE_RELATIONS:
  7204. if (irpSp->Parameters.QueryDeviceRelations.Type !=
  7205. TargetDeviceRelation) {
  7206. status = STATUS_NOT_SUPPORTED;
  7207. break;
  7208. }
  7209. deviceRelations = (PDEVICE_RELATIONS)
  7210. ExAllocatePool(PagedPool,
  7211. sizeof(DEVICE_RELATIONS));
  7212. if (!deviceRelations) {
  7213. status = STATUS_INSUFFICIENT_RESOURCES;
  7214. break;
  7215. }
  7216. ObReferenceObject(DeviceObject);
  7217. deviceRelations->Count = 1;
  7218. deviceRelations->Objects[0] = DeviceObject;
  7219. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  7220. status = STATUS_SUCCESS;
  7221. break;
  7222. case IRP_MN_QUERY_INTERFACE:
  7223. status = STATUS_NOT_SUPPORTED ;
  7224. break;
  7225. case IRP_MN_QUERY_CAPABILITIES:
  7226. capabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
  7227. capabilities->SilentInstall = 1;
  7228. capabilities->RawDeviceOK = 1;
  7229. capabilities->SurpriseRemovalOK = 1;
  7230. capabilities->Address = extension->VolumeNumber;
  7231. status = STATUS_SUCCESS;
  7232. break;
  7233. case IRP_MN_QUERY_ID:
  7234. status = FtpQueryId(extension, Irp);
  7235. break;
  7236. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  7237. Irp->IoStatus.Information = PNP_DEVICE_DONT_DISPLAY_IN_UI;
  7238. if ((extension->DeviceObject->Flags&DO_SYSTEM_BOOT_PARTITION) ||
  7239. extension->InPagingPath) {
  7240. Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
  7241. }
  7242. status = STATUS_SUCCESS;
  7243. break;
  7244. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  7245. return FtDiskPagingNotification(DeviceObject, Irp);
  7246. default:
  7247. status = STATUS_NOT_SUPPORTED;
  7248. break;
  7249. }
  7250. } else {
  7251. Irp->IoStatus.Information = 0;
  7252. status = STATUS_INVALID_DEVICE_REQUEST;
  7253. }
  7254. if (status != STATUS_NOT_SUPPORTED) {
  7255. Irp->IoStatus.Status = status;
  7256. } else {
  7257. status = Irp->IoStatus.Status;
  7258. }
  7259. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7260. return status;
  7261. }
  7262. class DELETE_FT_REGISTRY_WORK_ITEM : public WORK_QUEUE_ITEM {
  7263. public:
  7264. PROOT_EXTENSION RootExtension;
  7265. FT_LOGICAL_DISK_ID LogicalDiskId;
  7266. };
  7267. typedef DELETE_FT_REGISTRY_WORK_ITEM *PDELETE_FT_REGISTRY_WORK_ITEM;
  7268. VOID
  7269. FtpDeleteFtRegistryWorker(
  7270. IN PVOID WorkItem
  7271. )
  7272. {
  7273. PDELETE_FT_REGISTRY_WORK_ITEM workItem = (PDELETE_FT_REGISTRY_WORK_ITEM) WorkItem;
  7274. PROOT_EXTENSION rootExtension = workItem->RootExtension;
  7275. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet = rootExtension->DiskInfoSet;
  7276. FtpAcquire(rootExtension);
  7277. diskInfoSet->DeleteFtRegistryInfo(workItem->LogicalDiskId);
  7278. FtpRelease(rootExtension);
  7279. }
  7280. #ifdef ALLOC_PRAGMA
  7281. #pragma code_seg()
  7282. #endif
  7283. PVOLUME_EXTENSION
  7284. FtpFindExtensionCoveringPartition(
  7285. IN PROOT_EXTENSION RootExtension,
  7286. IN PDEVICE_OBJECT Partition
  7287. )
  7288. /*++
  7289. Routine Description:
  7290. This routine finds the device extension covering the given partition.
  7291. Arguments:
  7292. RootExtension - Supplies the root extension.
  7293. Partition - Supplies the partition.
  7294. Return Value:
  7295. The volume extension covering the given partition.
  7296. --*/
  7297. {
  7298. PLIST_ENTRY l;
  7299. PVOLUME_EXTENSION extension;
  7300. PFT_VOLUME vol;
  7301. for (l = RootExtension->VolumeList.Flink; l != &RootExtension->VolumeList;
  7302. l = l->Flink) {
  7303. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  7304. if (extension->TargetObject) {
  7305. if (extension->TargetObject == Partition) {
  7306. return extension;
  7307. }
  7308. continue;
  7309. }
  7310. vol = extension->FtVolume;
  7311. if (vol && vol->GetContainedLogicalDisk(Partition)) {
  7312. return extension;
  7313. }
  7314. }
  7315. return NULL;
  7316. }
  7317. VOID
  7318. FtpAcquire(
  7319. IN OUT PROOT_EXTENSION RootExtension
  7320. )
  7321. /*++
  7322. Routine Description:
  7323. This routine grabs the root semaphore.
  7324. Arguments:
  7325. RootExtension - Supplies the root extension.
  7326. Return Value:
  7327. None.
  7328. --*/
  7329. {
  7330. KeWaitForSingleObject(&RootExtension->Mutex, Executive, KernelMode,
  7331. FALSE, NULL);
  7332. }
  7333. VOID
  7334. FtpRelease(
  7335. IN OUT PROOT_EXTENSION RootExtension
  7336. )
  7337. /*++
  7338. Routine Description:
  7339. This routine releases the root semaphore.
  7340. Arguments:
  7341. RootExtension - Supplies the root extension.
  7342. Return Value:
  7343. None.
  7344. --*/
  7345. {
  7346. KeReleaseSemaphore(&RootExtension->Mutex, IO_NO_INCREMENT, 1, FALSE);
  7347. }
  7348. VOID
  7349. FtpCancelChangeNotify(
  7350. IN PDEVICE_OBJECT DeviceObject,
  7351. IN PIRP Irp
  7352. )
  7353. /*++
  7354. Routine Description:
  7355. This is the cancel routine for notification IRPs.
  7356. Arguments:
  7357. DeviceObject - Supplies the device object.
  7358. Irp - Supplies the IO request packet.
  7359. Return Value:
  7360. None
  7361. --*/
  7362. {
  7363. PVOLUME_EXTENSION Extension;
  7364. IoReleaseCancelSpinLock (Irp->CancelIrql);
  7365. Extension = (PVOLUME_EXTENSION) Irp->Tail.Overlay.DriverContext[0];
  7366. FtpAcquire(Extension->Root);
  7367. RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
  7368. FtpRelease(Extension->Root);
  7369. Irp->IoStatus.Status = STATUS_CANCELLED;
  7370. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7371. }
  7372. NTSTATUS
  7373. FtDiskCreate(
  7374. IN PDEVICE_OBJECT DeviceObject,
  7375. IN PIRP Irp
  7376. )
  7377. /*++
  7378. Routine Description:
  7379. This routine is the dispatch for IRP_MJ_CREATE.
  7380. Arguments:
  7381. DeviceObject - Supplies the device object.
  7382. Irp - Supplies the IO request block.
  7383. Return Value:
  7384. NTSTATUS
  7385. --*/
  7386. {
  7387. Irp->IoStatus.Status = STATUS_SUCCESS;
  7388. Irp->IoStatus.Information = 0;
  7389. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7390. return STATUS_SUCCESS;
  7391. }
  7392. VOID
  7393. FtpEventSignalCompletion(
  7394. IN PVOID Event,
  7395. IN NTSTATUS Status
  7396. )
  7397. /*++
  7398. Routine Description:
  7399. Completion routine of type FT_COMPLETION_ROUTINE that sets
  7400. the status of the given event to Signaled
  7401. Arguments:
  7402. Event - Supplies the event
  7403. Status - Supplies the status of the operation.
  7404. Return Value:
  7405. None.
  7406. --*/
  7407. {
  7408. KeSetEvent( (PKEVENT) Event, IO_NO_INCREMENT, FALSE );
  7409. }
  7410. VOID
  7411. FtpVolumeOnlineCallback(
  7412. IN PVOLUME_EXTENSION Extension
  7413. )
  7414. {
  7415. if (Extension->IsOffline) {
  7416. Extension->IsOffline = FALSE;
  7417. Extension->IsComplete = FALSE;
  7418. }
  7419. KeSetEvent((PKEVENT) Extension->ZeroRefContext, IO_NO_INCREMENT, FALSE);
  7420. }
  7421. VOID
  7422. FtpVolumeOfflineCallback(
  7423. IN PVOLUME_EXTENSION Extension
  7424. )
  7425. {
  7426. if (!Extension->IsOffline) {
  7427. Extension->IsOffline = TRUE;
  7428. if (Extension->FtVolume) {
  7429. Extension->FtVolume->SetDirtyBit(FALSE, NULL, NULL);
  7430. }
  7431. }
  7432. KeSetEvent((PKEVENT) Extension->ZeroRefContext, IO_NO_INCREMENT, FALSE);
  7433. }
  7434. NTSTATUS
  7435. FtpAllSystemsGo(
  7436. IN PVOLUME_EXTENSION Extension,
  7437. IN PIRP Irp,
  7438. IN BOOLEAN MustBeComplete,
  7439. IN BOOLEAN MustHaveVolume,
  7440. IN BOOLEAN MustBeOnline
  7441. )
  7442. /*++
  7443. Routine Description:
  7444. This routine checks the device extension states to make sure that the
  7445. IRP can proceed. If the IRP can proceed then the device extension ref
  7446. count is incremented. If the IRP is queued then STATUS_PENDING returned.
  7447. Arguments:
  7448. Extension - Supplies the device extension.
  7449. Irp - Supplies the I/O request packet.
  7450. MustBeComplete - Supplies whether or not the FT set must be complete.
  7451. MustHaveVolume - Supplies whether or not the PDO still refers to an
  7452. existing volume.
  7453. MustBeOnline - Supplies whether or not the volume must be online.
  7454. Return Value:
  7455. STATUS_PENDING - The IRP was put on the ZeroRef queue.
  7456. STATUS_SUCCESS - The IRP can proceed. The ref count was incremented.
  7457. !NT_SUCCESS(status) - The IRP must fail with the status returned.
  7458. --*/
  7459. {
  7460. KIRQL irql;
  7461. PFT_VOLUME vol;
  7462. BOOLEAN deleteFtRegistryInfo;
  7463. PDELETE_FT_REGISTRY_WORK_ITEM workItem;
  7464. if (MustBeComplete) {
  7465. MustHaveVolume = TRUE;
  7466. MustBeOnline = TRUE;
  7467. }
  7468. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  7469. if (MustHaveVolume && !Extension->TargetObject && !Extension->FtVolume) {
  7470. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7471. return STATUS_NO_SUCH_DEVICE;
  7472. }
  7473. if (!Extension->IsStarted) {
  7474. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7475. return STATUS_NO_SUCH_DEVICE;
  7476. }
  7477. if (MustBeOnline && Extension->IsOffline) {
  7478. if (Extension->DeviceObject->Flags&DO_SYSTEM_BOOT_PARTITION) {
  7479. Extension->IsOffline = FALSE;
  7480. } else {
  7481. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7482. return STATUS_NO_SUCH_DEVICE;
  7483. }
  7484. }
  7485. if (Extension->ZeroRefCallback || Extension->RemoveInProgress) {
  7486. ASSERT(Irp);
  7487. IoMarkIrpPending(Irp);
  7488. InsertTailList(&Extension->ZeroRefHoldQueue,
  7489. &Irp->Tail.Overlay.ListEntry);
  7490. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7491. return STATUS_PENDING;
  7492. }
  7493. if (Extension->TargetObject) {
  7494. InterlockedIncrement(&Extension->RefCount);
  7495. if (!Extension->IsOffline) {
  7496. InterlockedExchange(&Extension->AllSystemsGo, TRUE);
  7497. }
  7498. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7499. return STATUS_SUCCESS;
  7500. }
  7501. if (!MustBeComplete || Extension->IsComplete) {
  7502. InterlockedIncrement(&Extension->RefCount);
  7503. if (Extension->IsComplete && MustHaveVolume && !Extension->IsOffline) {
  7504. InterlockedExchange(&Extension->AllSystemsGo, TRUE);
  7505. }
  7506. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7507. return STATUS_SUCCESS;
  7508. }
  7509. vol = Extension->FtVolume;
  7510. ASSERT(vol);
  7511. if (!vol->IsComplete(TRUE)) {
  7512. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7513. return STATUS_NO_SUCH_DEVICE;
  7514. }
  7515. vol->CompleteNotification(TRUE);
  7516. if (vol->IsComplete(FALSE)) {
  7517. deleteFtRegistryInfo = FALSE;
  7518. } else {
  7519. deleteFtRegistryInfo = TRUE;
  7520. }
  7521. Extension->IsComplete = TRUE;
  7522. InterlockedIncrement(&Extension->RefCount);
  7523. InterlockedIncrement(&Extension->RefCount);
  7524. InterlockedExchange(&Extension->AllSystemsGo, TRUE);
  7525. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7526. vol->StartSyncOperations(FALSE, FtpRefCountCompletion, Extension);
  7527. vol->SetDirtyBit(TRUE, NULL, NULL);
  7528. if (deleteFtRegistryInfo) {
  7529. workItem = (PDELETE_FT_REGISTRY_WORK_ITEM)
  7530. ExAllocatePool(NonPagedPool,
  7531. sizeof(DELETE_FT_REGISTRY_WORK_ITEM));
  7532. if (!workItem) {
  7533. return STATUS_SUCCESS;
  7534. }
  7535. ExInitializeWorkItem(workItem, FtpDeleteFtRegistryWorker, workItem);
  7536. workItem->RootExtension = Extension->Root;
  7537. workItem->LogicalDiskId = vol->QueryLogicalDiskId();
  7538. FtpQueueWorkItem(Extension->Root, workItem);
  7539. }
  7540. return STATUS_SUCCESS;
  7541. }
  7542. VOID
  7543. FtpZeroRefCallback(
  7544. IN PVOLUME_EXTENSION Extension,
  7545. IN ZERO_REF_CALLBACK ZeroRefCallback,
  7546. IN PVOID ZeroRefContext,
  7547. IN BOOLEAN AcquireSemaphore
  7548. )
  7549. /*++
  7550. Routine Description:
  7551. This routine sets up the given zero ref callback and state.
  7552. Arguments:
  7553. Extension - Supplies the device extension.
  7554. ZeroRefCallback - Supplies the zero ref callback.
  7555. ZeroRefContext - Supplies the zero ref context.
  7556. AcquireSemaphore - Supplies whether or not to acquire the semaphore.
  7557. Return Value:
  7558. None.
  7559. --*/
  7560. {
  7561. KIRQL irql;
  7562. if (AcquireSemaphore) {
  7563. KeWaitForSingleObject(&Extension->Semaphore, Executive, KernelMode,
  7564. FALSE, NULL);
  7565. }
  7566. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  7567. InterlockedExchange(&Extension->AllSystemsGo, FALSE);
  7568. ASSERT(!Extension->ZeroRefCallback);
  7569. Extension->ZeroRefCallback = ZeroRefCallback;
  7570. Extension->ZeroRefContext = ZeroRefContext;
  7571. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7572. if (Extension->FtVolume) {
  7573. Extension->FtVolume->StopSyncOperations();
  7574. }
  7575. FtpDecrementRefCount(Extension);
  7576. }
  7577. NTSTATUS
  7578. FtDiskPower(
  7579. IN PDEVICE_OBJECT DeviceObject,
  7580. IN PIRP Irp
  7581. )
  7582. /*++
  7583. Routine Description:
  7584. This routine is the dispatch for IRP_MJ_PNP.
  7585. Arguments:
  7586. DeviceObject - Supplies the device object.
  7587. Irp - Supplies the IO request packet.
  7588. Return Value:
  7589. NTSTATUS
  7590. --*/
  7591. {
  7592. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  7593. PROOT_EXTENSION rootExtension = extension->Root;
  7594. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  7595. NTSTATUS status;
  7596. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  7597. PoStartNextPowerIrp(Irp);
  7598. IoSkipCurrentIrpStackLocation(Irp);
  7599. return PoCallDriver(rootExtension->TargetObject, Irp);
  7600. }
  7601. switch (irpSp->MinorFunction) {
  7602. case IRP_MN_WAIT_WAKE:
  7603. case IRP_MN_POWER_SEQUENCE:
  7604. case IRP_MN_SET_POWER:
  7605. case IRP_MN_QUERY_POWER:
  7606. status = STATUS_SUCCESS;
  7607. break;
  7608. default:
  7609. status = Irp->IoStatus.Status;
  7610. break;
  7611. }
  7612. Irp->IoStatus.Status = status;
  7613. PoStartNextPowerIrp(Irp);
  7614. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7615. return status;
  7616. }
  7617. VOID
  7618. FtpWorkerThread(
  7619. IN PVOID RootExtension
  7620. )
  7621. /*++
  7622. Routine Description:
  7623. This is a worker thread to process work queue items.
  7624. Arguments:
  7625. RootExtension - Supplies the root device extension.
  7626. Return Value:
  7627. None.
  7628. --*/
  7629. {
  7630. PROOT_EXTENSION extension = (PROOT_EXTENSION) RootExtension;
  7631. KIRQL irql;
  7632. PLIST_ENTRY l;
  7633. PWORK_QUEUE_ITEM queueItem;
  7634. for (;;) {
  7635. KeWaitForSingleObject(&extension->WorkerSemaphore,
  7636. Executive, KernelMode, FALSE, NULL);
  7637. KeAcquireSpinLock(&extension->SpinLock, &irql);
  7638. if (extension->TerminateThread) {
  7639. KeReleaseSpinLock(&extension->SpinLock, irql);
  7640. PsTerminateSystemThread(STATUS_SUCCESS);
  7641. return;
  7642. }
  7643. ASSERT(!IsListEmpty(&extension->WorkerQueue));
  7644. l = RemoveHeadList(&extension->WorkerQueue);
  7645. KeReleaseSpinLock(&extension->SpinLock, irql);
  7646. queueItem = CONTAINING_RECORD(l, WORK_QUEUE_ITEM, List);
  7647. queueItem->WorkerRoutine(queueItem->Parameter);
  7648. ExFreePool(queueItem);
  7649. }
  7650. }
  7651. VOID
  7652. FtpEmptyQueueAtDispatchLevel(
  7653. IN OUT PVOLUME_EXTENSION Extension,
  7654. IN OUT PLIST_ENTRY IrpQueue
  7655. )
  7656. /*++
  7657. Routine Description:
  7658. This routine empties the given queue of irps that are callable at
  7659. dispatch level by calling their respective dispatch routines.
  7660. Arguments:
  7661. Extension - Supplies the device extension.
  7662. IrpQueue - Supplies the queue of IRPs.
  7663. Return Value:
  7664. None.
  7665. --*/
  7666. {
  7667. PDRIVER_OBJECT driverObject;
  7668. PDEVICE_OBJECT deviceObject;
  7669. PLIST_ENTRY l, tmp;
  7670. PIRP irp;
  7671. PIO_STACK_LOCATION irpSp;
  7672. driverObject = Extension->Root->DriverObject;
  7673. deviceObject = Extension->DeviceObject;
  7674. for (l = IrpQueue->Flink; l != IrpQueue; l = l->Flink) {
  7675. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  7676. irpSp = IoGetCurrentIrpStackLocation(irp);
  7677. switch (irpSp->MajorFunction) {
  7678. case IRP_MJ_POWER:
  7679. case IRP_MJ_READ:
  7680. case IRP_MJ_WRITE:
  7681. tmp = l->Blink;
  7682. RemoveEntryList(l);
  7683. l = tmp;
  7684. driverObject->MajorFunction[irpSp->MajorFunction](
  7685. deviceObject, irp);
  7686. break;
  7687. }
  7688. }
  7689. }
  7690. VOID
  7691. FtpDecrementRefCount(
  7692. IN OUT PVOLUME_EXTENSION Extension
  7693. )
  7694. /*++
  7695. Routine Description:
  7696. This routine decrements the ref count and handles the case
  7697. when the ref count goes to zero.
  7698. Arguments:
  7699. Extension - Supplies the volume extension.
  7700. Return Value:
  7701. None.
  7702. --*/
  7703. {
  7704. LONG count;
  7705. KIRQL irql;
  7706. BOOLEAN startSync, list;
  7707. LIST_ENTRY q;
  7708. PEMPTY_IRP_QUEUE_WORK_ITEM workItem;
  7709. PLIST_ENTRY l;
  7710. PIRP irp;
  7711. count = InterlockedDecrement(&Extension->RefCount);
  7712. if (count) {
  7713. return;
  7714. }
  7715. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  7716. if (!Extension->ZeroRefCallback) {
  7717. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7718. return;
  7719. }
  7720. Extension->ZeroRefCallback(Extension);
  7721. Extension->ZeroRefCallback = NULL;
  7722. InterlockedIncrement(&Extension->RefCount);
  7723. if (Extension->FtVolume && Extension->IsComplete && Extension->IsStarted &&
  7724. !Extension->IsOffline) {
  7725. startSync = TRUE;
  7726. InterlockedIncrement(&Extension->RefCount);
  7727. } else {
  7728. startSync = FALSE;
  7729. }
  7730. if (IsListEmpty(&Extension->ZeroRefHoldQueue) ||
  7731. Extension->RemoveInProgress) {
  7732. list = FALSE;
  7733. } else {
  7734. list = TRUE;
  7735. q = Extension->ZeroRefHoldQueue;
  7736. InitializeListHead(&Extension->ZeroRefHoldQueue);
  7737. }
  7738. KeReleaseSpinLock(&Extension->SpinLock, irql);
  7739. KeReleaseSemaphore(&Extension->Semaphore, IO_NO_INCREMENT, 1, FALSE);
  7740. if (startSync) {
  7741. Extension->FtVolume->StartSyncOperations(FALSE, FtpRefCountCompletion,
  7742. Extension);
  7743. }
  7744. if (!list) {
  7745. return;
  7746. }
  7747. q.Flink->Blink = &q;
  7748. q.Blink->Flink = &q;
  7749. FtpEmptyQueueAtDispatchLevel(Extension, &q);
  7750. if (IsListEmpty(&q)) {
  7751. return;
  7752. }
  7753. workItem = (PEMPTY_IRP_QUEUE_WORK_ITEM)
  7754. ExAllocatePool(NonPagedPool,
  7755. sizeof(EMPTY_IRP_QUEUE_WORK_ITEM));
  7756. if (!workItem) {
  7757. workItem = (PEMPTY_IRP_QUEUE_WORK_ITEM)
  7758. ExAllocatePool(NonPagedPool,
  7759. sizeof(EMPTY_IRP_QUEUE_WORK_ITEM));
  7760. if (!workItem) {
  7761. while (!IsListEmpty(&q)) {
  7762. l = RemoveHeadList(&q);
  7763. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  7764. irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  7765. irp->IoStatus.Information = 0;
  7766. IoCompleteRequest(irp, IO_NO_INCREMENT);
  7767. }
  7768. return;
  7769. }
  7770. }
  7771. ExInitializeWorkItem(workItem, FtpEmptyQueueWorkerRoutine, workItem);
  7772. workItem->IrpQueue = q;
  7773. workItem->IrpQueue.Flink->Blink = &workItem->IrpQueue;
  7774. workItem->IrpQueue.Blink->Flink = &workItem->IrpQueue;
  7775. workItem->Extension = Extension;
  7776. ExQueueWorkItem(workItem, CriticalWorkQueue);
  7777. }
  7778. NTSTATUS
  7779. FtDiskAddDevice(
  7780. IN PDRIVER_OBJECT DriverObject,
  7781. IN PDEVICE_OBJECT PhysicalDeviceObject
  7782. )
  7783. /*++
  7784. Routine Description:
  7785. This routine creates and initializes a new FDO for the corresponding
  7786. PDO.
  7787. Arguments:
  7788. DriverObject - Supplies the FTDISK driver object.
  7789. PhysicalDeviceObject - Supplies the physical device object.
  7790. Return Value:
  7791. NTSTATUS
  7792. --*/
  7793. {
  7794. UNICODE_STRING deviceName, dosName;
  7795. NTSTATUS status;
  7796. PDEVICE_OBJECT deviceObject;
  7797. PROOT_EXTENSION rootExtension;
  7798. HANDLE handle;
  7799. KIRQL irql;
  7800. //
  7801. // Create the FT root device.
  7802. //
  7803. RtlInitUnicodeString(&deviceName, DD_FT_CONTROL_DEVICE_NAME);
  7804. status = IoCreateDevice(DriverObject, sizeof(ROOT_EXTENSION),
  7805. &deviceName, FILE_DEVICE_NETWORK,
  7806. FILE_DEVICE_SECURE_OPEN, FALSE,
  7807. &deviceObject);
  7808. if (!NT_SUCCESS(status)) {
  7809. return status;
  7810. }
  7811. RtlInitUnicodeString(&dosName, L"\\DosDevices\\FtControl");
  7812. IoCreateSymbolicLink(&dosName, &deviceName);
  7813. rootExtension = (PROOT_EXTENSION) deviceObject->DeviceExtension;
  7814. RtlZeroMemory(rootExtension, sizeof(ROOT_EXTENSION));
  7815. rootExtension->DeviceObject = deviceObject;
  7816. rootExtension->Root = rootExtension;
  7817. rootExtension->DeviceExtensionType = DEVICE_EXTENSION_ROOT;
  7818. KeInitializeSpinLock(&rootExtension->SpinLock);
  7819. rootExtension->DriverObject = DriverObject;
  7820. rootExtension->TargetObject =
  7821. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  7822. if (!rootExtension->TargetObject) {
  7823. IoDeleteSymbolicLink(&dosName);
  7824. IoDeleteDevice(deviceObject);
  7825. return STATUS_NO_SUCH_DEVICE;
  7826. }
  7827. rootExtension->Pdo = PhysicalDeviceObject;
  7828. InitializeListHead(&rootExtension->VolumeList);
  7829. InitializeListHead(&rootExtension->DeadVolumeList);
  7830. rootExtension->NextVolumeNumber = 1;
  7831. rootExtension->DiskInfoSet = new FT_LOGICAL_DISK_INFORMATION_SET;
  7832. if (!rootExtension->DiskInfoSet) {
  7833. IoDeleteSymbolicLink(&dosName);
  7834. IoDetachDevice(rootExtension->TargetObject);
  7835. IoDeleteDevice(deviceObject);
  7836. return STATUS_INSUFFICIENT_RESOURCES;
  7837. }
  7838. status = rootExtension->DiskInfoSet->Initialize();
  7839. if (!NT_SUCCESS(status)) {
  7840. delete rootExtension->DiskInfoSet;
  7841. IoDeleteSymbolicLink(&dosName);
  7842. IoDetachDevice(rootExtension->TargetObject);
  7843. IoDeleteDevice(deviceObject);
  7844. return status;
  7845. }
  7846. InitializeListHead(&rootExtension->WorkerQueue);
  7847. KeInitializeSemaphore(&rootExtension->WorkerSemaphore, 0, MAXLONG);
  7848. rootExtension->TerminateThread = TRUE;
  7849. InitializeListHead(&rootExtension->ChangeNotifyIrpList);
  7850. KeInitializeSemaphore(&rootExtension->Mutex, 1, 1);
  7851. status = IoRegisterShutdownNotification(deviceObject);
  7852. if (!NT_SUCCESS(status)) {
  7853. delete rootExtension->DiskInfoSet;
  7854. IoDeleteSymbolicLink(&dosName);
  7855. IoDetachDevice(rootExtension->TargetObject);
  7856. IoDeleteDevice(deviceObject);
  7857. return status;
  7858. }
  7859. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  7860. return STATUS_SUCCESS;
  7861. }
  7862. NTSTATUS
  7863. FtpRefCountCompletionRoutine(
  7864. IN PDEVICE_OBJECT DeviceObject,
  7865. IN PIRP Irp,
  7866. IN PVOID Extension
  7867. )
  7868. /*++
  7869. Routine Description:
  7870. This routine decrements the ref count in the device extension.
  7871. Arguments:
  7872. DeviceObject - Supplies the device object.
  7873. Irp - Supplies the IO request packet.
  7874. Extension - Supplies the device extension.
  7875. Return Value:
  7876. NTSTATUS
  7877. --*/
  7878. {
  7879. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Extension;
  7880. if (extension->CountersEnabled) {
  7881. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  7882. if (irpStack->MajorFunction == IRP_MJ_READ ||
  7883. irpStack->MajorFunction == IRP_MJ_WRITE) {
  7884. PPMWMICOUNTERLIB_CONTEXT counterLib;
  7885. counterLib = &extension->Root->PmWmiCounterLibContext;
  7886. counterLib->PmWmiCounterIoComplete(
  7887. extension->PmWmiCounterContext, Irp,
  7888. (PLARGE_INTEGER) &irpStack->Parameters.Read);
  7889. }
  7890. }
  7891. FtpDecrementRefCount(extension);
  7892. return STATUS_SUCCESS;
  7893. }
  7894. NTSTATUS
  7895. FtDiskReadWrite(
  7896. IN PDEVICE_OBJECT DeviceObject,
  7897. IN PIRP Irp
  7898. )
  7899. /*++
  7900. Routine Description:
  7901. This routine is the dispatch for IRP_MJ_READ and IRP_MJ_WRITE.
  7902. Arguments:
  7903. DeviceObject - Supplies the device object.
  7904. Irp - Supplies the IO request packet.
  7905. Return Value:
  7906. NTSTATUS
  7907. --*/
  7908. {
  7909. PVOLUME_EXTENSION extension;
  7910. NTSTATUS status;
  7911. PFT_VOLUME vol;
  7912. PDISPATCH_TP packet;
  7913. KIRQL irql;
  7914. PIO_STACK_LOCATION irpSp;
  7915. LONGLONG offset;
  7916. ULONG length;
  7917. extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  7918. if (extension->DeviceExtensionType != DEVICE_EXTENSION_VOLUME) {
  7919. Irp->IoStatus.Information = 0;
  7920. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  7921. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7922. return STATUS_NO_SUCH_DEVICE;
  7923. }
  7924. InterlockedIncrement(&extension->RefCount);
  7925. if (!extension->AllSystemsGo) {
  7926. FtpDecrementRefCount(extension);
  7927. status = FtpAllSystemsGo(extension, Irp, TRUE, TRUE, TRUE);
  7928. if (status == STATUS_PENDING) {
  7929. return STATUS_PENDING;
  7930. }
  7931. if (!NT_SUCCESS(status)) {
  7932. Irp->IoStatus.Information = 0;
  7933. Irp->IoStatus.Status = status;
  7934. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7935. return status;
  7936. }
  7937. }
  7938. if (extension->IsReadOnly) {
  7939. irpSp = IoGetCurrentIrpStackLocation(Irp);
  7940. if (irpSp->MajorFunction == IRP_MJ_WRITE) {
  7941. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  7942. Irp->IoStatus.Information = 0;
  7943. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7944. return STATUS_INVALID_DEVICE_REQUEST;
  7945. }
  7946. }
  7947. if (extension->TargetObject) {
  7948. IoCopyCurrentIrpStackLocationToNext(Irp);
  7949. if (extension->WholeDisk) {
  7950. irpSp = IoGetNextIrpStackLocation(Irp);
  7951. offset = irpSp->Parameters.Read.ByteOffset.QuadPart;
  7952. length = irpSp->Parameters.Read.Length;
  7953. if (offset < 0 || offset + length > extension->PartitionLength) {
  7954. FtpDecrementRefCount(extension);
  7955. Irp->IoStatus.Information = 0;
  7956. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  7957. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  7958. return STATUS_INVALID_PARAMETER;
  7959. }
  7960. if (extension->CountersEnabled) {
  7961. PIO_STACK_LOCATION currentIrpStack =
  7962. IoGetCurrentIrpStackLocation(Irp);
  7963. PPMWMICOUNTERLIB_CONTEXT counterLib;
  7964. counterLib = &extension->Root->PmWmiCounterLibContext;
  7965. counterLib->PmWmiCounterIoStart(
  7966. extension->PmWmiCounterContext,
  7967. (PLARGE_INTEGER) &currentIrpStack->Parameters.Read);
  7968. }
  7969. irpSp->Parameters.Read.ByteOffset.QuadPart +=
  7970. extension->PartitionOffset;
  7971. IoSetCompletionRoutine(Irp, FtpRefCountCompletionRoutine,
  7972. extension, TRUE, TRUE, TRUE);
  7973. IoMarkIrpPending(Irp);
  7974. IoCallDriver(extension->WholeDisk, Irp);
  7975. } else {
  7976. if (extension->CountersEnabled) {
  7977. PIO_STACK_LOCATION currentIrpStack =
  7978. IoGetCurrentIrpStackLocation(Irp);
  7979. PPMWMICOUNTERLIB_CONTEXT counterLib;
  7980. counterLib = &extension->Root->PmWmiCounterLibContext;
  7981. counterLib->PmWmiCounterIoStart(
  7982. extension->PmWmiCounterContext,
  7983. (PLARGE_INTEGER) &currentIrpStack->Parameters.Read);
  7984. }
  7985. IoSetCompletionRoutine(Irp, FtpRefCountCompletionRoutine,
  7986. extension, TRUE, TRUE, TRUE);
  7987. IoMarkIrpPending(Irp);
  7988. IoCallDriver(extension->TargetObject, Irp);
  7989. }
  7990. return STATUS_PENDING;
  7991. }
  7992. vol = extension->FtVolume;
  7993. ASSERT(vol);
  7994. packet = new DISPATCH_TP;
  7995. if (!packet) {
  7996. KeAcquireSpinLock(&extension->SpinLock, &irql);
  7997. if (extension->EmergencyTransferPacketInUse) {
  7998. IoMarkIrpPending(Irp);
  7999. InsertTailList(&extension->
  8000. EmergencyTransferPacketQueue,
  8001. &Irp->Tail.Overlay.ListEntry);
  8002. KeReleaseSpinLock(&extension->SpinLock, irql);
  8003. return STATUS_PENDING;
  8004. }
  8005. packet = extension->EmergencyTransferPacket;
  8006. extension->EmergencyTransferPacketInUse = TRUE;
  8007. KeReleaseSpinLock(&extension->SpinLock, irql);
  8008. }
  8009. irpSp = IoGetCurrentIrpStackLocation(Irp);
  8010. packet->Mdl = Irp->MdlAddress;
  8011. packet->OriginalIrp = Irp;
  8012. packet->Offset = irpSp->Parameters.Read.ByteOffset.QuadPart;
  8013. packet->Length = irpSp->Parameters.Read.Length;
  8014. packet->CompletionRoutine = FtpReadWriteCompletionRoutine;
  8015. packet->TargetVolume = vol;
  8016. packet->Thread = Irp->Tail.Overlay.Thread;
  8017. packet->IrpFlags = irpSp->Flags;
  8018. if (irpSp->MajorFunction == IRP_MJ_READ) {
  8019. packet->ReadPacket = TRUE;
  8020. } else {
  8021. packet->ReadPacket = FALSE;
  8022. }
  8023. packet->Irp = Irp;
  8024. packet->Extension = extension;
  8025. if (extension->CountersEnabled) {
  8026. PPMWMICOUNTERLIB_CONTEXT counterLib;
  8027. counterLib = &extension->Root->PmWmiCounterLibContext;
  8028. counterLib->PmWmiCounterIoStart(
  8029. extension->PmWmiCounterContext,
  8030. (PLARGE_INTEGER) &irpSp->Parameters.Read);
  8031. }
  8032. IoMarkIrpPending(Irp);
  8033. TRANSFER(packet);
  8034. return STATUS_PENDING;
  8035. }
  8036. NTSTATUS
  8037. FtpSetPowerState(
  8038. IN PROOT_EXTENSION RootExtension,
  8039. IN PIRP Irp
  8040. )
  8041. /*++
  8042. Routine Description:
  8043. This routine sets the power state for the volume from the power state
  8044. given to it by the disk.
  8045. Arguments:
  8046. RootExtension - Supplies the root extension.
  8047. Irp - Supplies the I/O request packet.
  8048. Return Value:
  8049. NTSTATUS
  8050. --*/
  8051. {
  8052. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  8053. PVOLMGR_POWER_STATE input = (PVOLMGR_POWER_STATE) Irp->AssociatedIrp.SystemBuffer;
  8054. PVOLUME_EXTENSION extension;
  8055. KIRQL irql;
  8056. POWER_STATE powerState;
  8057. if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  8058. sizeof(VOLMGR_POWER_STATE)) {
  8059. return STATUS_INVALID_PARAMETER;
  8060. }
  8061. extension = FtpFindExtensionCoveringPartition(
  8062. RootExtension, input->PartitionDeviceObject);
  8063. if (!extension) {
  8064. return STATUS_INVALID_DEVICE_REQUEST;
  8065. }
  8066. KeAcquireSpinLock(&extension->SpinLock, &irql);
  8067. if (extension->PowerState == input->PowerState) {
  8068. KeReleaseSpinLock(&extension->SpinLock, irql);
  8069. return STATUS_SUCCESS;
  8070. }
  8071. extension->PowerState = input->PowerState;
  8072. KeReleaseSpinLock(&extension->SpinLock, irql);
  8073. powerState.DeviceState = input->PowerState;
  8074. PoSetPowerState(extension->DeviceObject, DevicePowerState, powerState);
  8075. PoRequestPowerIrp(extension->DeviceObject, IRP_MN_SET_POWER,
  8076. powerState, NULL, NULL, NULL);
  8077. return STATUS_SUCCESS;
  8078. }
  8079. NTSTATUS
  8080. FtDiskInternalDeviceControl(
  8081. IN PDEVICE_OBJECT DeviceObject,
  8082. IN PIRP Irp
  8083. )
  8084. /*++
  8085. Routine Description:
  8086. This routine is the dispatch for IRP_MJ_DEVICE_CONTROL.
  8087. Arguments:
  8088. DeviceObject - Supplies the device object.
  8089. Irp - Supplies the IO request packet.
  8090. Return Value:
  8091. NTSTATUS
  8092. --*/
  8093. {
  8094. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  8095. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  8096. NTSTATUS status;
  8097. Irp->IoStatus.Information = 0;
  8098. FtpAcquire(extension->Root);
  8099. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  8100. case IOCTL_INTERNAL_VOLMGR_PARTITION_ARRIVED:
  8101. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8102. status = FtpPartitionArrived(extension->Root, Irp);
  8103. } else {
  8104. status = STATUS_INVALID_PARAMETER;
  8105. }
  8106. break;
  8107. case IOCTL_INTERNAL_VOLMGR_PARTITION_REMOVED:
  8108. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8109. status = FtpPartitionRemoved(extension->Root, Irp);
  8110. } else {
  8111. status = STATUS_INVALID_PARAMETER;
  8112. }
  8113. break;
  8114. case IOCTL_INTERNAL_VOLMGR_WHOLE_DISK_REMOVED:
  8115. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8116. status = FtpWholeDiskRemoved(extension->Root, Irp);
  8117. } else {
  8118. status = STATUS_INVALID_PARAMETER;
  8119. }
  8120. break;
  8121. case IOCTL_INTERNAL_VOLMGR_REFERENCE_DEPENDANT_VOLUMES:
  8122. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8123. status = FtpReferenceDependantVolume(extension->Root, Irp);
  8124. } else {
  8125. status = STATUS_INVALID_PARAMETER;
  8126. }
  8127. break;
  8128. case IOCTL_INTERNAL_VOLMGR_QUERY_CHANGE_PARTITION:
  8129. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8130. status = FtpQueryChangePartition(extension->Root, Irp);
  8131. } else {
  8132. status = STATUS_INVALID_PARAMETER;
  8133. }
  8134. break;
  8135. case IOCTL_INTERNAL_VOLMGR_CANCEL_CHANGE_PARTITION:
  8136. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8137. status = STATUS_SUCCESS;
  8138. } else {
  8139. status = STATUS_INVALID_PARAMETER;
  8140. }
  8141. break;
  8142. case IOCTL_INTERNAL_VOLMGR_PARTITION_CHANGED:
  8143. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8144. status = FtpPartitionChanged(extension->Root, Irp);
  8145. } else {
  8146. status = STATUS_INVALID_PARAMETER;
  8147. }
  8148. break;
  8149. case IOCTL_INTERNAL_VOLMGR_PMWMICOUNTERLIB_CONTEXT:
  8150. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8151. status = FtpPmWmiCounterLibContext(extension->Root, Irp);
  8152. } else {
  8153. status = STATUS_INVALID_PARAMETER;
  8154. }
  8155. break;
  8156. case IOCTL_INTERNAL_VOLMGR_SET_POWER_STATE:
  8157. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8158. status = FtpSetPowerState(extension->Root, Irp);
  8159. } else {
  8160. status = STATUS_INVALID_PARAMETER;
  8161. }
  8162. break;
  8163. default:
  8164. status = STATUS_INVALID_DEVICE_REQUEST;
  8165. break;
  8166. }
  8167. FtpRelease(extension->Root);
  8168. Irp->IoStatus.Status = status;
  8169. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8170. return status;
  8171. }
  8172. VOID
  8173. FtpVolumeReadOnlyCallback(
  8174. IN PVOLUME_EXTENSION Extension
  8175. )
  8176. {
  8177. if (Extension->ZeroRefContext) {
  8178. Extension->IsReadOnly = TRUE;
  8179. } else {
  8180. Extension->IsReadOnly = FALSE;
  8181. }
  8182. }
  8183. VOID
  8184. FtpSetTargetCallback(
  8185. IN PVOLUME_EXTENSION Extension
  8186. )
  8187. /*++
  8188. Routine Description:
  8189. This routine sets the given target object.
  8190. Arguments:
  8191. Extension - Supplies the volume extension.
  8192. Return Value:
  8193. None.
  8194. --*/
  8195. {
  8196. PSET_TARGET_CONTEXT context = (PSET_TARGET_CONTEXT) Extension->ZeroRefContext;
  8197. Extension->OldWholeDiskPdo = Extension->WholeDiskPdo;
  8198. Extension->TargetObject = context->TargetObject;
  8199. Extension->FtVolume = context->FtVolume;
  8200. Extension->WholeDiskPdo = context->WholeDiskPdo;
  8201. Extension->WholeDisk = NULL;
  8202. Extension->PartitionOffset = 0;
  8203. Extension->PartitionLength = 0;
  8204. KeSetEvent(&context->Event, IO_NO_INCREMENT, FALSE);
  8205. }
  8206. VOID
  8207. FtpCancelRoutine(
  8208. IN OUT PDEVICE_OBJECT DeviceObject,
  8209. IN OUT PIRP Irp
  8210. )
  8211. /*++
  8212. Routine Description:
  8213. This routine is called on when the given IRP is cancelled. It
  8214. will dequeue this IRP off the work queue and complete the
  8215. request as CANCELLED.
  8216. Arguments:
  8217. DeviceObject - Supplies the device object.
  8218. Irp - Supplies the IRP.
  8219. Return Value:
  8220. None.
  8221. --*/
  8222. {
  8223. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  8224. IoReleaseCancelSpinLock(Irp->CancelIrql);
  8225. Irp->IoStatus.Status = STATUS_CANCELLED;
  8226. Irp->IoStatus.Information = 0;
  8227. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8228. }
  8229. NTSTATUS
  8230. FtpChangeNotify(
  8231. IN OUT PROOT_EXTENSION RootExtension,
  8232. IN OUT PIRP Irp
  8233. )
  8234. /*++
  8235. Routine Description:
  8236. This routine queues up a change notify IRP to be completed when
  8237. a change occurs in the FT state.
  8238. Arguments:
  8239. Extension - Supplies the root extension.
  8240. Irp - Supplies the I/O request packet.
  8241. Return Value:
  8242. NTSTATUS
  8243. --*/
  8244. {
  8245. KIRQL irql;
  8246. NTSTATUS status;
  8247. Irp->IoStatus.Status = STATUS_SUCCESS;
  8248. Irp->IoStatus.Information = 0;
  8249. IoAcquireCancelSpinLock(&irql);
  8250. if (Irp->Cancel) {
  8251. status = STATUS_CANCELLED;
  8252. } else {
  8253. InsertTailList(&RootExtension->ChangeNotifyIrpList,
  8254. &Irp->Tail.Overlay.ListEntry);
  8255. status = STATUS_PENDING;
  8256. IoMarkIrpPending(Irp);
  8257. IoSetCancelRoutine(Irp, FtpCancelRoutine);
  8258. }
  8259. IoReleaseCancelSpinLock(irql);
  8260. if (status != STATUS_PENDING) {
  8261. Irp->IoStatus.Status = status;
  8262. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8263. }
  8264. return status;
  8265. }
  8266. VOID
  8267. FtDiskShutdownFlushCompletionRoutine(
  8268. IN PVOID Irp,
  8269. IN NTSTATUS Status
  8270. )
  8271. /*++
  8272. Routine Description:
  8273. This is the completion routine for FtDiskShutdownFlush and
  8274. FtDiskPagingNotification.
  8275. Arguments:
  8276. Irp - IRP involved.
  8277. Status - Status of operation.
  8278. Return Value:
  8279. None.
  8280. --*/
  8281. {
  8282. PIRP irp = (PIRP) Irp;
  8283. PIO_STACK_LOCATION irpSp;
  8284. PVOLUME_EXTENSION extension;
  8285. irpSp = IoGetCurrentIrpStackLocation(irp);
  8286. extension = (PVOLUME_EXTENSION) irpSp->DeviceObject->DeviceExtension;
  8287. FtpDecrementRefCount(extension);
  8288. irp->IoStatus.Status = Status;
  8289. irp->IoStatus.Information = 0;
  8290. if (irpSp->MajorFunction == IRP_MJ_POWER) {
  8291. PoStartNextPowerIrp(irp);
  8292. }
  8293. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  8294. }
  8295. typedef struct _FTP_SHUTDOWN_CONTEXT {
  8296. PIRP Irp;
  8297. LONG RefCount;
  8298. } FTP_SHUTDOWN_CONTEXT, *PFTP_SHUTDOWN_CONTEXT;
  8299. NTSTATUS
  8300. FtDiskShutdownFlush(
  8301. IN PDEVICE_OBJECT DeviceObject,
  8302. IN PIRP Irp
  8303. )
  8304. /*++
  8305. Routine Description:
  8306. This routine is the dispatch for IRP_MJ_SHUTDOWN and IRP_MJ_FLUSH.
  8307. Arguments:
  8308. DeviceObject - Supplies the device object.
  8309. Irp - Supplies the IO request packet.
  8310. Return Value:
  8311. NTSTATUS
  8312. --*/
  8313. {
  8314. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) DeviceObject->DeviceExtension;
  8315. PROOT_EXTENSION rootExtension;
  8316. ULONG numVolumes, i;
  8317. PVOLUME_EXTENSION* arrayOfVolumes;
  8318. PLIST_ENTRY l;
  8319. NTSTATUS status;
  8320. PFT_VOLUME vol;
  8321. PFTP_SHUTDOWN_CONTEXT context;
  8322. PIO_STACK_LOCATION irpSp;
  8323. if (extension->DeviceExtensionType == DEVICE_EXTENSION_ROOT) {
  8324. rootExtension = (PROOT_EXTENSION) extension;
  8325. FtpAcquire(rootExtension);
  8326. numVolumes = rootExtension->NextVolumeNumber;
  8327. arrayOfVolumes = (PVOLUME_EXTENSION*)
  8328. ExAllocatePool(PagedPool,
  8329. numVolumes*sizeof(PVOLUME_EXTENSION));
  8330. if (!arrayOfVolumes) {
  8331. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  8332. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8333. return STATUS_INSUFFICIENT_RESOURCES;
  8334. }
  8335. numVolumes = 0;
  8336. for (l = rootExtension->VolumeList.Flink;
  8337. l != &rootExtension->VolumeList; l = l->Flink) {
  8338. extension = CONTAINING_RECORD(l, VOLUME_EXTENSION, ListEntry);
  8339. status = FtpAllSystemsGo(extension, NULL, FALSE, TRUE, TRUE);
  8340. if (!NT_SUCCESS(status)) {
  8341. continue;
  8342. }
  8343. vol = extension->FtVolume;
  8344. if (vol) {
  8345. arrayOfVolumes[numVolumes++] = extension;
  8346. } else {
  8347. FtpDecrementRefCount(extension);
  8348. }
  8349. }
  8350. FtpRelease(rootExtension);
  8351. if (numVolumes) {
  8352. context = (PFTP_SHUTDOWN_CONTEXT)
  8353. ExAllocatePool(NonPagedPool,
  8354. sizeof(FTP_SHUTDOWN_CONTEXT));
  8355. if (!context) {
  8356. for (i = 0; i < numVolumes; i++) {
  8357. FtpDecrementRefCount(extension);
  8358. }
  8359. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  8360. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8361. return STATUS_INSUFFICIENT_RESOURCES;
  8362. }
  8363. Irp->IoStatus.Status = STATUS_SUCCESS;
  8364. context->Irp = Irp;
  8365. context->RefCount = (LONG) numVolumes;
  8366. IoMarkIrpPending(Irp);
  8367. for (i = 0; i < numVolumes; i++) {
  8368. vol = arrayOfVolumes[i]->FtVolume;
  8369. vol->SetDirtyBit(FALSE, FtDiskShutdownCompletionRoutine,
  8370. context);
  8371. }
  8372. ExFreePool(arrayOfVolumes);
  8373. return STATUS_PENDING;
  8374. }
  8375. ExFreePool(arrayOfVolumes);
  8376. //
  8377. // Complete this request.
  8378. //
  8379. Irp->IoStatus.Status = STATUS_SUCCESS;
  8380. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8381. return STATUS_SUCCESS;
  8382. }
  8383. status = FtpAllSystemsGo(extension, Irp, FALSE, TRUE, TRUE);
  8384. if (status == STATUS_PENDING) {
  8385. return status;
  8386. }
  8387. if (!NT_SUCCESS(status)) {
  8388. Irp->IoStatus.Information = 0;
  8389. Irp->IoStatus.Status = status;
  8390. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8391. return status;
  8392. }
  8393. if (extension->TargetObject) {
  8394. IoCopyCurrentIrpStackLocationToNext(Irp);
  8395. IoSetCompletionRoutine(Irp, FtpRefCountCompletionRoutine,
  8396. extension, TRUE, TRUE, TRUE);
  8397. IoMarkIrpPending(Irp);
  8398. IoCallDriver(extension->TargetObject, Irp);
  8399. return STATUS_PENDING;
  8400. }
  8401. vol = extension->FtVolume;
  8402. ASSERT(vol);
  8403. IoMarkIrpPending(Irp);
  8404. irpSp = IoGetCurrentIrpStackLocation(Irp);
  8405. irpSp->DeviceObject = DeviceObject;
  8406. vol->BroadcastIrp(Irp, FtDiskShutdownFlushCompletionRoutine, Irp);
  8407. return STATUS_PENDING;
  8408. }
  8409. NTSTATUS
  8410. FtpSignalCompletion(
  8411. IN PDEVICE_OBJECT DeviceObject,
  8412. IN PIRP Irp,
  8413. IN PVOID Event
  8414. )
  8415. {
  8416. KeSetEvent((PKEVENT) Event, IO_NO_INCREMENT, FALSE);
  8417. return STATUS_MORE_PROCESSING_REQUIRED;
  8418. }
  8419. VOID
  8420. FtpQueryRemoveCallback(
  8421. IN PVOLUME_EXTENSION Extension
  8422. )
  8423. /*++
  8424. Routine Description:
  8425. This routine sets the ZeroRef event.
  8426. Arguments:
  8427. Extension - Supplies the volume extension.
  8428. Return Value:
  8429. None.
  8430. --*/
  8431. {
  8432. KeSetEvent((PKEVENT) Extension->ZeroRefContext, IO_NO_INCREMENT, FALSE);
  8433. }
  8434. VOID
  8435. FtpStartCallback(
  8436. IN PVOLUME_EXTENSION Extension
  8437. )
  8438. /*++
  8439. Routine Description:
  8440. This routine sets the ZeroRef event.
  8441. Arguments:
  8442. Extension - Supplies the volume extension.
  8443. Return Value:
  8444. None.
  8445. --*/
  8446. {
  8447. Extension->IsStarted = TRUE;
  8448. KeSetEvent((PKEVENT) Extension->ZeroRefContext, IO_NO_INCREMENT, FALSE);
  8449. }
  8450. NTSTATUS
  8451. FtpCheckForQueryRemove(
  8452. IN OUT PVOLUME_EXTENSION Extension
  8453. )
  8454. {
  8455. KIRQL irql;
  8456. NTSTATUS status;
  8457. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  8458. if (Extension->InPagingPath || Extension->RemoveInProgress) {
  8459. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8460. status = STATUS_INVALID_DEVICE_REQUEST;
  8461. } else {
  8462. InterlockedExchange(&Extension->AllSystemsGo, FALSE);
  8463. Extension->RemoveInProgress = TRUE;
  8464. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8465. status = STATUS_SUCCESS;
  8466. }
  8467. return status;
  8468. }
  8469. BOOLEAN
  8470. FtpCheckForCancelRemove(
  8471. IN OUT PVOLUME_EXTENSION Extension
  8472. )
  8473. {
  8474. KIRQL irql;
  8475. BOOLEAN removeInProgress;
  8476. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  8477. removeInProgress = Extension->RemoveInProgress;
  8478. Extension->RemoveInProgress = FALSE;
  8479. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8480. return removeInProgress;
  8481. }
  8482. VOID
  8483. FtpRemoveHelper(
  8484. IN OUT PVOLUME_EXTENSION Extension
  8485. )
  8486. {
  8487. KIRQL irql;
  8488. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  8489. InterlockedExchange(&Extension->AllSystemsGo, FALSE);
  8490. Extension->IsStarted = FALSE;
  8491. Extension->RemoveInProgress = FALSE;
  8492. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8493. }
  8494. NTSTATUS
  8495. FtDiskCleanup(
  8496. IN PDEVICE_OBJECT DeviceObject,
  8497. IN PIRP Irp
  8498. )
  8499. /*++
  8500. Routine Description:
  8501. This routine cancels all of the IRPs currently queued on
  8502. the given device.
  8503. Arguments:
  8504. DeviceObject - Supplies the device object.
  8505. Irp - Supplies the cleanup IRP.
  8506. Return Value:
  8507. STATUS_SUCCESS - Success.
  8508. --*/
  8509. {
  8510. PROOT_EXTENSION rootExtension = (PROOT_EXTENSION) DeviceObject->DeviceExtension;
  8511. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  8512. PFILE_OBJECT file = irpSp->FileObject;
  8513. PVOLUME_EXTENSION extension;
  8514. KIRQL irql;
  8515. PLIST_ENTRY l;
  8516. PIRP irp;
  8517. Irp->IoStatus.Status = STATUS_SUCCESS;
  8518. Irp->IoStatus.Information = 0;
  8519. if (rootExtension->DeviceExtensionType != DEVICE_EXTENSION_ROOT) {
  8520. ASSERT(rootExtension->DeviceExtensionType == DEVICE_EXTENSION_VOLUME);
  8521. extension = (PVOLUME_EXTENSION) rootExtension;
  8522. if (extension->RevertOnCloseFileObject == file) {
  8523. FtpAcquire(extension->Root);
  8524. FtpRevertGptAttributes(extension);
  8525. FtpRelease(extension->Root);
  8526. }
  8527. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8528. return STATUS_SUCCESS;
  8529. }
  8530. IoAcquireCancelSpinLock(&irql);
  8531. for (;;) {
  8532. for (l = rootExtension->ChangeNotifyIrpList.Flink;
  8533. l != &rootExtension->ChangeNotifyIrpList; l = l->Flink) {
  8534. irp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  8535. if (IoGetCurrentIrpStackLocation(irp)->FileObject == file) {
  8536. break;
  8537. }
  8538. }
  8539. if (l == &rootExtension->ChangeNotifyIrpList) {
  8540. break;
  8541. }
  8542. irp->Cancel = TRUE;
  8543. irp->CancelIrql = irql;
  8544. irp->CancelRoutine = NULL;
  8545. FtpCancelRoutine(DeviceObject, irp);
  8546. IoAcquireCancelSpinLock(&irql);
  8547. }
  8548. IoReleaseCancelSpinLock(irql);
  8549. Irp->IoStatus.Status = STATUS_SUCCESS;
  8550. Irp->IoStatus.Information = 0;
  8551. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  8552. return STATUS_SUCCESS;
  8553. }
  8554. NTSTATUS
  8555. DriverEntry(
  8556. IN PDRIVER_OBJECT DriverObject,
  8557. IN PUNICODE_STRING RegistryPath
  8558. )
  8559. /*++
  8560. Routine Description:
  8561. This routine is called when the driver loads loads.
  8562. Arguments:
  8563. DriverObject - Supplies the driver object.
  8564. RegistryPath - Supplies the registry path.
  8565. Return Value:
  8566. NTSTATUS
  8567. --*/
  8568. {
  8569. NTSTATUS status;
  8570. PDEVICE_OBJECT pdo = 0, fdo;
  8571. PROOT_EXTENSION rootExtension;
  8572. DriverObject->DriverUnload = FtDiskUnload;
  8573. DriverObject->MajorFunction[IRP_MJ_CREATE] = FtDiskCreate;
  8574. DriverObject->MajorFunction[IRP_MJ_READ] = FtDiskReadWrite;
  8575. DriverObject->MajorFunction[IRP_MJ_WRITE] = FtDiskReadWrite;
  8576. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = FtDiskDeviceControl;
  8577. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = FtDiskInternalDeviceControl;
  8578. DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = FtDiskShutdownFlush;
  8579. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = FtDiskShutdownFlush;
  8580. DriverObject->MajorFunction[IRP_MJ_PNP] = FtDiskPnp;
  8581. DriverObject->MajorFunction[IRP_MJ_POWER] = FtDiskPower;
  8582. DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FtDiskCleanup;
  8583. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = FtWmi;
  8584. ObReferenceObject(DriverObject);
  8585. status = IoReportDetectedDevice(
  8586. DriverObject,
  8587. InterfaceTypeUndefined,
  8588. -1,
  8589. -1,
  8590. NULL,
  8591. NULL,
  8592. TRUE,
  8593. &pdo
  8594. );
  8595. if (!NT_SUCCESS(status)) {
  8596. return status;
  8597. }
  8598. status = FtDiskAddDevice(DriverObject, pdo);
  8599. if (!NT_SUCCESS(status)) {
  8600. return status;
  8601. }
  8602. fdo = IoGetAttachedDeviceReference(pdo);
  8603. ObDereferenceObject(fdo);
  8604. rootExtension = (PROOT_EXTENSION) fdo->DeviceExtension;
  8605. rootExtension->DiskPerfRegistryPath.MaximumLength =
  8606. RegistryPath->Length + sizeof(UNICODE_NULL);
  8607. rootExtension->DiskPerfRegistryPath.Buffer = (PWSTR)
  8608. ExAllocatePool(PagedPool,
  8609. rootExtension->DiskPerfRegistryPath.MaximumLength);
  8610. if (rootExtension->DiskPerfRegistryPath.Buffer) {
  8611. RtlCopyUnicodeString(&rootExtension->DiskPerfRegistryPath,
  8612. RegistryPath);
  8613. } else {
  8614. rootExtension->DiskPerfRegistryPath.Length = 0;
  8615. rootExtension->DiskPerfRegistryPath.MaximumLength = 0;
  8616. }
  8617. status = IoRegisterDeviceInterface(rootExtension->Pdo,
  8618. &VOLMGR_VOLUME_MANAGER_GUID, NULL,
  8619. &rootExtension->VolumeManagerInterfaceName);
  8620. if (NT_SUCCESS(status)) {
  8621. status = IoSetDeviceInterfaceState(
  8622. &rootExtension->VolumeManagerInterfaceName, TRUE);
  8623. } else {
  8624. rootExtension->VolumeManagerInterfaceName.Buffer = NULL;
  8625. }
  8626. IoRegisterBootDriverReinitialization(DriverObject,
  8627. FtpBootDriverReinitialization,
  8628. rootExtension);
  8629. IoRegisterDriverReinitialization(DriverObject, FtpDriverReinitialization,
  8630. rootExtension);
  8631. FtpQueryRegistryRevertEntries(rootExtension,
  8632. &rootExtension->GptAttributeRevertEntries,
  8633. &rootExtension->NumberOfAttributeRevertEntries);
  8634. RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, RegistryPath->Buffer,
  8635. REVERT_GPT_ATTRIBUTES_REGISTRY_NAME);
  8636. IoInvalidateDeviceState(rootExtension->Pdo);
  8637. return STATUS_SUCCESS;
  8638. }
  8639. VOID
  8640. FtpLogError(
  8641. IN PDEVICE_EXTENSION Extension,
  8642. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  8643. IN NTSTATUS SpecificIoStatus,
  8644. IN NTSTATUS FinalStatus,
  8645. IN ULONG UniqueErrorValue
  8646. )
  8647. /*++
  8648. Routine Description:
  8649. This routine performs error logging for the FT driver.
  8650. Arguments:
  8651. Extension - Extension.
  8652. LogicalDiskId - Logical disk id representing failing device.
  8653. SpecificIoStatus - IO error status value.
  8654. FinalStatus - Status returned for failure.
  8655. UniqueErrorValue - Values defined to uniquely identify error location.
  8656. Return Value:
  8657. None
  8658. --*/
  8659. {
  8660. PFTP_LOG_ERROR_CONTEXT context;
  8661. context = (PFTP_LOG_ERROR_CONTEXT)
  8662. ExAllocatePool(NonPagedPool, sizeof(FTP_LOG_ERROR_CONTEXT));
  8663. if (!context) {
  8664. return;
  8665. }
  8666. ExInitializeWorkItem(context, FtpLogErrorWorker, context);
  8667. context->Extension = Extension;
  8668. context->LogicalDiskId = LogicalDiskId;
  8669. context->SpecificIoStatus = SpecificIoStatus;
  8670. context->FinalStatus = FinalStatus;
  8671. context->UniqueErrorValue = UniqueErrorValue;
  8672. ExQueueWorkItem(context, CriticalWorkQueue);
  8673. }
  8674. VOID
  8675. FtpQueueWorkItem(
  8676. IN PROOT_EXTENSION RootExtension,
  8677. IN PWORK_QUEUE_ITEM WorkItem
  8678. )
  8679. /*++
  8680. Routine Description:
  8681. This routine queues a work item to a private worker thread.
  8682. Arguments:
  8683. RootExtension - Supplies the root device extension.
  8684. WorkItem - The work item to be queued.
  8685. Return Value:
  8686. None.
  8687. --*/
  8688. {
  8689. KIRQL irql;
  8690. KeAcquireSpinLock(&RootExtension->SpinLock, &irql);
  8691. InsertTailList(&RootExtension->WorkerQueue, &WorkItem->List);
  8692. KeReleaseSpinLock(&RootExtension->SpinLock, irql);
  8693. KeReleaseSemaphore(&RootExtension->WorkerSemaphore, 0, 1, FALSE);
  8694. }
  8695. VOID
  8696. FtpNotify(
  8697. IN OUT PROOT_EXTENSION RootExtension,
  8698. IN PVOLUME_EXTENSION Extension
  8699. )
  8700. /*++
  8701. Routine Description:
  8702. This routine completes all of the change notify irps in the queue.
  8703. Arguments:
  8704. RootExtension - Supplies the root extension.
  8705. Extension - Supplies the specific extension being changed.
  8706. Return Value:
  8707. None.
  8708. --*/
  8709. {
  8710. LIST_ENTRY q;
  8711. KIRQL irql;
  8712. PLIST_ENTRY p;
  8713. PIRP irp;
  8714. TARGET_DEVICE_CUSTOM_NOTIFICATION notification;
  8715. InitializeListHead(&q);
  8716. IoAcquireCancelSpinLock(&irql);
  8717. while (!IsListEmpty(&RootExtension->ChangeNotifyIrpList)) {
  8718. p = RemoveHeadList(&RootExtension->ChangeNotifyIrpList);
  8719. irp = CONTAINING_RECORD(p, IRP, Tail.Overlay.ListEntry);
  8720. IoSetCancelRoutine(irp, NULL);
  8721. InsertTailList(&q, p);
  8722. }
  8723. IoReleaseCancelSpinLock(irql);
  8724. while (!IsListEmpty(&q)) {
  8725. p = RemoveHeadList(&q);
  8726. irp = CONTAINING_RECORD(p, IRP, Tail.Overlay.ListEntry);
  8727. IoCompleteRequest(irp, IO_NO_INCREMENT);
  8728. }
  8729. if (Extension->IsStarted) {
  8730. notification.Version = 1;
  8731. notification.Size = (USHORT)
  8732. FIELD_OFFSET(TARGET_DEVICE_CUSTOM_NOTIFICATION,
  8733. CustomDataBuffer);
  8734. RtlCopyMemory(&notification.Event,
  8735. &GUID_IO_VOLUME_PHYSICAL_CONFIGURATION_CHANGE,
  8736. sizeof(GUID_IO_VOLUME_PHYSICAL_CONFIGURATION_CHANGE));
  8737. notification.FileObject = NULL;
  8738. notification.NameBufferOffset = -1;
  8739. IoReportTargetDeviceChangeAsynchronous(Extension->DeviceObject,
  8740. &notification, NULL, NULL);
  8741. }
  8742. }
  8743. #if DBG
  8744. ULONG FtDebug;
  8745. VOID
  8746. FtDebugPrint(
  8747. ULONG DebugPrintLevel,
  8748. PCCHAR DebugMessage,
  8749. ...
  8750. )
  8751. /*++
  8752. Routine Description:
  8753. Debug print for the Fault Tolerance Driver.
  8754. Arguments:
  8755. Debug print level between 0 and N, with N being the most verbose.
  8756. Return Value:
  8757. None
  8758. --*/
  8759. {
  8760. va_list ap;
  8761. char buffer[256];
  8762. va_start( ap, DebugMessage );
  8763. if (DebugPrintLevel <= FtDebug) {
  8764. vsprintf(buffer, DebugMessage, ap);
  8765. DbgPrint(buffer);
  8766. }
  8767. va_end(ap);
  8768. } // end FtDebugPrint()
  8769. #endif
  8770. #ifdef ALLOC_PRAGMA
  8771. #pragma code_seg("PAGELK")
  8772. #endif
  8773. NTSTATUS
  8774. FtpCheckForCompleteVolume(
  8775. IN PVOLUME_EXTENSION Extension,
  8776. IN PFT_VOLUME FtVolume
  8777. )
  8778. {
  8779. KIRQL irql;
  8780. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  8781. if (!FtVolume->IsComplete(TRUE)) {
  8782. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8783. return STATUS_NO_SUCH_DEVICE;
  8784. }
  8785. FtVolume->CompleteNotification(TRUE);
  8786. KeReleaseSpinLock(&Extension->SpinLock, irql);
  8787. return STATUS_SUCCESS;
  8788. }
  8789. BOOLEAN
  8790. FsRtlIsTotalDeviceFailure(
  8791. IN NTSTATUS Status
  8792. )
  8793. /*++
  8794. Routine Description:
  8795. This routine is given an NTSTATUS value and make a determination as to
  8796. if this value indicates that the complete device has failed and therefore
  8797. should no longer be used, or if the failure is one that indicates that
  8798. continued use of the device is ok (i.e. a sector failure).
  8799. Arguments:
  8800. Status - the NTSTATUS value to test.
  8801. Return Value:
  8802. TRUE - The status value given is believed to be a fatal device error.
  8803. FALSE - The status value given is believed to be a sector failure, but not
  8804. a complete device failure.
  8805. --*/
  8806. {
  8807. if (NT_SUCCESS(Status)) {
  8808. //
  8809. // All warning and informational errors will be resolved here.
  8810. //
  8811. return FALSE;
  8812. }
  8813. switch (Status) {
  8814. case STATUS_CRC_ERROR:
  8815. case STATUS_DEVICE_DATA_ERROR:
  8816. return FALSE;
  8817. default:
  8818. return TRUE;
  8819. }
  8820. }
  8821. BOOLEAN
  8822. FtpIsWorseStatus(
  8823. IN NTSTATUS Status1,
  8824. IN NTSTATUS Status2
  8825. )
  8826. /*++
  8827. Routine Description:
  8828. This routine compares two NTSTATUS codes and decides if Status1 is
  8829. worse than Status2.
  8830. Arguments:
  8831. Status1 - Supplies the first status.
  8832. Status2 - Supplies the second status.
  8833. Return Value:
  8834. FALSE - Status1 is not worse than Status2.
  8835. TRUE - Status1 is worse than Status2.
  8836. --*/
  8837. {
  8838. if (NT_ERROR(Status2) && FsRtlIsTotalDeviceFailure(Status2)) {
  8839. return FALSE;
  8840. }
  8841. if (NT_ERROR(Status1) && FsRtlIsTotalDeviceFailure(Status1)) {
  8842. return TRUE;
  8843. }
  8844. if (NT_ERROR(Status2)) {
  8845. return FALSE;
  8846. }
  8847. if (NT_ERROR(Status1)) {
  8848. return TRUE;
  8849. }
  8850. if (NT_WARNING(Status2)) {
  8851. return FALSE;
  8852. }
  8853. if (NT_WARNING(Status1)) {
  8854. return TRUE;
  8855. }
  8856. if (NT_INFORMATION(Status2)) {
  8857. return FALSE;
  8858. }
  8859. if (NT_INFORMATION(Status1)) {
  8860. return TRUE;
  8861. }
  8862. return FALSE;
  8863. }
  8864. VOID
  8865. FtDiskShutdownCompletionRoutine(
  8866. IN PVOID Context,
  8867. IN NTSTATUS Status
  8868. )
  8869. {
  8870. PFTP_SHUTDOWN_CONTEXT context = (PFTP_SHUTDOWN_CONTEXT) Context;
  8871. if (InterlockedDecrement(&context->RefCount)) {
  8872. return;
  8873. }
  8874. IoCompleteRequest(context->Irp, IO_NO_INCREMENT);
  8875. ExFreePool(context);
  8876. }
  8877. NTSTATUS
  8878. FtpCreateLogicalDiskHelper(
  8879. IN OUT PROOT_EXTENSION RootExtension,
  8880. IN FT_LOGICAL_DISK_TYPE LogicalDiskType,
  8881. IN USHORT NumberOfMembers,
  8882. IN PFT_LOGICAL_DISK_ID ArrayOfMembers,
  8883. IN USHORT ConfigurationInformationSize,
  8884. IN PVOID ConfigurationInformation,
  8885. IN USHORT StateInformationSize,
  8886. IN PVOID StateInformation,
  8887. OUT PFT_LOGICAL_DISK_ID NewLogicalDiskId
  8888. )
  8889. {
  8890. BOOLEAN lockZero;
  8891. FT_MIRROR_AND_SWP_STATE_INFORMATION actualStateInfo;
  8892. FT_REDISTRIBUTION_STATE_INFORMATION redistStateInfo;
  8893. PHANDLE handleArray;
  8894. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet;
  8895. NTSTATUS status;
  8896. FT_LOGICAL_DISK_ID newLogicalDiskId;
  8897. PFT_VOLUME* volArray;
  8898. PVOLUME_EXTENSION* extArray;
  8899. PVOLUME_EXTENSION extension;
  8900. KIRQL irql;
  8901. USHORT i, j;
  8902. KEVENT event;
  8903. PCOMPOSITE_FT_VOLUME comp;
  8904. WCHAR deviceNameBuffer[64];
  8905. UNICODE_STRING deviceName;
  8906. UCHAR newUniqueIdBuffer[UNIQUE_ID_MAX_BUFFER_SIZE];
  8907. PMOUNTDEV_UNIQUE_ID newUniqueId;
  8908. SET_TARGET_CONTEXT context;
  8909. ULONG alignment;
  8910. PFT_REDISTRIBUTION_CONFIGURATION_INFORMATION redistConfig;
  8911. PFT_REDISTRIBUTION_STATE_INFORMATION redistState;
  8912. PFT_MIRROR_AND_SWP_STATE_INFORMATION mirrorState;
  8913. switch (LogicalDiskType) {
  8914. case FtVolumeSet:
  8915. ConfigurationInformation = NULL;
  8916. ConfigurationInformationSize = 0;
  8917. StateInformation = NULL;
  8918. StateInformationSize = 0;
  8919. lockZero = FALSE;
  8920. if (NumberOfMembers == 0) {
  8921. return STATUS_INVALID_PARAMETER;
  8922. }
  8923. break;
  8924. case FtStripeSet:
  8925. if (ConfigurationInformationSize <
  8926. sizeof(FT_STRIPE_SET_CONFIGURATION_INFORMATION)) {
  8927. return STATUS_INVALID_PARAMETER;
  8928. }
  8929. ConfigurationInformationSize =
  8930. sizeof(FT_STRIPE_SET_CONFIGURATION_INFORMATION);
  8931. StateInformation = NULL;
  8932. StateInformationSize = 0;
  8933. lockZero = TRUE;
  8934. if (NumberOfMembers == 0) {
  8935. return STATUS_INVALID_PARAMETER;
  8936. }
  8937. break;
  8938. case FtMirrorSet:
  8939. if (ConfigurationInformationSize <
  8940. sizeof(FT_MIRROR_SET_CONFIGURATION_INFORMATION)) {
  8941. return STATUS_INVALID_PARAMETER;
  8942. }
  8943. ConfigurationInformationSize =
  8944. sizeof(FT_MIRROR_SET_CONFIGURATION_INFORMATION);
  8945. if (!StateInformation) {
  8946. actualStateInfo.IsDirty = TRUE;
  8947. actualStateInfo.IsInitializing = FALSE;
  8948. actualStateInfo.UnhealthyMemberNumber = 1;
  8949. actualStateInfo.UnhealthyMemberState = FtMemberRegenerating;
  8950. StateInformation = &actualStateInfo;
  8951. StateInformationSize = sizeof(actualStateInfo);
  8952. }
  8953. lockZero = FALSE;
  8954. if (NumberOfMembers != 2) {
  8955. return STATUS_INVALID_PARAMETER;
  8956. }
  8957. j = NumberOfMembers;
  8958. for (i = 0; i < NumberOfMembers; i++) {
  8959. if (!ArrayOfMembers[i]) {
  8960. if (j < NumberOfMembers) {
  8961. return STATUS_INVALID_PARAMETER;
  8962. }
  8963. j = i;
  8964. mirrorState = (PFT_MIRROR_AND_SWP_STATE_INFORMATION)
  8965. StateInformation;
  8966. mirrorState->UnhealthyMemberNumber = i;
  8967. mirrorState->UnhealthyMemberState = FtMemberOrphaned;
  8968. }
  8969. }
  8970. break;
  8971. case FtStripeSetWithParity:
  8972. if (ConfigurationInformationSize <
  8973. sizeof(FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION)) {
  8974. return STATUS_INVALID_PARAMETER;
  8975. }
  8976. ConfigurationInformationSize =
  8977. sizeof(FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION);
  8978. if (!StateInformation) {
  8979. actualStateInfo.IsDirty = TRUE;
  8980. actualStateInfo.IsInitializing = TRUE;
  8981. actualStateInfo.UnhealthyMemberNumber = 0;
  8982. actualStateInfo.UnhealthyMemberState = FtMemberHealthy;
  8983. StateInformation = &actualStateInfo;
  8984. StateInformationSize = sizeof(actualStateInfo);
  8985. }
  8986. lockZero = TRUE;
  8987. if (NumberOfMembers < 3) {
  8988. return STATUS_INVALID_PARAMETER;
  8989. }
  8990. j = NumberOfMembers;
  8991. for (i = 0; i < NumberOfMembers; i++) {
  8992. if (!ArrayOfMembers[i]) {
  8993. if (j < NumberOfMembers) {
  8994. return STATUS_INVALID_PARAMETER;
  8995. }
  8996. j = i;
  8997. mirrorState = (PFT_MIRROR_AND_SWP_STATE_INFORMATION)
  8998. StateInformation;
  8999. mirrorState->IsInitializing = FALSE;
  9000. mirrorState->UnhealthyMemberNumber = i;
  9001. mirrorState->UnhealthyMemberState = FtMemberOrphaned;
  9002. }
  9003. }
  9004. break;
  9005. case FtRedistribution:
  9006. if (ConfigurationInformationSize <
  9007. sizeof(FT_REDISTRIBUTION_CONFIGURATION_INFORMATION)) {
  9008. return STATUS_INVALID_PARAMETER;
  9009. }
  9010. ConfigurationInformationSize =
  9011. sizeof(FT_REDISTRIBUTION_CONFIGURATION_INFORMATION);
  9012. if (!StateInformation) {
  9013. redistStateInfo.BytesRedistributed = 0;
  9014. StateInformation = &redistStateInfo;
  9015. StateInformationSize = sizeof(redistStateInfo);
  9016. }
  9017. redistConfig = (PFT_REDISTRIBUTION_CONFIGURATION_INFORMATION)
  9018. ConfigurationInformation;
  9019. if (redistConfig->StripeSize&0x80000000) {
  9020. lockZero = TRUE;
  9021. redistConfig->StripeSize &= (~0x80000000);
  9022. redistState = (PFT_REDISTRIBUTION_STATE_INFORMATION)
  9023. StateInformation;
  9024. redistState->BytesRedistributed = 0x7FFFFFFFFFFFFFFF;
  9025. } else {
  9026. lockZero = FALSE;
  9027. }
  9028. if (NumberOfMembers != 2) {
  9029. return STATUS_INVALID_PARAMETER;
  9030. }
  9031. break;
  9032. default:
  9033. return STATUS_INVALID_PARAMETER;
  9034. }
  9035. handleArray = (PHANDLE)
  9036. ExAllocatePool(NonPagedPool, NumberOfMembers*sizeof(HANDLE));
  9037. if (!handleArray) {
  9038. return STATUS_INSUFFICIENT_RESOURCES;
  9039. }
  9040. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9041. if (!ArrayOfMembers[i]) {
  9042. continue;
  9043. }
  9044. if (!FtpLockLogicalDisk(RootExtension, ArrayOfMembers[i],
  9045. &handleArray[i])) {
  9046. break;
  9047. }
  9048. }
  9049. if (i < NumberOfMembers) {
  9050. for (j = lockZero ? 0 : 1; j < i; j++) {
  9051. if (ArrayOfMembers[j]) {
  9052. ZwClose(handleArray[j]);
  9053. }
  9054. }
  9055. ExFreePool(handleArray);
  9056. return STATUS_ACCESS_DENIED;
  9057. }
  9058. if (LogicalDiskType == FtMirrorSet &&
  9059. ArrayOfMembers[0] &&
  9060. !(extension = FtpFindExtension(RootExtension, ArrayOfMembers[0])) &&
  9061. (extension = FtpFindExtensionCoveringDiskId(RootExtension,
  9062. ArrayOfMembers[0]))) {
  9063. status = FtpInsertMirror(RootExtension, ArrayOfMembers,
  9064. NewLogicalDiskId);
  9065. if (ArrayOfMembers[1]) {
  9066. ZwClose(handleArray[1]);
  9067. }
  9068. ExFreePool(handleArray);
  9069. return status;
  9070. }
  9071. diskInfoSet = RootExtension->DiskInfoSet;
  9072. status = diskInfoSet->AddNewLogicalDisk(LogicalDiskType,
  9073. NumberOfMembers,
  9074. ArrayOfMembers,
  9075. ConfigurationInformationSize,
  9076. ConfigurationInformation,
  9077. StateInformationSize,
  9078. StateInformation,
  9079. &newLogicalDiskId);
  9080. if (!NT_SUCCESS(status)) {
  9081. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9082. if (ArrayOfMembers[i]) {
  9083. ZwClose(handleArray[i]);
  9084. }
  9085. }
  9086. ExFreePool(handleArray);
  9087. return status;
  9088. }
  9089. volArray = (PFT_VOLUME*)
  9090. ExAllocatePool(NonPagedPool, NumberOfMembers*sizeof(PFT_VOLUME));
  9091. if (!volArray) {
  9092. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9093. if (ArrayOfMembers[i]) {
  9094. ZwClose(handleArray[i]);
  9095. }
  9096. }
  9097. ExFreePool(handleArray);
  9098. diskInfoSet->BreakLogicalDisk(newLogicalDiskId);
  9099. return STATUS_INSUFFICIENT_RESOURCES;
  9100. }
  9101. extArray = (PVOLUME_EXTENSION*)
  9102. ExAllocatePool(NonPagedPool, NumberOfMembers*
  9103. sizeof(PVOLUME_EXTENSION));
  9104. if (!extArray) {
  9105. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9106. if (ArrayOfMembers[i]) {
  9107. ZwClose(handleArray[i]);
  9108. }
  9109. }
  9110. ExFreePool(handleArray);
  9111. ExFreePool(volArray);
  9112. diskInfoSet->BreakLogicalDisk(newLogicalDiskId);
  9113. return STATUS_INSUFFICIENT_RESOURCES;
  9114. }
  9115. alignment = 0;
  9116. for (i = 0; i < NumberOfMembers; i++) {
  9117. if (!ArrayOfMembers[i]) {
  9118. extArray[i] = NULL;
  9119. volArray[i] = NULL;
  9120. continue;
  9121. }
  9122. extension = FtpFindExtension(RootExtension, ArrayOfMembers[i]);
  9123. extArray[i] = extension;
  9124. if (!extension || !extension->FtVolume) {
  9125. break;
  9126. }
  9127. alignment |= extension->DeviceObject->AlignmentRequirement;
  9128. volArray[i] = extension->FtVolume;
  9129. if (!lockZero && i == 0) {
  9130. continue;
  9131. }
  9132. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  9133. context.TargetObject = NULL;
  9134. context.FtVolume = NULL;
  9135. context.WholeDiskPdo = NULL;
  9136. FtpZeroRefCallback(extension, FtpSetTargetCallback, &context, TRUE);
  9137. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  9138. NULL);
  9139. }
  9140. if (i < NumberOfMembers) {
  9141. for (j = 0; j < i; j++) {
  9142. if (ArrayOfMembers[j]) {
  9143. KeAcquireSpinLock(&extArray[j]->SpinLock, &irql);
  9144. extArray[j]->FtVolume = volArray[j];
  9145. KeReleaseSpinLock(&extArray[j]->SpinLock, irql);
  9146. }
  9147. }
  9148. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9149. if (ArrayOfMembers[i]) {
  9150. ZwClose(handleArray[i]);
  9151. }
  9152. }
  9153. ExFreePool(handleArray);
  9154. ExFreePool(extArray);
  9155. ExFreePool(volArray);
  9156. diskInfoSet->BreakLogicalDisk(newLogicalDiskId);
  9157. return STATUS_INVALID_PARAMETER;
  9158. }
  9159. switch (LogicalDiskType) {
  9160. case FtVolumeSet:
  9161. comp = new VOLUME_SET;
  9162. break;
  9163. case FtStripeSet:
  9164. comp = new STRIPE;
  9165. break;
  9166. case FtMirrorSet:
  9167. comp = new MIRROR;
  9168. break;
  9169. case FtStripeSetWithParity:
  9170. comp = new STRIPE_WP;
  9171. break;
  9172. case FtRedistribution:
  9173. comp = new REDISTRIBUTION;
  9174. break;
  9175. default:
  9176. comp = NULL;
  9177. break;
  9178. }
  9179. if (!comp) {
  9180. for (j = 0; j < NumberOfMembers; j++) {
  9181. if (ArrayOfMembers[j]) {
  9182. KeAcquireSpinLock(&extArray[j]->SpinLock, &irql);
  9183. extArray[j]->FtVolume = volArray[j];
  9184. KeReleaseSpinLock(&extArray[j]->SpinLock, irql);
  9185. }
  9186. }
  9187. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9188. if (ArrayOfMembers[i]) {
  9189. ZwClose(handleArray[i]);
  9190. }
  9191. }
  9192. ExFreePool(handleArray);
  9193. ExFreePool(extArray);
  9194. ExFreePool(volArray);
  9195. diskInfoSet->BreakLogicalDisk(newLogicalDiskId);
  9196. return STATUS_INSUFFICIENT_RESOURCES;
  9197. }
  9198. status = comp->Initialize(RootExtension, newLogicalDiskId,
  9199. volArray, NumberOfMembers,
  9200. ConfigurationInformation, StateInformation);
  9201. if (!NT_SUCCESS(status)) {
  9202. for (j = 0; j < NumberOfMembers; j++) {
  9203. if (ArrayOfMembers[j]) {
  9204. KeAcquireSpinLock(&extArray[j]->SpinLock, &irql);
  9205. extArray[j]->FtVolume = volArray[j];
  9206. KeReleaseSpinLock(&extArray[j]->SpinLock, irql);
  9207. }
  9208. }
  9209. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9210. if (ArrayOfMembers[i]) {
  9211. ZwClose(handleArray[i]);
  9212. }
  9213. }
  9214. delete comp;
  9215. ExFreePool(handleArray);
  9216. ExFreePool(extArray);
  9217. diskInfoSet->BreakLogicalDisk(newLogicalDiskId);
  9218. return status;
  9219. }
  9220. for (i = lockZero ? 0 : 1; i < NumberOfMembers; i++) {
  9221. extension = extArray[i];
  9222. if (!extension) {
  9223. continue;
  9224. }
  9225. RemoveEntryList(&extension->ListEntry);
  9226. InsertTailList(&RootExtension->DeadVolumeList, &extension->ListEntry);
  9227. FtpDeleteMountPoints(extension);
  9228. FtpCleanupVolumeExtension(extension);
  9229. ZwClose(handleArray[i]);
  9230. }
  9231. ExFreePool(handleArray);
  9232. extension = extArray[0];
  9233. ExFreePool(extArray);
  9234. if (lockZero || !extension) {
  9235. if (!FtpCreateNewDevice(RootExtension, NULL, comp, NULL, alignment,
  9236. FALSE, FALSE, FALSE, FALSE, 0)) {
  9237. return STATUS_INSUFFICIENT_RESOURCES;
  9238. }
  9239. } else {
  9240. swprintf(deviceNameBuffer, L"\\Device\\HarddiskVolume%d", extension->VolumeNumber);
  9241. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  9242. comp->CreateLegacyNameLinks(&deviceName);
  9243. extension->DeviceObject->AlignmentRequirement = alignment;
  9244. KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
  9245. context.TargetObject = NULL;
  9246. context.FtVolume = comp;
  9247. context.WholeDiskPdo = NULL;
  9248. FtpZeroRefCallback(extension, FtpSetTargetCallback, &context, TRUE);
  9249. KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE,
  9250. NULL);
  9251. newUniqueId = (PMOUNTDEV_UNIQUE_ID) newUniqueIdBuffer;
  9252. FtpQueryUniqueIdBuffer(extension, newUniqueId->UniqueId,
  9253. &newUniqueId->UniqueIdLength);
  9254. FtpUniqueIdNotify(extension, newUniqueId);
  9255. FtpNotify(RootExtension, extension);
  9256. }
  9257. *NewLogicalDiskId = newLogicalDiskId;
  9258. IoInvalidateDeviceRelations(RootExtension->Pdo, BusRelations);
  9259. return STATUS_SUCCESS;
  9260. }
  9261. VOID
  9262. FtpMemberOfflineCallback(
  9263. IN PVOLUME_EXTENSION Extension
  9264. )
  9265. /*++
  9266. Routine Description:
  9267. This routine is called to offline a partition after disk activity
  9268. has stopped.
  9269. Arguments:
  9270. Extension - Supplies the volume extension.
  9271. Return Value:
  9272. None.
  9273. --*/
  9274. {
  9275. PFT_PARTITION_OFFLINE_CONTEXT offline = (PFT_PARTITION_OFFLINE_CONTEXT) Extension->ZeroRefContext;
  9276. USHORT n, i;
  9277. if (offline->Parent) {
  9278. Extension->IsComplete = FALSE;
  9279. n = offline->Parent->QueryNumberOfMembers();
  9280. for (i = 0; i < n; i++) {
  9281. if (offline->Parent->GetMember(i) == offline->Child) {
  9282. offline->Parent->SetMember(i, NULL);
  9283. break;
  9284. }
  9285. }
  9286. if (!offline->Root->QueryNumberOfPartitions()) {
  9287. Extension->FtVolume = NULL;
  9288. }
  9289. } else {
  9290. Extension->FtVolume = NULL;
  9291. Extension->IsComplete = FALSE;
  9292. }
  9293. KeSetEvent(offline->Event, IO_NO_INCREMENT, FALSE);
  9294. }
  9295. VOID
  9296. FtpInsertMemberCallback(
  9297. IN PVOLUME_EXTENSION Extension
  9298. )
  9299. /*++
  9300. Routine Description:
  9301. This routine inserts the given member into the given set.
  9302. Arguments:
  9303. Extension - Supplies the volume extension.
  9304. Return Value:
  9305. None.
  9306. --*/
  9307. {
  9308. PINSERT_MEMBER_CONTEXT context = (PINSERT_MEMBER_CONTEXT) Extension->ZeroRefContext;
  9309. context->Parent->SetMember(context->MemberNumber, context->Member);
  9310. KeSetEvent(&context->Event, IO_NO_INCREMENT, FALSE);
  9311. }
  9312. VOID
  9313. FtpReadWriteCompletionRoutine(
  9314. IN PTRANSFER_PACKET TransferPacket
  9315. )
  9316. /*++
  9317. Routine Description:
  9318. Completion routine for FtDiskReadWrite dispatch routine.
  9319. Arguments:
  9320. TransferPacket - Supplies the transfer packet.
  9321. Return Value:
  9322. None.
  9323. --*/
  9324. {
  9325. PDISPATCH_TP transferPacket = (PDISPATCH_TP) TransferPacket;
  9326. PIRP irp = transferPacket->Irp;
  9327. PVOLUME_EXTENSION extension = transferPacket->Extension;
  9328. KIRQL irql;
  9329. PLIST_ENTRY l;
  9330. PDISPATCH_TP p;
  9331. PIO_STACK_LOCATION irpSp;
  9332. PIRP nextIrp;
  9333. irp->IoStatus = transferPacket->IoStatus;
  9334. if (transferPacket == extension->EmergencyTransferPacket) {
  9335. for (;;) {
  9336. KeAcquireSpinLock(&extension->SpinLock, &irql);
  9337. if (IsListEmpty(&extension->EmergencyTransferPacketQueue)) {
  9338. extension->EmergencyTransferPacketInUse = FALSE;
  9339. KeReleaseSpinLock(&extension->SpinLock, irql);
  9340. break;
  9341. }
  9342. l = RemoveHeadList(&extension->EmergencyTransferPacketQueue);
  9343. KeReleaseSpinLock(&extension->SpinLock, irql);
  9344. nextIrp = CONTAINING_RECORD(l, IRP, Tail.Overlay.ListEntry);
  9345. p = new DISPATCH_TP;
  9346. if (!p) {
  9347. p = transferPacket;
  9348. }
  9349. irpSp = IoGetCurrentIrpStackLocation(nextIrp);
  9350. p->Mdl = nextIrp->MdlAddress;
  9351. p->Offset = irpSp->Parameters.Read.ByteOffset.QuadPart;
  9352. p->Length = irpSp->Parameters.Read.Length;
  9353. p->CompletionRoutine = FtpReadWriteCompletionRoutine;
  9354. p->TargetVolume = extension->FtVolume;
  9355. p->Thread = nextIrp->Tail.Overlay.Thread;
  9356. p->IrpFlags = irpSp->Flags;
  9357. if (irpSp->MajorFunction == IRP_MJ_READ) {
  9358. p->ReadPacket = TRUE;
  9359. } else {
  9360. p->ReadPacket = FALSE;
  9361. }
  9362. p->Irp = nextIrp;
  9363. p->Extension = extension;
  9364. if (p == transferPacket) {
  9365. TRANSFER(p);
  9366. break;
  9367. } else {
  9368. TRANSFER(p);
  9369. }
  9370. }
  9371. } else {
  9372. delete transferPacket;
  9373. }
  9374. if (extension->CountersEnabled) {
  9375. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp);
  9376. if (irpStack->MajorFunction == IRP_MJ_READ ||
  9377. irpStack->MajorFunction == IRP_MJ_WRITE) {
  9378. PPMWMICOUNTERLIB_CONTEXT counterLib;
  9379. counterLib = &extension->Root->PmWmiCounterLibContext;
  9380. counterLib->PmWmiCounterIoComplete(
  9381. extension->PmWmiCounterContext, irp,
  9382. (PLARGE_INTEGER) &irpStack->Parameters.Read);
  9383. }
  9384. }
  9385. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  9386. FtpDecrementRefCount(extension);
  9387. }
  9388. VOID
  9389. FtpRefCountCompletion(
  9390. IN PVOID Extension,
  9391. IN NTSTATUS Status
  9392. )
  9393. /*++
  9394. Routine Description:
  9395. Completion routine of type FT_COMPLETION_ROUTINE that decrements
  9396. the ref count.
  9397. Arguments:
  9398. Extension - Supplies the device extension.
  9399. Status - Supplies the status of the operation.
  9400. Return Value:
  9401. None.
  9402. --*/
  9403. {
  9404. PVOLUME_EXTENSION extension = (PVOLUME_EXTENSION) Extension;
  9405. FtpDecrementRefCount(extension);
  9406. }
  9407. NTSTATUS
  9408. FtpAddPartition(
  9409. IN PVOLUME_EXTENSION Extension,
  9410. IN PDEVICE_OBJECT Partition,
  9411. IN PDEVICE_OBJECT WholeDiskPdo
  9412. )
  9413. /*++
  9414. Routine Description:
  9415. This routine adds the given partition to the given ft set.
  9416. Arguments:
  9417. Extension - Supplies the extension where the FT set is rooted.
  9418. Partition - Supplies the new partition.
  9419. WholeDiskPdo - Supplies the whole disk PDO.
  9420. Return Value:
  9421. NTSTATUS
  9422. --*/
  9423. {
  9424. PFT_VOLUME vol = Extension->FtVolume;
  9425. PROOT_EXTENSION rootExtension = Extension->Root;
  9426. PFT_LOGICAL_DISK_INFORMATION_SET diskInfoSet = rootExtension->DiskInfoSet;
  9427. NTSTATUS status;
  9428. ULONG diskNumber, n;
  9429. LONGLONG offset;
  9430. FT_LOGICAL_DISK_ID partitionDiskId, diskId;
  9431. PFT_LOGICAL_DISK_DESCRIPTION parentDesc;
  9432. PFT_VOLUME parent, child, c;
  9433. BOOLEAN inPagingPath, wasStarted;
  9434. KIRQL irql;
  9435. PDEVICE_OBJECT leftmost;
  9436. BOOLEAN nameChange;
  9437. WCHAR deviceNameBuffer[64];
  9438. UNICODE_STRING deviceName;
  9439. UCHAR registryState[100];
  9440. USHORT registryStateSize;
  9441. status = FtpQueryPartitionInformation(Extension->Root,
  9442. Partition, &diskNumber, &offset,
  9443. NULL, NULL, NULL, NULL, NULL, NULL,
  9444. NULL);
  9445. if (!NT_SUCCESS(status)) {
  9446. return status;
  9447. }
  9448. partitionDiskId = diskId =
  9449. diskInfoSet->QueryPartitionLogicalDiskId(diskNumber, offset);
  9450. if (!diskId) {
  9451. return STATUS_INVALID_PARAMETER;
  9452. }
  9453. for (;;) {
  9454. parentDesc = diskInfoSet->GetParentLogicalDiskDescription(diskId);
  9455. if (!parentDesc) {
  9456. return STATUS_INVALID_PARAMETER;
  9457. }
  9458. parent = vol->GetContainedLogicalDisk(parentDesc->LogicalDiskId);
  9459. if (parent) {
  9460. break;
  9461. }
  9462. diskId = parentDesc->LogicalDiskId;
  9463. }
  9464. child = FtpBuildFtVolume(rootExtension, diskId, Partition, WholeDiskPdo);
  9465. if (!child) {
  9466. return STATUS_INSUFFICIENT_RESOURCES;
  9467. }
  9468. parent->SetMember(parentDesc->u.Other.ThisMemberNumber, child);
  9469. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  9470. if (!Extension->IsComplete) {
  9471. KeReleaseSpinLock(&Extension->SpinLock, irql);
  9472. leftmost = Extension->FtVolume->GetLeftmostPartitionObject();
  9473. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  9474. if (!Extension->IsComplete) {
  9475. parentDesc = diskInfoSet->GetParentLogicalDiskDescription(
  9476. partitionDiskId, &n);
  9477. while (parentDesc) {
  9478. if (parentDesc->u.Other.ByteOffsetToStateInformation &&
  9479. (c = vol->GetContainedLogicalDisk(parentDesc->LogicalDiskId))) {
  9480. c->NewStateArrival((PCHAR) parentDesc +
  9481. parentDesc->u.Other.ByteOffsetToStateInformation);
  9482. KeReleaseSpinLock(&Extension->SpinLock, irql);
  9483. if (FtpQueryStateFromRegistry(parentDesc->LogicalDiskId,
  9484. &registryState,
  9485. sizeof(registryState),
  9486. &registryStateSize)) {
  9487. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  9488. if (Extension->IsComplete) {
  9489. break;
  9490. }
  9491. if (!Extension->IsOffline) {
  9492. c->NewStateArrival(&registryState);
  9493. }
  9494. } else {
  9495. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  9496. if (Extension->IsComplete) {
  9497. break;
  9498. }
  9499. }
  9500. }
  9501. parentDesc = diskInfoSet->GetParentLogicalDiskDescription(
  9502. parentDesc, n);
  9503. }
  9504. }
  9505. }
  9506. if (Extension->IsComplete) {
  9507. KeReleaseSpinLock(&Extension->SpinLock, irql);
  9508. status = FtpAllSystemsGo(Extension, NULL, TRUE, TRUE, TRUE);
  9509. if (NT_SUCCESS(status)) {
  9510. vol->StartSyncOperations(FALSE, FtpRefCountCompletion,
  9511. Extension);
  9512. }
  9513. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  9514. }
  9515. inPagingPath = Extension->InPagingPath;
  9516. KeReleaseSpinLock(&Extension->SpinLock, irql);
  9517. if (inPagingPath) {
  9518. FtpSendPagingNotification(Partition);
  9519. }
  9520. swprintf(deviceNameBuffer, L"\\Device\\HarddiskVolume%d", Extension->VolumeNumber);
  9521. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  9522. child->CreateLegacyNameLinks(&deviceName);
  9523. Extension->DeviceObject->AlignmentRequirement |=
  9524. Partition->AlignmentRequirement;
  9525. return STATUS_SUCCESS;
  9526. }
  9527. VOID
  9528. FtpPropogateRegistryState(
  9529. IN PVOLUME_EXTENSION Extension,
  9530. IN PFT_VOLUME Volume
  9531. )
  9532. {
  9533. UCHAR state[100];
  9534. USHORT stateSize;
  9535. KIRQL irql;
  9536. USHORT n, i;
  9537. PFT_VOLUME vol;
  9538. if (Volume->QueryLogicalDiskType() == FtPartition) {
  9539. return;
  9540. }
  9541. if (FtpQueryStateFromRegistry(Volume->QueryLogicalDiskId(), state,
  9542. 100, &stateSize)) {
  9543. KeAcquireSpinLock(&Extension->SpinLock, &irql);
  9544. if (!Extension->IsComplete) {
  9545. Volume->NewStateArrival(state);
  9546. }
  9547. KeReleaseSpinLock(&Extension->SpinLock, irql);
  9548. }
  9549. n = Volume->QueryNumberOfMembers();
  9550. for (i = 0; i < n; i++) {
  9551. vol = Volume->GetMember(i);
  9552. if (!vol) {
  9553. continue;
  9554. }
  9555. FtpPropogateRegistryState(Extension, vol);
  9556. }
  9557. }
  9558. VOID
  9559. FtpComputeParity(
  9560. IN PVOID TargetBuffer,
  9561. IN PVOID SourceBuffer,
  9562. IN ULONG BufferLength
  9563. )
  9564. /*++
  9565. Routine Description:
  9566. This routine computes the parity of the source and target buffers
  9567. and places the result of the computation into the target buffer.
  9568. I.E. TargetBuffer ^= SourceBuffer.
  9569. Arguments:
  9570. TargetBuffer - Supplies the target buffer.
  9571. SourceBuffer - Supplies the source buffer.
  9572. BufferLength - Supplies the buffer length.
  9573. Return Value:
  9574. None.
  9575. --*/
  9576. {
  9577. PULONGLONG p, q;
  9578. ULONG i, n;
  9579. ASSERT(sizeof(ULONGLONG) == 8);
  9580. p = (PULONGLONG) TargetBuffer;
  9581. q = (PULONGLONG) SourceBuffer;
  9582. n = BufferLength/128;
  9583. ASSERT(BufferLength%128 == 0);
  9584. for (i = 0; i < n; i++) {
  9585. *p++ ^= *q++;
  9586. *p++ ^= *q++;
  9587. *p++ ^= *q++;
  9588. *p++ ^= *q++;
  9589. *p++ ^= *q++;
  9590. *p++ ^= *q++;
  9591. *p++ ^= *q++;
  9592. *p++ ^= *q++;
  9593. *p++ ^= *q++;
  9594. *p++ ^= *q++;
  9595. *p++ ^= *q++;
  9596. *p++ ^= *q++;
  9597. *p++ ^= *q++;
  9598. *p++ ^= *q++;
  9599. *p++ ^= *q++;
  9600. *p++ ^= *q++;
  9601. }
  9602. }
  9603. NTSTATUS
  9604. FtpReadPartitionTableEx(
  9605. IN PDEVICE_OBJECT DeviceObject,
  9606. IN PDRIVE_LAYOUT_INFORMATION_EX* DriveLayout
  9607. )
  9608. /*++
  9609. Routine Description:
  9610. This routine reads the partition table for the disk.
  9611. The partition list is built in nonpaged pool that is allocated by this
  9612. routine. It is the caller's responsability to free this memory when it
  9613. is finished with the data.
  9614. Arguments:
  9615. DeviceObject - Pointer for device object for this disk.
  9616. DriveLayout - Pointer to the pointer that will return the patition list.
  9617. This buffer is allocated in nonpaged pool by this routine. It is
  9618. the responsability of the caller to free this memory if this
  9619. routine is successful.
  9620. Return Values:
  9621. Status.
  9622. --*/
  9623. {
  9624. NTSTATUS Status;
  9625. IO_STATUS_BLOCK IoStatus;
  9626. PIRP Irp;
  9627. KEVENT Event;
  9628. PVOID IoCtlBuffer;
  9629. ULONG IoCtlBufferSize;
  9630. ULONG NewAllocationSize;
  9631. ULONG NumTries;
  9632. //
  9633. // Initialize locals.
  9634. //
  9635. NumTries = 0;
  9636. IoCtlBuffer = NULL;
  9637. IoCtlBufferSize = 0;
  9638. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  9639. //
  9640. // Initialize the IOCTL buffer.
  9641. //
  9642. IoCtlBuffer = ExAllocatePoolWithTag(NonPagedPool,
  9643. PAGE_SIZE,
  9644. FTDISK_TAG_IOCTL_BUFFER);
  9645. if (!IoCtlBuffer) {
  9646. Status = STATUS_INSUFFICIENT_RESOURCES;
  9647. goto cleanup;
  9648. }
  9649. IoCtlBufferSize = PAGE_SIZE;
  9650. //
  9651. // First try to get the partition table by issuing an IOCTL.
  9652. //
  9653. do {
  9654. //
  9655. // Make sure the event is reset.
  9656. //
  9657. KeClearEvent(&Event);
  9658. //
  9659. // Build an IOCTL Irp.
  9660. //
  9661. Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  9662. DeviceObject,
  9663. NULL,
  9664. 0,
  9665. IoCtlBuffer,
  9666. IoCtlBufferSize,
  9667. FALSE,
  9668. &Event,
  9669. &IoStatus);
  9670. if (!Irp) {
  9671. Status = STATUS_INSUFFICIENT_RESOURCES;
  9672. goto cleanup;
  9673. }
  9674. //
  9675. // Call the driver.
  9676. //
  9677. Status = IoCallDriver(DeviceObject, Irp);
  9678. if (Status == STATUS_PENDING) {
  9679. KeWaitForSingleObject(&Event,
  9680. Executive,
  9681. KernelMode,
  9682. FALSE,
  9683. NULL);
  9684. //
  9685. // Update status.
  9686. //
  9687. Status = IoStatus.Status;
  9688. }
  9689. if (NT_SUCCESS(Status)) {
  9690. //
  9691. // We got it!
  9692. //
  9693. break;
  9694. }
  9695. if (Status != STATUS_BUFFER_TOO_SMALL) {
  9696. //
  9697. // It is a real error.
  9698. //
  9699. goto cleanup;
  9700. }
  9701. //
  9702. // Resize IOCTL buffer. We should not enter the loop with a
  9703. // NULL buffer.
  9704. //
  9705. ASSERT(IoCtlBuffer && IoCtlBufferSize);
  9706. NewAllocationSize = IoCtlBufferSize * 2;
  9707. ExFreePool(IoCtlBuffer);
  9708. IoCtlBufferSize = 0;
  9709. IoCtlBuffer = ExAllocatePoolWithTag(NonPagedPool,
  9710. NewAllocationSize,
  9711. FTDISK_TAG_IOCTL_BUFFER);
  9712. if (!IoCtlBuffer) {
  9713. Status = STATUS_INSUFFICIENT_RESOURCES;
  9714. goto cleanup;
  9715. }
  9716. IoCtlBufferSize = NewAllocationSize;
  9717. //
  9718. // Try again with the new buffer but do not loop forever.
  9719. //
  9720. NumTries++;
  9721. if (NumTries > 32) {
  9722. Status = STATUS_UNSUCCESSFUL;
  9723. goto cleanup;
  9724. }
  9725. } while (TRUE);
  9726. //
  9727. // If we came here we should have acquired the partition tables in
  9728. // IoCtlBuffer.
  9729. //
  9730. ASSERT(NT_SUCCESS(Status));
  9731. ASSERT(IoCtlBuffer && IoCtlBufferSize);
  9732. //
  9733. // Set the output parameter and clear IoCtlBuffer so we don't free
  9734. // it when we are cleaning up.
  9735. //
  9736. (*DriveLayout) = (PDRIVE_LAYOUT_INFORMATION_EX) IoCtlBuffer;
  9737. IoCtlBuffer = NULL;
  9738. IoCtlBufferSize = 0;
  9739. Status = STATUS_SUCCESS;
  9740. cleanup:
  9741. if (IoCtlBuffer) {
  9742. ASSERT(IoCtlBufferSize);
  9743. ExFreePool(IoCtlBuffer);
  9744. }
  9745. //
  9746. // If we were not successful with the IOCTL, pass the request off
  9747. // to IoReadPartitionTableEx.
  9748. //
  9749. if (!NT_SUCCESS(Status)) {
  9750. Status = IoReadPartitionTableEx(DeviceObject,
  9751. DriveLayout);
  9752. }
  9753. return Status;
  9754. }