"Fossies" - the Fresh Open Source Software Archive

Member "src/Driver/Ntdriver.c" (10 Oct 2018, 153646 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Ntdriver.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.22_Source_vs_1.23_Source.

    1 /*
    2  Legal Notice: Some portions of the source code contained in this file were
    3  derived from the source code of TrueCrypt 7.1a, which is
    4  Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
    5  governed by the TrueCrypt License 3.0, also from the source code of
    6  Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
    7  and which is governed by the 'License Agreement for Encryption for the Masses'
    8  Modifications and additions to the original source code (contained in this file)
    9  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
   10  and are governed by the Apache License 2.0 the full text of which is
   11  contained in the file License.txt included in VeraCrypt binary and source
   12  code distribution packages. */
   13 
   14 #include "TCdefs.h"
   15 #include <ntddk.h>
   16 #include "Crypto.h"
   17 #include "Fat.h"
   18 #include "Tests.h"
   19 #include "cpu.h"
   20 #include "Crc.h"
   21 
   22 #include "Apidrvr.h"
   23 #include "Boot/Windows/BootDefs.h"
   24 #include "EncryptedIoQueue.h"
   25 #include "EncryptionThreadPool.h"
   26 #include "Ntdriver.h"
   27 #include "Ntvol.h"
   28 #include "DriveFilter.h"
   29 #include "DumpFilter.h"
   30 #include "Cache.h"
   31 #include "Volumes.h"
   32 #include "VolumeFilter.h"
   33 
   34 #include <tchar.h>
   35 #include <initguid.h>
   36 #include <mountmgr.h>
   37 #include <mountdev.h>
   38 #include <ntddvol.h>
   39 
   40 #include <Ntstrsafe.h>
   41 #include <Intsafe.h>
   42 
   43 #ifndef IOCTL_DISK_GET_CLUSTER_INFO
   44 #define IOCTL_DISK_GET_CLUSTER_INFO             CTL_CODE(IOCTL_DISK_BASE, 0x0085, METHOD_BUFFERED, FILE_ANY_ACCESS)
   45 #endif
   46 
   47 #ifndef IOCTL_DISK_ARE_VOLUMES_READY
   48 #define IOCTL_DISK_ARE_VOLUMES_READY            CTL_CODE(IOCTL_DISK_BASE, 0x0087, METHOD_BUFFERED, FILE_READ_ACCESS)
   49 #endif
   50 
   51 #ifndef FT_BALANCED_READ_MODE
   52 #define FTTYPE  ((ULONG)'f') 
   53 #define FT_BALANCED_READ_MODE                       CTL_CODE(FTTYPE, 6, METHOD_NEITHER,  FILE_ANY_ACCESS) 
   54 #endif
   55 
   56 #ifndef IOCTL_VOLUME_QUERY_ALLOCATION_HINT
   57 #define IOCTL_VOLUME_QUERY_ALLOCATION_HINT      CTL_CODE(IOCTL_VOLUME_BASE, 20, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
   58 #endif
   59 
   60 #ifndef IOCTL_DISK_IS_CLUSTERED
   61 #define IOCTL_DISK_IS_CLUSTERED             CTL_CODE(IOCTL_DISK_BASE, 0x003e, METHOD_BUFFERED, FILE_ANY_ACCESS)
   62 #endif
   63 
   64 #ifndef IOCTL_VOLUME_POST_ONLINE
   65 #define IOCTL_VOLUME_POST_ONLINE                CTL_CODE(IOCTL_VOLUME_BASE, 25, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
   66 #endif
   67 
   68 #ifndef IOCTL_VOLUME_IS_DYNAMIC
   69 #define IOCTL_VOLUME_IS_DYNAMIC                 CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS)
   70 #endif
   71 
   72 #ifndef StorageDeviceLBProvisioningProperty
   73 #define StorageDeviceLBProvisioningProperty 11
   74 #endif
   75 
   76 #ifndef DeviceDsmAction_OffloadRead
   77 #define DeviceDsmAction_OffloadRead       ( 3  | DeviceDsmActionFlag_NonDestructive)
   78 #endif
   79 
   80 #ifndef DeviceDsmAction_OffloadWrite
   81 #define DeviceDsmAction_OffloadWrite        4
   82 #endif
   83 
   84 #ifndef DeviceDsmAction_Allocation
   85 #define DeviceDsmAction_Allocation        ( 5  | DeviceDsmActionFlag_NonDestructive)
   86 #endif
   87 
   88 #ifndef DeviceDsmAction_Repair
   89 #define DeviceDsmAction_Repair            ( 6  | DeviceDsmActionFlag_NonDestructive)
   90 #endif
   91 
   92 #ifndef DeviceDsmAction_Scrub
   93 #define DeviceDsmAction_Scrub             ( 7  | DeviceDsmActionFlag_NonDestructive)
   94 #endif
   95 
   96 #ifndef DeviceDsmAction_DrtQuery
   97 #define DeviceDsmAction_DrtQuery          ( 8  | DeviceDsmActionFlag_NonDestructive)
   98 #endif
   99 
  100 #ifndef DeviceDsmAction_DrtClear
  101 #define DeviceDsmAction_DrtClear          ( 9  | DeviceDsmActionFlag_NonDestructive)
  102 #endif
  103 
  104 #ifndef DeviceDsmAction_DrtDisable
  105 #define DeviceDsmAction_DrtDisable        (10  | DeviceDsmActionFlag_NonDestructive)
  106 #endif
  107 
  108 /* Init section, which is thrown away as soon as DriverEntry returns */
  109 #pragma alloc_text(INIT,DriverEntry)
  110 #pragma alloc_text(INIT,TCCreateRootDeviceObject)
  111 
  112 /* We need to silence 'type cast' warning in order to use MmGetSystemRoutineAddress.
  113  * MmGetSystemRoutineAddress() should have been declare FARPROC instead of PVOID.
  114  */
  115 #pragma warning(disable:4055)
  116 
  117 PDRIVER_OBJECT TCDriverObject;
  118 PDEVICE_OBJECT RootDeviceObject = NULL;
  119 static KMUTEX RootDeviceControlMutex;
  120 BOOL DriverShuttingDown = FALSE;
  121 BOOL SelfTestsPassed;
  122 int LastUniqueVolumeId;
  123 ULONG OsMajorVersion = 0;
  124 ULONG OsMinorVersion;
  125 BOOL DriverUnloadDisabled = FALSE;
  126 BOOL PortableMode = FALSE;
  127 BOOL VolumeClassFilterRegistered = FALSE;
  128 BOOL CacheBootPassword = FALSE;
  129 BOOL CacheBootPim = FALSE;
  130 BOOL NonAdminSystemFavoritesAccessDisabled = FALSE;
  131 BOOL BlockSystemTrimCommand = FALSE;
  132 BOOL AllowWindowsDefrag = FALSE;
  133 static size_t EncryptionThreadPoolFreeCpuCountLimit = 0;
  134 static BOOL SystemFavoriteVolumeDirty = FALSE;
  135 static BOOL PagingFileCreationPrevented = FALSE;
  136 static BOOL EnableExtendedIoctlSupport = FALSE;
  137 static BOOL AllowTrimCommand = FALSE;
  138 static KeSaveExtendedProcessorStateFn KeSaveExtendedProcessorStatePtr = NULL;
  139 static KeRestoreExtendedProcessorStateFn KeRestoreExtendedProcessorStatePtr = NULL;
  140 
  141 POOL_TYPE ExDefaultNonPagedPoolType = NonPagedPool;
  142 ULONG ExDefaultMdlProtection = 0;
  143 
  144 PDEVICE_OBJECT VirtualVolumeDeviceObjects[MAX_MOUNTED_VOLUME_DRIVE_NUMBER + 1];
  145 
  146 
  147 NTSTATUS DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
  148 {
  149     PKEY_VALUE_PARTIAL_INFORMATION startKeyValue;
  150     LONG version;
  151     int i;
  152 
  153     Dump ("DriverEntry " TC_APP_NAME " " VERSION_STRING "\n");
  154 
  155     DetectX86Features ();
  156 
  157     PsGetVersion (&OsMajorVersion, &OsMinorVersion, NULL, NULL);
  158 
  159     Dump ("OsMajorVersion=%d OsMinorVersion=%d\n", OsMajorVersion, OsMinorVersion);
  160 
  161     // NX pool support is available starting from Windows 8
  162     if ((OsMajorVersion > 6) || (OsMajorVersion == 6 && OsMinorVersion >= 2))
  163     {
  164         ExDefaultNonPagedPoolType = (POOL_TYPE) NonPagedPoolNx;
  165         ExDefaultMdlProtection = MdlMappingNoExecute;
  166     }
  167 
  168     // KeSaveExtendedProcessorState/KeRestoreExtendedProcessorState are available starting from Windows 7
  169     if ((OsMajorVersion > 6) || (OsMajorVersion == 6 && OsMinorVersion >= 1))
  170     {
  171         UNICODE_STRING saveFuncName, restoreFuncName;
  172         RtlInitUnicodeString(&saveFuncName, L"KeSaveExtendedProcessorState");
  173         RtlInitUnicodeString(&restoreFuncName, L"KeRestoreExtendedProcessorState");
  174         KeSaveExtendedProcessorStatePtr = (KeSaveExtendedProcessorStateFn) MmGetSystemRoutineAddress(&saveFuncName);
  175         KeRestoreExtendedProcessorStatePtr = (KeRestoreExtendedProcessorStateFn) MmGetSystemRoutineAddress(&restoreFuncName);
  176     }
  177 
  178     // Load dump filter if the main driver is already loaded
  179     if (NT_SUCCESS (TCDeviceIoControl (NT_ROOT_PREFIX, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &version, sizeof (version))))
  180         return DumpFilterEntry ((PFILTER_EXTENSION) DriverObject, (PFILTER_INITIALIZATION_DATA) RegistryPath);
  181 
  182     TCDriverObject = DriverObject;
  183     memset (VirtualVolumeDeviceObjects, 0, sizeof (VirtualVolumeDeviceObjects));
  184 
  185     ReadRegistryConfigFlags (TRUE);
  186     EncryptionThreadPoolStart (EncryptionThreadPoolFreeCpuCountLimit);
  187     SelfTestsPassed = AutoTestAlgorithms();
  188 
  189     // Enable device class filters and load boot arguments if the driver is set to start at system boot
  190 
  191     if (NT_SUCCESS (TCReadRegistryKey (RegistryPath, L"Start", &startKeyValue)))
  192     {
  193         if (startKeyValue->Type == REG_DWORD && *((uint32 *) startKeyValue->Data) == SERVICE_BOOT_START)
  194         {
  195             if (!SelfTestsPassed)
  196             {
  197                 // in case of system encryption, if self-tests fail, disable all extended CPU
  198                 // features and try again in order to workaround faulty configurations
  199                 DisableCPUExtendedFeatures ();
  200                 SelfTestsPassed = AutoTestAlgorithms();
  201 
  202                 // BUG CHECK if the self-tests still fail
  203                 if (!SelfTestsPassed)
  204                     TC_BUG_CHECK (STATUS_INVALID_PARAMETER);
  205             }
  206 
  207             LoadBootArguments();
  208             VolumeClassFilterRegistered = IsVolumeClassFilterRegistered();
  209 
  210             DriverObject->DriverExtension->AddDevice = DriverAddDevice;
  211         }
  212 
  213         TCfree (startKeyValue);
  214     }
  215 
  216     for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; ++i)
  217     {
  218         DriverObject->MajorFunction[i] = TCDispatchQueueIRP;
  219     }
  220 
  221     DriverObject->DriverUnload = TCUnloadDriver;
  222     return TCCreateRootDeviceObject (DriverObject);
  223 }
  224 
  225 
  226 NTSTATUS DriverAddDevice (PDRIVER_OBJECT driverObject, PDEVICE_OBJECT pdo)
  227 {
  228 #if defined(DEBUG) || defined (DEBUG_TRACE)
  229     char nameInfoBuffer[128];
  230     POBJECT_NAME_INFORMATION nameInfo = (POBJECT_NAME_INFORMATION) nameInfoBuffer;
  231     ULONG nameInfoSize;
  232     Dump ("AddDevice pdo=%p type=%x name=%ws\n", pdo, pdo->DeviceType, NT_SUCCESS (ObQueryNameString (pdo, nameInfo, sizeof (nameInfoBuffer), &nameInfoSize)) ? nameInfo->Name.Buffer : L"?");
  233 #endif
  234 
  235     if (VolumeClassFilterRegistered && BootArgsValid && BootArgs.HiddenSystemPartitionStart != 0)
  236     {
  237         PWSTR interfaceLinks = NULL;
  238         if (NT_SUCCESS (IoGetDeviceInterfaces (&GUID_DEVINTERFACE_VOLUME, pdo, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &interfaceLinks)) && interfaceLinks)
  239         {
  240             if (interfaceLinks[0] != UNICODE_NULL)
  241             {
  242                 Dump ("Volume pdo=%p interface=%ws\n", pdo, interfaceLinks);
  243                 ExFreePool (interfaceLinks);
  244 
  245                 return VolumeFilterAddDevice (driverObject, pdo);
  246             }
  247 
  248             ExFreePool (interfaceLinks);
  249         }
  250     }
  251 
  252     return DriveFilterAddDevice (driverObject, pdo);
  253 }
  254 
  255 
  256 // Dumps a memory region to debug output
  257 void DumpMemory (void *mem, int size)
  258 {
  259     unsigned char str[20];
  260     unsigned char *m = mem;
  261     int i,j;
  262 
  263     for (j = 0; j < size / 8; j++)
  264     {
  265         memset (str,0,sizeof str);
  266         for (i = 0; i < 8; i++)
  267         {
  268             if (m[i] > ' ' && m[i] <= '~')
  269                 str[i]=m[i];
  270             else
  271                 str[i]='.';
  272         }
  273 
  274         Dump ("0x%08p  %02x %02x %02x %02x %02x %02x %02x %02x  %s\n",
  275             m, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], str);
  276 
  277         m+=8;
  278     }
  279 }
  280 
  281 BOOL IsAllZeroes (unsigned char* pbData, DWORD dwDataLen)
  282 {
  283     while (dwDataLen--)
  284     {
  285         if (*pbData)
  286             return FALSE;
  287         pbData++;
  288     }
  289     return TRUE;
  290 }
  291 
  292 static wchar_t UpperCaseUnicodeChar (wchar_t c)
  293 {
  294     if (c >= L'a' && c <= L'z')
  295         return (c - L'a') + L'A';
  296     return c;
  297 }
  298 
  299 static BOOL StringNoCaseCompare (const wchar_t* str1, const wchar_t* str2, size_t len)
  300 {
  301     if (str1 && str2)
  302     {
  303         while (len)
  304         {
  305             if (UpperCaseUnicodeChar (*str1) != UpperCaseUnicodeChar (*str2))
  306                 return FALSE;
  307             str1++;
  308             str2++;
  309             len--;
  310         }
  311     }
  312 
  313     return TRUE;
  314 }
  315 
  316 static BOOL CheckStringLength (const wchar_t* str, size_t cchSize, size_t minLength, size_t maxLength, size_t* pcchLength)
  317 {
  318     size_t actualLength;
  319     for (actualLength = 0; actualLength < cchSize; actualLength++)
  320     {
  321         if (str[actualLength] == 0)
  322             break;
  323     }
  324 
  325     if (pcchLength)
  326         *pcchLength = actualLength;
  327 
  328     if (actualLength == cchSize)
  329         return FALSE;
  330 
  331     if ((minLength != ((size_t) -1)) && (actualLength < minLength))
  332         return FALSE;
  333 
  334     if ((maxLength != ((size_t) -1)) && (actualLength > maxLength))
  335         return FALSE;
  336 
  337     return TRUE;
  338 }
  339 
  340 BOOL ValidateIOBufferSize (PIRP irp, size_t requiredBufferSize, ValidateIOBufferSizeType type)
  341 {
  342     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (irp);
  343     BOOL input = (type == ValidateInput || type == ValidateInputOutput);
  344     BOOL output = (type == ValidateOutput || type == ValidateInputOutput);
  345 
  346     if ((input && irpSp->Parameters.DeviceIoControl.InputBufferLength < requiredBufferSize)
  347         || (output && irpSp->Parameters.DeviceIoControl.OutputBufferLength < requiredBufferSize))
  348     {
  349         Dump ("STATUS_BUFFER_TOO_SMALL ioctl=0x%x,%d in=%d out=%d reqsize=%d insize=%d outsize=%d\n", (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16), (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2), input, output, requiredBufferSize, irpSp->Parameters.DeviceIoControl.InputBufferLength, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
  350 
  351         irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  352         irp->IoStatus.Information = 0;
  353         return FALSE;
  354     }
  355 
  356     if (!input && output)
  357         memset (irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
  358 
  359     return TRUE;
  360 }
  361 
  362 
  363 PDEVICE_OBJECT GetVirtualVolumeDeviceObject (int driveNumber)
  364 {
  365     if (driveNumber < MIN_MOUNTED_VOLUME_DRIVE_NUMBER || driveNumber > MAX_MOUNTED_VOLUME_DRIVE_NUMBER)
  366         return NULL;
  367 
  368     return VirtualVolumeDeviceObjects[driveNumber];
  369 }
  370 
  371 
  372 /* TCDispatchQueueIRP queues any IRP's so that they can be processed later
  373    by the thread -- or in some cases handles them immediately! */
  374 NTSTATUS TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp)
  375 {
  376     PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension;
  377     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
  378     NTSTATUS ntStatus;
  379 
  380 #if defined(_DEBUG) || defined (_DEBUG_TRACE)
  381     if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL && (Extension->bRootDevice || Extension->IsVolumeDevice))
  382     {
  383         switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
  384         {
  385         case TC_IOCTL_GET_MOUNTED_VOLUMES:
  386         case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
  387         case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
  388         case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
  389         case TC_IOCTL_OPEN_TEST:
  390         case TC_IOCTL_GET_RESOLVED_SYMLINK:
  391         case TC_IOCTL_GET_DEVICE_REFCOUNT:
  392         case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
  393         case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
  394         case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
  395         case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS:
  396         case TC_IOCTL_GET_WARNING_FLAGS:
  397         case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
  398         case IOCTL_DISK_CHECK_VERIFY:
  399             break;
  400 
  401         default:
  402             Dump ("%ls (0x%x %d)\n",
  403                 TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode),
  404                 (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16),
  405                 (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2));
  406         }
  407     }
  408 #endif
  409 
  410     if (!Extension->bRootDevice)
  411     {
  412         // Drive filter IRP
  413         if (Extension->IsDriveFilterDevice)
  414             return DriveFilterDispatchIrp (DeviceObject, Irp);
  415 
  416         // Volume filter IRP
  417         if (Extension->IsVolumeFilterDevice)
  418             return VolumeFilterDispatchIrp (DeviceObject, Irp);
  419     }
  420 
  421     switch (irpSp->MajorFunction)
  422     {
  423     case IRP_MJ_CLOSE:
  424     case IRP_MJ_CREATE:
  425     case IRP_MJ_CLEANUP:
  426         return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0);
  427 
  428     case IRP_MJ_SHUTDOWN:
  429         if (Extension->bRootDevice)
  430         {
  431             Dump ("Driver shutting down\n");
  432             DriverShuttingDown = TRUE;
  433 
  434             if (EncryptionSetupThread)
  435                 while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
  436 
  437             if (DecoySystemWipeThread)
  438                 while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
  439 
  440             OnShutdownPending();
  441         }
  442 
  443         return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0);
  444 
  445     case IRP_MJ_FLUSH_BUFFERS:
  446     case IRP_MJ_READ:
  447     case IRP_MJ_WRITE:
  448     case IRP_MJ_DEVICE_CONTROL:
  449 
  450         if (Extension->bRootDevice)
  451         {
  452             if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
  453             {
  454                 NTSTATUS status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, NULL);
  455                 if (!NT_SUCCESS (status))
  456                     return status;
  457 
  458                 status = ProcessMainDeviceControlIrp (DeviceObject, Extension, Irp);
  459 
  460                 KeReleaseMutex (&RootDeviceControlMutex, FALSE);
  461                 return status;
  462             }
  463             break;
  464         }
  465 
  466         if (Extension->bShuttingDown)
  467         {
  468             Dump ("Device %d shutting down: STATUS_DELETE_PENDING\n", Extension->nDosDriveNo);
  469             return TCCompleteDiskIrp (Irp, STATUS_DELETE_PENDING, 0);
  470         }
  471 
  472         if (Extension->bRemovable
  473             && (DeviceObject->Flags & DO_VERIFY_VOLUME)
  474             && !(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME)
  475             && irpSp->MajorFunction != IRP_MJ_FLUSH_BUFFERS)
  476         {
  477             Dump ("Removable device %d has DO_VERIFY_VOLUME flag: STATUS_DEVICE_NOT_READY\n", Extension->nDosDriveNo);
  478             return TCCompleteDiskIrp (Irp, STATUS_DEVICE_NOT_READY, 0);
  479         }
  480 
  481         switch (irpSp->MajorFunction)
  482         {
  483         case IRP_MJ_READ:
  484         case IRP_MJ_WRITE:
  485             ntStatus = EncryptedIoQueueAddIrp (&Extension->Queue, Irp);
  486 
  487             if (ntStatus != STATUS_PENDING)
  488                 TCCompleteDiskIrp (Irp, ntStatus, 0);
  489 
  490             return ntStatus;
  491 
  492         case IRP_MJ_DEVICE_CONTROL:
  493             ntStatus = IoAcquireRemoveLock (&Extension->Queue.RemoveLock, Irp);
  494             if (!NT_SUCCESS (ntStatus))
  495                 return TCCompleteIrp (Irp, ntStatus, 0);
  496 
  497             IoMarkIrpPending (Irp);
  498 
  499             ExInterlockedInsertTailList (&Extension->ListEntry, &Irp->Tail.Overlay.ListEntry, &Extension->ListSpinLock);
  500             KeReleaseSemaphore (&Extension->RequestSemaphore, IO_DISK_INCREMENT, 1, FALSE);
  501 
  502             return STATUS_PENDING;
  503 
  504         case IRP_MJ_FLUSH_BUFFERS:
  505             return TCCompleteDiskIrp (Irp, STATUS_SUCCESS, 0);
  506         }
  507 
  508         break;
  509 
  510     case IRP_MJ_PNP:
  511         if (!Extension->bRootDevice
  512             && Extension->IsVolumeDevice
  513             && irpSp->MinorFunction == IRP_MN_DEVICE_USAGE_NOTIFICATION
  514             && irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging
  515             && irpSp->Parameters.UsageNotification.InPath)
  516         {
  517             PagingFileCreationPrevented = TRUE;
  518             return TCCompleteIrp (Irp, STATUS_UNSUCCESSFUL, 0);
  519         }
  520         break;
  521     }
  522 
  523     return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
  524 }
  525 
  526 NTSTATUS TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject)
  527 {
  528     UNICODE_STRING Win32NameString, ntUnicodeString;
  529     WCHAR dosname[32], ntname[32];
  530     PDEVICE_OBJECT DeviceObject;
  531     NTSTATUS ntStatus;
  532     BOOL *bRootExtension;
  533 
  534     Dump ("TCCreateRootDeviceObject BEGIN\n");
  535     ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
  536 
  537     RtlStringCbCopyW (dosname, sizeof(dosname),(LPWSTR) DOS_ROOT_PREFIX);
  538     RtlStringCbCopyW (ntname, sizeof(ntname),(LPWSTR) NT_ROOT_PREFIX);
  539     RtlInitUnicodeString (&ntUnicodeString, ntname);
  540     RtlInitUnicodeString (&Win32NameString, dosname);
  541 
  542     Dump ("Creating root device nt=%ls dos=%ls\n", ntname, dosname);
  543 
  544     ntStatus = IoCreateDevice (
  545                       DriverObject,
  546                       sizeof (BOOL),
  547                       &ntUnicodeString,
  548                       FILE_DEVICE_UNKNOWN,
  549                       FILE_DEVICE_SECURE_OPEN,
  550                       FALSE,
  551                       &DeviceObject);
  552 
  553     if (!NT_SUCCESS (ntStatus))
  554     {
  555         Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
  556         return ntStatus;/* Failed to create DeviceObject */
  557     }
  558 
  559     DeviceObject->Flags |= DO_DIRECT_IO;
  560     DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
  561 
  562     /* Setup the device extension */
  563     bRootExtension = (BOOL *) DeviceObject->DeviceExtension;
  564     *bRootExtension = TRUE;
  565 
  566     KeInitializeMutex (&RootDeviceControlMutex, 0);
  567 
  568     ntStatus = IoCreateSymbolicLink (&Win32NameString, &ntUnicodeString);
  569 
  570     if (!NT_SUCCESS (ntStatus))
  571     {
  572         Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
  573         IoDeleteDevice (DeviceObject);
  574         return ntStatus;
  575     }
  576 
  577     IoRegisterShutdownNotification (DeviceObject);
  578     RootDeviceObject = DeviceObject;
  579 
  580     Dump ("TCCreateRootDeviceObject STATUS_SUCCESS END\n");
  581     return STATUS_SUCCESS;
  582 }
  583 
  584 NTSTATUS TCCreateDeviceObject (PDRIVER_OBJECT DriverObject,
  585                PDEVICE_OBJECT * ppDeviceObject,
  586                MOUNT_STRUCT * mount)
  587 {
  588     UNICODE_STRING ntUnicodeString;
  589     WCHAR ntname[32];
  590     PEXTENSION Extension;
  591     NTSTATUS ntStatus;
  592     ULONG devChars = 0;
  593 #if defined (DEBUG) || defined (DEBUG_TRACE)
  594     WCHAR dosname[32];
  595 #endif
  596 
  597     Dump ("TCCreateDeviceObject BEGIN\n");
  598     ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
  599 
  600     TCGetNTNameFromNumber (ntname, sizeof(ntname),mount->nDosDriveNo);
  601     RtlInitUnicodeString (&ntUnicodeString, ntname);
  602 #if defined (DEBUG) || defined (DEBUG_TRACE)
  603     TCGetDosNameFromNumber (dosname, sizeof(dosname),mount->nDosDriveNo, DeviceNamespaceDefault);
  604 #endif
  605 
  606     devChars = FILE_DEVICE_SECURE_OPEN;
  607     devChars |= mount->bMountReadOnly ? FILE_READ_ONLY_DEVICE : 0;
  608     devChars |= mount->bMountRemovable ? FILE_REMOVABLE_MEDIA : 0;
  609 
  610 #if defined (DEBUG) || defined (DEBUG_TRACE)
  611     Dump ("Creating device nt=%ls dos=%ls\n", ntname, dosname);
  612 #endif
  613 
  614     ntStatus = IoCreateDevice (
  615                       DriverObject,         /* Our Driver Object */
  616                       sizeof (EXTENSION),   /* Size of state information */
  617                       &ntUnicodeString,     /* Device name "\Device\Name" */
  618                       FILE_DEVICE_DISK,     /* Device type */
  619                       devChars,             /* Device characteristics */
  620                       FALSE,                /* Exclusive device */
  621                       ppDeviceObject);      /* Returned ptr to Device Object */
  622 
  623     if (!NT_SUCCESS (ntStatus))
  624     {
  625         Dump ("TCCreateDeviceObject NTSTATUS = 0x%08x END\n", ntStatus);
  626         return ntStatus;/* Failed to create DeviceObject */
  627     }
  628     /* Initialize device object and extension. */
  629 
  630     (*ppDeviceObject)->Flags |= DO_DIRECT_IO;
  631     (*ppDeviceObject)->StackSize += 6;      // Reduce occurrence of NO_MORE_IRP_STACK_LOCATIONS bug check caused by buggy drivers
  632 
  633     /* Setup the device extension */
  634     Extension = (PEXTENSION) (*ppDeviceObject)->DeviceExtension;
  635     memset (Extension, 0, sizeof (EXTENSION));
  636 
  637     Extension->IsVolumeDevice = TRUE;
  638     Extension->nDosDriveNo = mount->nDosDriveNo;
  639     Extension->bRemovable = mount->bMountRemovable;
  640     Extension->PartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
  641     Extension->SystemFavorite = mount->SystemFavorite;
  642 
  643     KeInitializeEvent (&Extension->keCreateEvent, SynchronizationEvent, FALSE);
  644     KeInitializeSemaphore (&Extension->RequestSemaphore, 0L, MAXLONG);
  645     KeInitializeSpinLock (&Extension->ListSpinLock);
  646     InitializeListHead (&Extension->ListEntry);
  647     IoInitializeRemoveLock (&Extension->Queue.RemoveLock, 'LRCV', 0, 0);
  648 
  649     VirtualVolumeDeviceObjects[mount->nDosDriveNo] = *ppDeviceObject;
  650 
  651     Dump ("TCCreateDeviceObject STATUS_SUCCESS END\n");
  652 
  653     return STATUS_SUCCESS;
  654 }
  655 
  656 
  657 BOOL RootDeviceControlMutexAcquireNoWait ()
  658 {
  659     NTSTATUS status;
  660     LARGE_INTEGER timeout;
  661     timeout.QuadPart = 0;
  662 
  663     status = KeWaitForMutexObject (&RootDeviceControlMutex, Executive, KernelMode, FALSE, &timeout);
  664     return NT_SUCCESS (status) && status != STATUS_TIMEOUT;
  665 }
  666 
  667 
  668 void RootDeviceControlMutexRelease ()
  669 {
  670     KeReleaseMutex (&RootDeviceControlMutex, FALSE);
  671 }
  672 
  673 /*
  674 IOCTL_STORAGE_GET_DEVICE_NUMBER 0x002D1080 
  675 IOCTL_STORAGE_GET_HOTPLUG_INFO 0x002D0C14
  676 IOCTL_STORAGE_QUERY_PROPERTY 0x002D1400
  677 */
  678 
  679 NTSTATUS ProcessVolumeDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp)
  680 {
  681     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
  682 
  683     switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
  684     {
  685 
  686     case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
  687         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_MOUNTDEV_QUERY_DEVICE_NAME)\n");
  688         if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_NAME), ValidateOutput))
  689         {
  690             Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME);
  691             Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  692         }
  693         else
  694         {
  695             ULONG outLength;
  696             UNICODE_STRING ntUnicodeString;
  697             WCHAR ntName[256];
  698             PMOUNTDEV_NAME outputBuffer = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer;
  699 
  700             TCGetNTNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo);
  701             RtlInitUnicodeString (&ntUnicodeString, ntName);
  702 
  703             outputBuffer->NameLength = ntUnicodeString.Length;
  704             outLength = ntUnicodeString.Length + sizeof(USHORT);
  705 
  706             if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
  707             {
  708                 Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME);
  709                 Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  710 
  711                 break;
  712             }
  713 
  714             RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length);
  715 
  716             Irp->IoStatus.Status = STATUS_SUCCESS;
  717             Irp->IoStatus.Information = outLength;
  718 
  719             Dump ("name = %ls\n",ntName);
  720         }
  721         break;
  722 
  723     case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
  724         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_MOUNTDEV_QUERY_UNIQUE_ID)\n");
  725         if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_UNIQUE_ID), ValidateOutput))
  726         {
  727             Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID);
  728             Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  729         }
  730         else
  731         {
  732             ULONG outLength;
  733             UCHAR volId[128], tmp[] = { 0,0 };
  734             PMOUNTDEV_UNIQUE_ID outputBuffer = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer;
  735 
  736             RtlStringCbCopyA (volId, sizeof(volId),TC_UNIQUE_ID_PREFIX);
  737             tmp[0] = 'A' + (UCHAR) Extension->nDosDriveNo;
  738             RtlStringCbCatA (volId, sizeof(volId),tmp);
  739 
  740             outputBuffer->UniqueIdLength = (USHORT) strlen (volId);
  741             outLength = (ULONG) (strlen (volId) + sizeof (USHORT));
  742 
  743             if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
  744             {
  745                 Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID);
  746                 Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  747                 break;
  748             }
  749 
  750             RtlCopyMemory ((PCHAR)outputBuffer->UniqueId, volId, strlen (volId));
  751 
  752             Irp->IoStatus.Status = STATUS_SUCCESS;
  753             Irp->IoStatus.Information = outLength;
  754 
  755             Dump ("id = %s\n",volId);
  756         }
  757         break;
  758 
  759     case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
  760         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME)\n");
  761         {
  762             ULONG outLength;
  763             UNICODE_STRING ntUnicodeString;
  764             WCHAR ntName[256];
  765             PMOUNTDEV_SUGGESTED_LINK_NAME outputBuffer = (PMOUNTDEV_SUGGESTED_LINK_NAME) Irp->AssociatedIrp.SystemBuffer;
  766 
  767             if (!ValidateIOBufferSize (Irp, sizeof (MOUNTDEV_SUGGESTED_LINK_NAME), ValidateOutput))
  768             {
  769                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  770                 Irp->IoStatus.Information = 0;
  771                 break;
  772             }
  773 
  774             TCGetDosNameFromNumber (ntName, sizeof(ntName),Extension->nDosDriveNo, DeviceNamespaceDefault);
  775             RtlInitUnicodeString (&ntUnicodeString, ntName);
  776 
  777             outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length;
  778 
  779             outputBuffer->UseOnlyIfThereAreNoOtherLinks = FALSE;
  780             outputBuffer->NameLength = ntUnicodeString.Length;
  781 
  782             if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength)
  783             {
  784                 Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME);
  785                 Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  786                 break;
  787             }
  788 
  789             RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length);
  790 
  791             Irp->IoStatus.Status = STATUS_SUCCESS;
  792             Irp->IoStatus.Information = outLength;
  793 
  794             Dump ("link = %ls\n",ntName);
  795         }
  796         break;
  797 
  798     case IOCTL_DISK_GET_MEDIA_TYPES:
  799     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  800     case IOCTL_STORAGE_GET_MEDIA_TYPES:
  801     case IOCTL_DISK_UPDATE_DRIVE_SIZE:
  802         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_DRIVE_GEOMETRY)\n");
  803         /* Return the drive geometry for the disk.  Note that we
  804            return values which were made up to suit the disk size.  */
  805         if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY), ValidateOutput))
  806         {
  807             PDISK_GEOMETRY outputBuffer = (PDISK_GEOMETRY)
  808             Irp->AssociatedIrp.SystemBuffer;
  809 
  810             outputBuffer->MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia;
  811             outputBuffer->Cylinders.QuadPart = Extension->NumberOfCylinders;
  812             outputBuffer->TracksPerCylinder = Extension->TracksPerCylinder;
  813             outputBuffer->SectorsPerTrack = Extension->SectorsPerTrack;
  814             outputBuffer->BytesPerSector = Extension->BytesPerSector;
  815             Irp->IoStatus.Status = STATUS_SUCCESS;
  816             Irp->IoStatus.Information = sizeof (DISK_GEOMETRY);
  817         }
  818         break;
  819 
  820     case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:
  821         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_DRIVE_GEOMETRY_EX)\n");
  822         {
  823             ULONG minOutputSize = IsOSAtLeast (WIN_SERVER_2003)? sizeof (DISK_GEOMETRY_EX) : sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER);
  824             ULONG fullOutputSize = sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER) + sizeof (DISK_PARTITION_INFO) + sizeof (DISK_DETECTION_INFO);
  825 
  826             if (ValidateIOBufferSize (Irp, minOutputSize, ValidateOutput))
  827             {
  828                 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
  829                 BOOL bFullBuffer = (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= fullOutputSize)? TRUE : FALSE;
  830                 PDISK_GEOMETRY_EX outputBuffer = (PDISK_GEOMETRY_EX) Irp->AssociatedIrp.SystemBuffer;
  831 
  832                 outputBuffer->Geometry.MediaType = Extension->bRemovable ? RemovableMedia : FixedMedia;
  833                 outputBuffer->Geometry.Cylinders.QuadPart = Extension->NumberOfCylinders;
  834                 outputBuffer->Geometry.TracksPerCylinder = Extension->TracksPerCylinder;
  835                 outputBuffer->Geometry.SectorsPerTrack = Extension->SectorsPerTrack;
  836                 outputBuffer->Geometry.BytesPerSector = Extension->BytesPerSector;
  837                 /* add one sector to DiskLength since our partition size is DiskLength and its offset if BytesPerSector */
  838                 outputBuffer->DiskSize.QuadPart = Extension->DiskLength + Extension->BytesPerSector;
  839 
  840                 if (bFullBuffer)
  841                 {
  842                     PDISK_PARTITION_INFO pPartInfo = (PDISK_PARTITION_INFO)(((ULONG_PTR) outputBuffer) + sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER));
  843                     PDISK_DETECTION_INFO pDetectInfo = ((PDISK_DETECTION_INFO)((((ULONG_PTR) pPartInfo) + sizeof (DISK_PARTITION_INFO))));
  844 
  845                     pPartInfo->SizeOfPartitionInfo = sizeof (DISK_PARTITION_INFO);
  846                     pPartInfo->PartitionStyle = PARTITION_STYLE_MBR;
  847                     pPartInfo->Mbr.Signature = GetCrc32((unsigned char*) &(Extension->UniqueVolumeId), 4);
  848 
  849                     pDetectInfo->SizeOfDetectInfo = sizeof (DISK_DETECTION_INFO);
  850 
  851                     Irp->IoStatus.Information = fullOutputSize;
  852                 }
  853                 else
  854                 {
  855                     if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (DISK_GEOMETRY_EX))
  856                         Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX);
  857                     else
  858                         Irp->IoStatus.Information = minOutputSize;
  859                 }
  860 
  861                 Irp->IoStatus.Status = STATUS_SUCCESS;
  862             }
  863         }
  864         break;
  865 
  866     case IOCTL_STORAGE_GET_MEDIA_TYPES_EX:
  867         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_GET_MEDIA_TYPES_EX)\n");
  868         if (ValidateIOBufferSize (Irp, sizeof (GET_MEDIA_TYPES), ValidateOutput))
  869         {
  870             PGET_MEDIA_TYPES outputBuffer = (PGET_MEDIA_TYPES)
  871             Irp->AssociatedIrp.SystemBuffer;
  872             PDEVICE_MEDIA_INFO mediaInfo = &outputBuffer->MediaInfo[0];
  873 
  874             outputBuffer->DeviceType = FILE_DEVICE_DISK;
  875             outputBuffer->MediaInfoCount = 1;
  876 
  877             if (Extension->bRemovable)
  878             {
  879                 mediaInfo->DeviceSpecific.RemovableDiskInfo.NumberMediaSides = 1;
  880                 if (Extension->bReadOnly)
  881                     mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_ONLY | MEDIA_WRITE_PROTECTED);
  882                 else
  883                     mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE);
  884                 mediaInfo->DeviceSpecific.RemovableDiskInfo.MediaType = (STORAGE_MEDIA_TYPE) RemovableMedia;
  885                 mediaInfo->DeviceSpecific.RemovableDiskInfo.Cylinders.QuadPart = Extension->NumberOfCylinders;
  886                 mediaInfo->DeviceSpecific.RemovableDiskInfo.TracksPerCylinder = Extension->TracksPerCylinder;
  887                 mediaInfo->DeviceSpecific.RemovableDiskInfo.SectorsPerTrack = Extension->SectorsPerTrack;
  888                 mediaInfo->DeviceSpecific.RemovableDiskInfo.BytesPerSector = Extension->BytesPerSector;
  889             }
  890             else
  891             {
  892                 mediaInfo->DeviceSpecific.DiskInfo.NumberMediaSides = 1;
  893                 if (Extension->bReadOnly)
  894                     mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_ONLY | MEDIA_WRITE_PROTECTED);
  895                 else
  896                     mediaInfo->DeviceSpecific.DiskInfo.MediaCharacteristics = (MEDIA_CURRENTLY_MOUNTED | MEDIA_READ_WRITE);
  897                 mediaInfo->DeviceSpecific.DiskInfo.MediaType = (STORAGE_MEDIA_TYPE) FixedMedia;
  898                 mediaInfo->DeviceSpecific.DiskInfo.Cylinders.QuadPart = Extension->NumberOfCylinders;
  899                 mediaInfo->DeviceSpecific.DiskInfo.TracksPerCylinder = Extension->TracksPerCylinder;
  900                 mediaInfo->DeviceSpecific.DiskInfo.SectorsPerTrack = Extension->SectorsPerTrack;
  901                 mediaInfo->DeviceSpecific.DiskInfo.BytesPerSector = Extension->BytesPerSector;
  902             }
  903             Irp->IoStatus.Status = STATUS_SUCCESS;
  904             Irp->IoStatus.Information = sizeof (GET_MEDIA_TYPES);
  905         }
  906         break;
  907 
  908     case IOCTL_STORAGE_QUERY_PROPERTY:
  909         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_QUERY_PROPERTY)\n");        
  910         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  911         Irp->IoStatus.Information = 0;
  912         if (EnableExtendedIoctlSupport || Extension->TrimEnabled)
  913         {
  914             if (ValidateIOBufferSize (Irp, sizeof (STORAGE_PROPERTY_QUERY), ValidateInput))
  915             {
  916                 PSTORAGE_PROPERTY_QUERY pStoragePropQuery = (PSTORAGE_PROPERTY_QUERY) Irp->AssociatedIrp.SystemBuffer;
  917                 STORAGE_QUERY_TYPE type = pStoragePropQuery->QueryType;
  918 
  919                 Dump ("IOCTL_STORAGE_QUERY_PROPERTY - PropertyId = %d, type = %d, InputBufferLength = %d, OutputBufferLength = %d\n", pStoragePropQuery->PropertyId, type, (int) irpSp->Parameters.DeviceIoControl.InputBufferLength, (int) irpSp->Parameters.DeviceIoControl.OutputBufferLength);
  920 
  921                 if (Extension->bRawDevice &&
  922                         (pStoragePropQuery->PropertyId == (STORAGE_PROPERTY_ID) StorageDeviceLBProvisioningProperty)
  923                     )
  924                 {
  925                     IO_STATUS_BLOCK IoStatus;
  926                     Dump ("ProcessVolumeDeviceControlIrp: sending IOCTL_STORAGE_QUERY_PROPERTY (%d) to device\n", (int) pStoragePropQuery->PropertyId);
  927                     Irp->IoStatus.Status = ZwDeviceIoControlFile (
  928                         Extension->hDeviceFile,
  929                         NULL,
  930                         NULL,
  931                         NULL,
  932                         &IoStatus,
  933                         IOCTL_STORAGE_QUERY_PROPERTY,
  934                         Irp->AssociatedIrp.SystemBuffer,
  935                         irpSp->Parameters.DeviceIoControl.InputBufferLength,
  936                         Irp->AssociatedIrp.SystemBuffer,
  937                         irpSp->Parameters.DeviceIoControl.OutputBufferLength);
  938                     Dump ("ProcessVolumeDeviceControlIrp: ZwDeviceIoControlFile returned 0x%.8X\n", (DWORD) Irp->IoStatus.Status);
  939                     if (Irp->IoStatus.Status == STATUS_SUCCESS)
  940                     {
  941                         Irp->IoStatus.Status = IoStatus.Status;
  942                         Irp->IoStatus.Information = IoStatus.Information;
  943                     }
  944                 }
  945                 else if (   (pStoragePropQuery->PropertyId == StorageAccessAlignmentProperty)
  946                     ||  (pStoragePropQuery->PropertyId == StorageDeviceProperty)
  947                     ||  (pStoragePropQuery->PropertyId == StorageAdapterProperty)
  948                     ||  (pStoragePropQuery->PropertyId == StorageDeviceSeekPenaltyProperty)
  949                     ||  (pStoragePropQuery->PropertyId == StorageDeviceTrimProperty)
  950                     )
  951                 {
  952                     if (type == PropertyExistsQuery)
  953                     {
  954                         Irp->IoStatus.Status = STATUS_SUCCESS;
  955                         Irp->IoStatus.Information = 0;
  956                     }
  957                     else if (type == PropertyStandardQuery)
  958                     {
  959                         ULONG descriptorSize;
  960                         switch (pStoragePropQuery->PropertyId)
  961                         {
  962                             case StorageDeviceProperty:
  963                                 {
  964                                     Dump ("IOCTL_STORAGE_QUERY_PROPERTY - StorageDeviceProperty\n");
  965                                     /* Add 0x00 for NULL terminating string used as ProductId, ProductRevision, SerialNumber, VendorId */
  966                                     descriptorSize = sizeof (STORAGE_DEVICE_DESCRIPTOR) + 1;
  967                                     if (ValidateIOBufferSize (Irp, descriptorSize, ValidateOutput))
  968                                     {
  969                                         PSTORAGE_DEVICE_DESCRIPTOR outputBuffer = (PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
  970 
  971                                         outputBuffer->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
  972                                         outputBuffer->Size = descriptorSize;
  973                                         outputBuffer->DeviceType = FILE_DEVICE_DISK;
  974                                         outputBuffer->RemovableMedia = Extension->bRemovable? TRUE : FALSE;
  975                                         outputBuffer->ProductIdOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR);
  976                                         outputBuffer->SerialNumberOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR);
  977                                         outputBuffer->ProductRevisionOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR);
  978                                         outputBuffer->VendorIdOffset = sizeof (STORAGE_DEVICE_DESCRIPTOR);
  979                                         outputBuffer->BusType = BusTypeVirtual;
  980                                         Irp->IoStatus.Status = STATUS_SUCCESS;
  981                                         Irp->IoStatus.Information = descriptorSize;
  982                                     }
  983                                     else if (irpSp->Parameters.DeviceIoControl.OutputBufferLength == sizeof (STORAGE_DESCRIPTOR_HEADER))
  984                                     {
  985                                         PSTORAGE_DESCRIPTOR_HEADER outputBuffer = (PSTORAGE_DESCRIPTOR_HEADER) Irp->AssociatedIrp.SystemBuffer;
  986                                         outputBuffer->Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
  987                                         outputBuffer->Size = descriptorSize;
  988                                         Irp->IoStatus.Status = STATUS_SUCCESS;
  989                                         Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
  990                                     }
  991                                 }
  992                                 break;
  993                             case StorageAdapterProperty:
  994                                 {
  995                                     Dump ("IOCTL_STORAGE_QUERY_PROPERTY - StorageAdapterProperty\n");
  996                                     descriptorSize = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
  997                                     if (ValidateIOBufferSize (Irp, descriptorSize, ValidateOutput))
  998                                     {
  999                                         PSTORAGE_ADAPTER_DESCRIPTOR outputBuffer = (PSTORAGE_ADAPTER_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
 1000 
 1001                                         outputBuffer->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
 1002                                         outputBuffer->Size = descriptorSize;
 1003                                         outputBuffer->MaximumTransferLength = Extension->HostMaximumTransferLength;
 1004                                         outputBuffer->MaximumPhysicalPages = Extension->HostMaximumPhysicalPages;
 1005                                         outputBuffer->AlignmentMask = Extension->HostAlignmentMask;
 1006                                         outputBuffer->BusType = BusTypeVirtual;
 1007                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1008                                         Irp->IoStatus.Information = descriptorSize;
 1009                                     }
 1010                                     else if (irpSp->Parameters.DeviceIoControl.OutputBufferLength == sizeof (STORAGE_DESCRIPTOR_HEADER))
 1011                                     {
 1012                                         PSTORAGE_DESCRIPTOR_HEADER outputBuffer = (PSTORAGE_DESCRIPTOR_HEADER) Irp->AssociatedIrp.SystemBuffer;
 1013                                         outputBuffer->Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
 1014                                         outputBuffer->Size = descriptorSize;
 1015                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1016                                         Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
 1017                                     }
 1018                                 }
 1019                                 break;
 1020                             case StorageAccessAlignmentProperty:
 1021                                 {
 1022                                     Dump ("IOCTL_STORAGE_QUERY_PROPERTY - StorageAccessAlignmentProperty\n");
 1023                                     if (ValidateIOBufferSize (Irp, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), ValidateOutput))
 1024                                     {
 1025                                         PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR outputBuffer = (PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
 1026 
 1027                                         outputBuffer->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
 1028                                         outputBuffer->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
 1029                                         outputBuffer->BytesPerLogicalSector = Extension->BytesPerSector;
 1030                                         outputBuffer->BytesPerPhysicalSector = Extension->HostBytesPerPhysicalSector;                                       
 1031                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1032                                         Irp->IoStatus.Information = sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
 1033                                     }
 1034                                     else if (irpSp->Parameters.DeviceIoControl.OutputBufferLength == sizeof (STORAGE_DESCRIPTOR_HEADER))
 1035                                     {
 1036                                         PSTORAGE_DESCRIPTOR_HEADER outputBuffer = (PSTORAGE_DESCRIPTOR_HEADER) Irp->AssociatedIrp.SystemBuffer;
 1037                                         outputBuffer->Version = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
 1038                                         outputBuffer->Size = sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
 1039                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1040                                         Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
 1041                                     }
 1042                                 }
 1043                                 break;
 1044                             case StorageDeviceSeekPenaltyProperty:
 1045                                 {
 1046                                     Dump ("IOCTL_STORAGE_QUERY_PROPERTY - StorageDeviceSeekPenaltyProperty\n");
 1047                                     if (ValidateIOBufferSize (Irp, sizeof (DEVICE_SEEK_PENALTY_DESCRIPTOR), ValidateOutput))
 1048                                     {
 1049                                         PDEVICE_SEEK_PENALTY_DESCRIPTOR outputBuffer = (PDEVICE_SEEK_PENALTY_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
 1050                                         Dump ("IOCTL_STORAGE_QUERY_PROPERTY - StorageDeviceSeekPenaltyProperty: set IncursSeekPenalty to %s\n", Extension->IncursSeekPenalty? "TRUE" : "FALSE");
 1051                                         outputBuffer->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
 1052                                         outputBuffer->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
 1053                                         outputBuffer->IncursSeekPenalty = (BOOLEAN) Extension->IncursSeekPenalty;
 1054                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1055                                         Irp->IoStatus.Information = sizeof (DEVICE_SEEK_PENALTY_DESCRIPTOR);
 1056                                     }
 1057                                     else if (irpSp->Parameters.DeviceIoControl.OutputBufferLength == sizeof (STORAGE_DESCRIPTOR_HEADER))
 1058                                     {
 1059                                         PSTORAGE_DESCRIPTOR_HEADER outputBuffer = (PSTORAGE_DESCRIPTOR_HEADER) Irp->AssociatedIrp.SystemBuffer;
 1060                                         outputBuffer->Version = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
 1061                                         outputBuffer->Size = sizeof(DEVICE_SEEK_PENALTY_DESCRIPTOR);
 1062                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1063                                         Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
 1064                                     }
 1065                                 }
 1066                                 break;
 1067                             case StorageDeviceTrimProperty:
 1068                                 {
 1069                                     Dump ("IOCTL_STORAGE_QUERY_PROPERTY - StorageDeviceTrimProperty\n");
 1070                                     if (ValidateIOBufferSize (Irp, sizeof (DEVICE_TRIM_DESCRIPTOR), ValidateOutput))
 1071                                     {
 1072                                         PDEVICE_TRIM_DESCRIPTOR outputBuffer = (PDEVICE_TRIM_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer;
 1073                                         Dump ("IOCTL_STORAGE_QUERY_PROPERTY - StorageDeviceTrimProperty: set TrimEnabled to %s\n", Extension->TrimEnabled? "TRUE" : "FALSE");
 1074                                         outputBuffer->Version = sizeof(DEVICE_TRIM_DESCRIPTOR);
 1075                                         outputBuffer->Size = sizeof(DEVICE_TRIM_DESCRIPTOR);
 1076                                         outputBuffer->TrimEnabled = (BOOLEAN) Extension->TrimEnabled;
 1077                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1078                                         Irp->IoStatus.Information = sizeof (DEVICE_TRIM_DESCRIPTOR);
 1079                                     }
 1080                                     else if (irpSp->Parameters.DeviceIoControl.OutputBufferLength == sizeof (STORAGE_DESCRIPTOR_HEADER))
 1081                                     {
 1082                                         PSTORAGE_DESCRIPTOR_HEADER outputBuffer = (PSTORAGE_DESCRIPTOR_HEADER) Irp->AssociatedIrp.SystemBuffer;
 1083                                         outputBuffer->Version = sizeof(DEVICE_TRIM_DESCRIPTOR);
 1084                                         outputBuffer->Size = sizeof(DEVICE_TRIM_DESCRIPTOR);
 1085                                         Irp->IoStatus.Status = STATUS_SUCCESS;
 1086                                         Irp->IoStatus.Information = sizeof (STORAGE_DESCRIPTOR_HEADER);
 1087                                     }
 1088                                 }
 1089                                 break;
 1090                         }
 1091                     }
 1092                 }
 1093             }
 1094         }
 1095 
 1096         break;
 1097 
 1098     case IOCTL_DISK_GET_PARTITION_INFO:
 1099         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_PARTITION_INFO)\n");
 1100         if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION), ValidateOutput))
 1101         {
 1102             PPARTITION_INFORMATION outputBuffer = (PPARTITION_INFORMATION)
 1103             Irp->AssociatedIrp.SystemBuffer;
 1104 
 1105             outputBuffer->PartitionType = Extension->PartitionType;
 1106             outputBuffer->BootIndicator = FALSE;
 1107             outputBuffer->RecognizedPartition = TRUE;
 1108             outputBuffer->RewritePartition = FALSE;
 1109             outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector;
 1110             outputBuffer->PartitionLength.QuadPart= Extension->DiskLength;
 1111             outputBuffer->PartitionNumber = 1;
 1112             outputBuffer->HiddenSectors = 0;
 1113             Irp->IoStatus.Status = STATUS_SUCCESS;
 1114             Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION);
 1115         }
 1116         break;
 1117 
 1118     case IOCTL_DISK_GET_PARTITION_INFO_EX:
 1119         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_PARTITION_INFO_EX)\n");
 1120         if (ValidateIOBufferSize (Irp, sizeof (PARTITION_INFORMATION_EX), ValidateOutput))
 1121         {
 1122             PPARTITION_INFORMATION_EX outputBuffer = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
 1123 
 1124             outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
 1125             outputBuffer->RewritePartition = FALSE;
 1126             outputBuffer->StartingOffset.QuadPart = Extension->BytesPerSector;
 1127             outputBuffer->PartitionLength.QuadPart= Extension->DiskLength;
 1128             outputBuffer->PartitionNumber = 1;
 1129             outputBuffer->Mbr.PartitionType = Extension->PartitionType;
 1130             outputBuffer->Mbr.BootIndicator = FALSE;
 1131             outputBuffer->Mbr.RecognizedPartition = TRUE;
 1132             outputBuffer->Mbr.HiddenSectors = 0;
 1133             Irp->IoStatus.Status = STATUS_SUCCESS;
 1134             Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION_EX);
 1135         }
 1136         break;
 1137 
 1138     case IOCTL_DISK_GET_DRIVE_LAYOUT:
 1139         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_DRIVE_LAYOUT)\n");
 1140         if (ValidateIOBufferSize (Irp, sizeof (DRIVE_LAYOUT_INFORMATION), ValidateOutput))
 1141         {
 1142             PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
 1143             BOOL bFullBuffer = (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= (sizeof (DRIVE_LAYOUT_INFORMATION) + 3*sizeof(PARTITION_INFORMATION)))? TRUE : FALSE;
 1144             PDRIVE_LAYOUT_INFORMATION outputBuffer = (PDRIVE_LAYOUT_INFORMATION)
 1145             Irp->AssociatedIrp.SystemBuffer;
 1146 
 1147             outputBuffer->PartitionCount = bFullBuffer? 4 : 1;
 1148             outputBuffer->Signature = GetCrc32((unsigned char*) &(Extension->UniqueVolumeId), 4);
 1149 
 1150             outputBuffer->PartitionEntry->PartitionType = Extension->PartitionType;
 1151             outputBuffer->PartitionEntry->BootIndicator = FALSE;
 1152             outputBuffer->PartitionEntry->RecognizedPartition = TRUE;
 1153             outputBuffer->PartitionEntry->RewritePartition = FALSE;
 1154             outputBuffer->PartitionEntry->StartingOffset.QuadPart = Extension->BytesPerSector;
 1155             outputBuffer->PartitionEntry->PartitionLength.QuadPart = Extension->DiskLength;
 1156             outputBuffer->PartitionEntry->PartitionNumber = 1;
 1157             outputBuffer->PartitionEntry->HiddenSectors = 0;            
 1158 
 1159             Irp->IoStatus.Status = STATUS_SUCCESS;
 1160             Irp->IoStatus.Information = sizeof (DRIVE_LAYOUT_INFORMATION);
 1161             if (bFullBuffer)
 1162             {
 1163                 Irp->IoStatus.Information += 3*sizeof(PARTITION_INFORMATION);
 1164                 memset (((BYTE*) Irp->AssociatedIrp.SystemBuffer) + sizeof (DRIVE_LAYOUT_INFORMATION), 0, 3*sizeof(PARTITION_INFORMATION));
 1165             }               
 1166         }
 1167         break;
 1168 
 1169     case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:
 1170         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_DRIVE_LAYOUT_EX)\n");
 1171         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1172         Irp->IoStatus.Information = 0;
 1173         if (EnableExtendedIoctlSupport)
 1174         {
 1175             if (ValidateIOBufferSize (Irp, sizeof (DRIVE_LAYOUT_INFORMATION_EX), ValidateOutput))
 1176             {
 1177                 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
 1178                 BOOL bFullBuffer = (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= (sizeof (DRIVE_LAYOUT_INFORMATION_EX) + 3*sizeof(PARTITION_INFORMATION_EX)))? TRUE : FALSE;
 1179                 PDRIVE_LAYOUT_INFORMATION_EX outputBuffer = (PDRIVE_LAYOUT_INFORMATION_EX)
 1180                 Irp->AssociatedIrp.SystemBuffer;
 1181 
 1182                 outputBuffer->PartitionCount = bFullBuffer? 4 : 1;
 1183                 outputBuffer->PartitionStyle = PARTITION_STYLE_MBR;
 1184                 outputBuffer->Mbr.Signature = GetCrc32((unsigned char*) &(Extension->UniqueVolumeId), 4);
 1185 
 1186                 outputBuffer->PartitionEntry->PartitionStyle = PARTITION_STYLE_MBR;
 1187                 outputBuffer->PartitionEntry->Mbr.BootIndicator = FALSE;
 1188                 outputBuffer->PartitionEntry->Mbr.RecognizedPartition = TRUE;
 1189                 outputBuffer->PartitionEntry->RewritePartition = FALSE;
 1190                 outputBuffer->PartitionEntry->StartingOffset.QuadPart = Extension->BytesPerSector;
 1191                 outputBuffer->PartitionEntry->PartitionLength.QuadPart = Extension->DiskLength;
 1192                 outputBuffer->PartitionEntry->PartitionNumber = 1;
 1193                 outputBuffer->PartitionEntry->Mbr.HiddenSectors = 0;
 1194                 outputBuffer->PartitionEntry->Mbr.PartitionType = Extension->PartitionType;
 1195 
 1196                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1197                 Irp->IoStatus.Information = sizeof (DRIVE_LAYOUT_INFORMATION_EX);
 1198                 if (bFullBuffer)
 1199                 {
 1200                     Irp->IoStatus.Information += 3*sizeof(PARTITION_INFORMATION_EX);
 1201                 }
 1202             }
 1203         }
 1204         break;
 1205 
 1206     case IOCTL_DISK_GET_LENGTH_INFO:
 1207         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_GET_LENGTH_INFO)\n");
 1208         if (!ValidateIOBufferSize (Irp, sizeof (GET_LENGTH_INFORMATION), ValidateOutput))
 1209         {
 1210             Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
 1211             Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION);
 1212         }
 1213         else
 1214         {
 1215             PGET_LENGTH_INFORMATION outputBuffer = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
 1216 
 1217             outputBuffer->Length.QuadPart = Extension->DiskLength;
 1218             Irp->IoStatus.Status = STATUS_SUCCESS;
 1219             Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION);
 1220         }
 1221         break;
 1222 
 1223     case IOCTL_DISK_VERIFY:
 1224         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_VERIFY)\n");
 1225         if (ValidateIOBufferSize (Irp, sizeof (VERIFY_INFORMATION), ValidateInput))
 1226         {
 1227             HRESULT hResult;
 1228             ULONGLONG ullStartingOffset, ullNewOffset, ullEndOffset;
 1229             PVERIFY_INFORMATION pVerifyInformation;
 1230             pVerifyInformation = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
 1231 
 1232             ullStartingOffset = (ULONGLONG) pVerifyInformation->StartingOffset.QuadPart;
 1233             hResult = ULongLongAdd(ullStartingOffset,
 1234                 (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset,
 1235                 &ullNewOffset);
 1236             if (hResult != S_OK)
 1237                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1238             else if (S_OK != ULongLongAdd(ullStartingOffset, (ULONGLONG) pVerifyInformation->Length, &ullEndOffset))
 1239                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1240             else if (ullEndOffset > (ULONGLONG) Extension->DiskLength)
 1241                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1242             else
 1243             {
 1244                 IO_STATUS_BLOCK ioStatus;
 1245                 PVOID buffer = TCalloc (max (pVerifyInformation->Length, PAGE_SIZE));
 1246 
 1247                 if (!buffer)
 1248                 {
 1249                     Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
 1250                 }
 1251                 else
 1252                 {
 1253                     LARGE_INTEGER offset = pVerifyInformation->StartingOffset;
 1254                     offset.QuadPart = ullNewOffset;
 1255 
 1256                     Irp->IoStatus.Status = ZwReadFile (Extension->hDeviceFile, NULL, NULL, NULL, &ioStatus, buffer, pVerifyInformation->Length, &offset, NULL);
 1257                     TCfree (buffer);
 1258 
 1259                     if (NT_SUCCESS (Irp->IoStatus.Status) && ioStatus.Information != pVerifyInformation->Length)
 1260                         Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1261                 }
 1262             }
 1263 
 1264             Irp->IoStatus.Information = 0;
 1265         }
 1266         break;
 1267 
 1268     case IOCTL_DISK_CHECK_VERIFY:
 1269     case IOCTL_STORAGE_CHECK_VERIFY:
 1270     case IOCTL_STORAGE_CHECK_VERIFY2:
 1271         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_CHECK_VERIFY)\n");
 1272         {
 1273             Irp->IoStatus.Status = STATUS_SUCCESS;
 1274             Irp->IoStatus.Information = 0;
 1275 
 1276             if (irpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof (ULONG))
 1277             {
 1278                 *((ULONG *) Irp->AssociatedIrp.SystemBuffer) = 0;
 1279                 Irp->IoStatus.Information = sizeof (ULONG);
 1280             }
 1281         }
 1282         break;
 1283 
 1284     case IOCTL_DISK_IS_WRITABLE:
 1285         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_IS_WRITABLE)\n");
 1286         {
 1287             if (Extension->bReadOnly)
 1288                 Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
 1289             else
 1290                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1291             Irp->IoStatus.Information = 0;
 1292 
 1293         }
 1294         break;
 1295 
 1296     case IOCTL_VOLUME_ONLINE:
 1297         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_VOLUME_ONLINE)\n");
 1298         Irp->IoStatus.Status = STATUS_SUCCESS;
 1299         Irp->IoStatus.Information = 0;
 1300         break;
 1301 
 1302     case IOCTL_VOLUME_POST_ONLINE:
 1303         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_VOLUME_POST_ONLINE)\n");
 1304         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1305         Irp->IoStatus.Information = 0;
 1306         if (EnableExtendedIoctlSupport)
 1307         {
 1308             Irp->IoStatus.Status = STATUS_SUCCESS;
 1309             Irp->IoStatus.Information = 0;
 1310         }
 1311         break;
 1312 
 1313     case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
 1314         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS)\n");
 1315         // Vista's, Windows 8.1 and later filesystem defragmenter fails if IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS does not succeed.
 1316         if (!(OsMajorVersion == 6 && OsMinorVersion == 0) 
 1317             && !(IsOSAtLeast (WIN_8_1) && AllowWindowsDefrag && Extension->bRawDevice)
 1318             )
 1319         {
 1320             Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1321             Irp->IoStatus.Information = 0;
 1322         }
 1323         else if (ValidateIOBufferSize (Irp, sizeof (VOLUME_DISK_EXTENTS), ValidateOutput))
 1324         {
 1325             VOLUME_DISK_EXTENTS *extents = (VOLUME_DISK_EXTENTS *) Irp->AssociatedIrp.SystemBuffer;
 1326             
 1327 
 1328             if (IsOSAtLeast (WIN_8_1))
 1329             {
 1330                 // Windows 10 filesystem defragmenter works only if we report an extent with a real disk number
 1331                 // So in the case of a VeraCrypt disk based volume, we use the disk number
 1332                 // of the underlaying physical disk and we report a single extent 
 1333                 extents->NumberOfDiskExtents = 1;
 1334                 extents->Extents[0].DiskNumber = Extension->DeviceNumber;
 1335                 extents->Extents[0].StartingOffset.QuadPart = Extension->BytesPerSector;
 1336                 extents->Extents[0].ExtentLength.QuadPart = Extension->DiskLength;
 1337             }
 1338             else
 1339             {
 1340                 // Vista: No extent data can be returned as this is not a physical drive.               
 1341                 memset (extents, 0, sizeof (*extents));
 1342                 extents->NumberOfDiskExtents = 0;
 1343             }
 1344 
 1345             Irp->IoStatus.Status = STATUS_SUCCESS;
 1346             Irp->IoStatus.Information = sizeof (*extents);
 1347         }
 1348         break;
 1349 
 1350     case IOCTL_STORAGE_READ_CAPACITY:
 1351         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_READ_CAPACITY)\n");
 1352         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1353         Irp->IoStatus.Information = 0;
 1354         if (EnableExtendedIoctlSupport)
 1355         {
 1356             if (ValidateIOBufferSize (Irp, sizeof (STORAGE_READ_CAPACITY), ValidateOutput))
 1357             {
 1358                 STORAGE_READ_CAPACITY *capacity = (STORAGE_READ_CAPACITY *) Irp->AssociatedIrp.SystemBuffer;
 1359 
 1360                 capacity->Version = sizeof (STORAGE_READ_CAPACITY);
 1361                 capacity->Size = sizeof (STORAGE_READ_CAPACITY);
 1362                 capacity->BlockLength = Extension->BytesPerSector;
 1363                 capacity->NumberOfBlocks.QuadPart = (Extension->DiskLength / Extension->BytesPerSector) + 1;
 1364                 capacity->DiskLength.QuadPart = Extension->DiskLength + Extension->BytesPerSector;
 1365 
 1366                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1367                 Irp->IoStatus.Information = sizeof (STORAGE_READ_CAPACITY);
 1368             }
 1369         }
 1370         break;
 1371 
 1372     /*case IOCTL_STORAGE_GET_DEVICE_NUMBER:
 1373         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_GET_DEVICE_NUMBER)\n");
 1374         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1375         Irp->IoStatus.Information = 0;
 1376         if (EnableExtendedIoctlSupport)
 1377         {
 1378             if (ValidateIOBufferSize (Irp, sizeof (STORAGE_DEVICE_NUMBER), ValidateOutput))
 1379             {
 1380                 STORAGE_DEVICE_NUMBER *storage = (STORAGE_DEVICE_NUMBER *) Irp->AssociatedIrp.SystemBuffer;
 1381 
 1382                 storage->DeviceType = FILE_DEVICE_DISK;
 1383                 storage->DeviceNumber = (ULONG) -1;
 1384                 storage->PartitionNumber = 1;
 1385 
 1386                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1387                 Irp->IoStatus.Information = sizeof (STORAGE_DEVICE_NUMBER);
 1388             }
 1389         }
 1390         break;*/
 1391 
 1392     case IOCTL_STORAGE_GET_HOTPLUG_INFO:
 1393         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_STORAGE_GET_HOTPLUG_INFO)\n");
 1394         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1395         Irp->IoStatus.Information = 0;
 1396         if (EnableExtendedIoctlSupport)
 1397         {
 1398             if (ValidateIOBufferSize (Irp, sizeof (STORAGE_HOTPLUG_INFO), ValidateOutput))
 1399             {
 1400                 STORAGE_HOTPLUG_INFO *info = (STORAGE_HOTPLUG_INFO *) Irp->AssociatedIrp.SystemBuffer;
 1401 
 1402                 info->Size = sizeof (STORAGE_HOTPLUG_INFO);
 1403                 info->MediaRemovable = Extension->bRemovable? TRUE : FALSE;
 1404                 info->MediaHotplug = FALSE;
 1405                 info->DeviceHotplug = FALSE;
 1406                 info->WriteCacheEnableOverride = FALSE;
 1407 
 1408                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1409                 Irp->IoStatus.Information = sizeof (STORAGE_HOTPLUG_INFO);
 1410             }
 1411         }
 1412         break;
 1413 
 1414     case IOCTL_VOLUME_IS_DYNAMIC:
 1415         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_VOLUME_IS_DYNAMIC)\n");
 1416         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1417         Irp->IoStatus.Information = 0;
 1418         if (EnableExtendedIoctlSupport)
 1419         {
 1420             if (ValidateIOBufferSize (Irp, sizeof (BOOLEAN), ValidateOutput))
 1421             {
 1422                 BOOLEAN *pbDynamic = (BOOLEAN*) Irp->AssociatedIrp.SystemBuffer;
 1423 
 1424                 *pbDynamic = FALSE;
 1425 
 1426                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1427                 Irp->IoStatus.Information = sizeof (BOOLEAN);
 1428             }
 1429         }
 1430         break;
 1431 
 1432     case IOCTL_DISK_IS_CLUSTERED:
 1433         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_DISK_IS_CLUSTERED)\n");
 1434         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1435         Irp->IoStatus.Information = 0;
 1436         if (EnableExtendedIoctlSupport)
 1437         {
 1438             if (ValidateIOBufferSize (Irp, sizeof (BOOLEAN), ValidateOutput))
 1439             {
 1440                 BOOLEAN *pbIsClustered = (BOOLEAN*) Irp->AssociatedIrp.SystemBuffer;
 1441 
 1442                 *pbIsClustered = FALSE;
 1443 
 1444                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1445                 Irp->IoStatus.Information = sizeof (BOOLEAN);
 1446             }
 1447         }
 1448         break;
 1449 
 1450     case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
 1451         Dump ("ProcessVolumeDeviceControlIrp (IOCTL_VOLUME_GET_GPT_ATTRIBUTES)\n");
 1452         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1453         Irp->IoStatus.Information = 0;
 1454         if (EnableExtendedIoctlSupport)
 1455         {
 1456             if (ValidateIOBufferSize (Irp, sizeof (VOLUME_GET_GPT_ATTRIBUTES_INFORMATION), ValidateOutput))
 1457             {
 1458                 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION *pGptAttr = (VOLUME_GET_GPT_ATTRIBUTES_INFORMATION*) Irp->AssociatedIrp.SystemBuffer;
 1459 
 1460                 pGptAttr->GptAttributes = 0; // we are MBR not GPT
 1461 
 1462                 Irp->IoStatus.Status = STATUS_SUCCESS;
 1463                 Irp->IoStatus.Information = sizeof (VOLUME_GET_GPT_ATTRIBUTES_INFORMATION);
 1464             }
 1465         }
 1466         break;
 1467 
 1468     case IOCTL_UNKNOWN_WINDOWS10_EFS_ACCESS:
 1469         // This undocumented IOCTL is sent when handling EFS data
 1470         // We must return success otherwise EFS operations fail
 1471         Dump ("ProcessVolumeDeviceControlIrp (unknown IOCTL 0x%.8X, OutputBufferLength = %d). Returning fake success\n", irpSp->Parameters.DeviceIoControl.IoControlCode, (int) irpSp->Parameters.DeviceIoControl.OutputBufferLength);
 1472         Irp->IoStatus.Status = STATUS_SUCCESS;
 1473         Irp->IoStatus.Information = 0;
 1474 
 1475         break;
 1476 
 1477     case IOCTL_DISK_UPDATE_PROPERTIES:
 1478         Dump ("ProcessVolumeDeviceControlIrp: returning STATUS_SUCCESS for IOCTL_DISK_UPDATE_PROPERTIES\n");
 1479         Irp->IoStatus.Status = STATUS_SUCCESS;
 1480         Irp->IoStatus.Information = 0;
 1481 
 1482         break;
 1483 
 1484     case IOCTL_DISK_MEDIA_REMOVAL:
 1485     case IOCTL_STORAGE_MEDIA_REMOVAL:
 1486         Dump ("ProcessVolumeDeviceControlIrp: returning STATUS_SUCCESS for %ls\n", TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode));
 1487         Irp->IoStatus.Status = STATUS_SUCCESS;
 1488         Irp->IoStatus.Information = 0;
 1489 
 1490         break;
 1491 
 1492     case IOCTL_DISK_GET_CLUSTER_INFO:
 1493         Dump ("ProcessVolumeDeviceControlIrp: returning STATUS_NOT_SUPPORTED for %ls\n", TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode));
 1494         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1495         Irp->IoStatus.Information = 0;
 1496         if (EnableExtendedIoctlSupport)
 1497         {
 1498             Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
 1499             Irp->IoStatus.Information = 0;
 1500         }
 1501         break;
 1502 
 1503     case IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES:
 1504         Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES\n");
 1505         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1506         Irp->IoStatus.Information = 0;
 1507         if (Extension->bRawDevice && Extension->TrimEnabled)
 1508         {
 1509             if (ValidateIOBufferSize (Irp, sizeof (DEVICE_MANAGE_DATA_SET_ATTRIBUTES), ValidateInput))
 1510             {
 1511                 PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
 1512                 DWORD inputLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
 1513                 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES pInputAttrs = (PDEVICE_MANAGE_DATA_SET_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer;
 1514                 DEVICE_DATA_MANAGEMENT_SET_ACTION action = pInputAttrs->Action;
 1515                 BOOL bEntireSet = pInputAttrs->Flags & DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE? TRUE : FALSE;
 1516                 ULONGLONG minSizedataSet = (ULONGLONG) pInputAttrs->DataSetRangesOffset + (ULONGLONG) pInputAttrs->DataSetRangesLength;
 1517                 ULONGLONG minSizeParameter = (ULONGLONG) pInputAttrs->ParameterBlockOffset + (ULONGLONG) pInputAttrs->ParameterBlockLength;
 1518                 ULONGLONG minSizeGeneric = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES) + (ULONGLONG) pInputAttrs->ParameterBlockLength + (ULONGLONG) pInputAttrs->DataSetRangesLength;
 1519                 PDEVICE_MANAGE_DATA_SET_ATTRIBUTES pNewSetAttrs = NULL;
 1520                 ULONG ulNewInputLength = 0;
 1521                 BOOL bForwardIoctl = FALSE;
 1522 
 1523                 if (inputLength >= minSizeGeneric && inputLength >= minSizedataSet && inputLength >= minSizeParameter)
 1524                 {
 1525                     if (bEntireSet)
 1526                     {
 1527                         if (minSizedataSet)
 1528                         {
 1529                             Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE set but data set range specified=> Error.\n");
 1530                             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1531                             Irp->IoStatus.Information = 0;
 1532                         }
 1533                         else
 1534                         {
 1535                             DWORD dwDataSetOffset = ALIGN_VALUE (inputLength, sizeof(DEVICE_DATA_SET_RANGE));
 1536                             DWORD dwDataSetLength = sizeof(DEVICE_DATA_SET_RANGE);
 1537 
 1538                             Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE set. Setting data range to all volume.\n");
 1539 
 1540                             ulNewInputLength = dwDataSetOffset + dwDataSetLength;
 1541                             pNewSetAttrs = (PDEVICE_MANAGE_DATA_SET_ATTRIBUTES) TCalloc (ulNewInputLength);
 1542                             if (pNewSetAttrs)
 1543                             {
 1544                                 PDEVICE_DATA_SET_RANGE pRange = (PDEVICE_DATA_SET_RANGE) (((unsigned char*) pNewSetAttrs) + dwDataSetOffset);
 1545 
 1546                                 memcpy (pNewSetAttrs, pInputAttrs, inputLength);
 1547 
 1548                                 pRange->StartingOffset = (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset;
 1549                                 pRange->LengthInBytes = Extension->DiskLength;
 1550 
 1551                                 pNewSetAttrs->Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES);
 1552                                 pNewSetAttrs->Action = action;
 1553                                 pNewSetAttrs->Flags = pInputAttrs->Flags & (~DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE);
 1554                                 pNewSetAttrs->ParameterBlockOffset = pInputAttrs->ParameterBlockOffset;
 1555                                 pNewSetAttrs->ParameterBlockLength = pInputAttrs->ParameterBlockLength;
 1556                                 pNewSetAttrs->DataSetRangesOffset = dwDataSetOffset;
 1557                                 pNewSetAttrs->DataSetRangesLength = dwDataSetLength;
 1558 
 1559                                 bForwardIoctl = TRUE;
 1560                             }
 1561                             else
 1562                             {
 1563                                 Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - Failed to allocate memory.\n");
 1564                                 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
 1565                                 Irp->IoStatus.Information = 0;
 1566                             }
 1567                         }
 1568                     }
 1569                     else
 1570                     {                       
 1571                         Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - creating new data set range from input range.\n");
 1572                         ulNewInputLength = inputLength;
 1573                         pNewSetAttrs = (PDEVICE_MANAGE_DATA_SET_ATTRIBUTES) TCalloc (inputLength);
 1574                         if (pNewSetAttrs)
 1575                         {
 1576                             PDEVICE_DATA_SET_RANGE pNewRanges = (PDEVICE_DATA_SET_RANGE) (((unsigned char*) pNewSetAttrs) + pInputAttrs->DataSetRangesOffset);
 1577                             PDEVICE_DATA_SET_RANGE pInputRanges = (PDEVICE_DATA_SET_RANGE) (((unsigned char*) pInputAttrs) + pInputAttrs->DataSetRangesOffset);
 1578                             DWORD dwInputRangesCount = 0, dwNewRangesCount = 0, i;
 1579                             ULONGLONG ullStartingOffset, ullNewOffset, ullEndOffset;
 1580                             HRESULT hResult;
 1581 
 1582                             memcpy (pNewSetAttrs, pInputAttrs, inputLength);
 1583 
 1584                             dwInputRangesCount = pInputAttrs->DataSetRangesLength / sizeof(DEVICE_DATA_SET_RANGE);
 1585 
 1586                             for (i = 0; i < dwInputRangesCount; i++)
 1587                             {
 1588                                 ullStartingOffset = (ULONGLONG) pInputRanges[i].StartingOffset;
 1589                                 hResult = ULongLongAdd(ullStartingOffset,
 1590                                     (ULONGLONG) Extension->cryptoInfo->hiddenVolume ? Extension->cryptoInfo->hiddenVolumeOffset : Extension->cryptoInfo->volDataAreaOffset,
 1591                                     &ullNewOffset);
 1592                                 if (hResult != S_OK)
 1593                                     continue;
 1594                                 else if (S_OK != ULongLongAdd(ullStartingOffset, (ULONGLONG) pInputRanges[i].LengthInBytes, &ullEndOffset))
 1595                                     continue;
 1596                                 else if (ullEndOffset > (ULONGLONG) Extension->DiskLength)
 1597                                     continue;
 1598                                 else if (ullNewOffset > 0)
 1599                                 {
 1600                                     pNewRanges[dwNewRangesCount].StartingOffset = (LONGLONG) ullNewOffset;
 1601                                     pNewRanges[dwNewRangesCount].LengthInBytes = pInputRanges[i].LengthInBytes;
 1602 
 1603                                     dwNewRangesCount++;
 1604                                 }
 1605                             }
 1606 
 1607                             Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - %d valid range processed from %d range in input.\n", (int) dwNewRangesCount, (int) dwInputRangesCount);
 1608 
 1609                             pNewSetAttrs->DataSetRangesLength = dwNewRangesCount * sizeof (DEVICE_DATA_SET_RANGE);
 1610 
 1611                             bForwardIoctl = TRUE;
 1612                         }
 1613                         else
 1614                         {
 1615                             Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - Failed to allocate memory.\n");
 1616                             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
 1617                             Irp->IoStatus.Information = 0;
 1618                         }
 1619                     }
 1620                 }
 1621                 else
 1622                 {
 1623                     Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - buffer containing DEVICE_MANAGE_DATA_SET_ATTRIBUTES has invalid length.\n");
 1624                     Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1625                     Irp->IoStatus.Information = 0;
 1626                 }
 1627 
 1628 
 1629                 if (bForwardIoctl)
 1630                 {
 1631                     if (action == DeviceDsmAction_Trim)
 1632                     {
 1633                         Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_Trim.\n");
 1634 
 1635                         if (Extension->cryptoInfo->hiddenVolume || !AllowTrimCommand)
 1636                         {
 1637                             Dump ("ProcessVolumeDeviceControlIrp: TRIM command filtered\n");
 1638                             Irp->IoStatus.Status = STATUS_SUCCESS;
 1639                             Irp->IoStatus.Information = 0;
 1640                         }
 1641                         else
 1642                         {
 1643                             IO_STATUS_BLOCK IoStatus;
 1644                             Dump ("ProcessVolumeDeviceControlIrp: sending TRIM to device\n");
 1645                             Irp->IoStatus.Status = ZwDeviceIoControlFile (
 1646                                 Extension->hDeviceFile,
 1647                                 NULL,
 1648                                 NULL,
 1649                                 NULL,
 1650                                 &IoStatus,
 1651                                 IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES,
 1652                                 (PVOID) pNewSetAttrs,
 1653                                 ulNewInputLength,
 1654                                 NULL,
 1655                                 0);
 1656                             Dump ("ProcessVolumeDeviceControlIrp: ZwDeviceIoControlFile returned 0x%.8X\n", (DWORD) Irp->IoStatus.Status);
 1657                             if (Irp->IoStatus.Status == STATUS_SUCCESS)
 1658                             {
 1659                                 Irp->IoStatus.Status = IoStatus.Status;
 1660                                 Irp->IoStatus.Information = IoStatus.Information;
 1661                             }
 1662                             else
 1663                                 Irp->IoStatus.Information = 0;
 1664                         }                       
 1665                     }
 1666                     else
 1667                     {
 1668                         switch (action)
 1669                         {
 1670                             case DeviceDsmAction_Notification: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_Notification\n"); break;
 1671                             case DeviceDsmAction_OffloadRead: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_OffloadRead\n"); break;
 1672                             case DeviceDsmAction_OffloadWrite: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_OffloadWrite\n"); break;
 1673                             case DeviceDsmAction_Allocation: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_Allocation\n"); break;
 1674                             case DeviceDsmAction_Scrub: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_Scrub\n"); break;
 1675                             case DeviceDsmAction_DrtQuery: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_DrtQuery\n"); break;
 1676                             case DeviceDsmAction_DrtClear: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_DrtClear\n"); break;
 1677                             case DeviceDsmAction_DrtDisable: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - DeviceDsmAction_DrtDisable\n"); break;
 1678                             default: Dump ("ProcessVolumeDeviceControlIrp: IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES - unknown action %d\n", (int) action); break;
 1679                         }
 1680                     
 1681                     }
 1682                 }
 1683 
 1684                 if (pNewSetAttrs)
 1685                     TCfree (pNewSetAttrs);
 1686             }
 1687         }
 1688 #if defined (DEBUG) || defined (DEBUG_TRACE)
 1689         else
 1690             Dump ("ProcessVolumeDeviceControlIrp: returning STATUS_INVALID_DEVICE_REQUEST for IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES\n");
 1691 #endif
 1692         break;
 1693     
 1694     case IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT:
 1695     case IOCTL_VOLUME_QUERY_ALLOCATION_HINT:
 1696     case FT_BALANCED_READ_MODE:
 1697     case IOCTL_STORAGE_GET_DEVICE_NUMBER:
 1698     case IOCTL_MOUNTDEV_LINK_CREATED:
 1699         Dump ("ProcessVolumeDeviceControlIrp: returning STATUS_INVALID_DEVICE_REQUEST for %ls\n", TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode));
 1700         Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
 1701         Irp->IoStatus.Information = 0;      
 1702         break;
 1703     default:
 1704         Dump ("ProcessVolumeDeviceControlIrp (unknown code 0x%.8X)\n", irpSp->Parameters.DeviceIoControl.IoControlCode);
 1705         return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
 1706     }
 1707 
 1708 #if defined(DEBUG) || defined (DEBG_TRACE)
 1709     if (!NT_SUCCESS (Irp->IoStatus.Status))
 1710     {
 1711         Dump ("IOCTL error 0x%08x (0x%x %d)\n",
 1712             Irp->IoStatus.Status,
 1713             (int) (irpSp->Parameters.DeviceIoControl.IoControlCode >> 16),
 1714             (int) ((irpSp->Parameters.DeviceIoControl.IoControlCode & 0x1FFF) >> 2));
 1715     }
 1716 #endif
 1717 
 1718     return TCCompleteDiskIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information);
 1719 }
 1720 
 1721 
 1722 NTSTATUS ProcessMainDeviceControlIrp (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp)
 1723 {
 1724     PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
 1725     NTSTATUS ntStatus;
 1726 
 1727     switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
 1728     {
 1729     case TC_IOCTL_GET_DRIVER_VERSION:
 1730     case TC_IOCTL_LEGACY_GET_DRIVER_VERSION:
 1731         if (ValidateIOBufferSize (Irp, sizeof (LONG), ValidateOutput))
 1732         {
 1733             LONG tmp = VERSION_NUM;
 1734             memcpy (Irp->AssociatedIrp.SystemBuffer, &tmp, 4);
 1735             Irp->IoStatus.Information = sizeof (LONG);
 1736             Irp->IoStatus.Status = STATUS_SUCCESS;
 1737         }
 1738         break;
 1739 
 1740     case TC_IOCTL_GET_DEVICE_REFCOUNT:
 1741         if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
 1742         {
 1743             *(int *) Irp->AssociatedIrp.SystemBuffer = DeviceObject->ReferenceCount;
 1744             Irp->IoStatus.Information = sizeof (int);
 1745             Irp->IoStatus.Status = STATUS_SUCCESS;
 1746         }
 1747         break;
 1748 
 1749     case TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED:
 1750         if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
 1751         {
 1752             LONG deviceObjectCount = 0;
 1753 
 1754             *(int *) Irp->AssociatedIrp.SystemBuffer = DriverUnloadDisabled;
 1755 
 1756             if (IoEnumerateDeviceObjectList (TCDriverObject, NULL, 0, &deviceObjectCount) == STATUS_BUFFER_TOO_SMALL && deviceObjectCount > 1)
 1757                 *(int *) Irp->AssociatedIrp.SystemBuffer = TRUE;
 1758 
 1759             Irp->IoStatus.Information = sizeof (int);
 1760             Irp->IoStatus.Status = STATUS_SUCCESS;
 1761         }
 1762         break;
 1763 
 1764     case TC_IOCTL_IS_ANY_VOLUME_MOUNTED:
 1765         if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
 1766         {
 1767             int drive;
 1768             *(int *) Irp->AssociatedIrp.SystemBuffer = 0;
 1769 
 1770             for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
 1771             {
 1772                 if (GetVirtualVolumeDeviceObject (drive))
 1773                 {
 1774                     *(int *) Irp->AssociatedIrp.SystemBuffer = 1;
 1775                     break;
 1776                 }
 1777             }
 1778 
 1779             if (IsBootDriveMounted())
 1780                 *(int *) Irp->AssociatedIrp.SystemBuffer = 1;
 1781 
 1782             Irp->IoStatus.Information = sizeof (int);
 1783             Irp->IoStatus.Status = STATUS_SUCCESS;
 1784         }
 1785         break;
 1786 
 1787     case TC_IOCTL_OPEN_TEST:
 1788         {
 1789             OPEN_TEST_STRUCT *opentest = (OPEN_TEST_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 1790             OBJECT_ATTRIBUTES ObjectAttributes;
 1791             HANDLE NtFileHandle;
 1792             UNICODE_STRING FullFileName;
 1793             IO_STATUS_BLOCK IoStatus;
 1794             LARGE_INTEGER offset;
 1795             ACCESS_MASK access = FILE_READ_ATTRIBUTES;
 1796 
 1797             if (!ValidateIOBufferSize (Irp, sizeof (OPEN_TEST_STRUCT), ValidateInputOutput))
 1798                 break;
 1799 
 1800             // check that opentest->wszFileName is a device path that starts with "\\Device\\Harddisk"
 1801             // 16 is the length of "\\Device\\Harddisk" which is the mi
 1802             if (    !CheckStringLength (opentest->wszFileName, TC_MAX_PATH, 16, (size_t) -1, NULL)
 1803                 ||  (!StringNoCaseCompare (opentest->wszFileName, L"\\Device\\Harddisk", 16))
 1804                 )
 1805             {
 1806                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1807                 Irp->IoStatus.Information = 0;
 1808                 break;
 1809             }
 1810 
 1811 
 1812             EnsureNullTerminatedString (opentest->wszFileName, sizeof (opentest->wszFileName));
 1813             RtlInitUnicodeString (&FullFileName, opentest->wszFileName);
 1814 
 1815             InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
 1816 
 1817             if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bComputeVolumeIDs)
 1818                 access |= FILE_READ_DATA;
 1819 
 1820             ntStatus = ZwCreateFile (&NtFileHandle,
 1821                          SYNCHRONIZE | access, &ObjectAttributes, &IoStatus, NULL,
 1822                          0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
 1823 
 1824             if (NT_SUCCESS (ntStatus))
 1825             {
 1826                 opentest->TCBootLoaderDetected = FALSE;
 1827                 opentest->FilesystemDetected = FALSE;
 1828                 memset (opentest->VolumeIDComputed, 0, sizeof (opentest->VolumeIDComputed));
 1829                 memset (opentest->volumeIDs, 0, sizeof (opentest->volumeIDs));
 1830 
 1831                 if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem || opentest->bComputeVolumeIDs)
 1832                 {
 1833                     byte *readBuffer = TCalloc (TC_MAX_VOLUME_SECTOR_SIZE);
 1834                     if (!readBuffer)
 1835                     {
 1836                         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
 1837                     }
 1838                     else
 1839                     {
 1840                         if (opentest->bDetectTCBootLoader || opentest->DetectFilesystem)
 1841                         {
 1842                             // Determine if the first sector contains a portion of the VeraCrypt Boot Loader
 1843 
 1844                             offset.QuadPart = 0;
 1845 
 1846                             ntStatus = ZwReadFile (NtFileHandle,
 1847                                 NULL,
 1848                                 NULL,
 1849                                 NULL,
 1850                                 &IoStatus,
 1851                                 readBuffer,
 1852                                 TC_MAX_VOLUME_SECTOR_SIZE,
 1853                                 &offset,
 1854                                 NULL);
 1855 
 1856                             if (NT_SUCCESS (ntStatus))
 1857                             {
 1858                                 size_t i;
 1859 
 1860                                 if (opentest->bDetectTCBootLoader && IoStatus.Information >= TC_SECTOR_SIZE_BIOS)
 1861                                 {
 1862                                     // Search for the string "VeraCrypt"
 1863                                     for (i = 0; i < TC_SECTOR_SIZE_BIOS - strlen (TC_APP_NAME); ++i)
 1864                                     {
 1865                                         if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
 1866                                         {
 1867                                             opentest->TCBootLoaderDetected = TRUE;
 1868                                             break;
 1869                                         }
 1870                                     }
 1871                                 }
 1872 
 1873                                 if (opentest->DetectFilesystem && IoStatus.Information >= sizeof (int64))
 1874                                 {
 1875                                     switch (BE64 (*(uint64 *) readBuffer))
 1876                                     {
 1877                                     case 0xEB52904E54465320ULL: // NTFS
 1878                                     case 0xEB3C904D53444F53ULL: // FAT16/FAT32
 1879                                     case 0xEB58904D53444F53ULL: // FAT32
 1880                                     case 0xEB76904558464154ULL: // exFAT
 1881                                     case 0x0000005265465300ULL: // ReFS
 1882                                     case 0xEB58906D6B66732EULL: // FAT32 mkfs.fat
 1883                                     case 0xEB58906D6B646F73ULL: // FAT32 mkfs.vfat/mkdosfs
 1884                                     case 0xEB3C906D6B66732EULL: // FAT16/FAT12 mkfs.fat
 1885                                     case 0xEB3C906D6B646F73ULL: // FAT16/FAT12 mkfs.vfat/mkdosfs
 1886                                         opentest->FilesystemDetected = TRUE;
 1887                                         break;
 1888                                     case 0x0000000000000000ULL:
 1889                                         // all 512 bytes are zeroes => unencrypted filesystem like Microsoft reserved partition
 1890                                         if (IsAllZeroes (readBuffer + 8, TC_VOLUME_HEADER_EFFECTIVE_SIZE - 8))
 1891                                             opentest->FilesystemDetected = TRUE;
 1892                                         break;
 1893                                     }
 1894                                 }
 1895                             }
 1896                         }
 1897 
 1898                         if (opentest->bComputeVolumeIDs && (!opentest->DetectFilesystem || !opentest->FilesystemDetected))
 1899                         {
 1900                             int volumeType;
 1901                             // Go through all volume types (e.g., normal, hidden)
 1902                             for (volumeType = TC_VOLUME_TYPE_NORMAL;
 1903                                 volumeType < TC_VOLUME_TYPE_COUNT;
 1904                                 volumeType++)
 1905                             {
 1906                                 /* Read the volume header */
 1907                                 switch (volumeType)
 1908                                 {
 1909                                 case TC_VOLUME_TYPE_NORMAL:
 1910                                     offset.QuadPart = TC_VOLUME_HEADER_OFFSET;
 1911                                     break;
 1912 
 1913                                 case TC_VOLUME_TYPE_HIDDEN:
 1914 
 1915                                     offset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
 1916                                     break;
 1917                                 }
 1918 
 1919                                 ntStatus = ZwReadFile (NtFileHandle,
 1920                                 NULL,
 1921                                 NULL,
 1922                                 NULL,
 1923                                 &IoStatus,
 1924                                 readBuffer,
 1925                                 TC_MAX_VOLUME_SECTOR_SIZE,
 1926                                 &offset,
 1927                                 NULL);
 1928 
 1929                                 if (NT_SUCCESS (ntStatus) && (IoStatus.Information >= TC_VOLUME_HEADER_EFFECTIVE_SIZE))
 1930                                 {
 1931                                     /* compute the ID of this volume: SHA-256 of the effective header */
 1932                                     sha256 (opentest->volumeIDs[volumeType], readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
 1933                                     opentest->VolumeIDComputed[volumeType] = TRUE;
 1934                                 }
 1935                             }
 1936                         }
 1937 
 1938                         TCfree (readBuffer);
 1939                     }
 1940                 }
 1941 
 1942                 ZwClose (NtFileHandle);
 1943                 Dump ("Open test on file %ls success.\n", opentest->wszFileName);
 1944             }
 1945             else
 1946             {
 1947 #if 0
 1948                 Dump ("Open test on file %ls failed NTSTATUS 0x%08x\n", opentest->wszFileName, ntStatus);
 1949 #endif
 1950             }
 1951 
 1952             Irp->IoStatus.Information = NT_SUCCESS (ntStatus) ? sizeof (OPEN_TEST_STRUCT) : 0;
 1953             Irp->IoStatus.Status = ntStatus;
 1954         }
 1955         break;
 1956 
 1957     case TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG:
 1958         {
 1959             GetSystemDriveConfigurationRequest *request = (GetSystemDriveConfigurationRequest *) Irp->AssociatedIrp.SystemBuffer;
 1960             OBJECT_ATTRIBUTES ObjectAttributes;
 1961             HANDLE NtFileHandle;
 1962             UNICODE_STRING FullFileName;
 1963             IO_STATUS_BLOCK IoStatus;
 1964             LARGE_INTEGER offset;
 1965             size_t devicePathLen = 0;
 1966             WCHAR* wszPath = NULL;
 1967 
 1968             if (!ValidateIOBufferSize (Irp, sizeof (GetSystemDriveConfigurationRequest), ValidateInputOutput))
 1969                 break;
 1970 
 1971             // check that request->DevicePath has the expected format "\\Device\\HarddiskXXX\\Partition0"
 1972             // 28 is the length of "\\Device\\Harddisk0\\Partition0" which is the minimum
 1973             // 30 is the length of "\\Device\\Harddisk255\\Partition0" which is the maximum
 1974             wszPath = request->DevicePath;
 1975             if (    !CheckStringLength (wszPath, TC_MAX_PATH, 28, 30, &devicePathLen)
 1976                 ||  (memcmp (wszPath, L"\\Device\\Harddisk", 16 * sizeof (WCHAR)))
 1977                 ||  (memcmp (wszPath + (devicePathLen - 11), L"\\Partition0", 11 * sizeof (WCHAR)))
 1978                 )
 1979             {
 1980                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 1981                 Irp->IoStatus.Information = 0;
 1982                 break;
 1983             }
 1984 
 1985             EnsureNullTerminatedString (request->DevicePath, sizeof (request->DevicePath));
 1986             RtlInitUnicodeString (&FullFileName, request->DevicePath);
 1987 
 1988             InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
 1989 
 1990             ntStatus = ZwCreateFile (&NtFileHandle,
 1991                 SYNCHRONIZE | GENERIC_READ, &ObjectAttributes, &IoStatus, NULL,
 1992                 FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS, NULL, 0);
 1993 
 1994             if (NT_SUCCESS (ntStatus))
 1995             {
 1996                 byte *readBuffer = TCalloc (TC_MAX_VOLUME_SECTOR_SIZE);
 1997                 if (!readBuffer)
 1998                 {
 1999                     Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
 2000                     Irp->IoStatus.Information = 0;
 2001                 }
 2002                 else
 2003                 {
 2004                     // Determine if the first sector contains a portion of the VeraCrypt Boot Loader
 2005                     offset.QuadPart = 0;    // MBR
 2006 
 2007                     ntStatus = ZwReadFile (NtFileHandle,
 2008                         NULL,
 2009                         NULL,
 2010                         NULL,
 2011                         &IoStatus,
 2012                         readBuffer,
 2013                         TC_MAX_VOLUME_SECTOR_SIZE,
 2014                         &offset,
 2015                         NULL);
 2016 
 2017                     if (NT_SUCCESS (ntStatus))
 2018                     {
 2019                         // check that we could read all needed data
 2020                         if (IoStatus.Information >= TC_SECTOR_SIZE_BIOS)
 2021                         {
 2022                             size_t i;
 2023 
 2024                             // Check for dynamic drive
 2025                             request->DriveIsDynamic = FALSE;
 2026 
 2027                             if (readBuffer[510] == 0x55 && readBuffer[511] == 0xaa)
 2028                             {
 2029                                 int i;
 2030                                 for (i = 0; i < 4; ++i)
 2031                                 {
 2032                                     if (readBuffer[446 + i * 16 + 4] == PARTITION_LDM)
 2033                                     {
 2034                                         request->DriveIsDynamic = TRUE;
 2035                                         break;
 2036                                     }
 2037                                 }
 2038                             }
 2039 
 2040                             request->BootLoaderVersion = 0;
 2041                             request->Configuration = 0;
 2042                             request->UserConfiguration = 0;
 2043                             request->CustomUserMessage[0] = 0;
 2044 
 2045                             // Search for the string "VeraCrypt"
 2046                             for (i = 0; i < TC_SECTOR_SIZE_BIOS - strlen (TC_APP_NAME); ++i)
 2047                             {
 2048                                 if (memcmp (readBuffer + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
 2049                                 {
 2050                                     request->BootLoaderVersion = BE16 (*(uint16 *) (readBuffer + TC_BOOT_SECTOR_VERSION_OFFSET));
 2051                                     request->Configuration = readBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET];
 2052 
 2053                                     if (request->BootLoaderVersion != 0 && request->BootLoaderVersion <= VERSION_NUM)
 2054                                     {
 2055                                         request->UserConfiguration = readBuffer[TC_BOOT_SECTOR_USER_CONFIG_OFFSET];
 2056                                         memcpy (request->CustomUserMessage, readBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
 2057                                     }
 2058                                     break;
 2059                                 }
 2060                             }
 2061 
 2062                             Irp->IoStatus.Status = STATUS_SUCCESS;
 2063                             Irp->IoStatus.Information = sizeof (*request);
 2064                         }
 2065                         else
 2066                         {
 2067                             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 2068                             Irp->IoStatus.Information = 0;
 2069                         }
 2070                     }
 2071                     else
 2072                     {
 2073                         Irp->IoStatus.Status = ntStatus;
 2074                         Irp->IoStatus.Information = 0;
 2075                     }
 2076 
 2077                     TCfree (readBuffer);
 2078                 }
 2079 
 2080                 ZwClose (NtFileHandle);
 2081 
 2082             }
 2083             else
 2084             {
 2085                 Irp->IoStatus.Status = ntStatus;
 2086                 Irp->IoStatus.Information = 0;
 2087             }
 2088         }
 2089         break;
 2090 
 2091     case TC_IOCTL_WIPE_PASSWORD_CACHE:
 2092         WipeCache ();
 2093 
 2094         Irp->IoStatus.Status = STATUS_SUCCESS;
 2095         Irp->IoStatus.Information = 0;
 2096         break;
 2097 
 2098     case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
 2099         Irp->IoStatus.Status = cacheEmpty ? STATUS_PIPE_EMPTY : STATUS_SUCCESS;
 2100         Irp->IoStatus.Information = 0;
 2101         break;
 2102 
 2103     case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
 2104         if (!UserCanAccessDriveDevice())
 2105         {
 2106             Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
 2107             Irp->IoStatus.Information = 0;
 2108         }
 2109         else
 2110         {
 2111             PortableMode = TRUE;
 2112             Dump ("Setting portable mode\n");
 2113         }
 2114         break;
 2115 
 2116     case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
 2117         Irp->IoStatus.Status = PortableMode ? STATUS_SUCCESS : STATUS_PIPE_EMPTY;
 2118         Irp->IoStatus.Information = 0;
 2119         break;
 2120 
 2121     case TC_IOCTL_GET_MOUNTED_VOLUMES:
 2122 
 2123         if (ValidateIOBufferSize (Irp, sizeof (MOUNT_LIST_STRUCT), ValidateOutput))
 2124         {
 2125             MOUNT_LIST_STRUCT *list = (MOUNT_LIST_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2126             PDEVICE_OBJECT ListDevice;
 2127             int drive;
 2128 
 2129             list->ulMountedDrives = 0;
 2130 
 2131             for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
 2132             {
 2133                 PEXTENSION ListExtension;
 2134 
 2135                 ListDevice = GetVirtualVolumeDeviceObject (drive);
 2136                 if (!ListDevice)
 2137                     continue;
 2138 
 2139                 ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
 2140                 if (IsVolumeAccessibleByCurrentUser (ListExtension))
 2141                 {
 2142                     list->ulMountedDrives |= (1 << ListExtension->nDosDriveNo);
 2143                     RtlStringCbCopyW (list->wszVolume[ListExtension->nDosDriveNo], sizeof(list->wszVolume[ListExtension->nDosDriveNo]),ListExtension->wszVolume);
 2144                     RtlStringCbCopyW (list->wszLabel[ListExtension->nDosDriveNo], sizeof(list->wszLabel[ListExtension->nDosDriveNo]),ListExtension->wszLabel);
 2145                     memcpy (list->volumeID[ListExtension->nDosDriveNo], ListExtension->volumeID, VOLUME_ID_SIZE);
 2146                     list->diskLength[ListExtension->nDosDriveNo] = ListExtension->DiskLength;
 2147                     list->ea[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->ea;
 2148                     if (ListExtension->cryptoInfo->hiddenVolume)
 2149                         list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_HIDDEN;    // Hidden volume
 2150                     else if (ListExtension->cryptoInfo->bHiddenVolProtectionAction)
 2151                         list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED; // Normal/outer volume (hidden volume protected AND write already prevented)
 2152                     else if (ListExtension->cryptoInfo->bProtectHiddenVolume)
 2153                         list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_OUTER; // Normal/outer volume (hidden volume protected)
 2154                     else
 2155                         list->volumeType[ListExtension->nDosDriveNo] = PROP_VOL_TYPE_NORMAL;    // Normal volume
 2156                     list->truecryptMode[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->bTrueCryptMode;
 2157                 }
 2158             }
 2159 
 2160             Irp->IoStatus.Status = STATUS_SUCCESS;
 2161             Irp->IoStatus.Information = sizeof (MOUNT_LIST_STRUCT);
 2162         }
 2163         break;
 2164 
 2165     case TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES:
 2166         if (ValidateIOBufferSize (Irp, sizeof (uint32), ValidateOutput))
 2167         {
 2168             // Prevent the user from downgrading to versions lower than 5.0 by faking mounted volumes.
 2169             // The user could render the system unbootable by downgrading when boot encryption
 2170             // is active or being set up.
 2171 
 2172             memset (Irp->AssociatedIrp.SystemBuffer, 0, irpSp->Parameters.DeviceIoControl.OutputBufferLength);
 2173             *(uint32 *) Irp->AssociatedIrp.SystemBuffer = 0xffffFFFF;
 2174 
 2175             Irp->IoStatus.Status = STATUS_SUCCESS;
 2176             Irp->IoStatus.Information = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
 2177         }
 2178         break;
 2179 
 2180     case TC_IOCTL_GET_VOLUME_PROPERTIES:
 2181         if (ValidateIOBufferSize (Irp, sizeof (VOLUME_PROPERTIES_STRUCT), ValidateInputOutput))
 2182         {
 2183             VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2184             PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (prop->driveNo);
 2185 
 2186             Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 2187             Irp->IoStatus.Information = 0;
 2188 
 2189             if (ListDevice)
 2190             {
 2191                 PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
 2192                 if (IsVolumeAccessibleByCurrentUser (ListExtension))
 2193                 {
 2194                     prop->uniqueId = ListExtension->UniqueVolumeId;
 2195                     RtlStringCbCopyW (prop->wszVolume, sizeof(prop->wszVolume),ListExtension->wszVolume);
 2196                     RtlStringCbCopyW (prop->wszLabel, sizeof(prop->wszLabel),ListExtension->wszLabel);
 2197                     memcpy (prop->volumeID, ListExtension->volumeID, VOLUME_ID_SIZE);
 2198                     prop->bDriverSetLabel = ListExtension->bDriverSetLabel;
 2199                     prop->diskLength = ListExtension->DiskLength;
 2200                     prop->ea = ListExtension->cryptoInfo->ea;
 2201                     prop->mode = ListExtension->cryptoInfo->mode;
 2202                     prop->pkcs5 = ListExtension->cryptoInfo->pkcs5;
 2203                     prop->pkcs5Iterations = ListExtension->cryptoInfo->noIterations;
 2204                     prop->volumePim = ListExtension->cryptoInfo->volumePim;
 2205 #if 0
 2206                     prop->volumeCreationTime = ListExtension->cryptoInfo->volume_creation_time;
 2207                     prop->headerCreationTime = ListExtension->cryptoInfo->header_creation_time;
 2208 #endif
 2209                     prop->volumeHeaderFlags = ListExtension->cryptoInfo->HeaderFlags;
 2210                     prop->readOnly = ListExtension->bReadOnly;
 2211                     prop->removable = ListExtension->bRemovable;
 2212                     prop->partitionInInactiveSysEncScope = ListExtension->PartitionInInactiveSysEncScope;
 2213                     prop->hiddenVolume = ListExtension->cryptoInfo->hiddenVolume;
 2214 
 2215                     if (ListExtension->cryptoInfo->bProtectHiddenVolume)
 2216                         prop->hiddenVolProtection = ListExtension->cryptoInfo->bHiddenVolProtectionAction ? HIDVOL_PROT_STATUS_ACTION_TAKEN : HIDVOL_PROT_STATUS_ACTIVE;
 2217                     else
 2218                         prop->hiddenVolProtection = HIDVOL_PROT_STATUS_NONE;
 2219 
 2220                     prop->totalBytesRead = ListExtension->Queue.TotalBytesRead;
 2221                     prop->totalBytesWritten = ListExtension->Queue.TotalBytesWritten;
 2222 
 2223                     prop->volFormatVersion = ListExtension->cryptoInfo->LegacyVolume ? TC_VOLUME_FORMAT_VERSION_PRE_6_0 : TC_VOLUME_FORMAT_VERSION;
 2224 
 2225                     Irp->IoStatus.Status = STATUS_SUCCESS;
 2226                     Irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT);
 2227                 }
 2228             }
 2229         }
 2230         break;
 2231 
 2232     case TC_IOCTL_GET_RESOLVED_SYMLINK:
 2233         if (ValidateIOBufferSize (Irp, sizeof (RESOLVE_SYMLINK_STRUCT), ValidateInputOutput))
 2234         {
 2235             RESOLVE_SYMLINK_STRUCT *resolve = (RESOLVE_SYMLINK_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2236             {
 2237                 NTSTATUS ntStatus;
 2238 
 2239                 EnsureNullTerminatedString (resolve->symLinkName, sizeof (resolve->symLinkName));
 2240 
 2241                 ntStatus = SymbolicLinkToTarget (resolve->symLinkName,
 2242                     resolve->targetName,
 2243                     sizeof (resolve->targetName));
 2244 
 2245                 Irp->IoStatus.Information = sizeof (RESOLVE_SYMLINK_STRUCT);
 2246                 Irp->IoStatus.Status = ntStatus;
 2247             }
 2248         }
 2249         break;
 2250 
 2251     case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
 2252         if (ValidateIOBufferSize (Irp, sizeof (DISK_PARTITION_INFO_STRUCT), ValidateInputOutput))
 2253         {
 2254             DISK_PARTITION_INFO_STRUCT *info = (DISK_PARTITION_INFO_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2255             {
 2256                 PARTITION_INFORMATION_EX pi;
 2257                 NTSTATUS ntStatus;
 2258 
 2259                 EnsureNullTerminatedString (info->deviceName, sizeof (info->deviceName));
 2260 
 2261                 ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &pi, sizeof (pi));
 2262                 if (NT_SUCCESS(ntStatus))
 2263                 {
 2264                     memset (&info->partInfo, 0, sizeof (info->partInfo));
 2265 
 2266                     info->partInfo.PartitionLength = pi.PartitionLength;
 2267                     info->partInfo.PartitionNumber = pi.PartitionNumber;
 2268                     info->partInfo.StartingOffset = pi.StartingOffset;
 2269 
 2270                     if (pi.PartitionStyle == PARTITION_STYLE_MBR)
 2271                     {
 2272                         info->partInfo.PartitionType = pi.Mbr.PartitionType;
 2273                         info->partInfo.BootIndicator = pi.Mbr.BootIndicator;
 2274                     }
 2275 
 2276                     info->IsGPT = pi.PartitionStyle == PARTITION_STYLE_GPT;
 2277                 }
 2278                 else
 2279                 {
 2280                     // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
 2281                     ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &info->partInfo, sizeof (info->partInfo));
 2282                     info->IsGPT = FALSE;
 2283                 }
 2284 
 2285                 if (!NT_SUCCESS (ntStatus))
 2286                 {
 2287                     GET_LENGTH_INFORMATION lengthInfo;
 2288                     ntStatus = TCDeviceIoControl (info->deviceName, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &lengthInfo, sizeof (lengthInfo));
 2289 
 2290                     if (NT_SUCCESS (ntStatus))
 2291                     {
 2292                         memset (&info->partInfo, 0, sizeof (info->partInfo));
 2293                         info->partInfo.PartitionLength = lengthInfo.Length;
 2294                     }
 2295                 }
 2296 
 2297                 info->IsDynamic = FALSE;
 2298 
 2299                 if (NT_SUCCESS (ntStatus) && OsMajorVersion >= 6)
 2300                 {
 2301 #                   define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS)
 2302                     if (!NT_SUCCESS (TCDeviceIoControl (info->deviceName, IOCTL_VOLUME_IS_DYNAMIC, NULL, 0, &info->IsDynamic, sizeof (info->IsDynamic))))
 2303                         info->IsDynamic = FALSE;
 2304                 }
 2305 
 2306                 Irp->IoStatus.Information = sizeof (DISK_PARTITION_INFO_STRUCT);
 2307                 Irp->IoStatus.Status = ntStatus;
 2308             }
 2309         }
 2310         break;
 2311 
 2312     case TC_IOCTL_GET_DRIVE_GEOMETRY:
 2313         if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_STRUCT), ValidateInputOutput))
 2314         {
 2315             DISK_GEOMETRY_STRUCT *g = (DISK_GEOMETRY_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2316             {
 2317                 NTSTATUS ntStatus;
 2318 
 2319                 EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName));
 2320                 Dump ("Calling IOCTL_DISK_GET_DRIVE_GEOMETRY on %ls\n", g->deviceName);
 2321 
 2322                 ntStatus = TCDeviceIoControl (g->deviceName,
 2323                     IOCTL_DISK_GET_DRIVE_GEOMETRY,
 2324                     NULL, 0, &g->diskGeometry, sizeof (g->diskGeometry));
 2325 
 2326                 Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_STRUCT);
 2327                 Irp->IoStatus.Status = ntStatus;
 2328             }
 2329         }
 2330         break;
 2331 
 2332     case VC_IOCTL_GET_DRIVE_GEOMETRY_EX:
 2333         if (ValidateIOBufferSize (Irp, sizeof (DISK_GEOMETRY_EX_STRUCT), ValidateInputOutput))
 2334         {
 2335             DISK_GEOMETRY_EX_STRUCT *g = (DISK_GEOMETRY_EX_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2336             {
 2337                 NTSTATUS ntStatus;
 2338                 PVOID buffer = TCalloc (256); // enough for DISK_GEOMETRY_EX and padded data
 2339                 if (buffer)
 2340                 {
 2341                     EnsureNullTerminatedString (g->deviceName, sizeof (g->deviceName));
 2342                     Dump ("Calling IOCTL_DISK_GET_DRIVE_GEOMETRY_EX on %ls\n", g->deviceName);
 2343 
 2344                     ntStatus = TCDeviceIoControl (g->deviceName,
 2345                         IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
 2346                         NULL, 0, buffer, 256);
 2347 
 2348                     if (NT_SUCCESS(ntStatus))
 2349                     {
 2350                         PDISK_GEOMETRY_EX pGeo = (PDISK_GEOMETRY_EX) buffer;
 2351                         memcpy (&g->diskGeometry, &pGeo->Geometry, sizeof (DISK_GEOMETRY));
 2352                         g->DiskSize.QuadPart = pGeo->DiskSize.QuadPart;
 2353                     }
 2354                     else
 2355                     {
 2356                         DISK_GEOMETRY dg = {0};
 2357                         Dump ("Failed. Calling IOCTL_DISK_GET_DRIVE_GEOMETRY on %ls\n", g->deviceName);
 2358                         ntStatus = TCDeviceIoControl (g->deviceName,
 2359                             IOCTL_DISK_GET_DRIVE_GEOMETRY,
 2360                             NULL, 0, &dg, sizeof (dg));
 2361 
 2362                         if (NT_SUCCESS(ntStatus))
 2363                         {
 2364                             memcpy (&g->diskGeometry, &dg, sizeof (DISK_GEOMETRY));
 2365                             g->DiskSize.QuadPart = dg.Cylinders.QuadPart * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.BytesPerSector;
 2366 
 2367                             if (OsMajorVersion >= 6)
 2368                             {
 2369                                 STORAGE_READ_CAPACITY storage = {0};
 2370                                 NTSTATUS lStatus;
 2371                                 storage.Version = sizeof (STORAGE_READ_CAPACITY);
 2372                                 Dump ("Calling IOCTL_STORAGE_READ_CAPACITY on %ls\n", g->deviceName);
 2373                                 lStatus = TCDeviceIoControl (g->deviceName,
 2374                                     IOCTL_STORAGE_READ_CAPACITY,
 2375                                     NULL, 0, &storage, sizeof (STORAGE_READ_CAPACITY));
 2376                                 if (    NT_SUCCESS(lStatus)
 2377                                     && (storage.Size == sizeof (STORAGE_READ_CAPACITY))
 2378                                     )
 2379                                 {
 2380                                     g->DiskSize.QuadPart = storage.DiskLength.QuadPart;
 2381                                 }
 2382                             }
 2383                         }
 2384                     }
 2385 
 2386                     TCfree (buffer);
 2387 
 2388                     Irp->IoStatus.Information = sizeof (DISK_GEOMETRY_EX_STRUCT);
 2389                     Irp->IoStatus.Status = ntStatus;
 2390                 }
 2391                 else
 2392                 {
 2393                     Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
 2394                     Irp->IoStatus.Information = 0;
 2395                 }
 2396             }
 2397         }
 2398         break;
 2399 
 2400     case TC_IOCTL_PROBE_REAL_DRIVE_SIZE:
 2401         if (ValidateIOBufferSize (Irp, sizeof (ProbeRealDriveSizeRequest), ValidateInputOutput))
 2402         {
 2403             ProbeRealDriveSizeRequest *request = (ProbeRealDriveSizeRequest *) Irp->AssociatedIrp.SystemBuffer;
 2404             NTSTATUS status;
 2405             UNICODE_STRING name;
 2406             PFILE_OBJECT fileObject;
 2407             PDEVICE_OBJECT deviceObject;
 2408 
 2409             EnsureNullTerminatedString (request->DeviceName, sizeof (request->DeviceName));
 2410 
 2411             RtlInitUnicodeString (&name, request->DeviceName);
 2412             status = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
 2413             if (!NT_SUCCESS (status))
 2414             {
 2415                 Irp->IoStatus.Information = 0;
 2416                 Irp->IoStatus.Status = status;
 2417                 break;
 2418             }
 2419 
 2420             status = ProbeRealDriveSize (deviceObject, &request->RealDriveSize);
 2421             ObDereferenceObject (fileObject);
 2422 
 2423             if (status == STATUS_TIMEOUT)
 2424             {
 2425                 request->TimeOut = TRUE;
 2426                 Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest);
 2427                 Irp->IoStatus.Status = STATUS_SUCCESS;
 2428             }
 2429             else if (!NT_SUCCESS (status))
 2430             {
 2431                 Irp->IoStatus.Information = 0;
 2432                 Irp->IoStatus.Status = status;
 2433             }
 2434             else
 2435             {
 2436                 request->TimeOut = FALSE;
 2437                 Irp->IoStatus.Information = sizeof (ProbeRealDriveSizeRequest);
 2438                 Irp->IoStatus.Status = status;
 2439             }
 2440         }
 2441         break;
 2442 
 2443     case TC_IOCTL_MOUNT_VOLUME:
 2444         if (ValidateIOBufferSize (Irp, sizeof (MOUNT_STRUCT), ValidateInputOutput))
 2445         {
 2446             MOUNT_STRUCT *mount = (MOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2447 
 2448             if (mount->VolumePassword.Length > MAX_PASSWORD || mount->ProtectedHidVolPassword.Length > MAX_PASSWORD
 2449                 ||  mount->pkcs5_prf < 0 || mount->pkcs5_prf > LAST_PRF_ID
 2450                 ||  mount->VolumePim < -1 || mount->VolumePim == INT_MAX
 2451                 || mount->ProtectedHidVolPkcs5Prf < 0 || mount->ProtectedHidVolPkcs5Prf > LAST_PRF_ID
 2452                 || (mount->bTrueCryptMode != FALSE && mount->bTrueCryptMode != TRUE)
 2453                 )
 2454             {
 2455                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 2456                 Irp->IoStatus.Information = 0;
 2457                 break;
 2458             }
 2459 
 2460             EnsureNullTerminatedString (mount->wszVolume, sizeof (mount->wszVolume));
 2461             EnsureNullTerminatedString (mount->wszLabel, sizeof (mount->wszLabel));
 2462 
 2463             Irp->IoStatus.Information = sizeof (MOUNT_STRUCT);
 2464             Irp->IoStatus.Status = MountDevice (DeviceObject, mount);
 2465 
 2466             burn (&mount->VolumePassword, sizeof (mount->VolumePassword));
 2467             burn (&mount->ProtectedHidVolPassword, sizeof (mount->ProtectedHidVolPassword));
 2468             burn (&mount->pkcs5_prf, sizeof (mount->pkcs5_prf));
 2469             burn (&mount->VolumePim, sizeof (mount->VolumePim));
 2470             burn (&mount->bTrueCryptMode, sizeof (mount->bTrueCryptMode));
 2471             burn (&mount->ProtectedHidVolPkcs5Prf, sizeof (mount->ProtectedHidVolPkcs5Prf));
 2472             burn (&mount->ProtectedHidVolPim, sizeof (mount->ProtectedHidVolPim));
 2473         }
 2474         break;
 2475 
 2476     case TC_IOCTL_DISMOUNT_VOLUME:
 2477         if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput))
 2478         {
 2479             UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2480             PDEVICE_OBJECT ListDevice = GetVirtualVolumeDeviceObject (unmount->nDosDriveNo);
 2481 
 2482             unmount->nReturnCode = ERR_DRIVE_NOT_FOUND;
 2483 
 2484             if (ListDevice)
 2485             {
 2486                 PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
 2487 
 2488                 if (IsVolumeAccessibleByCurrentUser (ListExtension))
 2489                     unmount->nReturnCode = UnmountDevice (unmount, ListDevice, unmount->ignoreOpenFiles);
 2490             }
 2491 
 2492             Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT);
 2493             Irp->IoStatus.Status = STATUS_SUCCESS;
 2494         }
 2495         break;
 2496 
 2497     case TC_IOCTL_DISMOUNT_ALL_VOLUMES:
 2498         if (ValidateIOBufferSize (Irp, sizeof (UNMOUNT_STRUCT), ValidateInputOutput))
 2499         {
 2500             UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer;
 2501 
 2502             unmount->nReturnCode = UnmountAllDevices (unmount, unmount->ignoreOpenFiles);
 2503 
 2504             Irp->IoStatus.Information = sizeof (UNMOUNT_STRUCT);
 2505             Irp->IoStatus.Status = STATUS_SUCCESS;
 2506         }
 2507         break;
 2508 
 2509     case TC_IOCTL_BOOT_ENCRYPTION_SETUP:
 2510         Irp->IoStatus.Status = StartBootEncryptionSetup (DeviceObject, Irp, irpSp);
 2511         Irp->IoStatus.Information = 0;
 2512         break;
 2513 
 2514     case TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP:
 2515         Irp->IoStatus.Status = AbortBootEncryptionSetup();
 2516         Irp->IoStatus.Information = 0;
 2517         break;
 2518 
 2519     case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
 2520         GetBootEncryptionStatus (Irp, irpSp);
 2521         break;
 2522 
 2523     case TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT:
 2524         Irp->IoStatus.Information = 0;
 2525         Irp->IoStatus.Status = GetSetupResult();
 2526         break;
 2527 
 2528     case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
 2529         GetBootDriveVolumeProperties (Irp, irpSp);
 2530         break;
 2531 
 2532     case TC_IOCTL_GET_BOOT_LOADER_VERSION:
 2533         GetBootLoaderVersion (Irp, irpSp);
 2534         break;
 2535 
 2536     case TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER:
 2537         ReopenBootVolumeHeader (Irp, irpSp);
 2538         break;
 2539 
 2540     case VC_IOCTL_GET_BOOT_LOADER_FINGERPRINT:
 2541         GetBootLoaderFingerprint (Irp, irpSp);
 2542         break;
 2543 
 2544     case TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME:
 2545         GetBootEncryptionAlgorithmName (Irp, irpSp);
 2546         break;
 2547 
 2548     case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
 2549         if (ValidateIOBufferSize (Irp, sizeof (int), ValidateOutput))
 2550         {
 2551             *(int *) Irp->AssociatedIrp.SystemBuffer = IsHiddenSystemRunning() ? 1 : 0;
 2552             Irp->IoStatus.Information = sizeof (int);
 2553             Irp->IoStatus.Status = STATUS_SUCCESS;
 2554         }
 2555         break;
 2556 
 2557     case TC_IOCTL_START_DECOY_SYSTEM_WIPE:
 2558         Irp->IoStatus.Status = StartDecoySystemWipe (DeviceObject, Irp, irpSp);
 2559         Irp->IoStatus.Information = 0;
 2560         break;
 2561 
 2562     case TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE:
 2563         Irp->IoStatus.Status = AbortDecoySystemWipe();
 2564         Irp->IoStatus.Information = 0;
 2565         break;
 2566 
 2567     case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT:
 2568         Irp->IoStatus.Status = GetDecoySystemWipeResult();
 2569         Irp->IoStatus.Information = 0;
 2570         break;
 2571 
 2572     case TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS:
 2573         GetDecoySystemWipeStatus (Irp, irpSp);
 2574         break;
 2575 
 2576     case TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR:
 2577         Irp->IoStatus.Status = WriteBootDriveSector (Irp, irpSp);
 2578         Irp->IoStatus.Information = 0;
 2579         break;
 2580 
 2581     case TC_IOCTL_GET_WARNING_FLAGS:
 2582         if (ValidateIOBufferSize (Irp, sizeof (GetWarningFlagsRequest), ValidateOutput))
 2583         {
 2584             GetWarningFlagsRequest *flags = (GetWarningFlagsRequest *) Irp->AssociatedIrp.SystemBuffer;
 2585 
 2586             flags->PagingFileCreationPrevented = PagingFileCreationPrevented;
 2587             PagingFileCreationPrevented = FALSE;
 2588             flags->SystemFavoriteVolumeDirty = SystemFavoriteVolumeDirty;
 2589             SystemFavoriteVolumeDirty = FALSE;
 2590 
 2591             Irp->IoStatus.Information = sizeof (GetWarningFlagsRequest);
 2592             Irp->IoStatus.Status = STATUS_SUCCESS;
 2593         }
 2594         break;
 2595 
 2596     case TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY:
 2597         if (UserCanAccessDriveDevice())
 2598         {
 2599             SystemFavoriteVolumeDirty = TRUE;
 2600             Irp->IoStatus.Status = STATUS_SUCCESS;
 2601         }
 2602         else
 2603             Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
 2604 
 2605         Irp->IoStatus.Information = 0;
 2606         break;
 2607 
 2608     case TC_IOCTL_REREAD_DRIVER_CONFIG:
 2609         Irp->IoStatus.Status = ReadRegistryConfigFlags (FALSE);
 2610         Irp->IoStatus.Information = 0;
 2611         break;
 2612 
 2613     case TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG:
 2614         if (    (ValidateIOBufferSize (Irp, sizeof (GetSystemDriveDumpConfigRequest), ValidateOutput))
 2615             &&  (Irp->RequestorMode == KernelMode)
 2616             )
 2617         {
 2618             GetSystemDriveDumpConfigRequest *request = (GetSystemDriveDumpConfigRequest *) Irp->AssociatedIrp.SystemBuffer;
 2619 
 2620             request->BootDriveFilterExtension = GetBootDriveFilterExtension();
 2621             if (IsBootDriveMounted() && request->BootDriveFilterExtension)
 2622             {
 2623                 request->HwEncryptionEnabled = IsHwEncryptionEnabled();
 2624                 Irp->IoStatus.Status = STATUS_SUCCESS;
 2625                 Irp->IoStatus.Information = sizeof (*request);
 2626             }
 2627             else
 2628             {
 2629                 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
 2630                 Irp->IoStatus.Information = 0;
 2631             }
 2632         }
 2633         break;
 2634 
 2635     default:
 2636         return TCCompleteIrp (Irp, STATUS_INVALID_DEVICE_REQUEST, 0);
 2637     }
 2638 
 2639 
 2640 #if defined(DEBUG) || defined(DEBUG_TRACE)
 2641     if (!NT_SUCCESS (Irp->IoStatus.Status))
 2642     {
 2643         switch (irpSp->Parameters.DeviceIoControl.IoControlCode)
 2644         {
 2645         case TC_IOCTL_GET_MOUNTED_VOLUMES:
 2646         case TC_IOCTL_GET_PASSWORD_CACHE_STATUS:
 2647         case TC_IOCTL_GET_PORTABLE_MODE_STATUS:
 2648         case TC_IOCTL_SET_PORTABLE_MODE_STATUS:
 2649         case TC_IOCTL_OPEN_TEST:
 2650         case TC_IOCTL_GET_RESOLVED_SYMLINK:
 2651         case TC_IOCTL_GET_DRIVE_PARTITION_INFO:
 2652         case TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES:
 2653         case TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS:
 2654         case TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING:
 2655             break;
 2656 
 2657         default:
 2658             Dump ("IOCTL error 0x%08x\n", Irp->IoStatus.Status);
 2659         }
 2660     }
 2661 #endif
 2662 
 2663     return TCCompleteIrp (Irp, Irp->IoStatus.Status, Irp->IoStatus.Information);
 2664 }
 2665 
 2666 
 2667 NTSTATUS TCStartThread (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread)
 2668 {
 2669     return TCStartThreadInProcess (threadProc, threadArg, kThread, NULL);
 2670 }
 2671 
 2672 
 2673 NTSTATUS TCStartThreadInProcess (PKSTART_ROUTINE threadProc, PVOID threadArg, PKTHREAD *kThread, PEPROCESS process)
 2674 {
 2675     NTSTATUS status;
 2676     HANDLE threadHandle;
 2677     HANDLE processHandle = NULL;
 2678     OBJECT_ATTRIBUTES threadObjAttributes;
 2679 
 2680     if (process)
 2681     {
 2682         status = ObOpenObjectByPointer (process, OBJ_KERNEL_HANDLE, NULL, 0, NULL, KernelMode, &processHandle);
 2683         if (!NT_SUCCESS (status))
 2684             return status;
 2685     }
 2686 
 2687     InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
 2688 
 2689     status = PsCreateSystemThread (&threadHandle, THREAD_ALL_ACCESS, &threadObjAttributes, processHandle, NULL, threadProc, threadArg);
 2690     if (!NT_SUCCESS (status))
 2691         return status;
 2692 
 2693     status = ObReferenceObjectByHandle (threadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID *) kThread, NULL);
 2694     if (!NT_SUCCESS (status))
 2695     {
 2696         ZwClose (threadHandle);
 2697         *kThread = NULL;
 2698         return status;
 2699     }
 2700 
 2701     if (processHandle)
 2702         ZwClose (processHandle);
 2703 
 2704     ZwClose (threadHandle);
 2705     return STATUS_SUCCESS;
 2706 }
 2707 
 2708 
 2709 void TCStopThread (PKTHREAD kThread, PKEVENT wakeUpEvent)
 2710 {
 2711     if (wakeUpEvent)
 2712         KeSetEvent (wakeUpEvent, 0, FALSE);
 2713 
 2714     KeWaitForSingleObject (kThread, Executive, KernelMode, FALSE, NULL);
 2715     ObDereferenceObject (kThread);
 2716 }
 2717 
 2718 
 2719 NTSTATUS TCStartVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount)
 2720 {
 2721     PTHREAD_BLOCK pThreadBlock = TCalloc (sizeof (THREAD_BLOCK));
 2722     HANDLE hThread;
 2723     NTSTATUS ntStatus;
 2724     OBJECT_ATTRIBUTES threadObjAttributes;
 2725     SECURITY_QUALITY_OF_SERVICE qos;
 2726 
 2727     Dump ("Starting thread...\n");
 2728 
 2729     if (pThreadBlock == NULL)
 2730     {
 2731         return STATUS_INSUFFICIENT_RESOURCES;
 2732     }
 2733     else
 2734     {
 2735         pThreadBlock->DeviceObject = DeviceObject;
 2736         pThreadBlock->mount = mount;
 2737     }
 2738 
 2739     qos.Length = sizeof (qos);
 2740     qos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
 2741     qos.EffectiveOnly = TRUE;
 2742     qos.ImpersonationLevel = SecurityImpersonation;
 2743 
 2744     ntStatus = SeCreateClientSecurity (PsGetCurrentThread(), &qos, FALSE, &Extension->SecurityClientContext);
 2745     if (!NT_SUCCESS (ntStatus))
 2746         goto ret;
 2747 
 2748     Extension->SecurityClientContextValid = TRUE;
 2749 
 2750     Extension->bThreadShouldQuit = FALSE;
 2751 
 2752     InitializeObjectAttributes (&threadObjAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
 2753 
 2754     ntStatus = PsCreateSystemThread (&hThread,
 2755                      THREAD_ALL_ACCESS,
 2756                      &threadObjAttributes,
 2757                      NULL,
 2758                      NULL,
 2759                      VolumeThreadProc,
 2760                      pThreadBlock);
 2761 
 2762     if (!NT_SUCCESS (ntStatus))
 2763     {
 2764         Dump ("PsCreateSystemThread Failed END\n");
 2765         goto ret;
 2766     }
 2767 
 2768     ntStatus = ObReferenceObjectByHandle (hThread,
 2769                    THREAD_ALL_ACCESS,
 2770                    NULL,
 2771                    KernelMode,
 2772                    &Extension->peThread,
 2773                    NULL);
 2774 
 2775     ZwClose (hThread);
 2776 
 2777     if (!NT_SUCCESS (ntStatus))
 2778         goto ret;
 2779 
 2780     Dump ("Waiting for thread to initialize...\n");
 2781 
 2782     KeWaitForSingleObject (&Extension->keCreateEvent,
 2783                    Executive,
 2784                    KernelMode,
 2785                    FALSE,
 2786                    NULL);
 2787 
 2788     Dump ("Waiting completed! Thread returns 0x%08x\n", pThreadBlock->ntCreateStatus);
 2789     ntStatus = pThreadBlock->ntCreateStatus;
 2790 
 2791 ret:
 2792     TCfree (pThreadBlock);
 2793     return ntStatus;
 2794 }
 2795 
 2796 void TCStopVolumeThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
 2797 {
 2798     NTSTATUS ntStatus;
 2799 
 2800     UNREFERENCED_PARAMETER (DeviceObject);  /* Remove compiler warning */
 2801 
 2802     Dump ("Signalling thread to quit...\n");
 2803 
 2804     Extension->bThreadShouldQuit = TRUE;
 2805 
 2806     KeReleaseSemaphore (&Extension->RequestSemaphore,
 2807                 0,
 2808                 1,
 2809                 TRUE);
 2810 
 2811     ntStatus = KeWaitForSingleObject (Extension->peThread,
 2812                       Executive,
 2813                       KernelMode,
 2814                       FALSE,
 2815                       NULL);
 2816 
 2817     ASSERT (NT_SUCCESS (ntStatus));
 2818 
 2819     ObDereferenceObject (Extension->peThread);
 2820     Extension->peThread = NULL;
 2821 
 2822     Dump ("Thread exited\n");
 2823 }
 2824 
 2825 
 2826 // Suspend current thread for a number of milliseconds
 2827 void TCSleep (int milliSeconds)
 2828 {
 2829     PKTIMER timer = (PKTIMER) TCalloc (sizeof (KTIMER));
 2830     LARGE_INTEGER duetime;
 2831 
 2832     if (!timer)
 2833         return;
 2834 
 2835     duetime.QuadPart = (__int64) milliSeconds * -10000;
 2836     KeInitializeTimerEx(timer, NotificationTimer);
 2837     KeSetTimerEx(timer, duetime, 0, NULL);
 2838 
 2839     KeWaitForSingleObject (timer, Executive, KernelMode, FALSE, NULL);
 2840 
 2841     TCfree (timer);
 2842 }
 2843 
 2844 BOOL IsDeviceName(wchar_t wszVolume[TC_MAX_PATH])
 2845 {
 2846     if  (   (wszVolume[0] == '\\')
 2847         &&  (wszVolume[1] == 'D' || wszVolume[1] == 'd')
 2848         &&  (wszVolume[2] == 'E' || wszVolume[2] == 'e')
 2849         &&  (wszVolume[3] == 'V' || wszVolume[3] == 'v')
 2850         &&  (wszVolume[4] == 'I' || wszVolume[4] == 'i')
 2851         &&  (wszVolume[5] == 'C' || wszVolume[5] == 'c')
 2852         &&  (wszVolume[6] == 'E' || wszVolume[6] == 'e')
 2853         )
 2854     {
 2855         return TRUE;
 2856     }
 2857     else
 2858         return FALSE;
 2859 }
 2860 
 2861 /* VolumeThreadProc does all the work of processing IRP's, and dispatching them
 2862    to either the ReadWrite function or the DeviceControl function */
 2863 VOID VolumeThreadProc (PVOID Context)
 2864 {
 2865     PTHREAD_BLOCK pThreadBlock = (PTHREAD_BLOCK) Context;
 2866     PDEVICE_OBJECT DeviceObject = pThreadBlock->DeviceObject;
 2867     PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension;
 2868     BOOL bDevice;
 2869 
 2870     /* Set thread priority to lowest realtime level. */
 2871     KeSetPriorityThread (KeGetCurrentThread (), LOW_REALTIME_PRIORITY);
 2872 
 2873     Dump ("Mount THREAD OPENING VOLUME BEGIN\n");
 2874 
 2875     if ( !IsDeviceName (pThreadBlock->mount->wszVolume))
 2876     {
 2877         RtlStringCbCopyW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),WIDE ("\\??\\"));
 2878         RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume);
 2879         bDevice = FALSE;
 2880     }
 2881     else
 2882     {
 2883         pThreadBlock->wszMountVolume[0] = 0;
 2884         RtlStringCbCatW (pThreadBlock->wszMountVolume, sizeof(pThreadBlock->wszMountVolume),pThreadBlock->mount->wszVolume);
 2885         bDevice = TRUE;
 2886     }
 2887 
 2888     Dump ("Mount THREAD request for File %ls DriveNumber %d Device = %d\n",
 2889           pThreadBlock->wszMountVolume, pThreadBlock->mount->nDosDriveNo, bDevice);
 2890 
 2891     pThreadBlock->ntCreateStatus = TCOpenVolume (DeviceObject,
 2892         Extension,
 2893         pThreadBlock->mount,
 2894         pThreadBlock->wszMountVolume,
 2895         bDevice);
 2896 
 2897     if (!NT_SUCCESS (pThreadBlock->ntCreateStatus) || pThreadBlock->mount->nReturnCode != 0)
 2898     {
 2899         KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
 2900         PsTerminateSystemThread (STATUS_SUCCESS);
 2901     }
 2902 
 2903     // Start IO queue
 2904     Extension->Queue.IsFilterDevice = FALSE;
 2905     Extension->Queue.DeviceObject = DeviceObject;
 2906     Extension->Queue.CryptoInfo = Extension->cryptoInfo;
 2907     Extension->Queue.HostFileHandle = Extension->hDeviceFile;
 2908     Extension->Queue.VirtualDeviceLength = Extension->DiskLength;
 2909     Extension->Queue.MaxReadAheadOffset.QuadPart = Extension->HostLength;
 2910 
 2911     if (Extension->SecurityClientContextValid)
 2912         Extension->Queue.SecurityClientContext = &Extension->SecurityClientContext;
 2913     else
 2914         Extension->Queue.SecurityClientContext = NULL;
 2915 
 2916     pThreadBlock->ntCreateStatus = EncryptedIoQueueStart (&Extension->Queue);
 2917 
 2918     if (!NT_SUCCESS (pThreadBlock->ntCreateStatus))
 2919     {
 2920         TCCloseVolume (DeviceObject, Extension);
 2921 
 2922         pThreadBlock->mount->nReturnCode = ERR_OS_ERROR;
 2923         KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
 2924         PsTerminateSystemThread (STATUS_SUCCESS);
 2925     }
 2926 
 2927     KeSetEvent (&Extension->keCreateEvent, 0, FALSE);
 2928     /* From this point on pThreadBlock cannot be used as it will have been released! */
 2929     pThreadBlock = NULL;
 2930 
 2931     for (;;)
 2932     {
 2933         /* Wait for a request from the dispatch routines. */
 2934         KeWaitForSingleObject ((PVOID) & Extension->RequestSemaphore, Executive, KernelMode, FALSE, NULL);
 2935 
 2936         for (;;)
 2937         {
 2938             PIO_STACK_LOCATION irpSp;
 2939             PLIST_ENTRY request;
 2940             PIRP irp;
 2941 
 2942             request = ExInterlockedRemoveHeadList (&Extension->ListEntry, &Extension->ListSpinLock);
 2943             if (request == NULL)
 2944                 break;
 2945 
 2946             irp = CONTAINING_RECORD (request, IRP, Tail.Overlay.ListEntry);
 2947             irpSp = IoGetCurrentIrpStackLocation (irp);
 2948 
 2949             ASSERT (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
 2950 
 2951             ProcessVolumeDeviceControlIrp (DeviceObject, Extension, irp);
 2952             IoReleaseRemoveLock (&Extension->Queue.RemoveLock, irp);
 2953         }
 2954 
 2955         if (Extension->bThreadShouldQuit)
 2956         {
 2957             Dump ("Closing volume\n");
 2958             EncryptedIoQueueStop (&Extension->Queue);
 2959 
 2960             TCCloseVolume (DeviceObject, Extension);
 2961             PsTerminateSystemThread (STATUS_SUCCESS);
 2962         }
 2963     }
 2964 }
 2965 
 2966 void TCGetNTNameFromNumber (LPWSTR ntname, int cbNtName, int nDriveNo)
 2967 {
 2968     WCHAR tmp[2] =
 2969     {0, 0};
 2970     int j = nDriveNo + (WCHAR) 'A';
 2971 
 2972     tmp[0] = (short) j;
 2973     RtlStringCbCopyW (ntname, cbNtName,(LPWSTR) NT_MOUNT_PREFIX);
 2974     RtlStringCbCatW (ntname, cbNtName, tmp);
 2975 }
 2976 
 2977 void TCGetDosNameFromNumber (LPWSTR dosname,int cbDosName, int nDriveNo, DeviceNamespaceType namespaceType)
 2978 {
 2979     WCHAR tmp[3] =
 2980     {0, ':', 0};
 2981     int j = nDriveNo + (WCHAR) 'A';
 2982 
 2983     tmp[0] = (short) j;
 2984 
 2985     if (DeviceNamespaceGlobal == namespaceType)
 2986     {
 2987         RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_GLOBAL);
 2988     }
 2989     else
 2990     {
 2991         RtlStringCbCopyW (dosname, cbDosName, (LPWSTR) DOS_MOUNT_PREFIX_DEFAULT);
 2992     }
 2993 
 2994     RtlStringCbCatW (dosname, cbDosName, tmp);
 2995 }
 2996 
 2997 #if defined(_DEBUG) || defined (_DEBUG_TRACE)
 2998 LPWSTR TCTranslateCode (ULONG ulCode)
 2999 {
 3000     switch (ulCode)
 3001     {
 3002 #define TC_CASE_RET_NAME(CODE) case CODE : return L###CODE
 3003 
 3004         TC_CASE_RET_NAME (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP);
 3005         TC_CASE_RET_NAME (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE);
 3006         TC_CASE_RET_NAME (TC_IOCTL_BOOT_ENCRYPTION_SETUP);
 3007         TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_ALL_VOLUMES);
 3008         TC_CASE_RET_NAME (TC_IOCTL_DISMOUNT_VOLUME);
 3009         TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES);
 3010         TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME);
 3011         TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT);
 3012         TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS);
 3013         TC_CASE_RET_NAME (TC_IOCTL_GET_BOOT_LOADER_VERSION);
 3014         TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT);
 3015         TC_CASE_RET_NAME (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS);
 3016         TC_CASE_RET_NAME (TC_IOCTL_GET_DEVICE_REFCOUNT);
 3017         TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_GEOMETRY);
 3018         TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVE_PARTITION_INFO);
 3019         TC_CASE_RET_NAME (TC_IOCTL_GET_DRIVER_VERSION);
 3020         TC_CASE_RET_NAME (TC_IOCTL_GET_MOUNTED_VOLUMES);
 3021         TC_CASE_RET_NAME (TC_IOCTL_GET_PASSWORD_CACHE_STATUS);
 3022         TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG);
 3023         TC_CASE_RET_NAME (TC_IOCTL_GET_PORTABLE_MODE_STATUS);
 3024         TC_CASE_RET_NAME (TC_IOCTL_SET_PORTABLE_MODE_STATUS);
 3025         TC_CASE_RET_NAME (TC_IOCTL_GET_RESOLVED_SYMLINK);
 3026         TC_CASE_RET_NAME (TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG);
 3027         TC_CASE_RET_NAME (TC_IOCTL_GET_VOLUME_PROPERTIES);
 3028         TC_CASE_RET_NAME (TC_IOCTL_GET_WARNING_FLAGS);
 3029         TC_CASE_RET_NAME (TC_IOCTL_DISK_IS_WRITABLE);
 3030         TC_CASE_RET_NAME (TC_IOCTL_IS_ANY_VOLUME_MOUNTED);
 3031         TC_CASE_RET_NAME (TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED);
 3032         TC_CASE_RET_NAME (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING);
 3033         TC_CASE_RET_NAME (TC_IOCTL_MOUNT_VOLUME);
 3034         TC_CASE_RET_NAME (TC_IOCTL_OPEN_TEST);
 3035         TC_CASE_RET_NAME (TC_IOCTL_PROBE_REAL_DRIVE_SIZE);
 3036         TC_CASE_RET_NAME (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER);
 3037         TC_CASE_RET_NAME (TC_IOCTL_REREAD_DRIVER_CONFIG);
 3038         TC_CASE_RET_NAME (TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY);
 3039         TC_CASE_RET_NAME (TC_IOCTL_START_DECOY_SYSTEM_WIPE);
 3040         TC_CASE_RET_NAME (TC_IOCTL_WIPE_PASSWORD_CACHE);
 3041         TC_CASE_RET_NAME (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR);
 3042         TC_CASE_RET_NAME (VC_IOCTL_GET_DRIVE_GEOMETRY_EX);
 3043 
 3044         TC_CASE_RET_NAME (IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS);
 3045 
 3046 #undef TC_CASE_RET_NAME
 3047     }
 3048 
 3049     if (ulCode ==            IOCTL_DISK_GET_DRIVE_GEOMETRY)
 3050         return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY");
 3051     else if (ulCode ==       IOCTL_DISK_GET_DRIVE_GEOMETRY_EX)
 3052         return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX");
 3053     else if (ulCode ==       IOCTL_MOUNTDEV_QUERY_DEVICE_NAME)
 3054         return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME");
 3055     else if (ulCode ==       IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME)
 3056         return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME");
 3057     else if (ulCode ==       IOCTL_MOUNTDEV_QUERY_UNIQUE_ID)
 3058         return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID");
 3059     else if (ulCode ==       IOCTL_VOLUME_ONLINE)
 3060         return (LPWSTR) _T ("IOCTL_VOLUME_ONLINE");
 3061     else if (ulCode ==       IOCTL_MOUNTDEV_LINK_CREATED)
 3062         return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_CREATED");
 3063     else if (ulCode ==       IOCTL_MOUNTDEV_LINK_DELETED)
 3064         return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_DELETED");
 3065     else if (ulCode ==       IOCTL_MOUNTMGR_QUERY_POINTS)
 3066         return (LPWSTR) _T ("IOCTL_MOUNTMGR_QUERY_POINTS");
 3067     else if (ulCode ==       IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED)
 3068         return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED");
 3069     else if (ulCode ==       IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED)
 3070         return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED");
 3071     else if (ulCode ==       IOCTL_DISK_GET_LENGTH_INFO)
 3072         return (LPWSTR) _T ("IOCTL_DISK_GET_LENGTH_INFO");
 3073     else if (ulCode ==       IOCTL_STORAGE_GET_DEVICE_NUMBER)
 3074         return (LPWSTR) _T ("IOCTL_STORAGE_GET_DEVICE_NUMBER");
 3075     else if (ulCode ==       IOCTL_DISK_GET_PARTITION_INFO)
 3076         return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO");
 3077     else if (ulCode ==       IOCTL_DISK_GET_PARTITION_INFO_EX)
 3078         return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO_EX");
 3079     else if (ulCode ==       IOCTL_DISK_SET_PARTITION_INFO)
 3080         return (LPWSTR) _T ("IOCTL_DISK_SET_PARTITION_INFO");
 3081     else if (ulCode ==       IOCTL_DISK_GET_DRIVE_LAYOUT)
 3082         return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_LAYOUT");
 3083     else if (ulCode ==       IOCTL_DISK_GET_DRIVE_LAYOUT_EX)
 3084         return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_LAYOUT_EX");
 3085     else if (ulCode ==       IOCTL_DISK_SET_DRIVE_LAYOUT_EX)
 3086         return (LPWSTR) _T ("IOCTL_DISK_SET_DRIVE_LAYOUT_EX");
 3087     else if (ulCode ==       IOCTL_DISK_VERIFY)
 3088         return (LPWSTR) _T ("IOCTL_DISK_VERIFY");
 3089     else if (ulCode == IOCTL_DISK_FORMAT_TRACKS)
 3090         return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS");
 3091     else if (ulCode == IOCTL_DISK_REASSIGN_BLOCKS)
 3092         return (LPWSTR) _T ("IOCTL_DISK_REASSIGN_BLOCKS");
 3093     else if (ulCode == IOCTL_DISK_PERFORMANCE)
 3094         return (LPWSTR) _T ("IOCTL_DISK_PERFORMANCE");
 3095     else if (ulCode == IOCTL_DISK_IS_WRITABLE)
 3096         return (LPWSTR) _T ("IOCTL_DISK_IS_WRITABLE");
 3097     else if (ulCode == IOCTL_DISK_LOGGING)
 3098         return (LPWSTR) _T ("IOCTL_DISK_LOGGING");
 3099     else if (ulCode == IOCTL_DISK_FORMAT_TRACKS_EX)
 3100         return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS_EX");
 3101     else if (ulCode == IOCTL_DISK_HISTOGRAM_STRUCTURE)
 3102         return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_STRUCTURE");
 3103     else if (ulCode == IOCTL_DISK_HISTOGRAM_DATA)
 3104         return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_DATA");
 3105     else if (ulCode == IOCTL_DISK_HISTOGRAM_RESET)
 3106         return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_RESET");
 3107     else if (ulCode == IOCTL_DISK_REQUEST_STRUCTURE)
 3108         return (LPWSTR) _T ("IOCTL_DISK_REQUEST_STRUCTURE");
 3109     else if (ulCode == IOCTL_DISK_REQUEST_DATA)
 3110         return (LPWSTR) _T ("IOCTL_DISK_REQUEST_DATA");
 3111     else if (ulCode == IOCTL_DISK_CONTROLLER_NUMBER)
 3112         return (LPWSTR) _T ("IOCTL_DISK_CONTROLLER_NUMBER");
 3113     else if (ulCode == SMART_GET_VERSION)
 3114         return (LPWSTR) _T ("SMART_GET_VERSION");
 3115     else if (ulCode == SMART_SEND_DRIVE_COMMAND)
 3116         return (LPWSTR) _T ("SMART_SEND_DRIVE_COMMAND");
 3117     else if (ulCode == SMART_RCV_DRIVE_DATA)
 3118         return (LPWSTR) _T ("SMART_RCV_DRIVE_DATA");
 3119     else if (ulCode == IOCTL_DISK_INTERNAL_SET_VERIFY)
 3120         return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_SET_VERIFY");
 3121     else if (ulCode == IOCTL_DISK_INTERNAL_CLEAR_VERIFY)
 3122         return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_CLEAR_VERIFY");
 3123     else if (ulCode == IOCTL_DISK_CHECK_VERIFY)
 3124         return (LPWSTR) _T ("IOCTL_DISK_CHECK_VERIFY");
 3125     else if (ulCode == IOCTL_DISK_MEDIA_REMOVAL)
 3126         return (LPWSTR) _T ("IOCTL_DISK_MEDIA_REMOVAL");
 3127     else if (ulCode == IOCTL_DISK_EJECT_MEDIA)
 3128         return (LPWSTR) _T ("IOCTL_DISK_EJECT_MEDIA");
 3129     else if (ulCode == IOCTL_DISK_LOAD_MEDIA)
 3130         return (LPWSTR) _T ("IOCTL_DISK_LOAD_MEDIA");
 3131     else if (ulCode == IOCTL_DISK_RESERVE)
 3132         return (LPWSTR) _T ("IOCTL_DISK_RESERVE");
 3133     else if (ulCode == IOCTL_DISK_RELEASE)
 3134         return (LPWSTR) _T ("IOCTL_DISK_RELEASE");
 3135     else if (ulCode == IOCTL_DISK_FIND_NEW_DEVICES)
 3136         return (LPWSTR) _T ("IOCTL_DISK_FIND_NEW_DEVICES");
 3137     else if (ulCode == IOCTL_DISK_GET_MEDIA_TYPES)
 3138         return (LPWSTR) _T ("IOCTL_DISK_GET_MEDIA_TYPES");
 3139     else if (ulCode == IOCTL_DISK_IS_CLUSTERED)
 3140         return (LPWSTR) _T ("IOCTL_DISK_IS_CLUSTERED"); 
 3141     else if (ulCode == IOCTL_DISK_UPDATE_DRIVE_SIZE)
 3142         return (LPWSTR) _T ("IOCTL_DISK_UPDATE_DRIVE_SIZE");
 3143     else if (ulCode == IOCTL_STORAGE_GET_MEDIA_TYPES)
 3144         return (LPWSTR) _T ("IOCTL_STORAGE_GET_MEDIA_TYPES");
 3145     else if (ulCode == IOCTL_STORAGE_GET_HOTPLUG_INFO)
 3146         return (LPWSTR) _T ("IOCTL_STORAGE_GET_HOTPLUG_INFO");
 3147     else if (ulCode == IOCTL_STORAGE_SET_HOTPLUG_INFO)
 3148         return (LPWSTR) _T ("IOCTL_STORAGE_SET_HOTPLUG_INFO");
 3149     else if (ulCode == IOCTL_STORAGE_QUERY_PROPERTY)
 3150         return (LPWSTR) _T ("IOCTL_STORAGE_QUERY_PROPERTY");
 3151     else if (ulCode == IOCTL_VOLUME_GET_GPT_ATTRIBUTES)
 3152         return (LPWSTR) _T ("IOCTL_VOLUME_GET_GPT_ATTRIBUTES"); 
 3153     else if (ulCode == FT_BALANCED_READ_MODE)
 3154         return (LPWSTR) _T ("FT_BALANCED_READ_MODE");
 3155     else if (ulCode == IOCTL_VOLUME_QUERY_ALLOCATION_HINT)
 3156         return (LPWSTR) _T ("IOCTL_VOLUME_QUERY_ALLOCATION_HINT");
 3157     else if (ulCode == IOCTL_DISK_GET_CLUSTER_INFO)
 3158         return (LPWSTR) _T ("IOCTL_DISK_GET_CLUSTER_INFO");
 3159     else if (ulCode == IOCTL_DISK_ARE_VOLUMES_READY)
 3160         return (LPWSTR) _T ("IOCTL_DISK_ARE_VOLUMES_READY");            
 3161     else if (ulCode == IOCTL_VOLUME_IS_DYNAMIC)
 3162         return (LPWSTR) _T ("IOCTL_VOLUME_IS_DYNAMIC");
 3163     else if (ulCode == IOCTL_MOUNTDEV_QUERY_STABLE_GUID)
 3164         return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_STABLE_GUID");
 3165     else if (ulCode == IOCTL_VOLUME_POST_ONLINE)
 3166         return (LPWSTR) _T ("IOCTL_VOLUME_POST_ONLINE");
 3167     else if (ulCode == IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT)
 3168         return (LPWSTR) _T ("IOCTL_STORAGE_CHECK_PRIORITY_HINT_SUPPORT");
 3169     else if (ulCode == IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES)
 3170         return (LPWSTR) _T ("IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES");
 3171     else if (ulCode == IRP_MJ_READ)
 3172         return (LPWSTR) _T ("IRP_MJ_READ");
 3173     else if (ulCode == IRP_MJ_WRITE)
 3174         return (LPWSTR) _T ("IRP_MJ_WRITE");
 3175     else if (ulCode == IRP_MJ_CREATE)
 3176         return (LPWSTR) _T ("IRP_MJ_CREATE");
 3177     else if (ulCode == IRP_MJ_CLOSE)
 3178         return (LPWSTR) _T ("IRP_MJ_CLOSE");
 3179     else if (ulCode == IRP_MJ_CLEANUP)
 3180         return (LPWSTR) _T ("IRP_MJ_CLEANUP");
 3181     else if (ulCode == IRP_MJ_FLUSH_BUFFERS)
 3182         return (LPWSTR) _T ("IRP_MJ_FLUSH_BUFFERS");
 3183     else if (ulCode == IRP_MJ_SHUTDOWN)
 3184         return (LPWSTR) _T ("IRP_MJ_SHUTDOWN");
 3185     else if (ulCode == IRP_MJ_DEVICE_CONTROL)
 3186         return (LPWSTR) _T ("IRP_MJ_DEVICE_CONTROL");
 3187     else
 3188     {
 3189         return (LPWSTR) _T ("IOCTL");
 3190     }
 3191 }
 3192 
 3193 #endif
 3194 
 3195 void TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
 3196 {
 3197     UNICODE_STRING Win32NameString;
 3198     NTSTATUS ntStatus;
 3199 
 3200     Dump ("TCDeleteDeviceObject BEGIN\n");
 3201 
 3202     if (Extension->bRootDevice)
 3203     {
 3204         RtlInitUnicodeString (&Win32NameString, (LPWSTR) DOS_ROOT_PREFIX);
 3205         ntStatus = IoDeleteSymbolicLink (&Win32NameString);
 3206         if (!NT_SUCCESS (ntStatus))
 3207             Dump ("IoDeleteSymbolicLink failed ntStatus = 0x%08x\n", ntStatus);
 3208 
 3209         RootDeviceObject = NULL;
 3210     }
 3211     else
 3212     {
 3213         if (Extension->peThread != NULL)
 3214             TCStopVolumeThread (DeviceObject, Extension);
 3215 
 3216         if (Extension->UserSid)
 3217             TCfree (Extension->UserSid);
 3218 
 3219         if (Extension->SecurityClientContextValid)
 3220         {
 3221             if (OsMajorVersion == 5 && OsMinorVersion == 0)
 3222             {
 3223                 ObDereferenceObject (Extension->SecurityClientContext.ClientToken);
 3224             }
 3225             else
 3226             {
 3227                 // Windows 2000 does not support PsDereferenceImpersonationToken() used by SeDeleteClientSecurity().
 3228                 // TODO: Use only SeDeleteClientSecurity() once support for Windows 2000 is dropped.
 3229 
 3230                 VOID (*PsDereferenceImpersonationTokenD) (PACCESS_TOKEN ImpersonationToken);
 3231                 UNICODE_STRING name;
 3232                 RtlInitUnicodeString (&name, L"PsDereferenceImpersonationToken");
 3233 
 3234                 PsDereferenceImpersonationTokenD = MmGetSystemRoutineAddress (&name);
 3235                 if (!PsDereferenceImpersonationTokenD)
 3236                     TC_BUG_CHECK (STATUS_NOT_IMPLEMENTED);
 3237 
 3238 #               define PsDereferencePrimaryToken
 3239 #               define PsDereferenceImpersonationToken PsDereferenceImpersonationTokenD
 3240 
 3241                 SeDeleteClientSecurity (&Extension->SecurityClientContext);
 3242 
 3243 #               undef PsDereferencePrimaryToken
 3244 #               undef PsDereferenceImpersonationToken
 3245             }
 3246         }
 3247 
 3248         VirtualVolumeDeviceObjects[Extension->nDosDriveNo] = NULL;
 3249     }
 3250 
 3251     IoDeleteDevice (DeviceObject);
 3252 
 3253     Dump ("TCDeleteDeviceObject END\n");
 3254 }
 3255 
 3256 
 3257 VOID TCUnloadDriver (PDRIVER_OBJECT DriverObject)
 3258 {
 3259     Dump ("TCUnloadDriver BEGIN\n");
 3260 
 3261     OnShutdownPending();
 3262 
 3263     if (IsBootDriveMounted())
 3264         TC_BUG_CHECK (STATUS_INVALID_DEVICE_STATE);
 3265 
 3266     EncryptionThreadPoolStop();
 3267     TCDeleteDeviceObject (RootDeviceObject, (PEXTENSION) RootDeviceObject->DeviceExtension);
 3268 
 3269     Dump ("TCUnloadDriver END\n");
 3270 }
 3271 
 3272 
 3273 void OnShutdownPending ()
 3274 {
 3275     UNMOUNT_STRUCT unmount;
 3276     memset (&unmount, 0, sizeof (unmount));
 3277     unmount.ignoreOpenFiles = TRUE;
 3278 
 3279     while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_DISMOUNT_ALL_VOLUMES, &unmount, sizeof (unmount), &unmount, sizeof (unmount)) == STATUS_INSUFFICIENT_RESOURCES || unmount.HiddenVolumeProtectionTriggered)
 3280         unmount.HiddenVolumeProtectionTriggered = FALSE;
 3281 
 3282     while (SendDeviceIoControlRequest (RootDeviceObject, TC_IOCTL_WIPE_PASSWORD_CACHE, NULL, 0, NULL, 0) == STATUS_INSUFFICIENT_RESOURCES);
 3283 }
 3284 
 3285 
 3286 NTSTATUS TCDeviceIoControl (PWSTR deviceName, ULONG IoControlCode, void *InputBuffer, ULONG InputBufferSize, void *OutputBuffer, ULONG OutputBufferSize)
 3287 {
 3288     IO_STATUS_BLOCK ioStatusBlock;
 3289     NTSTATUS ntStatus;
 3290     PIRP irp;
 3291     PFILE_OBJECT fileObject;
 3292     PDEVICE_OBJECT deviceObject;
 3293     KEVENT event;
 3294     UNICODE_STRING name;
 3295 
 3296     RtlInitUnicodeString(&name, deviceName);
 3297     ntStatus = IoGetDeviceObjectPointer (&name, FILE_READ_ATTRIBUTES, &fileObject, &deviceObject);
 3298 
 3299     if (!NT_SUCCESS (ntStatus))
 3300         return ntStatus;
 3301 
 3302     KeInitializeEvent(&event, NotificationEvent, FALSE);
 3303 
 3304     irp = IoBuildDeviceIoControlRequest (IoControlCode,
 3305                          deviceObject,
 3306                          InputBuffer, InputBufferSize,
 3307                          OutputBuffer, OutputBufferSize,
 3308                          FALSE,
 3309                          &event,
 3310                          &ioStatusBlock);
 3311 
 3312     if (irp == NULL)
 3313     {
 3314         Dump ("IRP allocation failed\n");
 3315         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
 3316         goto ret;
 3317     }
 3318 
 3319     IoGetNextIrpStackLocation (irp)->FileObject = fileObject;
 3320 
 3321     ntStatus = IoCallDriver (deviceObject, irp);
 3322     if (ntStatus == STATUS_PENDING)
 3323     {
 3324         KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
 3325         ntStatus = ioStatusBlock.Status;
 3326     }
 3327 
 3328 ret:
 3329     ObDereferenceObject (fileObject);
 3330     return ntStatus;
 3331 }
 3332 
 3333 
 3334 typedef struct
 3335 {
 3336     PDEVICE_OBJECT deviceObject; ULONG ioControlCode; void *inputBuffer; int inputBufferSize; void *outputBuffer; int outputBufferSize;
 3337     NTSTATUS Status;
 3338     KEVENT WorkItemCompletedEvent;
 3339 } SendDeviceIoControlRequestWorkItemArgs;
 3340 
 3341 
 3342 static VOID SendDeviceIoControlRequestWorkItemRoutine (PDEVICE_OBJECT rootDeviceObject, SendDeviceIoControlRequestWorkItemArgs *arg)
 3343 {
 3344     arg->Status = SendDeviceIoControlRequest (arg->deviceObject, arg->ioControlCode, arg->inputBuffer, arg->inputBufferSize, arg->outputBuffer, arg->outputBufferSize);
 3345     KeSetEvent (&arg->WorkItemCompletedEvent, IO_NO_INCREMENT, FALSE);
 3346 }
 3347 
 3348 
 3349 NTSTATUS SendDeviceIoControlRequest (PDEVICE_OBJECT deviceObject, ULONG ioControlCode, void *inputBuffer, int inputBufferSize, void *outputBuffer, int outputBufferSize)
 3350 {
 3351     IO_STATUS_BLOCK ioStatusBlock;
 3352     NTSTATUS status;
 3353     PIRP irp;
 3354     KEVENT event;
 3355 
 3356     if (KeGetCurrentIrql() > APC_LEVEL)
 3357     {
 3358         SendDeviceIoControlRequestWorkItemArgs args;
 3359 
 3360         PIO_WORKITEM workItem = IoAllocateWorkItem (RootDeviceObject);
 3361         if (!workItem)
 3362             return STATUS_INSUFFICIENT_RESOURCES;
 3363 
 3364         args.deviceObject = deviceObject;
 3365         args.ioControlCode = ioControlCode;
 3366         args.inputBuffer = inputBuffer;
 3367         args.inputBufferSize = inputBufferSize;
 3368         args.outputBuffer = outputBuffer;
 3369         args.outputBufferSize = outputBufferSize;
 3370 
 3371         KeInitializeEvent (&args.WorkItemCompletedEvent, SynchronizationEvent, FALSE);
 3372         IoQueueWorkItem (workItem, SendDeviceIoControlRequestWorkItemRoutine, DelayedWorkQueue, &args);
 3373 
 3374         KeWaitForSingleObject (&args.WorkItemCompletedEvent, Executive, KernelMode, FALSE, NULL);
 3375         IoFreeWorkItem (workItem);
 3376 
 3377         return args.Status;
 3378     }
 3379 
 3380     KeInitializeEvent (&event, NotificationEvent, FALSE);
 3381 
 3382     irp = IoBuildDeviceIoControlRequest (ioControlCode, deviceObject, inputBuffer, inputBufferSize,
 3383         outputBuffer, outputBufferSize, FALSE, &event, &ioStatusBlock);
 3384 
 3385     if (!irp)
 3386         return STATUS_INSUFFICIENT_RESOURCES;
 3387 
 3388     ObReferenceObject (deviceObject);
 3389 
 3390     status = IoCallDriver (deviceObject, irp);
 3391     if (status == STATUS_PENDING)
 3392     {
 3393         KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
 3394         status = ioStatusBlock.Status;
 3395     }
 3396 
 3397     ObDereferenceObject (deviceObject);
 3398     return status;
 3399 }
 3400 
 3401 
 3402 NTSTATUS ProbeRealDriveSize (PDEVICE_OBJECT driveDeviceObject, LARGE_INTEGER *driveSize)
 3403 {
 3404     NTSTATUS status;
 3405     LARGE_INTEGER sysLength;
 3406     LARGE_INTEGER offset;
 3407     byte *sectorBuffer;
 3408     ULONGLONG startTime;
 3409 
 3410     if (!UserCanAccessDriveDevice())
 3411         return STATUS_ACCESS_DENIED;
 3412 
 3413     sectorBuffer = TCalloc (TC_SECTOR_SIZE_BIOS);
 3414     if (!sectorBuffer)
 3415         return STATUS_INSUFFICIENT_RESOURCES;
 3416 
 3417     status = SendDeviceIoControlRequest (driveDeviceObject, IOCTL_DISK_GET_LENGTH_INFO,
 3418         NULL, 0, &sysLength, sizeof (sysLength));
 3419 
 3420     if (!NT_SUCCESS (status))
 3421     {
 3422         Dump ("Failed to get drive size - error %x\n", status);
 3423         TCfree (sectorBuffer);
 3424         return status;
 3425     }
 3426 
 3427     startTime = KeQueryInterruptTime ();
 3428     for (offset.QuadPart = sysLength.QuadPart; ; offset.QuadPart += TC_SECTOR_SIZE_BIOS)
 3429     {
 3430         status = TCReadDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS);
 3431 
 3432         if (NT_SUCCESS (status))
 3433             status = TCWriteDevice (driveDeviceObject, sectorBuffer, offset, TC_SECTOR_SIZE_BIOS);
 3434 
 3435         if (!NT_SUCCESS (status))
 3436         {
 3437             driveSize->QuadPart = offset.QuadPart;
 3438             Dump ("Real drive size = %I64d bytes (%I64d hidden)\n", driveSize->QuadPart, driveSize->QuadPart - sysLength.QuadPart);
 3439             TCfree (sectorBuffer);
 3440             return STATUS_SUCCESS;
 3441         }
 3442 
 3443         if (KeQueryInterruptTime() - startTime > 3ULL * 60 * 1000 * 1000 * 10)
 3444         {
 3445             // Abort if probing for more than 3 minutes
 3446             driveSize->QuadPart = sysLength.QuadPart;
 3447             TCfree (sectorBuffer);
 3448             return STATUS_TIMEOUT;
 3449         }
 3450     }
 3451 }
 3452 
 3453 
 3454 NTSTATUS TCOpenFsVolume (PEXTENSION Extension, PHANDLE volumeHandle, PFILE_OBJECT * fileObject)
 3455 {
 3456     NTSTATUS ntStatus;
 3457     OBJECT_ATTRIBUTES objectAttributes;
 3458     UNICODE_STRING fullFileName;
 3459     IO_STATUS_BLOCK ioStatus;
 3460     WCHAR volumeName[TC_MAX_PATH];
 3461 
 3462     TCGetNTNameFromNumber (volumeName, sizeof(volumeName),Extension->nDosDriveNo);
 3463     RtlInitUnicodeString (&fullFileName, volumeName);
 3464     InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
 3465 
 3466     ntStatus = ZwCreateFile (volumeHandle,
 3467         SYNCHRONIZE | GENERIC_READ,
 3468         &objectAttributes,
 3469         &ioStatus,
 3470         NULL,
 3471         FILE_ATTRIBUTE_NORMAL,
 3472         FILE_SHARE_READ | FILE_SHARE_WRITE,
 3473         FILE_OPEN,
 3474         FILE_SYNCHRONOUS_IO_NONALERT,
 3475         NULL,
 3476         0);
 3477 
 3478     Dump ("Volume %ls open NTSTATUS 0x%08x\n", volumeName, ntStatus);
 3479 
 3480     if (!NT_SUCCESS (ntStatus))
 3481         return ntStatus;
 3482 
 3483     ntStatus = ObReferenceObjectByHandle (*volumeHandle,
 3484         FILE_READ_DATA,
 3485         NULL,
 3486         KernelMode,
 3487         fileObject,
 3488         NULL);
 3489 
 3490     if (!NT_SUCCESS (ntStatus))
 3491         ZwClose (*volumeHandle);
 3492 
 3493     return ntStatus;
 3494 }
 3495 
 3496 
 3497 void TCCloseFsVolume (HANDLE volumeHandle, PFILE_OBJECT fileObject)
 3498 {
 3499     ObDereferenceObject (fileObject);
 3500     ZwClose (volumeHandle);
 3501 }
 3502 
 3503 
 3504 static NTSTATUS TCReadWriteDevice (BOOL write, PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
 3505 {
 3506     NTSTATUS status;
 3507     IO_STATUS_BLOCK ioStatusBlock;
 3508     PIRP irp;
 3509     KEVENT completionEvent;
 3510 
 3511     ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
 3512 
 3513     KeInitializeEvent (&completionEvent, NotificationEvent, FALSE);
 3514     irp = IoBuildSynchronousFsdRequest (write ? IRP_MJ_WRITE : IRP_MJ_READ, deviceObject, buffer, length, &offset, &completionEvent, &ioStatusBlock);
 3515     if (!irp)
 3516         return STATUS_INSUFFICIENT_RESOURCES;
 3517 
 3518     ObReferenceObject (deviceObject);
 3519     status = IoCallDriver (deviceObject, irp);
 3520 
 3521     if (status == STATUS_PENDING)
 3522     {
 3523         status = KeWaitForSingleObject (&completionEvent, Executive, KernelMode, FALSE, NULL);
 3524         if (NT_SUCCESS (status))
 3525             status = ioStatusBlock.Status;
 3526     }
 3527 
 3528     ObDereferenceObject (deviceObject);
 3529     return status;
 3530 }
 3531 
 3532 
 3533 NTSTATUS TCReadDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
 3534 {
 3535     return TCReadWriteDevice (FALSE, deviceObject, buffer, offset, length);
 3536 }
 3537 
 3538 
 3539 NTSTATUS TCWriteDevice (PDEVICE_OBJECT deviceObject, PVOID buffer, LARGE_INTEGER offset, ULONG length)
 3540 {
 3541     return TCReadWriteDevice (TRUE, deviceObject, buffer, offset, length);
 3542 }
 3543 
 3544 
 3545 NTSTATUS TCFsctlCall (PFILE_OBJECT fileObject, LONG IoControlCode,
 3546     void *InputBuffer, int InputBufferSize, void *OutputBuffer, int OutputBufferSize)
 3547 {
 3548     IO_STATUS_BLOCK ioStatusBlock;
 3549     NTSTATUS ntStatus;
 3550     PIRP irp;
 3551     KEVENT event;
 3552     PIO_STACK_LOCATION stack;
 3553     PDEVICE_OBJECT deviceObject = IoGetRelatedDeviceObject (fileObject);
 3554 
 3555     KeInitializeEvent(&event, NotificationEvent, FALSE);
 3556 
 3557     irp = IoBuildDeviceIoControlRequest (IoControlCode,
 3558                          deviceObject,
 3559                          InputBuffer, InputBufferSize,
 3560                          OutputBuffer, OutputBufferSize,
 3561                          FALSE,
 3562                          &event,
 3563                          &ioStatusBlock);
 3564 
 3565     if (irp == NULL)
 3566         return STATUS_INSUFFICIENT_RESOURCES;
 3567 
 3568     stack = IoGetNextIrpStackLocation(irp);
 3569 
 3570     stack->MajorFunction = IRP_MJ_FILE_SYSTEM_CONTROL;
 3571     stack->MinorFunction = IRP_MN_USER_FS_REQUEST;
 3572     stack->FileObject = fileObject;
 3573 
 3574     ntStatus = IoCallDriver (deviceObject, irp);
 3575     if (ntStatus == STATUS_PENDING)
 3576     {
 3577         KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
 3578         ntStatus = ioStatusBlock.Status;
 3579     }
 3580 
 3581     return ntStatus;
 3582 }
 3583 
 3584 
 3585 NTSTATUS CreateDriveLink (int nDosDriveNo)
 3586 {
 3587     WCHAR dev[128], link[128];
 3588     UNICODE_STRING deviceName, symLink;
 3589     NTSTATUS ntStatus;
 3590 
 3591     TCGetNTNameFromNumber (dev, sizeof(dev),nDosDriveNo);
 3592     TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
 3593 
 3594     RtlInitUnicodeString (&deviceName, dev);
 3595     RtlInitUnicodeString (&symLink, link);
 3596 
 3597     ntStatus = IoCreateSymbolicLink (&symLink, &deviceName);
 3598     Dump ("IoCreateSymbolicLink returned %X\n", ntStatus);
 3599     return ntStatus;
 3600 }
 3601 
 3602 
 3603 NTSTATUS RemoveDriveLink (int nDosDriveNo)
 3604 {
 3605     WCHAR link[256];
 3606     UNICODE_STRING symLink;
 3607     NTSTATUS ntStatus;
 3608 
 3609     TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, DeviceNamespaceDefault);
 3610     RtlInitUnicodeString (&symLink, link);
 3611 
 3612     ntStatus = IoDeleteSymbolicLink (&symLink);
 3613     Dump ("IoDeleteSymbolicLink returned %X\n", ntStatus);
 3614     return ntStatus;
 3615 }
 3616 
 3617 
 3618 NTSTATUS MountManagerMount (MOUNT_STRUCT *mount)
 3619 {
 3620     NTSTATUS ntStatus;
 3621     WCHAR arrVolume[256];
 3622     char buf[200];
 3623     PMOUNTMGR_TARGET_NAME in = (PMOUNTMGR_TARGET_NAME) buf;
 3624     PMOUNTMGR_CREATE_POINT_INPUT point = (PMOUNTMGR_CREATE_POINT_INPUT) buf;
 3625 
 3626     TCGetNTNameFromNumber (arrVolume, sizeof(arrVolume),mount->nDosDriveNo);
 3627     in->DeviceNameLength = (USHORT) wcslen (arrVolume) * 2;
 3628     RtlStringCbCopyW(in->DeviceName, sizeof(buf) - sizeof(in->DeviceNameLength),arrVolume);
 3629 
 3630     ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
 3631         in, (ULONG) (sizeof (in->DeviceNameLength) + wcslen (arrVolume) * 2), 0, 0);
 3632 
 3633     memset (buf, 0, sizeof buf);
 3634     TCGetDosNameFromNumber ((PWSTR) &point[1], sizeof(buf) - sizeof(MOUNTMGR_CREATE_POINT_INPUT),mount->nDosDriveNo, DeviceNamespaceDefault);
 3635 
 3636     point->SymbolicLinkNameOffset = sizeof (MOUNTMGR_CREATE_POINT_INPUT);
 3637     point->SymbolicLinkNameLength = (USHORT) wcslen ((PWSTR) &point[1]) * 2;
 3638 
 3639     point->DeviceNameOffset = point->SymbolicLinkNameOffset + point->SymbolicLinkNameLength;
 3640     TCGetNTNameFromNumber ((PWSTR) (buf + point->DeviceNameOffset), sizeof(buf) - point->DeviceNameOffset,mount->nDosDriveNo);
 3641     point->DeviceNameLength = (USHORT) wcslen ((PWSTR) (buf + point->DeviceNameOffset)) * 2;
 3642 
 3643     ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_CREATE_POINT, point,
 3644             point->DeviceNameOffset + point->DeviceNameLength, 0, 0);
 3645 
 3646     return ntStatus;
 3647 }
 3648 
 3649 
 3650 NTSTATUS MountManagerUnmount (int nDosDriveNo)
 3651 {
 3652     NTSTATUS ntStatus;
 3653     char buf[256], out[300];
 3654     PMOUNTMGR_MOUNT_POINT in = (PMOUNTMGR_MOUNT_POINT) buf;
 3655 
 3656     memset (buf, 0, sizeof buf);
 3657 
 3658     TCGetDosNameFromNumber ((PWSTR) &in[1], sizeof(buf) - sizeof(MOUNTMGR_MOUNT_POINT),nDosDriveNo, DeviceNamespaceDefault);
 3659 
 3660     // Only symbolic link can be deleted with IOCTL_MOUNTMGR_DELETE_POINTS. If any other entry is specified, the mount manager will ignore subsequent IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for the same volume ID.
 3661     in->SymbolicLinkNameOffset = sizeof (MOUNTMGR_MOUNT_POINT);
 3662     in->SymbolicLinkNameLength = (USHORT) wcslen ((PWCHAR) &in[1]) * 2;
 3663 
 3664     ntStatus = TCDeviceIoControl (MOUNTMGR_DEVICE_NAME, IOCTL_MOUNTMGR_DELETE_POINTS,
 3665         in, sizeof(MOUNTMGR_MOUNT_POINT) + in->SymbolicLinkNameLength, out, sizeof out);
 3666 
 3667     Dump ("IOCTL_MOUNTMGR_DELETE_POINTS returned 0x%08x\n", ntStatus);
 3668 
 3669     return ntStatus;
 3670 }
 3671 
 3672 
 3673 NTSTATUS MountDevice (PDEVICE_OBJECT DeviceObject, MOUNT_STRUCT *mount)
 3674 {
 3675     PDEVICE_OBJECT NewDeviceObject;
 3676     NTSTATUS ntStatus;
 3677 
 3678     // Make sure the user is asking for a reasonable nDosDriveNo
 3679     if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25
 3680         && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault) // drive letter must not exist both locally and globally
 3681         && IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal)
 3682         )
 3683     {
 3684         Dump ("Mount request looks valid\n");
 3685     }
 3686     else
 3687     {
 3688         Dump ("WARNING: MOUNT DRIVE LETTER INVALID\n");
 3689         mount->nReturnCode = ERR_DRIVE_NOT_FOUND;
 3690         return ERR_DRIVE_NOT_FOUND;
 3691     }
 3692 
 3693     if (!SelfTestsPassed)
 3694     {
 3695         Dump ("Failure of built-in automatic self-tests! Mounting not allowed.\n");
 3696         mount->nReturnCode = ERR_SELF_TESTS_FAILED;
 3697         return ERR_SELF_TESTS_FAILED;
 3698     }
 3699 
 3700     ntStatus = TCCreateDeviceObject (DeviceObject->DriverObject, &NewDeviceObject, mount);
 3701 
 3702     if (!NT_SUCCESS (ntStatus))
 3703     {
 3704         Dump ("Mount CREATE DEVICE ERROR, ntStatus = 0x%08x\n", ntStatus);
 3705         return ntStatus;
 3706     }
 3707     else
 3708     {
 3709         PEXTENSION NewExtension = (PEXTENSION) NewDeviceObject->DeviceExtension;
 3710         SECURITY_SUBJECT_CONTEXT subContext;
 3711         PACCESS_TOKEN accessToken;
 3712 
 3713         SeCaptureSubjectContext (&subContext);
 3714         SeLockSubjectContext(&subContext);
 3715         if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation)
 3716             accessToken = subContext.ClientToken;
 3717         else
 3718             accessToken = subContext.PrimaryToken;
 3719 
 3720         if (!accessToken)
 3721         {
 3722             ntStatus = STATUS_INVALID_PARAMETER;
 3723         }
 3724         else
 3725         {
 3726             PTOKEN_USER tokenUser;
 3727 
 3728             ntStatus = SeQueryInformationToken (accessToken, TokenUser, &tokenUser);
 3729             if (NT_SUCCESS (ntStatus))
 3730             {
 3731                 ULONG sidLength = RtlLengthSid (tokenUser->User.Sid);
 3732 
 3733                 NewExtension->UserSid = TCalloc (sidLength);
 3734                 if (!NewExtension->UserSid)
 3735                     ntStatus = STATUS_INSUFFICIENT_RESOURCES;
 3736                 else
 3737                     ntStatus = RtlCopySid (sidLength, NewExtension->UserSid, tokenUser->User.Sid);
 3738 
 3739                 ExFreePool (tokenUser);     // Documented in newer versions of WDK
 3740             }
 3741         }
 3742 
 3743         SeUnlockSubjectContext(&subContext);
 3744         SeReleaseSubjectContext (&subContext);
 3745 
 3746         if (NT_SUCCESS (ntStatus))
 3747             ntStatus = TCStartVolumeThread (NewDeviceObject, NewExtension, mount);
 3748 
 3749         if (!NT_SUCCESS (ntStatus))
 3750         {
 3751             Dump ("Mount FAILURE NT ERROR, ntStatus = 0x%08x\n", ntStatus);
 3752             TCDeleteDeviceObject (NewDeviceObject, NewExtension);
 3753             return ntStatus;
 3754         }
 3755         else
 3756         {
 3757             if (mount->nReturnCode == 0)
 3758             {
 3759                 HANDLE volumeHandle;
 3760                 PFILE_OBJECT volumeFileObject;
 3761                 ULONG labelLen = (ULONG) wcslen (mount->wszLabel);
 3762                 BOOL bIsNTFS = FALSE;
 3763                 ULONG labelMaxLen, labelEffectiveLen;
 3764 
 3765                 Dump ("Mount SUCCESS TC code = 0x%08x READ-ONLY = %d\n", mount->nReturnCode, NewExtension->bReadOnly);
 3766 
 3767                 if (NewExtension->bReadOnly)
 3768                     NewDeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
 3769 
 3770                 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
 3771 
 3772                 NewExtension->UniqueVolumeId = LastUniqueVolumeId++;
 3773 
 3774                 // check again that the drive letter is available globally and locally
 3775                 if (    !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceDefault)
 3776                     || !IsDriveLetterAvailable (mount->nDosDriveNo, DeviceNamespaceGlobal)
 3777                     )
 3778                 {
 3779                         TCDeleteDeviceObject (NewDeviceObject, NewExtension);
 3780                         mount->nReturnCode = ERR_DRIVE_NOT_FOUND;
 3781                         return ERR_DRIVE_NOT_FOUND;
 3782                 }
 3783 
 3784                 if (mount->bMountManager)
 3785                     MountManagerMount (mount);
 3786 
 3787                 NewExtension->bMountManager = mount->bMountManager;
 3788 
 3789                 // We create symbolic link even if mount manager is notified of
 3790                 // arriving volume as it apparently sometimes fails to create the link
 3791                 CreateDriveLink (mount->nDosDriveNo);
 3792 
 3793                 mount->FilesystemDirty = FALSE;
 3794 
 3795                 if (NT_SUCCESS (TCOpenFsVolume (NewExtension, &volumeHandle, &volumeFileObject)))
 3796                 {
 3797                     __try
 3798                     {
 3799                         ULONG fsStatus;
 3800 
 3801                         if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_IS_VOLUME_DIRTY, NULL, 0, &fsStatus, sizeof (fsStatus)))
 3802                             && (fsStatus & VOLUME_IS_DIRTY))
 3803                         {
 3804                             mount->FilesystemDirty = TRUE;
 3805                         }
 3806                     }
 3807                     __except (EXCEPTION_EXECUTE_HANDLER)
 3808                     {
 3809                         mount->FilesystemDirty = TRUE;
 3810                     }
 3811 
 3812                     // detect if the filesystem is NTFS or FAT
 3813                     __try
 3814                     {
 3815                         NTFS_VOLUME_DATA_BUFFER ntfsData;
 3816                         if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData))))
 3817                         {
 3818                             bIsNTFS = TRUE;
 3819                         }
 3820                     }
 3821                     __except (EXCEPTION_EXECUTE_HANDLER)
 3822                     {
 3823                         bIsNTFS = FALSE;
 3824                     }
 3825 
 3826                     NewExtension->bIsNTFS = bIsNTFS;
 3827                     mount->bIsNTFS = bIsNTFS;
 3828 
 3829                     if (labelLen > 0)
 3830                     {
 3831                         if (bIsNTFS)
 3832                             labelMaxLen = 32; // NTFS maximum label length
 3833                         else
 3834                             labelMaxLen = 11; // FAT maximum label length
 3835 
 3836                         // calculate label effective length
 3837                         labelEffectiveLen = labelLen > labelMaxLen? labelMaxLen : labelLen;
 3838 
 3839                         // correct the label in the device
 3840                         memset (&NewExtension->wszLabel[labelEffectiveLen], 0, 33 - labelEffectiveLen);
 3841                         memcpy (mount->wszLabel, NewExtension->wszLabel, 33);
 3842 
 3843                         // set the volume label
 3844                         __try
 3845                         {
 3846                             IO_STATUS_BLOCK ioblock;
 3847                             ULONG labelInfoSize = sizeof(FILE_FS_LABEL_INFORMATION) + (labelEffectiveLen * sizeof(WCHAR));
 3848                             FILE_FS_LABEL_INFORMATION* labelInfo = (FILE_FS_LABEL_INFORMATION*) TCalloc (labelInfoSize);
 3849                             if (labelInfo)
 3850                             {
 3851                                 labelInfo->VolumeLabelLength = labelEffectiveLen * sizeof(WCHAR);
 3852                                 memcpy (labelInfo->VolumeLabel, mount->wszLabel, labelInfo->VolumeLabelLength);
 3853 
 3854                                 if (STATUS_SUCCESS == ZwSetVolumeInformationFile (volumeHandle, &ioblock, labelInfo, labelInfoSize, FileFsLabelInformation))
 3855                                 {
 3856                                     mount->bDriverSetLabel = TRUE;
 3857                                     NewExtension->bDriverSetLabel = TRUE;
 3858                                 }
 3859 
 3860                                 TCfree(labelInfo);
 3861                             }
 3862                         }
 3863                         __except (EXCEPTION_EXECUTE_HANDLER)
 3864                         {
 3865 
 3866                         }
 3867                     }
 3868 
 3869                     TCCloseFsVolume (volumeHandle, volumeFileObject);
 3870                 }
 3871             }
 3872             else
 3873             {
 3874                 Dump ("Mount FAILURE TC code = 0x%08x\n", mount->nReturnCode);
 3875                 TCDeleteDeviceObject (NewDeviceObject, NewExtension);
 3876             }
 3877 
 3878             return STATUS_SUCCESS;
 3879         }
 3880     }
 3881 }
 3882 
 3883 NTSTATUS UnmountDevice (UNMOUNT_STRUCT *unmountRequest, PDEVICE_OBJECT deviceObject, BOOL ignoreOpenFiles)
 3884 {
 3885     PEXTENSION extension = deviceObject->DeviceExtension;
 3886     NTSTATUS ntStatus;
 3887     HANDLE volumeHandle;
 3888     PFILE_OBJECT volumeFileObject;
 3889 
 3890     Dump ("UnmountDevice %d\n", extension->nDosDriveNo);
 3891 
 3892     ntStatus = TCOpenFsVolume (extension, &volumeHandle, &volumeFileObject);
 3893 
 3894     if (NT_SUCCESS (ntStatus))
 3895     {
 3896         int dismountRetry;
 3897 
 3898         // Dismounting a writable NTFS filesystem prevents the driver from being unloaded on Windows 7
 3899         if (IsOSAtLeast (WIN_7) && !extension->bReadOnly)
 3900         {
 3901             NTFS_VOLUME_DATA_BUFFER ntfsData;
 3902 
 3903             if (NT_SUCCESS (TCFsctlCall (volumeFileObject, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &ntfsData, sizeof (ntfsData))))
 3904                 DriverUnloadDisabled = TRUE;
 3905         }
 3906 
 3907         // Lock volume
 3908         ntStatus = TCFsctlCall (volumeFileObject, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);
 3909         Dump ("FSCTL_LOCK_VOLUME returned %X\n", ntStatus);
 3910 
 3911         if (!NT_SUCCESS (ntStatus) && !ignoreOpenFiles)
 3912         {
 3913             TCCloseFsVolume (volumeHandle, volumeFileObject);
 3914             return ERR_FILES_OPEN;
 3915         }
 3916 
 3917         // Dismount volume
 3918         for (dismountRetry = 0; dismountRetry < 200; ++dismountRetry)
 3919         {
 3920             ntStatus = TCFsctlCall (volumeFileObject, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0);
 3921             Dump ("FSCTL_DISMOUNT_VOLUME returned %X\n", ntStatus);
 3922 
 3923             if (NT_SUCCESS (ntStatus) || ntStatus == STATUS_VOLUME_DISMOUNTED)
 3924                 break;
 3925 
 3926             if (!ignoreOpenFiles)
 3927             {
 3928                 TCCloseFsVolume (volumeHandle, volumeFileObject);
 3929                 return ERR_FILES_OPEN;
 3930             }
 3931 
 3932             TCSleep (100);
 3933         }
 3934     }
 3935     else
 3936     {
 3937         // Volume cannot be opened => force dismount if allowed
 3938         if (!ignoreOpenFiles)
 3939             return ERR_FILES_OPEN;
 3940         else
 3941             volumeHandle = NULL;
 3942     }
 3943 
 3944     if (extension->bMountManager)
 3945         MountManagerUnmount (extension->nDosDriveNo);
 3946 
 3947     // We always remove symbolic link as mount manager might fail to do so
 3948     RemoveDriveLink (extension->nDosDriveNo);
 3949 
 3950     extension->bShuttingDown = TRUE;
 3951 
 3952     ntStatus = IoAcquireRemoveLock (&extension->Queue.RemoveLock, NULL);
 3953     ASSERT (NT_SUCCESS (ntStatus));
 3954     IoReleaseRemoveLockAndWait (&extension->Queue.RemoveLock, NULL);
 3955 
 3956     if (volumeHandle != NULL)
 3957         TCCloseFsVolume (volumeHandle, volumeFileObject);
 3958 
 3959     if (unmountRequest)
 3960     {
 3961         PCRYPTO_INFO cryptoInfo = ((PEXTENSION) deviceObject->DeviceExtension)->cryptoInfo;
 3962         unmountRequest->HiddenVolumeProtectionTriggered = (cryptoInfo->bProtectHiddenVolume && cryptoInfo->bHiddenVolProtectionAction);
 3963     }
 3964 
 3965     TCDeleteDeviceObject (deviceObject, (PEXTENSION) deviceObject->DeviceExtension);
 3966     return 0;
 3967 }
 3968 
 3969 
 3970 static PDEVICE_OBJECT FindVolumeWithHighestUniqueId (int maxUniqueId)
 3971 {
 3972     PDEVICE_OBJECT highestIdDevice = NULL;
 3973     int highestId = -1;
 3974     int drive;
 3975 
 3976     for (drive = MIN_MOUNTED_VOLUME_DRIVE_NUMBER; drive <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; ++drive)
 3977     {
 3978         PDEVICE_OBJECT device = GetVirtualVolumeDeviceObject (drive);
 3979         if (device)
 3980         {
 3981             PEXTENSION extension = (PEXTENSION) device->DeviceExtension;
 3982             if (extension->UniqueVolumeId > highestId && extension->UniqueVolumeId <= maxUniqueId)
 3983             {
 3984                 highestId = extension->UniqueVolumeId;
 3985                 highestIdDevice = device;
 3986             }
 3987         }
 3988     }
 3989 
 3990     return highestIdDevice;
 3991 }
 3992 
 3993 
 3994 NTSTATUS UnmountAllDevices (UNMOUNT_STRUCT *unmountRequest, BOOL ignoreOpenFiles)
 3995 {
 3996     NTSTATUS status = 0;
 3997     PDEVICE_OBJECT ListDevice;
 3998     int maxUniqueId = LastUniqueVolumeId;
 3999 
 4000     Dump ("Unmounting all volumes\n");
 4001 
 4002     if (unmountRequest)
 4003         unmountRequest->HiddenVolumeProtectionTriggered = FALSE;
 4004 
 4005     // Dismount volumes in the reverse order they were mounted to properly dismount nested volumes
 4006     while ((ListDevice = FindVolumeWithHighestUniqueId (maxUniqueId)) != NULL)
 4007     {
 4008         PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension;
 4009         maxUniqueId = ListExtension->UniqueVolumeId - 1;
 4010 
 4011         if (IsVolumeAccessibleByCurrentUser (ListExtension))
 4012         {
 4013             NTSTATUS ntStatus;
 4014 
 4015             if (unmountRequest)
 4016                 unmountRequest->nDosDriveNo = ListExtension->nDosDriveNo;
 4017 
 4018             ntStatus = UnmountDevice (unmountRequest, ListDevice, ignoreOpenFiles);
 4019             status = ntStatus == 0 ? status : ntStatus;
 4020 
 4021             if (unmountRequest && unmountRequest->HiddenVolumeProtectionTriggered)
 4022                 break;
 4023         }
 4024     }
 4025 
 4026     return status;
 4027 }
 4028 
 4029 // Resolves symbolic link name to its target name
 4030 NTSTATUS SymbolicLinkToTarget (PWSTR symlinkName, PWSTR targetName, USHORT maxTargetNameLength)
 4031 {
 4032     NTSTATUS ntStatus;
 4033     OBJECT_ATTRIBUTES objectAttributes;
 4034     UNICODE_STRING fullFileName;
 4035     HANDLE handle;
 4036 
 4037     RtlInitUnicodeString (&fullFileName, symlinkName);
 4038     InitializeObjectAttributes (&objectAttributes, &fullFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
 4039 
 4040     ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes);
 4041 
 4042     if (NT_SUCCESS (ntStatus))
 4043     {
 4044         UNICODE_STRING target;
 4045         target.Buffer = targetName;
 4046         target.Length = 0;
 4047         target.MaximumLength = maxTargetNameLength;
 4048         memset (targetName, 0, maxTargetNameLength);
 4049 
 4050         ntStatus = ZwQuerySymbolicLinkObject (handle, &target, NULL);
 4051 
 4052         ZwClose (handle);
 4053     }
 4054 
 4055     return ntStatus;
 4056 }
 4057 
 4058 
 4059 // Checks if two regions overlap (borders are parts of regions)
 4060 BOOL RegionsOverlap (unsigned __int64 start1, unsigned __int64 end1, unsigned __int64 start2, unsigned __int64 end2)
 4061 {
 4062     return (start1 < start2) ? (end1 >= start2) : (start1 <= end2);
 4063 }
 4064 
 4065 
 4066 void GetIntersection (uint64 start1, uint32 length1, uint64 start2, uint64 end2, uint64 *intersectStart, uint32 *intersectLength)
 4067 {
 4068     uint64 end1 = start1 + length1 - 1;
 4069     uint64 intersectEnd = (end1 <= end2) ? end1 : end2;
 4070 
 4071     *intersectStart = (start1 >= start2) ? start1 : start2;
 4072     *intersectLength = (uint32) ((*intersectStart > intersectEnd) ? 0 : intersectEnd + 1 - *intersectStart);
 4073 
 4074     if (*intersectLength == 0)
 4075         *intersectStart = start1;
 4076 }
 4077 
 4078 
 4079 BOOL IsAccessibleByUser (PUNICODE_STRING objectFileName, BOOL readOnly)
 4080 {
 4081     OBJECT_ATTRIBUTES fileObjAttributes;
 4082     IO_STATUS_BLOCK ioStatusBlock;
 4083     HANDLE fileHandle;
 4084     NTSTATUS status;
 4085 
 4086     ASSERT (!IoIsSystemThread (PsGetCurrentThread()));
 4087 
 4088     InitializeObjectAttributes (&fileObjAttributes, objectFileName, OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE, NULL, NULL);
 4089 
 4090     status = ZwCreateFile (&fileHandle,
 4091         readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
 4092         &fileObjAttributes,
 4093         &ioStatusBlock,
 4094         NULL,
 4095         FILE_ATTRIBUTE_NORMAL,
 4096         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 4097         FILE_OPEN,
 4098         FILE_SYNCHRONOUS_IO_NONALERT,
 4099         NULL,
 4100         0);
 4101 
 4102     if (NT_SUCCESS (status))
 4103     {
 4104         ZwClose (fileHandle);
 4105         return TRUE;
 4106     }
 4107 
 4108     return FALSE;
 4109 }
 4110 
 4111 
 4112 BOOL UserCanAccessDriveDevice ()
 4113 {
 4114     UNICODE_STRING name;
 4115     RtlInitUnicodeString (&name, L"\\Device\\MountPointManager");
 4116 
 4117     return IsAccessibleByUser (&name, FALSE);
 4118 }
 4119 
 4120 BOOL IsDriveLetterAvailable (int nDosDriveNo, DeviceNamespaceType namespaceType)
 4121 {
 4122     OBJECT_ATTRIBUTES objectAttributes;
 4123     UNICODE_STRING objectName;
 4124     WCHAR link[128];
 4125     HANDLE handle;
 4126     NTSTATUS ntStatus;
 4127 
 4128     TCGetDosNameFromNumber (link, sizeof(link),nDosDriveNo, namespaceType);
 4129     RtlInitUnicodeString (&objectName, link);
 4130     InitializeObjectAttributes (&objectAttributes, &objectName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
 4131 
 4132     if (NT_SUCCESS (ntStatus = ZwOpenSymbolicLinkObject (&handle, GENERIC_READ, &objectAttributes)))
 4133     {
 4134         ZwClose (handle);
 4135         return FALSE;
 4136     }
 4137 
 4138     return (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND)? TRUE : FALSE;
 4139 }
 4140 
 4141 
 4142 NTSTATUS TCCompleteIrp (PIRP irp, NTSTATUS status, ULONG_PTR information)
 4143 {
 4144     irp->IoStatus.Status = status;
 4145     irp->IoStatus.Information = information;
 4146     IoCompleteRequest (irp, IO_NO_INCREMENT);
 4147     return status;
 4148 }
 4149 
 4150 
 4151 NTSTATUS TCCompleteDiskIrp (PIRP irp, NTSTATUS status, ULONG_PTR information)
 4152 {
 4153     irp->IoStatus.Status = status;
 4154     irp->IoStatus.Information = information;
 4155     IoCompleteRequest (irp, NT_SUCCESS (status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
 4156     return status;
 4157 }
 4158 
 4159 
 4160 size_t GetCpuCount ()
 4161 {
 4162     KAFFINITY activeCpuMap = KeQueryActiveProcessors();
 4163     size_t mapSize = sizeof (activeCpuMap) * 8;
 4164     size_t cpuCount = 0;
 4165 
 4166     while (mapSize--)
 4167     {
 4168         if (activeCpuMap & 1)
 4169             ++cpuCount;
 4170 
 4171         activeCpuMap >>= 1;
 4172     }
 4173 
 4174     if (cpuCount == 0)
 4175         return 1;
 4176 
 4177     return cpuCount;
 4178 }
 4179 
 4180 
 4181 void EnsureNullTerminatedString (wchar_t *str, size_t maxSizeInBytes)
 4182 {
 4183     ASSERT ((maxSizeInBytes & 1) == 0);
 4184     str[maxSizeInBytes / sizeof (wchar_t) - 1] = 0;
 4185 }
 4186 
 4187 
 4188 void *AllocateMemoryWithTimeout (size_t size, int retryDelay, int timeout)
 4189 {
 4190     LARGE_INTEGER waitInterval;
 4191     waitInterval.QuadPart = retryDelay * -10000;
 4192 
 4193     ASSERT (KeGetCurrentIrql() <= APC_LEVEL);
 4194     ASSERT (retryDelay > 0 && retryDelay <= timeout);
 4195 
 4196     while (TRUE)
 4197     {
 4198         void *memory = TCalloc (size);
 4199         if (memory)
 4200             return memory;
 4201 
 4202         timeout -= retryDelay;
 4203         if (timeout <= 0)
 4204             break;
 4205 
 4206         KeDelayExecutionThread (KernelMode, FALSE, &waitInterval);
 4207     }
 4208 
 4209     return NULL;
 4210 }
 4211 
 4212 
 4213 NTSTATUS TCReadRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, PKEY_VALUE_PARTIAL_INFORMATION *keyData)
 4214 {
 4215     OBJECT_ATTRIBUTES regObjAttribs;
 4216     HANDLE regKeyHandle;
 4217     NTSTATUS status;
 4218     UNICODE_STRING valName;
 4219     ULONG size = 0;
 4220     ULONG resultSize;
 4221 
 4222     InitializeObjectAttributes (&regObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
 4223     status = ZwOpenKey (&regKeyHandle, KEY_READ, &regObjAttribs);
 4224     if (!NT_SUCCESS (status))
 4225         return status;
 4226 
 4227     RtlInitUnicodeString (&valName, keyValueName);
 4228     status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, NULL, 0, &size);
 4229 
 4230     if (!NT_SUCCESS (status) && status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
 4231     {
 4232         ZwClose (regKeyHandle);
 4233         return status;
 4234     }
 4235 
 4236     if (size == 0)
 4237     {
 4238         ZwClose (regKeyHandle);
 4239         return STATUS_NO_DATA_DETECTED;
 4240     }
 4241 
 4242     *keyData = (PKEY_VALUE_PARTIAL_INFORMATION) TCalloc (size);
 4243     if (!*keyData)
 4244     {
 4245         ZwClose (regKeyHandle);
 4246         return STATUS_INSUFFICIENT_RESOURCES;
 4247     }
 4248 
 4249     status = ZwQueryValueKey (regKeyHandle, &valName, KeyValuePartialInformation, *keyData, size, &resultSize);
 4250 
 4251     ZwClose (regKeyHandle);
 4252     return status;
 4253 }
 4254 
 4255 
 4256 NTSTATUS TCWriteRegistryKey (PUNICODE_STRING keyPath, wchar_t *keyValueName, ULONG keyValueType, void *valueData, ULONG valueSize)
 4257 {
 4258     OBJECT_ATTRIBUTES regObjAttribs;
 4259     HANDLE regKeyHandle;
 4260     NTSTATUS status;
 4261     UNICODE_STRING valName;
 4262 
 4263     InitializeObjectAttributes (&regObjAttribs, keyPath, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
 4264     status = ZwOpenKey (&regKeyHandle, KEY_READ | KEY_WRITE, &regObjAttribs);
 4265     if (!NT_SUCCESS (status))
 4266         return status;
 4267 
 4268     RtlInitUnicodeString (&valName, keyValueName);
 4269 
 4270     status = ZwSetValueKey (regKeyHandle, &valName, 0, keyValueType, valueData, valueSize);
 4271 
 4272     ZwClose (regKeyHandle);
 4273     return status;
 4274 }
 4275 
 4276 
 4277 BOOL IsVolumeClassFilterRegistered ()
 4278 {
 4279     UNICODE_STRING name;
 4280     NTSTATUS status;
 4281     BOOL registered = FALSE;
 4282 
 4283     PKEY_VALUE_PARTIAL_INFORMATION data;
 4284 
 4285     RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class\\{71A27CDD-812A-11D0-BEC7-08002BE2092F}");
 4286     status = TCReadRegistryKey (&name, L"UpperFilters", &data);
 4287 
 4288     if (NT_SUCCESS (status))
 4289     {
 4290         if (data->Type == REG_MULTI_SZ && data->DataLength >= 9 * sizeof (wchar_t))
 4291         {
 4292             // Search for the string "veracrypt"
 4293             ULONG i;
 4294             for (i = 0; i <= data->DataLength - 9 * sizeof (wchar_t); ++i)
 4295             {
 4296                 if (memcmp (data->Data + i, L"veracrypt", 9 * sizeof (wchar_t)) == 0)
 4297                 {
 4298                     Dump ("Volume class filter active\n");
 4299                     registered = TRUE;
 4300                     break;
 4301                 }
 4302             }
 4303         }
 4304 
 4305         TCfree (data);
 4306     }
 4307 
 4308     return registered;
 4309 }
 4310 
 4311 
 4312 NTSTATUS ReadRegistryConfigFlags (BOOL driverEntry)
 4313 {
 4314     PKEY_VALUE_PARTIAL_INFORMATION data;
 4315     UNICODE_STRING name;
 4316     NTSTATUS status;
 4317     uint32 flags = 0;
 4318 
 4319     RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt");
 4320     status = TCReadRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, &data);
 4321 
 4322     if (NT_SUCCESS (status))
 4323     {
 4324         if (data->Type == REG_DWORD)
 4325         {
 4326             flags = *(uint32 *) data->Data;
 4327             Dump ("Configuration flags = 0x%x\n", flags);
 4328 
 4329             if (driverEntry)
 4330             {
 4331                 if (flags & (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD | TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES))
 4332                     CacheBootPassword = TRUE;
 4333 
 4334                 if (flags & TC_DRIVER_CONFIG_DISABLE_NONADMIN_SYS_FAVORITES_ACCESS)
 4335                     NonAdminSystemFavoritesAccessDisabled = TRUE;
 4336 
 4337                 if (flags & TC_DRIVER_CONFIG_CACHE_BOOT_PIM)
 4338                     CacheBootPim = TRUE;
 4339 
 4340                 if (flags & VC_DRIVER_CONFIG_BLOCK_SYS_TRIM)
 4341                     BlockSystemTrimCommand = TRUE;
 4342             }
 4343 
 4344             EnableHwEncryption ((flags & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? FALSE : TRUE);
 4345 
 4346             EnableExtendedIoctlSupport = (flags & TC_DRIVER_CONFIG_ENABLE_EXTENDED_IOCTL)? TRUE : FALSE;
 4347             AllowTrimCommand = (flags & VC_DRIVER_CONFIG_ALLOW_NONSYS_TRIM)? TRUE : FALSE;
 4348             AllowWindowsDefrag = (flags & VC_DRIVER_CONFIG_ALLOW_WINDOWS_DEFRAG)? TRUE : FALSE;
 4349         }
 4350         else
 4351             status = STATUS_INVALID_PARAMETER;
 4352 
 4353         TCfree (data);
 4354     }
 4355 
 4356     if (driverEntry && NT_SUCCESS (TCReadRegistryKey (&name, TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME, &data)))
 4357     {
 4358         if (data->Type == REG_DWORD)
 4359             EncryptionThreadPoolFreeCpuCountLimit = *(uint32 *) data->Data;
 4360 
 4361         TCfree (data);
 4362     }
 4363 
 4364     return status;
 4365 }
 4366 
 4367 
 4368 NTSTATUS WriteRegistryConfigFlags (uint32 flags)
 4369 {
 4370     UNICODE_STRING name;
 4371     RtlInitUnicodeString (&name, L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\veracrypt");
 4372 
 4373     return TCWriteRegistryKey (&name, TC_DRIVER_CONFIG_REG_VALUE_NAME, REG_DWORD, &flags, sizeof (flags));
 4374 }
 4375 
 4376 
 4377 NTSTATUS GetDeviceSectorSize (PDEVICE_OBJECT deviceObject, ULONG *bytesPerSector)
 4378 {
 4379     NTSTATUS status;
 4380     DISK_GEOMETRY geometry;
 4381 
 4382     status = SendDeviceIoControlRequest (deviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry));
 4383     if (!NT_SUCCESS (status))
 4384         return status;
 4385 
 4386     *bytesPerSector = geometry.BytesPerSector;
 4387     
 4388     return STATUS_SUCCESS;
 4389 }
 4390 
 4391 
 4392 NTSTATUS ZeroUnreadableSectors (PDEVICE_OBJECT deviceObject, LARGE_INTEGER startOffset, ULONG size, uint64 *zeroedSectorCount)
 4393 {
 4394     NTSTATUS status;
 4395     ULONG sectorSize;
 4396     ULONG sectorCount;
 4397     byte *sectorBuffer = NULL;
 4398 
 4399     *zeroedSectorCount = 0;
 4400 
 4401     status = GetDeviceSectorSize (deviceObject, &sectorSize);
 4402     if (!NT_SUCCESS (status))
 4403         return status;
 4404 
 4405     sectorBuffer = TCalloc (sectorSize);
 4406     if (!sectorBuffer)
 4407         return STATUS_INSUFFICIENT_RESOURCES;
 4408 
 4409     for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize)
 4410     {
 4411         status = TCReadDevice (deviceObject, sectorBuffer, startOffset, sectorSize);
 4412         if (!NT_SUCCESS (status))
 4413         {
 4414             Dump ("Zeroing sector at %I64d\n", startOffset.QuadPart);
 4415             memset (sectorBuffer, 0, sectorSize);
 4416 
 4417             status = TCWriteDevice (deviceObject, sectorBuffer, startOffset, sectorSize);
 4418             if (!NT_SUCCESS (status))
 4419                 goto err;
 4420 
 4421             ++(*zeroedSectorCount);
 4422         }
 4423     }
 4424 
 4425     status = STATUS_SUCCESS;
 4426 
 4427 err:
 4428     if (sectorBuffer)
 4429         TCfree (sectorBuffer);
 4430 
 4431     return status;
 4432 }
 4433 
 4434 
 4435 NTSTATUS ReadDeviceSkipUnreadableSectors (PDEVICE_OBJECT deviceObject, byte *buffer, LARGE_INTEGER startOffset, ULONG size, uint64 *badSectorCount)
 4436 {
 4437     NTSTATUS status;
 4438     ULONG sectorSize;
 4439     ULONG sectorCount;
 4440 
 4441     *badSectorCount = 0;
 4442 
 4443     status = GetDeviceSectorSize (deviceObject, &sectorSize);
 4444     if (!NT_SUCCESS (status))
 4445         return status;
 4446 
 4447     for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount, startOffset.QuadPart += sectorSize, buffer += sectorSize)
 4448     {
 4449         status = TCReadDevice (deviceObject, buffer, startOffset, sectorSize);
 4450         if (!NT_SUCCESS (status))
 4451         {
 4452             Dump ("Skipping bad sector at %I64d\n", startOffset.QuadPart);
 4453             memset (buffer, 0, sectorSize);
 4454             ++(*badSectorCount);
 4455         }
 4456     }
 4457 
 4458     return STATUS_SUCCESS;
 4459 }
 4460 
 4461 
 4462 BOOL IsVolumeAccessibleByCurrentUser (PEXTENSION volumeDeviceExtension)
 4463 {
 4464     SECURITY_SUBJECT_CONTEXT subContext;
 4465     PACCESS_TOKEN accessToken;
 4466     PTOKEN_USER tokenUser;
 4467     BOOL result = FALSE;
 4468 
 4469     if (IoIsSystemThread (PsGetCurrentThread())
 4470         || UserCanAccessDriveDevice()
 4471         || !volumeDeviceExtension->UserSid
 4472         || (volumeDeviceExtension->SystemFavorite && !NonAdminSystemFavoritesAccessDisabled))
 4473     {
 4474         return TRUE;
 4475     }
 4476 
 4477     SeCaptureSubjectContext (&subContext);
 4478     SeLockSubjectContext(&subContext);
 4479     if (subContext.ClientToken && subContext.ImpersonationLevel >= SecurityImpersonation)
 4480         accessToken = subContext.ClientToken;
 4481     else
 4482         accessToken = subContext.PrimaryToken;
 4483 
 4484     if (!accessToken)
 4485         goto ret;
 4486 
 4487     if (SeTokenIsAdmin (accessToken))
 4488     {
 4489         result = TRUE;
 4490         goto ret;
 4491     }
 4492 
 4493     if (!NT_SUCCESS (SeQueryInformationToken (accessToken, TokenUser, &tokenUser)))
 4494         goto ret;
 4495 
 4496     result = RtlEqualSid (volumeDeviceExtension->UserSid, tokenUser->User.Sid);
 4497     ExFreePool (tokenUser);     // Documented in newer versions of WDK
 4498 
 4499 ret:
 4500     SeUnlockSubjectContext(&subContext);
 4501     SeReleaseSubjectContext (&subContext);
 4502     return result;
 4503 }
 4504 
 4505 
 4506 void GetElapsedTimeInit (LARGE_INTEGER *lastPerfCounter)
 4507 {
 4508     *lastPerfCounter = KeQueryPerformanceCounter (NULL);
 4509 }
 4510 
 4511 
 4512 // Returns elapsed time in microseconds since last call
 4513 int64 GetElapsedTime (LARGE_INTEGER *lastPerfCounter)
 4514 {
 4515     LARGE_INTEGER freq;
 4516     LARGE_INTEGER counter = KeQueryPerformanceCounter (&freq);
 4517 
 4518     int64 elapsed = (counter.QuadPart - lastPerfCounter->QuadPart) * 1000000LL / freq.QuadPart;
 4519     *lastPerfCounter = counter;
 4520 
 4521     return elapsed;
 4522 }
 4523 
 4524 
 4525 BOOL IsOSAtLeast (OSVersionEnum reqMinOS)
 4526 {
 4527     /* When updating this function, update IsOSVersionAtLeast() in Dlgcode.c too. */
 4528 
 4529     ULONG major = 0, minor = 0;
 4530 
 4531     ASSERT (OsMajorVersion != 0);
 4532 
 4533     switch (reqMinOS)
 4534     {
 4535     case WIN_2000:          major = 5; minor = 0; break;
 4536     case WIN_XP:            major = 5; minor = 1; break;
 4537     case WIN_SERVER_2003:   major = 5; minor = 2; break;
 4538     case WIN_VISTA:         major = 6; minor = 0; break;
 4539     case WIN_7:             major = 6; minor = 1; break;
 4540     case WIN_8:             major = 6; minor = 2; break;
 4541     case WIN_8_1:           major = 6; minor = 3; break;
 4542     case WIN_10:            major = 10; minor = 0; break;
 4543 
 4544     default:
 4545         TC_THROW_FATAL_EXCEPTION;
 4546         break;
 4547     }
 4548 
 4549     return ((OsMajorVersion << 16 | OsMinorVersion << 8)
 4550         >= (major << 16 | minor << 8));
 4551 }
 4552 
 4553 NTSTATUS NTAPI KeSaveExtendedProcessorState (
 4554     __in ULONG64 Mask,
 4555     PXSTATE_SAVE XStateSave
 4556     )
 4557 {
 4558     if (KeSaveExtendedProcessorStatePtr)
 4559     {
 4560         return (KeSaveExtendedProcessorStatePtr) (Mask, XStateSave);
 4561     }
 4562     else
 4563     {
 4564         return STATUS_SUCCESS;
 4565     }
 4566 }
 4567 
 4568 VOID NTAPI KeRestoreExtendedProcessorState (
 4569     PXSTATE_SAVE XStateSave
 4570     )
 4571 {
 4572     if (KeRestoreExtendedProcessorStatePtr)
 4573     {
 4574         (KeRestoreExtendedProcessorStatePtr) (XStateSave);
 4575     }
 4576 }