From 20889d4553a132cd8749a73853715fd3a0f237e5 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sat, 18 Aug 2018 11:13:20 +0200 Subject: [PATCH] Windows: Implement workaround on Windows 10 to make VeraCrypt encrypted disks visible to Windows defragmenter --- src/Driver/Ntdriver.c | 26 +++++++++++++++++++++----- src/Driver/Ntdriver.h | 1 + src/Driver/Ntvol.c | 10 ++++++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/Driver/Ntdriver.c b/src/Driver/Ntdriver.c index e7451a8f..6e774724 100644 --- a/src/Driver/Ntdriver.c +++ b/src/Driver/Ntdriver.c @@ -1263,8 +1263,10 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: Dump ("ProcessVolumeDeviceControlIrp (IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS)\n"); - // Vista's filesystem defragmenter fails if IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS does not succeed. - if (!(OsMajorVersion == 6 && OsMinorVersion == 0)) + // Vista's and Windows 10 filesystem defragmenter fails if IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS does not succeed. + if (!(OsMajorVersion == 6 && OsMinorVersion == 0) + && !(OsMajorVersion == 10 && EnableExtendedIoctlSupport && Extension->bRawDevice) + ) { Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; Irp->IoStatus.Information = 0; @@ -1272,10 +1274,24 @@ NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION else if (ValidateIOBufferSize (Irp, sizeof (VOLUME_DISK_EXTENTS), ValidateOutput)) { VOLUME_DISK_EXTENTS *extents = (VOLUME_DISK_EXTENTS *) Irp->AssociatedIrp.SystemBuffer; + - // No extent data can be returned as this is not a physical drive. - memset (extents, 0, sizeof (*extents)); - extents->NumberOfDiskExtents = 0; + if (OsMajorVersion == 10) + { + // Windows 10 filesystem defragmenter works only if we report an extent with a real disk number + // So in the case of a VeraCrypt disk based volume, we use the disk number + // of the underlaying physical disk and we report a single extent + extents->NumberOfDiskExtents = 1; + extents->Extents[0].DiskNumber = Extension->DeviceNumber; + extents->Extents[0].StartingOffset.QuadPart = Extension->BytesPerSector; + extents->Extents[0].ExtentLength.QuadPart = Extension->DiskLength; + } + else + { + // Vista: No extent data can be returned as this is not a physical drive. + memset (extents, 0, sizeof (*extents)); + extents->NumberOfDiskExtents = 0; + } Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = sizeof (*extents); diff --git a/src/Driver/Ntdriver.h b/src/Driver/Ntdriver.h index 8403f212..b679952a 100644 --- a/src/Driver/Ntdriver.h +++ b/src/Driver/Ntdriver.h @@ -66,6 +66,7 @@ typedef struct EXTENSION ULONG HostMaximumTransferLength; ULONG HostMaximumPhysicalPages; ULONG HostAlignmentMask; + ULONG DeviceNumber; BOOL IncursSeekPenalty; BOOL TrimEnabled; diff --git a/src/Driver/Ntvol.c b/src/Driver/Ntvol.c index c8552ab3..852aafd0 100644 --- a/src/Driver/Ntvol.c +++ b/src/Driver/Ntvol.c @@ -72,6 +72,8 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, Extension->IncursSeekPenalty = TRUE; Extension->TrimEnabled = FALSE; + Extension->DeviceNumber = (ULONG) -1; + RtlInitUnicodeString (&FullFileName, pwszMountVolume); InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0) | OBJ_KERNEL_HANDLE, NULL, NULL); KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE); @@ -94,6 +96,7 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, DISK_GEOMETRY_EX dg; STORAGE_PROPERTY_QUERY storagePropertyQuery = {0}; byte* dgBuffer; + STORAGE_DEVICE_NUMBER storageDeviceNumber; ntStatus = IoGetDeviceObjectPointer (&FullFileName, FILE_READ_DATA | FILE_READ_ATTRIBUTES, @@ -147,6 +150,13 @@ NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject, TCfree (dgBuffer); + if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, + IOCTL_STORAGE_GET_DEVICE_NUMBER, + (char*) &storageDeviceNumber, sizeof (storageDeviceNumber)))) + { + Extension->DeviceNumber = storageDeviceNumber.DeviceNumber; + } + lDiskLength.QuadPart = dg.DiskSize.QuadPart; Extension->HostBytesPerSector = dg.Geometry.BytesPerSector; Extension->HostBytesPerPhysicalSector = dg.Geometry.BytesPerSector;