"Fossies" - the Fresh Open Source Software Archive

Member "src/Driver/Ntvol.c" (10 Oct 2018, 32570 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 "Ntvol.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 <wchar.h>
   16 #include "Crypto.h"
   17 #include "Volumes.h"
   18 
   19 #include "Apidrvr.h"
   20 #include "DriveFilter.h"
   21 #include "Ntdriver.h"
   22 #include "Ntvol.h"
   23 #include "VolumeFilter.h"
   24 
   25 #include "Boot/Windows/BootCommon.h"
   26 
   27 #include "Cache.h"
   28 
   29 #if 0 && _DEBUG
   30 #define EXTRA_INFO 1
   31 #endif
   32 
   33 #pragma warning( disable : 4127 )
   34 
   35 #include <Ntstrsafe.h>
   36 
   37 volatile BOOL ProbingHostDeviceForWrite = FALSE;
   38 
   39 
   40 NTSTATUS TCOpenVolume (PDEVICE_OBJECT DeviceObject,
   41            PEXTENSION Extension,
   42            MOUNT_STRUCT *mount,
   43            PWSTR pwszMountVolume,
   44            BOOL bRawDevice)
   45 {
   46     FILE_STANDARD_INFORMATION FileStandardInfo;
   47     FILE_BASIC_INFORMATION FileBasicInfo;
   48     OBJECT_ATTRIBUTES oaFileAttributes;
   49     UNICODE_STRING FullFileName;
   50     IO_STATUS_BLOCK IoStatusBlock;
   51     PCRYPTO_INFO cryptoInfoPtr = NULL;
   52     PCRYPTO_INFO tmpCryptoInfo = NULL;
   53     LARGE_INTEGER lDiskLength;
   54     __int64 partitionStartingOffset = 0;
   55     int volumeType;
   56     char *readBuffer = 0;
   57     NTSTATUS ntStatus = 0;
   58     BOOL forceAccessCheck = (!bRawDevice && !(OsMajorVersion == 5 &&OsMinorVersion == 0)); // Windows 2000 does not support OBJ_FORCE_ACCESS_CHECK attribute
   59     BOOL disableBuffering = TRUE;
   60     BOOL exclusiveAccess = mount->bExclusiveAccess;
   61 
   62     Extension->pfoDeviceFile = NULL;
   63     Extension->hDeviceFile = NULL;
   64     Extension->bTimeStampValid = FALSE;
   65 
   66     /* default value for storage alignment */
   67     Extension->HostMaximumTransferLength = 65536;
   68     Extension->HostMaximumPhysicalPages = 17;
   69     Extension->HostAlignmentMask = 0;
   70 
   71     /* default values for non-SSD drives */
   72     Extension->IncursSeekPenalty = TRUE;
   73     Extension->TrimEnabled = FALSE;
   74 
   75     Extension->DeviceNumber = (ULONG) -1;
   76 
   77     RtlInitUnicodeString (&FullFileName, pwszMountVolume);
   78     InitializeObjectAttributes (&oaFileAttributes, &FullFileName, OBJ_CASE_INSENSITIVE | (forceAccessCheck ? OBJ_FORCE_ACCESS_CHECK : 0) | OBJ_KERNEL_HANDLE, NULL, NULL);
   79     KeInitializeEvent (&Extension->keVolumeEvent, NotificationEvent, FALSE);
   80 
   81     if (Extension->SecurityClientContextValid)
   82     {
   83         ntStatus = SeImpersonateClientEx (&Extension->SecurityClientContext, NULL);
   84         if (!NT_SUCCESS (ntStatus))
   85             goto error;
   86     }
   87 
   88     mount->VolumeMountedReadOnlyAfterDeviceWriteProtected = FALSE;
   89 
   90     // If we are opening a device, query its size first
   91     if (bRawDevice)
   92     {
   93         PARTITION_INFORMATION pi;
   94         PARTITION_INFORMATION_EX pix;
   95         LARGE_INTEGER diskLengthInfo;
   96         DISK_GEOMETRY_EX dg;
   97         STORAGE_PROPERTY_QUERY storagePropertyQuery = {0};
   98         byte* dgBuffer;
   99         STORAGE_DEVICE_NUMBER storageDeviceNumber;
  100 
  101         ntStatus = IoGetDeviceObjectPointer (&FullFileName,
  102             FILE_READ_DATA | FILE_READ_ATTRIBUTES,
  103             &Extension->pfoDeviceFile,
  104             &Extension->pFsdDevice);
  105 
  106         if (!NT_SUCCESS (ntStatus))
  107             goto error;
  108 
  109         dgBuffer = TCalloc (256);
  110         if (!dgBuffer)
  111         {
  112             ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  113             goto error;
  114         }
  115 
  116         ntStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, (char *) dgBuffer, 256);
  117         if (!NT_SUCCESS (ntStatus))
  118         {
  119             DISK_GEOMETRY geo;
  120             ntStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_DRIVE_GEOMETRY, (char *) &geo, sizeof (geo));
  121             if (!NT_SUCCESS (ntStatus))
  122             {
  123                 TCfree (dgBuffer);
  124                 goto error;
  125             }
  126             memset (&dg, 0, sizeof (dg));
  127             memcpy (&dg.Geometry, &geo, sizeof (geo));
  128             dg.DiskSize.QuadPart = geo.Cylinders.QuadPart * geo.SectorsPerTrack * geo.TracksPerCylinder * geo.BytesPerSector;
  129 
  130             if (OsMajorVersion >= 6)
  131             {
  132                 STORAGE_READ_CAPACITY storage = {0};
  133                 NTSTATUS lStatus;
  134 
  135                 storage.Version = sizeof (STORAGE_READ_CAPACITY);
  136                 storage.Size = sizeof (STORAGE_READ_CAPACITY);
  137                 lStatus = TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
  138                     IOCTL_STORAGE_READ_CAPACITY,
  139                     (char*)  &storage, sizeof (STORAGE_READ_CAPACITY));
  140                 if (    NT_SUCCESS(lStatus)
  141                     && (storage.Size == sizeof (STORAGE_READ_CAPACITY))
  142                     )
  143                 {
  144                     dg.DiskSize.QuadPart = storage.DiskLength.QuadPart;
  145                 }
  146             }
  147         }
  148         else
  149             memcpy (&dg, dgBuffer, sizeof (DISK_GEOMETRY_EX));
  150 
  151         TCfree (dgBuffer);
  152 
  153         if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
  154                     IOCTL_STORAGE_GET_DEVICE_NUMBER,
  155                     (char*) &storageDeviceNumber, sizeof (storageDeviceNumber))))
  156         {
  157             Extension->DeviceNumber = storageDeviceNumber.DeviceNumber;
  158         }
  159 
  160         lDiskLength.QuadPart = dg.DiskSize.QuadPart;
  161         Extension->HostBytesPerSector = dg.Geometry.BytesPerSector;
  162         Extension->HostBytesPerPhysicalSector = dg.Geometry.BytesPerSector;
  163 
  164         /* IOCTL_STORAGE_QUERY_PROPERTY supported only on Vista and above */
  165         if (OsMajorVersion >= 6)
  166         {
  167             STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR alignmentDesc = {0};
  168             STORAGE_ADAPTER_DESCRIPTOR adapterDesc = {0};
  169             DEVICE_SEEK_PENALTY_DESCRIPTOR penaltyDesc = {0};
  170             DEVICE_TRIM_DESCRIPTOR trimDesc = {0};
  171 
  172             storagePropertyQuery.PropertyId = StorageAccessAlignmentProperty;
  173             storagePropertyQuery.QueryType = PropertyStandardQuery;
  174 
  175             alignmentDesc.Version = sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
  176             alignmentDesc.Size = sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR);
  177 
  178             if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY,
  179                 (char*) &storagePropertyQuery, sizeof(storagePropertyQuery),
  180                 (char *) &alignmentDesc, sizeof (alignmentDesc))))
  181             {
  182                 Extension->HostBytesPerPhysicalSector = alignmentDesc.BytesPerPhysicalSector;
  183             }
  184 
  185             storagePropertyQuery.PropertyId = StorageAdapterProperty;
  186             adapterDesc.Version = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
  187             adapterDesc.Size = sizeof (STORAGE_ADAPTER_DESCRIPTOR);
  188 
  189             if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY,
  190                 (char*) &storagePropertyQuery, sizeof(storagePropertyQuery),
  191                 (char *) &adapterDesc, sizeof (adapterDesc))))
  192             {
  193                 Extension->HostMaximumTransferLength = adapterDesc.MaximumTransferLength;
  194                 Extension->HostMaximumPhysicalPages = adapterDesc.MaximumPhysicalPages;
  195                 Extension->HostAlignmentMask = adapterDesc.AlignmentMask;
  196             }
  197 
  198             storagePropertyQuery.PropertyId = StorageDeviceSeekPenaltyProperty;
  199             penaltyDesc.Version = sizeof (DEVICE_SEEK_PENALTY_DESCRIPTOR);
  200             penaltyDesc.Size = sizeof (DEVICE_SEEK_PENALTY_DESCRIPTOR);
  201 
  202             if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY,
  203                 (char*) &storagePropertyQuery, sizeof(storagePropertyQuery),
  204                 (char *) &penaltyDesc, sizeof (penaltyDesc))))
  205             {
  206                 Extension->IncursSeekPenalty = penaltyDesc.IncursSeekPenalty;
  207             }
  208 
  209             storagePropertyQuery.PropertyId = StorageDeviceTrimProperty;
  210             trimDesc.Version = sizeof (DEVICE_TRIM_DESCRIPTOR);
  211             trimDesc.Size = sizeof (DEVICE_TRIM_DESCRIPTOR);
  212 
  213             if (NT_SUCCESS (TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IOCTL_STORAGE_QUERY_PROPERTY,
  214                 (char*) &storagePropertyQuery, sizeof(storagePropertyQuery),
  215                 (char *) &trimDesc, sizeof (trimDesc))))
  216             {
  217                 Extension->TrimEnabled = trimDesc.TrimEnabled;
  218             }
  219         }
  220 
  221         // Drive geometry is used only when IOCTL_DISK_GET_PARTITION_INFO fails
  222         if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO_EX, (char *) &pix, sizeof (pix))))
  223         {
  224             lDiskLength.QuadPart = pix.PartitionLength.QuadPart;
  225             partitionStartingOffset = pix.StartingOffset.QuadPart;
  226         }
  227         // Windows 2000 does not support IOCTL_DISK_GET_PARTITION_INFO_EX
  228         else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_PARTITION_INFO, (char *) &pi, sizeof (pi))))
  229         {
  230             lDiskLength.QuadPart = pi.PartitionLength.QuadPart;
  231             partitionStartingOffset = pi.StartingOffset.QuadPart;
  232         }
  233         else if (NT_SUCCESS (TCSendHostDeviceIoControlRequest (DeviceObject, Extension, IOCTL_DISK_GET_LENGTH_INFO, &diskLengthInfo, sizeof (diskLengthInfo))))
  234         {
  235             lDiskLength = diskLengthInfo;
  236         }
  237 
  238         ProbingHostDeviceForWrite = TRUE;
  239 
  240         if (!mount->bMountReadOnly
  241             && TCSendHostDeviceIoControlRequest (DeviceObject, Extension,
  242                 IsHiddenSystemRunning() ? TC_IOCTL_DISK_IS_WRITABLE : IOCTL_DISK_IS_WRITABLE, NULL, 0) == STATUS_MEDIA_WRITE_PROTECTED)
  243         {
  244             mount->bMountReadOnly = TRUE;
  245             DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
  246             mount->VolumeMountedReadOnlyAfterDeviceWriteProtected = TRUE;
  247         }
  248 
  249         ProbingHostDeviceForWrite = FALSE;
  250 
  251         // Some Windows tools (e.g. diskmgmt, diskpart, vssadmin) fail or experience timeouts when there is a raw device
  252         // open for exclusive access. Therefore, exclusive access is used only for file-hosted volumes.
  253         // Applications requiring a consistent device image need to acquire exclusive write access first. This is prevented
  254         // when a device-hosted volume is mounted.
  255 
  256         exclusiveAccess = FALSE;
  257     }
  258     else
  259     {
  260         // Limit the maximum required buffer size
  261         if (mount->BytesPerSector > 128 * BYTES_PER_KB)
  262         {
  263             ntStatus = STATUS_INVALID_PARAMETER;
  264             goto error;
  265         }
  266 
  267         Extension->HostBytesPerSector = mount->BytesPerSector;
  268         Extension->HostBytesPerPhysicalSector = mount->BytesPerPhysicalSector;
  269         Extension->HostMaximumTransferLength = mount->MaximumTransferLength;
  270         Extension->HostMaximumPhysicalPages = mount->MaximumPhysicalPages;
  271         Extension->HostAlignmentMask = mount->AlignmentMask;
  272 
  273         if (Extension->HostBytesPerSector != TC_SECTOR_SIZE_FILE_HOSTED_VOLUME)
  274             disableBuffering = FALSE;
  275     }
  276 
  277     // Open the volume hosting file/device
  278     if (!mount->bMountReadOnly)
  279     {
  280         ntStatus = ZwCreateFile (&Extension->hDeviceFile,
  281             GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  282             &oaFileAttributes,
  283             &IoStatusBlock,
  284             NULL,
  285             FILE_ATTRIBUTE_NORMAL |
  286             FILE_ATTRIBUTE_SYSTEM,
  287             exclusiveAccess ? 0 : FILE_SHARE_READ | FILE_SHARE_WRITE,
  288             FILE_OPEN,
  289             FILE_RANDOM_ACCESS |
  290             FILE_WRITE_THROUGH |
  291             (disableBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
  292             FILE_SYNCHRONOUS_IO_NONALERT,
  293             NULL,
  294             0);
  295     }
  296 
  297     /* 26-4-99 NT for some partitions returns this code, it is really a access denied */
  298     if (ntStatus == 0xc000001b)
  299         ntStatus = STATUS_ACCESS_DENIED;
  300 
  301     mount->VolumeMountedReadOnlyAfterAccessDenied = FALSE;
  302 
  303     if (mount->bMountReadOnly || ntStatus == STATUS_ACCESS_DENIED)
  304     {
  305         ntStatus = ZwCreateFile (&Extension->hDeviceFile,
  306             GENERIC_READ | SYNCHRONIZE,
  307             &oaFileAttributes,
  308             &IoStatusBlock,
  309             NULL,
  310             FILE_ATTRIBUTE_NORMAL |
  311             FILE_ATTRIBUTE_SYSTEM,
  312             exclusiveAccess ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
  313             FILE_OPEN,
  314             FILE_RANDOM_ACCESS |
  315             FILE_WRITE_THROUGH |
  316             (disableBuffering ? FILE_NO_INTERMEDIATE_BUFFERING : 0) |
  317             FILE_SYNCHRONOUS_IO_NONALERT,
  318             NULL,
  319             0);
  320 
  321         if (NT_SUCCESS (ntStatus) && !mount->bMountReadOnly)
  322             mount->VolumeMountedReadOnlyAfterAccessDenied = TRUE;
  323 
  324         Extension->bReadOnly = TRUE;
  325         DeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE;
  326     }
  327     else
  328         Extension->bReadOnly = FALSE;
  329 
  330     /* 26-4-99 NT for some partitions returns this code, it is really a
  331     access denied */
  332     if (ntStatus == 0xc000001b)
  333     {
  334         /* Partitions which return this code can still be opened with
  335         FILE_SHARE_READ but this causes NT problems elsewhere in
  336         particular if you do FILE_SHARE_READ NT will die later if
  337         anyone even tries to open the partition (or file for that
  338         matter...)  */
  339         ntStatus = STATUS_SHARING_VIOLATION;
  340     }
  341 
  342     if (!NT_SUCCESS (ntStatus))
  343     {
  344         goto error;
  345     }
  346 
  347     // If we have opened a file, query its size now
  348     if (bRawDevice == FALSE)
  349     {
  350         ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
  351             &IoStatusBlock,
  352             &FileBasicInfo,
  353             sizeof (FileBasicInfo),
  354             FileBasicInformation);
  355 
  356         if (NT_SUCCESS (ntStatus))
  357         {
  358             if (mount->bPreserveTimestamp)
  359             {
  360                 Extension->fileCreationTime = FileBasicInfo.CreationTime;
  361                 Extension->fileLastAccessTime = FileBasicInfo.LastAccessTime;
  362                 Extension->fileLastWriteTime = FileBasicInfo.LastWriteTime;
  363                 Extension->fileLastChangeTime = FileBasicInfo.ChangeTime;
  364                 Extension->bTimeStampValid = TRUE;
  365             }
  366 
  367             ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
  368                 &IoStatusBlock,
  369                 &FileStandardInfo,
  370                 sizeof (FileStandardInfo),
  371                 FileStandardInformation);
  372         }
  373 
  374         if (!NT_SUCCESS (ntStatus))
  375         {
  376             Dump ("ZwQueryInformationFile failed while opening file: NTSTATUS 0x%08x\n",
  377                 ntStatus);
  378             goto error;
  379         }
  380 
  381         lDiskLength.QuadPart = FileStandardInfo.EndOfFile.QuadPart;
  382 
  383         if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED)
  384         {
  385             Dump ("File \"%ls\" is marked as compressed - not supported!\n", pwszMountVolume);
  386             mount->nReturnCode = ERR_COMPRESSION_NOT_SUPPORTED;
  387             ntStatus = STATUS_SUCCESS;
  388             goto error;
  389         }
  390 
  391         ntStatus = ObReferenceObjectByHandle (Extension->hDeviceFile,
  392             FILE_ALL_ACCESS,
  393             *IoFileObjectType,
  394             KernelMode,
  395             &Extension->pfoDeviceFile,
  396             0);
  397 
  398         if (!NT_SUCCESS (ntStatus))
  399         {
  400             goto error;
  401         }
  402 
  403         /* Get the FSD device for the file (probably either NTFS or FAT) */
  404         Extension->pFsdDevice = IoGetRelatedDeviceObject (Extension->pfoDeviceFile);
  405     }
  406     else
  407     {
  408         // Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise,
  409         // the NTFS driver guards hidden sectors and prevents mounting using a backup header e.g. after the user
  410         // accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS).
  411 
  412         PFILE_OBJECT pfoTmpDeviceFile = NULL;
  413 
  414         if (NT_SUCCESS (ObReferenceObjectByHandle (Extension->hDeviceFile, FILE_ALL_ACCESS, *IoFileObjectType, KernelMode, &pfoTmpDeviceFile, NULL))
  415             && pfoTmpDeviceFile != NULL)
  416         {
  417             TCFsctlCall (pfoTmpDeviceFile, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0);
  418             ObDereferenceObject (pfoTmpDeviceFile);
  419         }
  420     }
  421 
  422     // Check volume size
  423     if (lDiskLength.QuadPart < TC_MIN_VOLUME_SIZE_LEGACY || lDiskLength.QuadPart > TC_MAX_VOLUME_SIZE)
  424     {
  425         mount->nReturnCode = ERR_VOL_SIZE_WRONG;
  426         ntStatus = STATUS_SUCCESS;
  427         goto error;
  428     }
  429 
  430     Extension->DiskLength = lDiskLength.QuadPart;
  431     Extension->HostLength = lDiskLength.QuadPart;
  432 
  433     readBuffer = TCalloc (max (max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, PAGE_SIZE), Extension->HostBytesPerSector));
  434     if (readBuffer == NULL)
  435     {
  436         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  437         goto error;
  438     }
  439 
  440     // Go through all volume types (e.g., normal, hidden)
  441     for (volumeType = TC_VOLUME_TYPE_NORMAL;
  442         volumeType < TC_VOLUME_TYPE_COUNT;
  443         volumeType++)
  444     {
  445         Dump ("Trying to open volume type %d\n", volumeType);
  446 
  447         /* Read the volume header */
  448 
  449         if (!mount->bPartitionInInactiveSysEncScope
  450             || (mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_HIDDEN))
  451         {
  452             // Header of a volume that is not within the scope of system encryption, or
  453             // header of a system hidden volume (containing a hidden OS)
  454 
  455             LARGE_INTEGER headerOffset;
  456 
  457             if (mount->UseBackupHeader && lDiskLength.QuadPart <= TC_TOTAL_VOLUME_HEADERS_SIZE)
  458                 continue;
  459 
  460             switch (volumeType)
  461             {
  462             case TC_VOLUME_TYPE_NORMAL:
  463                 headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
  464                 break;
  465 
  466             case TC_VOLUME_TYPE_HIDDEN:
  467                 if (lDiskLength.QuadPart <= TC_VOLUME_HEADER_GROUP_SIZE)
  468                     continue;
  469 
  470                 headerOffset.QuadPart = mount->UseBackupHeader ? lDiskLength.QuadPart - TC_HIDDEN_VOLUME_HEADER_OFFSET : TC_HIDDEN_VOLUME_HEADER_OFFSET;
  471                 break;
  472             }
  473 
  474             Dump ("Reading volume header at %I64d\n", headerOffset.QuadPart);
  475 
  476             ntStatus = ZwReadFile (Extension->hDeviceFile,
  477             NULL,
  478             NULL,
  479             NULL,
  480             &IoStatusBlock,
  481             readBuffer,
  482             bRawDevice ? max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, Extension->HostBytesPerSector) : TC_VOLUME_HEADER_EFFECTIVE_SIZE,
  483             &headerOffset,
  484             NULL);
  485         }
  486         else
  487         {
  488             // Header of a partition that is within the scope of system encryption
  489 
  490             WCHAR parentDrivePath [47+1] = {0};
  491             HANDLE hParentDeviceFile = NULL;
  492             UNICODE_STRING FullParentPath;
  493             OBJECT_ATTRIBUTES oaParentFileAttributes;
  494             LARGE_INTEGER parentKeyDataOffset;
  495 
  496             RtlStringCbPrintfW (parentDrivePath,
  497                 sizeof (parentDrivePath),
  498                 WIDE ("\\Device\\Harddisk%d\\Partition0"),
  499                 mount->nPartitionInInactiveSysEncScopeDriveNo);
  500 
  501             Dump ("Mounting partition within scope of system encryption (reading key data from: %ls)\n", parentDrivePath);
  502 
  503             RtlInitUnicodeString (&FullParentPath, parentDrivePath);
  504             InitializeObjectAttributes (&oaParentFileAttributes, &FullParentPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
  505 
  506             ntStatus = ZwCreateFile (&hParentDeviceFile,
  507                 GENERIC_READ | SYNCHRONIZE,
  508                 &oaParentFileAttributes,
  509                 &IoStatusBlock,
  510                 NULL,
  511                 FILE_ATTRIBUTE_NORMAL |
  512                 FILE_ATTRIBUTE_SYSTEM,
  513                 FILE_SHARE_READ | FILE_SHARE_WRITE,
  514                 FILE_OPEN,
  515                 FILE_RANDOM_ACCESS |
  516                 FILE_WRITE_THROUGH |
  517                 FILE_NO_INTERMEDIATE_BUFFERING |
  518                 FILE_SYNCHRONOUS_IO_NONALERT,
  519                 NULL,
  520                 0);
  521 
  522             if (!NT_SUCCESS (ntStatus))
  523             {
  524                 if (hParentDeviceFile != NULL)
  525                     ZwClose (hParentDeviceFile);
  526 
  527                 Dump ("Cannot open %ls\n", parentDrivePath);
  528 
  529                 goto error;
  530             }
  531 
  532             parentKeyDataOffset.QuadPart = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
  533 
  534             ntStatus = ZwReadFile (hParentDeviceFile,
  535                 NULL,
  536                 NULL,
  537                 NULL,
  538                 &IoStatusBlock,
  539                 readBuffer,
  540                 max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, Extension->HostBytesPerSector),
  541                 &parentKeyDataOffset,
  542                 NULL);
  543 
  544             if (hParentDeviceFile != NULL)
  545                 ZwClose (hParentDeviceFile);
  546         }
  547 
  548         if (!NT_SUCCESS (ntStatus) && ntStatus != STATUS_END_OF_FILE)
  549         {
  550             Dump ("Read failed: NTSTATUS 0x%08x\n", ntStatus);
  551             goto error;
  552         }
  553 
  554         if (ntStatus == STATUS_END_OF_FILE || IoStatusBlock.Information < TC_VOLUME_HEADER_EFFECTIVE_SIZE)
  555         {
  556             Dump ("Read didn't read enough data\n");
  557 
  558             // If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
  559             // filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
  560             // shorter than the partition). This can happen for example after the user quick-formats a dismounted
  561             // partition-hosted TrueCrypt volume and then tries to mount the volume using the embedded backup header.
  562             memset (readBuffer, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
  563         }
  564 
  565         /* Attempt to recognize the volume (decrypt the header) */
  566 
  567         ReadVolumeHeaderRecoveryMode = mount->RecoveryMode;
  568 
  569         if ((volumeType == TC_VOLUME_TYPE_HIDDEN) && mount->bProtectHiddenVolume)
  570         {
  571             mount->nReturnCode = ReadVolumeHeaderWCache (
  572                 FALSE,
  573                 mount->bCache,
  574                 mount->bCachePim,
  575                 readBuffer,
  576                 &mount->ProtectedHidVolPassword,
  577                 mount->ProtectedHidVolPkcs5Prf,
  578                 mount->ProtectedHidVolPim,
  579                 mount->bTrueCryptMode,
  580                 &tmpCryptoInfo);
  581         }
  582         else
  583         {
  584             mount->nReturnCode = ReadVolumeHeaderWCache (
  585                 mount->bPartitionInInactiveSysEncScope && volumeType == TC_VOLUME_TYPE_NORMAL,
  586                 mount->bCache,
  587                 mount->bCachePim,
  588                 readBuffer,
  589                 &mount->VolumePassword,
  590                 mount->pkcs5_prf,
  591                 mount->VolumePim,
  592                 mount->bTrueCryptMode,
  593                 &Extension->cryptoInfo);
  594         }
  595 
  596         ReadVolumeHeaderRecoveryMode = FALSE;
  597 
  598         if (mount->nReturnCode == 0 || mount->nReturnCode == ERR_CIPHER_INIT_WEAK_KEY)
  599         {
  600             /* Volume header successfully decrypted */
  601 
  602             if (!Extension->cryptoInfo)
  603             {
  604                 /* should never happen */
  605                 mount->nReturnCode = ERR_OUTOFMEMORY;
  606                 ntStatus = STATUS_SUCCESS;
  607                 goto error;
  608             }
  609 
  610             Dump ("Volume header decrypted\n");
  611             Dump ("Required program version = %x\n", (int) Extension->cryptoInfo->RequiredProgramVersion);
  612             Dump ("Legacy volume = %d\n", (int) Extension->cryptoInfo->LegacyVolume);
  613 
  614             if (IsHiddenSystemRunning() && !Extension->cryptoInfo->hiddenVolume)
  615             {
  616                 Extension->bReadOnly = mount->bMountReadOnly = TRUE;
  617                 HiddenSysLeakProtectionCount++;
  618             }
  619 
  620             Extension->cryptoInfo->bProtectHiddenVolume = FALSE;
  621             Extension->cryptoInfo->bHiddenVolProtectionAction = FALSE;
  622 
  623             Extension->cryptoInfo->bPartitionInInactiveSysEncScope = mount->bPartitionInInactiveSysEncScope;
  624 
  625             /* compute the ID of this volume: SHA-256 of the effective header */
  626             sha256 (Extension->volumeID, readBuffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
  627 
  628             if (volumeType == TC_VOLUME_TYPE_NORMAL)
  629             {
  630                 if (mount->bPartitionInInactiveSysEncScope)
  631                 {
  632                     if (Extension->cryptoInfo->EncryptedAreaStart.Value > (unsigned __int64) partitionStartingOffset
  633                         || Extension->cryptoInfo->EncryptedAreaStart.Value + Extension->cryptoInfo->VolumeSize.Value <= (unsigned __int64) partitionStartingOffset)
  634                     {
  635                         // The partition is not within the key scope of system encryption
  636                         mount->nReturnCode = ERR_PASSWORD_WRONG;
  637                         ntStatus = STATUS_SUCCESS;
  638                         goto error;
  639                     }
  640 
  641                     if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
  642                     {
  643                         // Partial encryption is not supported for volumes mounted as regular
  644                         mount->nReturnCode = ERR_ENCRYPTION_NOT_COMPLETED;
  645                         ntStatus = STATUS_SUCCESS;
  646                         goto error;
  647                     }
  648                 }
  649                 else if (Extension->cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC)
  650                 {
  651                     if (Extension->cryptoInfo->EncryptedAreaLength.Value != Extension->cryptoInfo->VolumeSize.Value)
  652                     {
  653                         // Non-system in-place encryption process has not been completed on this volume
  654                         mount->nReturnCode = ERR_NONSYS_INPLACE_ENC_INCOMPLETE;
  655                         ntStatus = STATUS_SUCCESS;
  656                         goto error;
  657                     }
  658                 }
  659             }
  660 
  661             Extension->cryptoInfo->FirstDataUnitNo.Value = 0;
  662 
  663             if (Extension->cryptoInfo->hiddenVolume && IsHiddenSystemRunning())
  664             {
  665                 // Prevent mount of a hidden system partition if the system hosted on it is currently running
  666                 if (memcmp (Extension->cryptoInfo->master_keydata, GetSystemDriveCryptoInfo()->master_keydata, EAGetKeySize (Extension->cryptoInfo->ea)) == 0)
  667                 {
  668                     mount->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
  669                     ntStatus = STATUS_SUCCESS;
  670                     goto error;
  671                 }
  672             }
  673 
  674             switch (volumeType)
  675             {
  676             case TC_VOLUME_TYPE_NORMAL:
  677 
  678                 Extension->cryptoInfo->hiddenVolume = FALSE;
  679 
  680                 if (mount->bPartitionInInactiveSysEncScope)
  681                 {
  682                     Extension->cryptoInfo->volDataAreaOffset = 0;
  683                     Extension->DiskLength = lDiskLength.QuadPart;
  684                     Extension->cryptoInfo->FirstDataUnitNo.Value = partitionStartingOffset / ENCRYPTION_DATA_UNIT_SIZE;
  685                 }
  686                 else if (Extension->cryptoInfo->LegacyVolume)
  687                 {
  688                     Extension->cryptoInfo->volDataAreaOffset = TC_VOLUME_HEADER_SIZE_LEGACY;
  689                     Extension->DiskLength = lDiskLength.QuadPart - TC_VOLUME_HEADER_SIZE_LEGACY;
  690                 }
  691                 else
  692                 {
  693                     Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->EncryptedAreaStart.Value;
  694                     Extension->DiskLength = Extension->cryptoInfo->VolumeSize.Value;
  695                 }
  696 
  697                 break;
  698 
  699             case TC_VOLUME_TYPE_HIDDEN:
  700 
  701                 cryptoInfoPtr = mount->bProtectHiddenVolume ? tmpCryptoInfo : Extension->cryptoInfo;
  702 
  703                 Extension->cryptoInfo->hiddenVolumeOffset = cryptoInfoPtr->EncryptedAreaStart.Value;
  704 
  705                 Dump ("Hidden volume offset = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset);
  706                 Dump ("Hidden volume size = %I64d\n", cryptoInfoPtr->hiddenVolumeSize);
  707                 Dump ("Hidden volume end = %I64d\n", Extension->cryptoInfo->hiddenVolumeOffset + cryptoInfoPtr->hiddenVolumeSize - 1);
  708 
  709                 // Validate the offset
  710                 if (Extension->cryptoInfo->hiddenVolumeOffset % ENCRYPTION_DATA_UNIT_SIZE != 0)
  711                 {
  712                     mount->nReturnCode = ERR_VOL_SIZE_WRONG;
  713                     ntStatus = STATUS_SUCCESS;
  714                     goto error;
  715                 }
  716 
  717                 // If we are supposed to actually mount the hidden volume (not just to protect it)
  718                 if (!mount->bProtectHiddenVolume)
  719                 {
  720                     Extension->DiskLength = cryptoInfoPtr->hiddenVolumeSize;
  721                     Extension->cryptoInfo->hiddenVolume = TRUE;
  722                     Extension->cryptoInfo->volDataAreaOffset = Extension->cryptoInfo->hiddenVolumeOffset;
  723                 }
  724                 else
  725                 {
  726                     // Hidden volume protection
  727                     Extension->cryptoInfo->hiddenVolume = FALSE;
  728                     Extension->cryptoInfo->bProtectHiddenVolume = TRUE;
  729 
  730                     Extension->cryptoInfo->hiddenVolumeProtectedSize = tmpCryptoInfo->hiddenVolumeSize;
  731 
  732                     Dump ("Hidden volume protection active: %I64d-%I64d (%I64d)\n", Extension->cryptoInfo->hiddenVolumeOffset, Extension->cryptoInfo->hiddenVolumeProtectedSize + Extension->cryptoInfo->hiddenVolumeOffset - 1, Extension->cryptoInfo->hiddenVolumeProtectedSize);
  733                 }
  734 
  735                 break;
  736             }
  737 
  738             Dump ("Volume data offset = %I64d\n", Extension->cryptoInfo->volDataAreaOffset);
  739             Dump ("Volume data size = %I64d\n", Extension->DiskLength);
  740             Dump ("Volume data end = %I64d\n", Extension->cryptoInfo->volDataAreaOffset + Extension->DiskLength - 1);
  741 
  742             if (Extension->DiskLength == 0)
  743             {
  744                 Dump ("Incorrect volume size\n");
  745                 continue;
  746             }
  747 
  748             // If this is a hidden volume, make sure we are supposed to actually
  749             // mount it (i.e. not just to protect it)
  750             if (volumeType == TC_VOLUME_TYPE_NORMAL || !mount->bProtectHiddenVolume)
  751             {
  752                 // Validate sector size
  753                 if (bRawDevice && Extension->cryptoInfo->SectorSize != Extension->HostBytesPerSector)
  754                 {
  755                     mount->nReturnCode = ERR_PARAMETER_INCORRECT;
  756                     ntStatus = STATUS_SUCCESS;
  757                     goto error;
  758                 }
  759 
  760                 // Calculate virtual volume geometry
  761                 Extension->TracksPerCylinder = 1;
  762                 Extension->SectorsPerTrack = 1;
  763                 Extension->BytesPerSector = Extension->cryptoInfo->SectorSize;
  764                 // Add extra sector since our virtual partition starts at Extension->BytesPerSector and not 0
  765                 Extension->NumberOfCylinders = (Extension->DiskLength / Extension->BytesPerSector) + 1;
  766                 Extension->PartitionType = 0;
  767 
  768                 Extension->bRawDevice = bRawDevice;
  769 
  770                 memset (Extension->wszVolume, 0, sizeof (Extension->wszVolume));
  771                 if ((wcslen (pwszMountVolume) > 8)  && (0 == memcmp (pwszMountVolume, WIDE ("\\??\\UNC\\"), 8 * sizeof (WCHAR))))
  772                 {
  773                     /* UNC path */
  774                     RtlStringCbPrintfW (Extension->wszVolume,
  775                         sizeof (Extension->wszVolume),
  776                         WIDE ("\\??\\\\%s"),
  777                         pwszMountVolume + 7);
  778                 }
  779                 else
  780                 {
  781                     RtlStringCbCopyW (Extension->wszVolume, sizeof(Extension->wszVolume),pwszMountVolume);
  782                 }
  783 
  784                 memset (Extension->wszLabel, 0, sizeof (Extension->wszLabel));
  785                 RtlStringCbCopyW (Extension->wszLabel, sizeof(Extension->wszLabel), mount->wszLabel);
  786             }
  787 
  788             // If we are to protect a hidden volume we cannot exit yet, for we must also
  789             // decrypt the hidden volume header.
  790             if (!(volumeType == TC_VOLUME_TYPE_NORMAL && mount->bProtectHiddenVolume))
  791             {
  792                 TCfree (readBuffer);
  793 
  794                 if (tmpCryptoInfo != NULL)
  795                 {
  796                     crypto_close (tmpCryptoInfo);
  797                     tmpCryptoInfo = NULL;
  798                 }
  799 
  800                 return STATUS_SUCCESS;
  801             }
  802         }
  803         else if ((mount->bProtectHiddenVolume && volumeType == TC_VOLUME_TYPE_NORMAL)
  804               || mount->nReturnCode != ERR_PASSWORD_WRONG)
  805         {
  806              /* If we are not supposed to protect a hidden volume, the only error that is
  807                 tolerated is ERR_PASSWORD_WRONG (to allow mounting a possible hidden volume).
  808 
  809                 If we _are_ supposed to protect a hidden volume, we do not tolerate any error
  810                 (both volume headers must be successfully decrypted). */
  811 
  812             break;
  813         }
  814     }
  815 
  816     /* Failed due to some non-OS reason so we drop through and return NT
  817        SUCCESS then nReturnCode is checked later in user-mode */
  818 
  819     if (mount->nReturnCode == ERR_OUTOFMEMORY)
  820         ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  821     else
  822         ntStatus = STATUS_SUCCESS;
  823 
  824 error:
  825     if (mount->nReturnCode == ERR_SUCCESS)
  826         mount->nReturnCode = ERR_PASSWORD_WRONG;
  827 
  828     if (tmpCryptoInfo != NULL)
  829     {
  830         crypto_close (tmpCryptoInfo);
  831         tmpCryptoInfo = NULL;
  832     }
  833 
  834     if (Extension->cryptoInfo)
  835     {
  836         crypto_close (Extension->cryptoInfo);
  837         Extension->cryptoInfo = NULL;
  838     }
  839 
  840     if (Extension->bTimeStampValid)
  841     {
  842         RestoreTimeStamp (Extension);
  843     }
  844 
  845     /* Close the hDeviceFile */
  846     if (Extension->hDeviceFile != NULL)
  847         ZwClose (Extension->hDeviceFile);
  848 
  849     /* The cryptoInfo pointer is deallocated if the readheader routines
  850        fail so there is no need to deallocate here  */
  851 
  852     /* Dereference the user-mode file object */
  853     if (Extension->pfoDeviceFile != NULL)
  854         ObDereferenceObject (Extension->pfoDeviceFile);
  855 
  856     /* Free the tmp IO buffers */
  857     if (readBuffer != NULL)
  858         TCfree (readBuffer);
  859 
  860     return ntStatus;
  861 }
  862 
  863 void TCCloseVolume (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension)
  864 {
  865     UNREFERENCED_PARAMETER (DeviceObject);  /* Remove compiler warning */
  866 
  867     if (Extension->hDeviceFile != NULL)
  868     {
  869         if (Extension->bRawDevice == FALSE
  870             && Extension->bTimeStampValid)
  871         {
  872             RestoreTimeStamp (Extension);
  873         }
  874         ZwClose (Extension->hDeviceFile);
  875     }
  876     ObDereferenceObject (Extension->pfoDeviceFile);
  877     if (Extension->cryptoInfo)
  878     {
  879         crypto_close (Extension->cryptoInfo);
  880         Extension->cryptoInfo = NULL;
  881     }
  882 }
  883 
  884 
  885 NTSTATUS TCSendHostDeviceIoControlRequestEx (PDEVICE_OBJECT DeviceObject,
  886                    PEXTENSION Extension,
  887                    ULONG IoControlCode,
  888                      void *InputBuffer,
  889                      ULONG InputBufferSize,
  890                    void *OutputBuffer,
  891                    ULONG OutputBufferSize)
  892 {
  893     IO_STATUS_BLOCK IoStatusBlock;
  894     NTSTATUS ntStatus;
  895     PIRP Irp;
  896 
  897     UNREFERENCED_PARAMETER(DeviceObject);   /* Remove compiler warning */
  898 
  899     KeClearEvent (&Extension->keVolumeEvent);
  900 
  901     Irp = IoBuildDeviceIoControlRequest (IoControlCode,
  902                          Extension->pFsdDevice,
  903                          InputBuffer, InputBufferSize,
  904                          OutputBuffer, OutputBufferSize,
  905                          FALSE,
  906                          &Extension->keVolumeEvent,
  907                          &IoStatusBlock);
  908 
  909     if (Irp == NULL)
  910     {
  911         Dump ("IRP allocation failed\n");
  912         return STATUS_INSUFFICIENT_RESOURCES;
  913     }
  914 
  915     // Disk device may be used by filesystem driver which needs file object
  916     IoGetNextIrpStackLocation (Irp) -> FileObject = Extension->pfoDeviceFile;
  917 
  918     ntStatus = IoCallDriver (Extension->pFsdDevice, Irp);
  919     if (ntStatus == STATUS_PENDING)
  920     {
  921         KeWaitForSingleObject (&Extension->keVolumeEvent, Executive, KernelMode, FALSE, NULL);
  922         ntStatus = IoStatusBlock.Status;
  923     }
  924 
  925     return ntStatus;
  926 }
  927 
  928 NTSTATUS TCSendHostDeviceIoControlRequest (PDEVICE_OBJECT DeviceObject,
  929                    PEXTENSION Extension,
  930                    ULONG IoControlCode,
  931                    void *OutputBuffer,
  932                    ULONG OutputBufferSize)
  933 {
  934     return TCSendHostDeviceIoControlRequestEx (DeviceObject, Extension, IoControlCode, NULL, 0, OutputBuffer, OutputBufferSize);
  935 }
  936 
  937 NTSTATUS COMPLETE_IRP (PDEVICE_OBJECT DeviceObject,
  938           PIRP Irp,
  939           NTSTATUS IrpStatus,
  940           ULONG_PTR IrpInformation)
  941 {
  942     Irp->IoStatus.Status = IrpStatus;
  943     Irp->IoStatus.Information = IrpInformation;
  944 
  945     UNREFERENCED_PARAMETER (DeviceObject);  /* Remove compiler warning */
  946 
  947 #if EXTRA_INFO
  948     if (!NT_SUCCESS (IrpStatus))
  949     {
  950         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
  951         Dump ("COMPLETE_IRP FAILING IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
  952               (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
  953     }
  954     else
  955     {
  956         PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp);
  957         Dump ("COMPLETE_IRP SUCCESS IRP %ls Flags 0x%08x vpb 0x%08x NTSTATUS 0x%08x\n", TCTranslateCode (irpSp->MajorFunction),
  958               (ULONG) DeviceObject->Flags, (ULONG) DeviceObject->Vpb->Flags, IrpStatus);
  959     }
  960 #endif
  961     IoCompleteRequest (Irp, IO_NO_INCREMENT);
  962     return IrpStatus;
  963 }
  964 
  965 
  966 static void RestoreTimeStamp (PEXTENSION Extension)
  967 {
  968     NTSTATUS ntStatus;
  969     FILE_BASIC_INFORMATION FileBasicInfo;
  970     IO_STATUS_BLOCK IoStatusBlock;
  971 
  972     if (Extension->hDeviceFile != NULL
  973         && Extension->bRawDevice == FALSE
  974         && Extension->bReadOnly == FALSE
  975         && Extension->bTimeStampValid)
  976     {
  977         ntStatus = ZwQueryInformationFile (Extension->hDeviceFile,
  978             &IoStatusBlock,
  979             &FileBasicInfo,
  980             sizeof (FileBasicInfo),
  981             FileBasicInformation);
  982 
  983         if (!NT_SUCCESS (ntStatus))
  984         {
  985             Dump ("ZwQueryInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",
  986                 ntStatus);
  987         }
  988         else
  989         {
  990             FileBasicInfo.CreationTime = Extension->fileCreationTime;
  991             FileBasicInfo.LastAccessTime = Extension->fileLastAccessTime;
  992             FileBasicInfo.LastWriteTime = Extension->fileLastWriteTime;
  993             FileBasicInfo.ChangeTime = Extension->fileLastChangeTime;
  994 
  995             ntStatus = ZwSetInformationFile(
  996                 Extension->hDeviceFile,
  997                 &IoStatusBlock,
  998                 &FileBasicInfo,
  999                 sizeof (FileBasicInfo),
 1000                 FileBasicInformation);
 1001 
 1002             if (!NT_SUCCESS (ntStatus))
 1003                 Dump ("ZwSetInformationFile failed in RestoreTimeStamp: NTSTATUS 0x%08x\n",ntStatus);
 1004         }
 1005     }
 1006 }