|
|
1.1 root 1: /*
2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
3:
4: Governed by the TrueCrypt License 2.6 the full text of which is contained
5: in the file License.txt included in TrueCrypt binary and source code
6: distribution packages.
7: */
8:
9:
10: /* In this file, _WIN32_WINNT is defined as 0x0600 to make file shrink available (Vista
11: or later). _WIN32_WINNT cannot be defined as 0x0600 for the entire user-space projects
12: because it breaks the main font app when the app is running on XP (likely an MS bug).
13: IMPORTANT: Due to this issue, functions in this file must not directly interact with GUI. */
14: #define TC_LOCAL_WIN32_WINNT_OVERRIDE 1
15: #if (_WIN32_WINNT < 0x0600)
16: # undef _WIN32_WINNT
17: # define _WIN32_WINNT 0x0600
18: #endif
19:
20:
21: #include <stdlib.h>
22: #include <string.h>
23: #include <string>
24:
25: #include "Tcdefs.h"
26: #include "Platform/Finally.h"
27:
28: #include "Common.h"
29: #include "Crc.h"
30: #include "Dlgcode.h"
31: #include "Language.h"
32: #include "Tcformat.h"
33: #include "Volumes.h"
34:
35: #include "InPlace.h"
36:
37: using namespace std;
38: using namespace TrueCrypt;
39:
40: #define TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE (2048 * BYTES_PER_KB)
41: #define TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE (2 * TC_MAX_VOLUME_SECTOR_SIZE)
42: #define TC_NTFS_CONCEAL_CONSTANT 0xFF
43: #define TC_NONSYS_INPLACE_ENC_HEADER_UPDATE_INTERVAL (64 * BYTES_PER_MB)
44: #define TC_NONSYS_INPLACE_ENC_MIN_VOL_SIZE (TC_TOTAL_VOLUME_HEADERS_SIZE + TC_MIN_NTFS_FS_SIZE * 2)
45:
46:
47: // If the returned value is greater than 0, it is the desired volume size in NTFS sectors (not in bytes)
48: // after shrinking has been performed. If there's any error, returns -1.
49: static __int64 NewFileSysSizeAfterShrink (HANDLE dev, const char *devicePath, int64 *totalClusterCount, DWORD *bytesPerCluster, BOOL silent)
50: {
51: NTFS_VOLUME_DATA_BUFFER ntfsVolData;
52: DWORD nBytesReturned;
53: __int64 fileSysSize, desiredNbrSectors;
54:
55: // Filesystem size and sector size
56:
57: if (!DeviceIoControl (dev,
58: FSCTL_GET_NTFS_VOLUME_DATA,
59: NULL,
60: 0,
61: (LPVOID) &ntfsVolData,
62: sizeof (ntfsVolData),
63: &nBytesReturned,
64: NULL))
65: {
66: if (!silent)
67: handleWin32Error (MainDlg);
68:
69: return -1;
70: }
71:
72: fileSysSize = ntfsVolData.NumberSectors.QuadPart * ntfsVolData.BytesPerSector;
73:
74: desiredNbrSectors = (fileSysSize - TC_TOTAL_VOLUME_HEADERS_SIZE) / ntfsVolData.BytesPerSector;
75:
76: if (desiredNbrSectors <= 0)
77: return -1;
78:
79: if (totalClusterCount)
80: *totalClusterCount = ntfsVolData.TotalClusters.QuadPart;
81: if (bytesPerCluster)
82: *bytesPerCluster = ntfsVolData.BytesPerCluster;
83:
84: return desiredNbrSectors;
85: }
86:
87:
88: BOOL CheckRequirementsForNonSysInPlaceEnc (const char *devicePath, BOOL silent)
89: {
90: NTFS_VOLUME_DATA_BUFFER ntfsVolData;
91: DWORD nBytesReturned;
92: HANDLE dev;
93: char szFileSysName [256];
94: WCHAR devPath [MAX_PATH];
95: char dosDev [TC_MAX_PATH] = {0};
96: char devName [MAX_PATH] = {0};
97: int driveLetterNo = -1;
98: char szRootPath[4] = {0, ':', '\\', 0};
99: __int64 deviceSize;
100: int partitionNumber = -1, driveNumber = -1;
101:
102:
103: /* ---------- Checks that do not require admin rights ----------- */
104:
105:
106: /* Operating system */
107:
108: if (CurrentOSMajor < 6)
109: {
110: if (!silent)
111: ShowInPlaceEncErrMsgWAltSteps ("OS_NOT_SUPPORTED_FOR_NONSYS_INPLACE_ENC", FALSE);
112:
113: return FALSE;
114: }
115:
116:
117: /* Volume type (must be a partition or a dynamic volume) */
118:
119: if (sscanf (devicePath, "\\Device\\HarddiskVolume%d", &partitionNumber) != 1
120: && sscanf (devicePath, "\\Device\\Harddisk%d\\Partition%d", &partitionNumber, &driveNumber) != 2)
121: {
122: if (!silent)
123: Error ("INPLACE_ENC_INVALID_PATH");
124:
125: return FALSE;
126: }
127:
128: if (driveNumber == 0)
129: {
130: if (!silent)
131: Warning ("RAW_DEV_NOT_SUPPORTED_FOR_INPLACE_ENC");
132:
133: return FALSE;
134: }
135:
136:
137: /* Admin rights */
138:
139: if (!IsAdmin())
140: {
141: // We rely on the wizard process to call us only when the whole wizard process has been elevated (so UAC
142: // status can be ignored). In case the IsAdmin() detection somehow fails, we allow the user to continue.
143:
144: if (!silent)
145: Warning ("ADMIN_PRIVILEGES_WARN_DEVICES");
146: }
147:
148:
149: /* ---------- Checks that may require admin rights ----------- */
150:
151:
152: /* Access to the partition */
153:
154: strcpy ((char *) devPath, devicePath);
155: ToUNICODE ((char *) devPath);
156:
157: driveLetterNo = GetDiskDeviceDriveLetter (devPath);
158:
159: if (driveLetterNo >= 0)
160: szRootPath[0] = driveLetterNo + 'A';
161:
162: if (FakeDosNameForDevice (devicePath, dosDev, devName, FALSE) != 0)
163: {
164: if (!silent)
165: {
166: handleWin32Error (MainDlg);
167: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
168: }
169: return FALSE;
170: }
171:
172: dev = OpenPartitionVolume (devName,
173: FALSE, // Do not require exclusive access
174: TRUE, // Require shared access (must be TRUE; otherwise, volume properties will not be possible to obtain)
175: FALSE, // Do not ask the user to confirm shared access (if exclusive fails)
176: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages)
177: silent); // Silent mode
178:
179: if (dev == INVALID_HANDLE_VALUE)
180: return FALSE;
181:
182:
183: /* File system type */
184:
185: GetVolumeInformation (szRootPath, NULL, 0, NULL, NULL, NULL, szFileSysName, sizeof(szFileSysName));
186:
187: if (strncmp (szFileSysName, "NTFS", 4))
188: {
189: // The previous filesystem type detection method failed (or it's not NTFS) -- try an alternative method
190:
191: if (!DeviceIoControl (dev,
192: FSCTL_GET_NTFS_VOLUME_DATA,
193: NULL,
194: 0,
195: (LPVOID) &ntfsVolData,
196: sizeof (ntfsVolData),
197: &nBytesReturned,
198: NULL))
199: {
200: if (!silent)
201: {
202: // The filesystem is not NTFS or the filesystem type could not be determined (or the NTFS filesystem
203: // is dismounted).
204:
205: if (IsDeviceMounted (devName))
206: ShowInPlaceEncErrMsgWAltSteps ("ONLY_NTFS_SUPPORTED_FOR_NONSYS_INPLACE_ENC", FALSE);
207: else
208: Warning ("ONLY_MOUNTED_VOL_SUPPORTED_FOR_NONSYS_INPLACE_ENC");
209: }
210:
211: CloseHandle (dev);
212: return FALSE;
213: }
214: }
215:
216:
217: /* Attempt to determine whether the filesystem can be safely shrunk */
218:
219: if (NewFileSysSizeAfterShrink (dev, devicePath, NULL, NULL, silent) == -1)
220: {
221: // Cannot determine whether shrinking is required
222: if (!silent)
223: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
224:
225: CloseHandle (dev);
226: return FALSE;
227: }
228:
229:
230: /* Partition size */
231:
232: deviceSize = GetDeviceSize (devicePath);
233: if (deviceSize < 0)
234: {
235: // Cannot determine the size of the partition
236: if (!silent)
237: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
238:
239: CloseHandle (dev);
240: return FALSE;
241: }
242:
243: if (deviceSize < TC_NONSYS_INPLACE_ENC_MIN_VOL_SIZE)
244: {
245: // The partition is too small
246: if (!silent)
247: {
248: ShowInPlaceEncErrMsgWAltSteps ("PARTITION_TOO_SMALL_FOR_NONSYS_INPLACE_ENC", FALSE);
249: }
250:
251: CloseHandle (dev);
252: return FALSE;
253: }
254:
255:
256: /* Free space on the filesystem */
257:
258: if (!DeviceIoControl (dev,
259: FSCTL_GET_NTFS_VOLUME_DATA,
260: NULL,
261: 0,
262: (LPVOID) &ntfsVolData,
263: sizeof (ntfsVolData),
264: &nBytesReturned,
265: NULL))
266: {
267: if (!silent)
268: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL", TRUE);
269:
270: CloseHandle (dev);
271: return FALSE;
272: }
273:
274: if (ntfsVolData.FreeClusters.QuadPart * ntfsVolData.BytesPerCluster < TC_TOTAL_VOLUME_HEADERS_SIZE)
275: {
276: if (!silent)
277: ShowInPlaceEncErrMsgWAltSteps ("NOT_ENOUGH_FREE_FILESYS_SPACE_FOR_SHRINK", TRUE);
278:
279: CloseHandle (dev);
280: return FALSE;
281: }
282:
283:
284: /* Filesystem sector size */
285:
286: if (ntfsVolData.BytesPerSector > TC_MAX_VOLUME_SECTOR_SIZE
287: || ntfsVolData.BytesPerSector % ENCRYPTION_DATA_UNIT_SIZE != 0)
288: {
289: if (!silent)
290: ShowInPlaceEncErrMsgWAltSteps ("ERR_UNSUPPORTED_SECTOR_SIZE_GENERIC", TRUE);
291:
292: CloseHandle (dev);
293: return FALSE;
294: }
295:
296:
297: CloseHandle (dev);
298: return TRUE;
299: }
300:
301:
302: int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, volatile HANDLE *outHandle, WipeAlgorithmId wipeAlgorithm)
303: {
304: SHRINK_VOLUME_INFORMATION shrinkVolInfo;
305: signed __int64 sizeToShrinkTo;
306: int nStatus = ERR_SUCCESS;
307: PCRYPTO_INFO cryptoInfo = NULL;
308: PCRYPTO_INFO cryptoInfo2 = NULL;
309: HANDLE dev = INVALID_HANDLE_VALUE;
310: DWORD dwError;
311: char *header;
312: char dosDev[TC_MAX_PATH] = {0};
313: char devName[MAX_PATH] = {0};
314: int driveLetter = -1;
315: WCHAR deviceName[MAX_PATH];
316: uint64 dataAreaSize;
317: __int64 deviceSize;
318: LARGE_INTEGER offset;
319: DWORD dwResult;
320:
321: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PREPARING);
322:
323:
324: if (!CheckRequirementsForNonSysInPlaceEnc (volParams->volumePath, FALSE))
325: return ERR_DONT_REPORT;
326:
327:
328: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
329: if (!header)
330: return ERR_OUTOFMEMORY;
331:
332: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
333:
334: deviceSize = GetDeviceSize (volParams->volumePath);
335: if (deviceSize < 0)
336: {
337: // Cannot determine the size of the partition
338: nStatus = ERR_PARAMETER_INCORRECT;
339: goto closing_seq;
340: }
341:
342: if (deviceSize < TC_NONSYS_INPLACE_ENC_MIN_VOL_SIZE)
343: {
344: ShowInPlaceEncErrMsgWAltSteps ("PARTITION_TOO_SMALL_FOR_NONSYS_INPLACE_ENC", TRUE);
345: nStatus = ERR_DONT_REPORT;
346: goto closing_seq;
347: }
348:
349: dataAreaSize = GetVolumeDataAreaSize (volParams->hiddenVol, deviceSize);
350:
351: strcpy ((char *)deviceName, volParams->volumePath);
352: ToUNICODE ((char *)deviceName);
353:
354: driveLetter = GetDiskDeviceDriveLetter (deviceName);
355:
356:
357: if (FakeDosNameForDevice (volParams->volumePath, dosDev, devName, FALSE) != 0)
358: {
359: nStatus = ERR_OS_ERROR;
360: goto closing_seq;
361: }
362:
363: if (IsDeviceMounted (devName))
364: {
365: dev = OpenPartitionVolume (devName,
366: FALSE, // Do not require exclusive access (must be FALSE; otherwise, it will not be possible to dismount the volume or obtain its properties and FSCTL_ALLOW_EXTENDED_DASD_IO will fail too)
367: TRUE, // Require shared access (must be TRUE; otherwise, it will not be possible to dismount the volume or obtain its properties and FSCTL_ALLOW_EXTENDED_DASD_IO will fail too)
368: FALSE, // Do not ask the user to confirm shared access (if exclusive fails)
369: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages)
370: FALSE); // Non-silent mode
371:
372: if (dev == INVALID_HANDLE_VALUE)
373: {
374: nStatus = ERR_DONT_REPORT;
375: goto closing_seq;
376: }
377: }
378: else
379: {
380: // The volume is not mounted so we can't work with the filesystem.
381: Error ("ONLY_MOUNTED_VOL_SUPPORTED_FOR_NONSYS_INPLACE_ENC");
382: nStatus = ERR_DONT_REPORT;
383: goto closing_seq;
384: }
385:
386:
387: /* Gain "raw" access to the partition (the NTFS driver guards hidden sectors). */
388:
389: if (!DeviceIoControl (dev,
390: FSCTL_ALLOW_EXTENDED_DASD_IO,
391: NULL,
392: 0,
393: NULL,
394: 0,
395: &dwResult,
396: NULL))
397: {
398: handleWin32Error (MainDlg);
399: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
400: nStatus = ERR_DONT_REPORT;
401: goto closing_seq;
402: }
403:
404:
405:
406: /* Shrink the filesystem */
407:
408: int64 totalClusterCount;
409: DWORD bytesPerCluster;
410:
411: sizeToShrinkTo = NewFileSysSizeAfterShrink (dev, volParams->volumePath, &totalClusterCount, &bytesPerCluster, FALSE);
412:
413: if (sizeToShrinkTo == -1)
414: {
415: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
416: nStatus = ERR_DONT_REPORT;
417: goto closing_seq;
418: }
419:
420: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_RESIZING);
421:
422: memset (&shrinkVolInfo, 0, sizeof (shrinkVolInfo));
423:
424: shrinkVolInfo.ShrinkRequestType = ShrinkPrepare;
425: shrinkVolInfo.NewNumberOfSectors = sizeToShrinkTo;
426:
427: if (!DeviceIoControl (dev,
428: FSCTL_SHRINK_VOLUME,
429: (LPVOID) &shrinkVolInfo,
430: sizeof (shrinkVolInfo),
431: NULL,
432: 0,
433: &dwResult,
434: NULL))
435: {
436: handleWin32Error (MainDlg);
437: ShowInPlaceEncErrMsgWAltSteps ("CANNOT_RESIZE_FILESYS", TRUE);
438: nStatus = ERR_DONT_REPORT;
439: goto closing_seq;
440: }
441:
442: BOOL clustersMovedBeforeVolumeEnd = FALSE;
443:
444: while (true)
445: {
446: shrinkVolInfo.ShrinkRequestType = ShrinkCommit;
447: shrinkVolInfo.NewNumberOfSectors = 0;
448:
449: if (!DeviceIoControl (dev, FSCTL_SHRINK_VOLUME, &shrinkVolInfo, sizeof (shrinkVolInfo), NULL, 0, &dwResult, NULL))
450: {
451: // If there are any occupied clusters beyond the new desired end of the volume, the call fails with
452: // ERROR_ACCESS_DENIED (STATUS_ALREADY_COMMITTED).
453: if (GetLastError () == ERROR_ACCESS_DENIED)
454: {
455: if (!clustersMovedBeforeVolumeEnd)
456: {
457: if (MoveClustersBeforeThreshold (dev, deviceName, totalClusterCount - (bytesPerCluster > TC_TOTAL_VOLUME_HEADERS_SIZE ? 1 : TC_TOTAL_VOLUME_HEADERS_SIZE / bytesPerCluster)))
458: {
459: clustersMovedBeforeVolumeEnd = TRUE;
460: continue;
461: }
462:
463: handleWin32Error (MainDlg);
464: }
465: }
466: else
467: handleWin32Error (MainDlg);
468:
469: ShowInPlaceEncErrMsgWAltSteps ("CANNOT_RESIZE_FILESYS", TRUE);
470: nStatus = ERR_DONT_REPORT;
471: goto closing_seq;
472: }
473:
474: break;
475: }
476:
477: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PREPARING);
478:
479:
480: /* Gain exclusive access to the volume */
481:
482: nStatus = DismountFileSystem (dev,
483: driveLetter,
484: TRUE,
485: TRUE,
486: FALSE);
487:
488: if (nStatus != ERR_SUCCESS)
489: {
490: nStatus = ERR_DONT_REPORT;
491: goto closing_seq;
492: }
493:
494:
495:
496: /* Create header backup on the partition. Until the volume is fully encrypted, the backup header will provide
497: us with the master key, encrypted range, and other data for pause/resume operations. We cannot create the
498: primary header until the entire partition is encrypted (because we encrypt backwards and the primary header
499: area is occuppied by data until the very end of the process). */
500:
501: // Prepare the backup header
502: nStatus = CreateVolumeHeaderInMemory (FALSE,
503: header,
504: volParams->ea,
505: FIRST_MODE_OF_OPERATION_ID,
506: volParams->password,
507: volParams->pkcs5,
508: NULL,
509: &cryptoInfo,
510: dataAreaSize,
511: 0,
512: TC_VOLUME_DATA_OFFSET + dataAreaSize, // Start of the encrypted area = the first byte of the backup heeader (encrypting from the end)
513: 0, // No data is encrypted yet
514: 0,
515: volParams->headerFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC,
516: FALSE);
517:
518: if (nStatus != 0)
519: goto closing_seq;
520:
521: offset.QuadPart = TC_VOLUME_DATA_OFFSET + dataAreaSize;
522:
523: if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
524: {
525: nStatus = ERR_OS_ERROR;
526: goto closing_seq;
527: }
528:
529: // Write the backup header to the partition
530: if (_lwrite ((HFILE) dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE) == HFILE_ERROR)
531: {
532: nStatus = ERR_OS_ERROR;
533: goto closing_seq;
534: }
535:
536: // Fill the reserved sectors of the backup header area with random data
537: nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, dataAreaSize, FALSE, TRUE);
538:
539: if (nStatus != ERR_SUCCESS)
540: goto closing_seq;
541:
542:
543:
544: /* Now we will try to decrypt the backup header to verify it has been correctly written. */
545:
546: nStatus = OpenBackupHeader (dev, volParams->volumePath, volParams->password, &cryptoInfo2, NULL, deviceSize);
547:
548: if (nStatus != ERR_SUCCESS
549: || cryptoInfo->EncryptedAreaStart.Value != cryptoInfo2->EncryptedAreaStart.Value
550: || cryptoInfo2->EncryptedAreaStart.Value == 0)
551: {
552: if (nStatus == ERR_SUCCESS)
553: nStatus = ERR_PARAMETER_INCORRECT;
554:
555: goto closing_seq;
556: }
557:
558: // The backup header is valid so we know we should be able to safely resume in-place encryption
559: // of this partition even if the system/app crashes.
560:
561:
562:
563: /* Conceal the NTFS filesystem (by performing an easy-to-undo modification). This will prevent Windows
564: and apps from interfering with the volume until it has been fully encrypted. */
565:
566: nStatus = ConcealNTFS (dev);
567:
568: if (nStatus != ERR_SUCCESS)
569: goto closing_seq;
570:
571:
572:
573: // /* If a drive letter is assigned to the device, remove it (so that users do not try to open it, which
574: //would cause Windows to ask them if they want to format the volume and other dangerous things). */
575:
576: //if (driveLetter >= 0)
577: //{
578: // char rootPath[] = { driveLetter + 'A', ':', '\\', 0 };
579:
580: // // Try to remove the assigned drive letter
581: // if (DeleteVolumeMountPoint (rootPath))
582: // driveLetter = -1;
583: //}
584:
585:
586:
587: /* Update config files and app data */
588:
589: // In the config file, increase the number of partitions where in-place encryption is in progress
590:
591: SaveNonSysInPlaceEncSettings (1, wipeAlgorithm);
592:
593:
594: // Add the wizard to the system startup sequence if appropriate
595:
596: if (!IsNonInstallMode ())
597: ManageStartupSeqWiz (FALSE, "/prinplace");
598:
599:
600: nStatus = ERR_SUCCESS;
601:
602:
603: closing_seq:
604:
605: dwError = GetLastError();
606:
607: if (cryptoInfo != NULL)
608: {
609: crypto_close (cryptoInfo);
610: cryptoInfo = NULL;
611: }
612:
613: if (cryptoInfo2 != NULL)
614: {
615: crypto_close (cryptoInfo2);
616: cryptoInfo2 = NULL;
617: }
618:
619: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
620: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
621: TCfree (header);
622:
623: if (dosDev[0])
624: RemoveFakeDosName (volParams->volumePath, dosDev);
625:
626: *outHandle = dev;
627:
628: if (nStatus != ERR_SUCCESS)
629: SetLastError (dwError);
630:
631: return nStatus;
632: }
633:
634:
635: int EncryptPartitionInPlaceResume (HANDLE dev,
636: volatile FORMAT_VOL_PARAMETERS *volParams,
637: WipeAlgorithmId wipeAlgorithm,
638: volatile BOOL *bTryToCorrectReadErrors)
639: {
640: PCRYPTO_INFO masterCryptoInfo = NULL, headerCryptoInfo = NULL, tmpCryptoInfo = NULL;
641: UINT64_STRUCT unitNo;
642: char *buf = NULL, *header = NULL;
643: byte *wipeBuffer = NULL;
644: byte wipeRandChars [TC_WIPE_RAND_CHAR_COUNT];
645: byte wipeRandCharsUpdate [TC_WIPE_RAND_CHAR_COUNT];
646: char dosDev[TC_MAX_PATH] = {0};
647: char devName[MAX_PATH] = {0};
648: WCHAR deviceName[MAX_PATH];
649: int nStatus = ERR_SUCCESS;
650: __int64 deviceSize;
651: uint64 remainingBytes, lastHeaderUpdateDistance = 0, zeroedSectorCount = 0;
652: uint32 workChunkSize;
653: DWORD dwError, dwResult;
654: BOOL bPause = FALSE, bEncryptedAreaSizeChanged = FALSE;
655: LARGE_INTEGER offset;
656: int sectorSize;
657: int i;
658: DWORD n;
659: char *devicePath = volParams->volumePath;
660: Password *password = volParams->password;
661: DISK_GEOMETRY driveGeometry;
662:
663:
664: bInPlaceEncNonSysResumed = TRUE;
665:
666: buf = (char *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE);
667: if (!buf)
668: {
669: nStatus = ERR_OUTOFMEMORY;
670: goto closing_seq;
671: }
672:
673: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
674: if (!header)
675: {
676: nStatus = ERR_OUTOFMEMORY;
677: goto closing_seq;
678: }
679:
680: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
681:
682: if (wipeAlgorithm != TC_WIPE_NONE)
683: {
684: wipeBuffer = (byte *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE);
685: if (!wipeBuffer)
686: {
687: nStatus = ERR_OUTOFMEMORY;
688: goto closing_seq;
689: }
690: }
691:
692: headerCryptoInfo = crypto_open();
693:
694: if (headerCryptoInfo == NULL)
695: {
696: nStatus = ERR_OUTOFMEMORY;
697: goto closing_seq;
698: }
699:
700: deviceSize = GetDeviceSize (devicePath);
701: if (deviceSize < 0)
702: {
703: // Cannot determine the size of the partition
704: nStatus = ERR_OS_ERROR;
705: goto closing_seq;
706: }
707:
708: if (dev == INVALID_HANDLE_VALUE)
709: {
710: strcpy ((char *)deviceName, devicePath);
711: ToUNICODE ((char *)deviceName);
712:
713: if (FakeDosNameForDevice (devicePath, dosDev, devName, FALSE) != 0)
714: {
715: nStatus = ERR_OS_ERROR;
716: goto closing_seq;
717: }
718:
719: dev = OpenPartitionVolume (devName,
720: FALSE, // Do not require exclusive access
721: FALSE, // Do not require shared access
722: TRUE, // Ask the user to confirm shared access (if exclusive fails)
723: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages)
724: FALSE); // Non-silent mode
725:
726: if (dev == INVALID_HANDLE_VALUE)
727: {
728: nStatus = ERR_DONT_REPORT;
729: goto closing_seq;
730: }
731: }
732:
733: // This should never be needed, but is still performed for extra safety (without checking the result)
734: DeviceIoControl (dev,
735: FSCTL_ALLOW_EXTENDED_DASD_IO,
736: NULL,
737: 0,
738: NULL,
739: 0,
740: &dwResult,
741: NULL);
742:
743:
744: if (!DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveGeometry, sizeof (driveGeometry), &dwResult, NULL))
745: {
746: nStatus = ERR_OS_ERROR;
747: goto closing_seq;
748: }
749:
750: sectorSize = driveGeometry.BytesPerSector;
751:
752:
753: nStatus = OpenBackupHeader (dev, devicePath, password, &masterCryptoInfo, headerCryptoInfo, deviceSize);
754:
755: if (nStatus != ERR_SUCCESS)
756: goto closing_seq;
757:
758:
759:
760: remainingBytes = masterCryptoInfo->VolumeSize.Value - masterCryptoInfo->EncryptedAreaLength.Value;
761:
762: lastHeaderUpdateDistance = 0;
763:
764:
765: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value / SECTOR_SIZE);
766:
767: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_ENCRYPTING);
768:
769: bFirstNonSysInPlaceEncResumeDone = TRUE;
770:
771:
772: /* The in-place encryption core */
773:
774: while (remainingBytes > 0)
775: {
776: workChunkSize = (uint32) min (remainingBytes, TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE);
777:
778: if (workChunkSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
779: {
780: nStatus = ERR_PARAMETER_INCORRECT;
781: goto closing_seq;
782: }
783:
784: unitNo.Value = (remainingBytes - workChunkSize + TC_VOLUME_DATA_OFFSET) / ENCRYPTION_DATA_UNIT_SIZE;
785:
786:
787: // Read the plaintext into RAM
788:
789: inplace_enc_read:
790:
791: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET;
792:
793: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
794: {
795: nStatus = ERR_OS_ERROR;
796: goto closing_seq;
797: }
798:
799: if (ReadFile (dev, buf, workChunkSize, &n, NULL) == 0)
800: {
801: // Read error
802:
803: DWORD dwTmpErr = GetLastError ();
804:
805: if (dwTmpErr == ERROR_CRC || dwTmpErr == ERROR_IO_DEVICE)
806: {
807: // Physical defect or data corruption
808:
809: if (!*bTryToCorrectReadErrors)
810: {
811: *bTryToCorrectReadErrors = (AskWarnYesNo ("ENABLE_BAD_SECTOR_ZEROING") == IDYES);
812: }
813:
814: if (*bTryToCorrectReadErrors)
815: {
816: // Try to correct the read errors physically
817:
818: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET;
819:
820: nStatus = ZeroUnreadableSectors (dev, offset, workChunkSize, sectorSize, &zeroedSectorCount);
821:
822: if (nStatus != ERR_SUCCESS)
823: {
824: // Due to write errors, we can't correct the read errors
825: nStatus = ERR_OS_ERROR;
826: goto closing_seq;
827: }
828:
829: goto inplace_enc_read;
830: }
831: }
832:
833: SetLastError (dwTmpErr); // Preserve the original error code
834:
835: nStatus = ERR_OS_ERROR;
836: goto closing_seq;
837: }
838:
839: if (remainingBytes - workChunkSize < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE)
840: {
841: // We reached the inital portion of the filesystem, which we had concealed (in order to prevent
842: // Windows from interfering with the volume). Now we need to undo that modification.
843:
844: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE - (remainingBytes - workChunkSize); i++)
845: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
846: }
847:
848:
849: // Encrypt the plaintext in RAM
850:
851: EncryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
852:
853:
854: // If enabled, wipe the area to which we will write the ciphertext
855:
856: if (wipeAlgorithm != TC_WIPE_NONE)
857: {
858: byte wipePass;
859:
860: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize;
861:
862: for (wipePass = 1; wipePass <= GetWipePassCount (wipeAlgorithm); ++wipePass)
863: {
864: if (!WipeBuffer (wipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, workChunkSize))
865: {
866: ULONG i;
867: for (i = 0; i < workChunkSize; ++i)
868: {
869: wipeBuffer[i] = buf[i] + wipePass;
870: }
871:
872: EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
873: memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate));
874: }
875:
876: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
877: || WriteFile (dev, wipeBuffer, workChunkSize, &n, NULL) == 0)
878: {
879: // Write error
880: dwError = GetLastError();
881:
882: // Undo failed write operation
883: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
884: {
885: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
886: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL);
887: }
888:
889: SetLastError (dwError);
890: nStatus = ERR_OS_ERROR;
891: goto closing_seq;
892: }
893: }
894:
895: memcpy (wipeRandChars, wipeRandCharsUpdate, sizeof (wipeRandCharsUpdate));
896: }
897:
898:
899: // Write the ciphertext
900:
901: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize;
902:
903: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
904: {
905: nStatus = ERR_OS_ERROR;
906: goto closing_seq;
907: }
908:
909: if (WriteFile (dev, buf, workChunkSize, &n, NULL) == 0)
910: {
911: // Write error
912: dwError = GetLastError();
913:
914: // Undo failed write operation
915: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
916: {
917: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
918: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL);
919: }
920:
921: SetLastError (dwError);
922: nStatus = ERR_OS_ERROR;
923: goto closing_seq;
924: }
925:
926:
927: masterCryptoInfo->EncryptedAreaStart.Value -= workChunkSize;
928: masterCryptoInfo->EncryptedAreaLength.Value += workChunkSize;
929:
930: remainingBytes -= workChunkSize;
931: lastHeaderUpdateDistance += workChunkSize;
932:
933: bEncryptedAreaSizeChanged = TRUE;
934:
935: if (lastHeaderUpdateDistance >= TC_NONSYS_INPLACE_ENC_HEADER_UPDATE_INTERVAL)
936: {
937: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize);
938:
939: if (nStatus != ERR_SUCCESS)
940: goto closing_seq;
941:
942: lastHeaderUpdateDistance = 0;
943: }
944:
945: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value / SECTOR_SIZE);
946:
947: if (bVolTransformThreadCancel)
948: {
949: bPause = TRUE;
950: break;
951: }
952: }
953:
954: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize);
955:
956:
957: if (nStatus != ERR_SUCCESS)
958: goto closing_seq;
959:
960:
961: if (!bPause)
962: {
963: /* The data area has been fully encrypted; create and write the primary volume header */
964:
965: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINALIZING);
966:
967: nStatus = CreateVolumeHeaderInMemory (FALSE,
968: header,
969: headerCryptoInfo->ea,
970: headerCryptoInfo->mode,
971: password,
972: masterCryptoInfo->pkcs5,
973: (char *) masterCryptoInfo->master_keydata,
974: &tmpCryptoInfo,
975: masterCryptoInfo->VolumeSize.Value,
976: 0,
977: masterCryptoInfo->EncryptedAreaStart.Value,
978: masterCryptoInfo->EncryptedAreaLength.Value,
979: masterCryptoInfo->RequiredProgramVersion,
980: masterCryptoInfo->HeaderFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC,
981: FALSE);
982:
983: if (nStatus != ERR_SUCCESS)
984: goto closing_seq;
985:
986:
987: offset.QuadPart = TC_VOLUME_HEADER_OFFSET;
988:
989: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
990: || WriteFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
991: {
992: nStatus = ERR_OS_ERROR;
993: goto closing_seq;
994: }
995:
996: // Fill the reserved sectors of the header area with random data
997: nStatus = WriteRandomDataToReservedHeaderAreas (dev, headerCryptoInfo, masterCryptoInfo->VolumeSize.Value, TRUE, FALSE);
998:
999: if (nStatus != ERR_SUCCESS)
1000: goto closing_seq;
1001:
1002:
1003: // Update the configuration files
1004:
1005: SaveNonSysInPlaceEncSettings (-1, wipeAlgorithm);
1006:
1007:
1008:
1009: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINISHED);
1010:
1011: nStatus = ERR_SUCCESS;
1012: }
1013: else
1014: {
1015: // The process has been paused by the user or aborted by the wizard (e.g. on app exit)
1016:
1017: nStatus = ERR_USER_ABORT;
1018:
1019: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PAUSED);
1020: }
1021:
1022:
1023: closing_seq:
1024:
1025: dwError = GetLastError();
1026:
1027: if (bEncryptedAreaSizeChanged
1028: && dev != INVALID_HANDLE_VALUE
1029: && masterCryptoInfo != NULL
1030: && headerCryptoInfo != NULL
1031: && deviceSize > 0)
1032: {
1033: // Execution of the core loop may have been interrupted due to an error or user action without updating the header
1034: FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize);
1035: }
1036:
1037: if (masterCryptoInfo != NULL)
1038: {
1039: crypto_close (masterCryptoInfo);
1040: masterCryptoInfo = NULL;
1041: }
1042:
1043: if (headerCryptoInfo != NULL)
1044: {
1045: crypto_close (headerCryptoInfo);
1046: headerCryptoInfo = NULL;
1047: }
1048:
1049: if (tmpCryptoInfo != NULL)
1050: {
1051: crypto_close (tmpCryptoInfo);
1052: tmpCryptoInfo = NULL;
1053: }
1054:
1055: if (dosDev[0])
1056: RemoveFakeDosName (devicePath, dosDev);
1057:
1058: if (dev != INVALID_HANDLE_VALUE)
1059: {
1060: CloseHandle (dev);
1061: dev = INVALID_HANDLE_VALUE;
1062: }
1063:
1064: if (buf != NULL)
1065: TCfree (buf);
1066:
1067: if (header != NULL)
1068: {
1069: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1070: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1071: TCfree (header);
1072: }
1073:
1074: if (wipeBuffer != NULL)
1075: TCfree (wipeBuffer);
1076:
1077: if (zeroedSectorCount > 0)
1078: {
1079: wchar_t msg[30000] = {0};
1080: wchar_t sizeStr[500] = {0};
1081:
1082: GetSizeString (zeroedSectorCount * sectorSize, sizeStr);
1083:
1084: wsprintfW (msg,
1085: GetString ("ZEROED_BAD_SECTOR_COUNT"),
1086: zeroedSectorCount,
1087: sizeStr);
1088:
1089: WarningDirect (msg);
1090: }
1091:
1092: if (nStatus != ERR_SUCCESS && nStatus != ERR_USER_ABORT)
1093: SetLastError (dwError);
1094:
1095: return nStatus;
1096: }
1097:
1098:
1099: int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_INFO *masterCryptoInfo, __int64 deviceSize)
1100: {
1101: LARGE_INTEGER offset;
1102: DWORD n;
1103: int nStatus = ERR_SUCCESS;
1104: byte *header;
1105: DWORD dwError;
1106: uint32 headerCrc32;
1107: byte *fieldPos;
1108:
1109: header = (byte *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1110:
1111: if (!header)
1112: return ERR_OUTOFMEMORY;
1113:
1114: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1115:
1116:
1117: fieldPos = (byte *) header + TC_HEADER_OFFSET_ENCRYPTED_AREA_START;
1118:
1119: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE;
1120:
1121: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1122: || ReadFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
1123: {
1124: nStatus = ERR_OS_ERROR;
1125: goto closing_seq;
1126: }
1127:
1128:
1129: DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1130:
1131: if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545)
1132: {
1133: nStatus = ERR_PARAMETER_INCORRECT;
1134: goto closing_seq;
1135: }
1136:
1137: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaStart.Value));
1138: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaLength.Value));
1139:
1140:
1141: headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
1142: fieldPos = (byte *) header + TC_HEADER_OFFSET_HEADER_CRC;
1143: mputLong (fieldPos, headerCrc32);
1144:
1145: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1146:
1147:
1148: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1149: || WriteFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
1150: {
1151: nStatus = ERR_OS_ERROR;
1152: goto closing_seq;
1153: }
1154:
1155:
1156: closing_seq:
1157:
1158: dwError = GetLastError();
1159:
1160: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1161: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1162: TCfree (header);
1163:
1164: if (nStatus != ERR_SUCCESS)
1165: SetLastError (dwError);
1166:
1167: return nStatus;
1168: }
1169:
1170:
1171: static HANDLE OpenPartitionVolume (const char *devName,
1172: BOOL bExclusiveRequired,
1173: BOOL bSharedRequired,
1174: BOOL bSharedRequiresConfirmation,
1175: BOOL bShowAlternativeSteps,
1176: BOOL bSilent)
1177: {
1178: HANDLE dev = INVALID_HANDLE_VALUE;
1179: int retryCount = 0;
1180:
1181: if (bExclusiveRequired)
1182: bSharedRequired = FALSE;
1183:
1184: if (bExclusiveRequired || !bSharedRequired)
1185: {
1186: // Exclusive access
1187: // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries).
1188: while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES)
1189: {
1190: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
1191:
1192: if (retryCount > 1)
1193: Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY);
1194: }
1195: }
1196:
1197: if (dev == INVALID_HANDLE_VALUE)
1198: {
1199: if (bExclusiveRequired)
1200: {
1201: if (!bSilent)
1202: {
1203: handleWin32Error (MainDlg);
1204:
1205: if (bShowAlternativeSteps)
1206: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
1207: else
1208: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
1209: }
1210: return INVALID_HANDLE_VALUE;
1211: }
1212:
1213: // Shared mode
1214: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
1215: if (dev != INVALID_HANDLE_VALUE)
1216: {
1217: if (bSharedRequiresConfirmation
1218: && !bSilent
1219: && AskWarnNoYes ("DEVICE_IN_USE_INPLACE_ENC") == IDNO)
1220: {
1221: CloseHandle (dev);
1222: return INVALID_HANDLE_VALUE;
1223: }
1224: }
1225: else
1226: {
1227: if (!bSilent)
1228: {
1229: handleWin32Error (MainDlg);
1230:
1231: if (bShowAlternativeSteps)
1232: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
1233: else
1234: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
1235: }
1236: return INVALID_HANDLE_VALUE;
1237: }
1238: }
1239:
1240: return dev;
1241: }
1242:
1243:
1244: static int DismountFileSystem (HANDLE dev,
1245: int driveLetter,
1246: BOOL bForcedAllowed,
1247: BOOL bForcedRequiresConfirmation,
1248: BOOL bSilent)
1249: {
1250: int attempt;
1251: BOOL bResult;
1252: DWORD dwResult;
1253:
1254: CloseVolumeExplorerWindows (MainDlg, driveLetter);
1255:
1256: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10;
1257:
1258: while (!(bResult = DeviceIoControl (dev, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
1259: && attempt > 0)
1260: {
1261: Sleep (UNMOUNT_AUTO_RETRY_DELAY);
1262: attempt--;
1263: }
1264:
1265: if (!bResult)
1266: {
1267: if (!bForcedAllowed)
1268: {
1269: if (!bSilent)
1270: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE);
1271:
1272: return ERR_DONT_REPORT;
1273: }
1274:
1275: if (bForcedRequiresConfirmation
1276: && !bSilent
1277: && AskWarnYesNo ("VOL_LOCK_FAILED_OFFER_FORCED_DISMOUNT") == IDNO)
1278: {
1279: return ERR_DONT_REPORT;
1280: }
1281: }
1282:
1283: // Dismount the volume
1284:
1285: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10;
1286:
1287: while (!(bResult = DeviceIoControl (dev, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
1288: && attempt > 0)
1289: {
1290: Sleep (UNMOUNT_AUTO_RETRY_DELAY);
1291: attempt--;
1292: }
1293:
1294: if (!bResult)
1295: {
1296: if (!bSilent)
1297: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE);
1298:
1299: return ERR_DONT_REPORT;
1300: }
1301:
1302: return ERR_SUCCESS;
1303: }
1304:
1305:
1306: // Easy-to-undo modification applied to conceal the NTFS filesystem (to prevent Windows and apps from
1307: // interfering with it until the volume has been fully encrypted). Note that this function will precisely
1308: // undo any modifications it made to the filesystem automatically if an error occurs when writing (including
1309: // physical drive defects).
1310: static int ConcealNTFS (HANDLE dev)
1311: {
1312: char buf [TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE];
1313: DWORD nbrBytesProcessed, nbrBytesProcessed2;
1314: int i;
1315: LARGE_INTEGER offset;
1316: DWORD dwError;
1317:
1318: offset.QuadPart = 0;
1319:
1320: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
1321: return ERR_OS_ERROR;
1322:
1323: if (ReadFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
1324: return ERR_OS_ERROR;
1325:
1326: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++)
1327: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
1328:
1329: offset.QuadPart = 0;
1330:
1331: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
1332: return ERR_OS_ERROR;
1333:
1334: if (WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
1335: {
1336: // One or more of the sectors is/are probably damaged and cause write errors.
1337: // We must undo the modifications we made.
1338:
1339: dwError = GetLastError();
1340:
1341: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++)
1342: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
1343:
1344: offset.QuadPart = 0;
1345:
1346: do
1347: {
1348: Sleep (1);
1349: }
1350: while (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1351: || WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed2, NULL) == 0);
1352:
1353: SetLastError (dwError);
1354:
1355: return ERR_OS_ERROR;
1356: }
1357:
1358: return ERR_SUCCESS;
1359: }
1360:
1361:
1362: void ShowInPlaceEncErrMsgWAltSteps (char *iniStrId, BOOL bErr)
1363: {
1364: wchar_t msg[30000];
1365:
1366: wcscpy (msg, GetString (iniStrId));
1367:
1368: wcscat (msg, L"\n\n\n");
1369: wcscat (msg, GetString ("INPLACE_ENC_ALTERNATIVE_STEPS"));
1370:
1371: if (bErr)
1372: ErrorDirect (msg);
1373: else
1374: WarningDirect (msg);
1375: }
1376:
1377:
1378: static void ExportProgressStats (__int64 bytesDone, __int64 totalSectors)
1379: {
1380: NonSysInplaceEncBytesDone = bytesDone;
1381: NonSysInplaceEncTotalSectors = totalSectors;
1382: }
1383:
1384:
1385: void SetNonSysInplaceEncUIStatus (int nonSysInplaceEncStatus)
1386: {
1387: NonSysInplaceEncStatus = nonSysInplaceEncStatus;
1388: }
1389:
1390:
1391: BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm)
1392: {
1393: int count;
1394: char str[32];
1395: WipeAlgorithmId savedWipeAlgorithm = TC_WIPE_NONE;
1396:
1397: if (delta == 0)
1398: return TRUE;
1399:
1400: count = LoadNonSysInPlaceEncSettings (&savedWipeAlgorithm) + delta;
1401:
1402: if (count < 1)
1403: {
1404: if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC)))
1405: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC));
1406:
1407: if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
1408: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE));
1409:
1410: if (!IsNonInstallMode () && SystemEncryptionStatus == SYSENC_STATUS_NONE)
1411: ManageStartupSeqWiz (TRUE, "");
1412:
1413: return TRUE;
1414: }
1415: else
1416: {
1417: if (newWipeAlgorithm != TC_WIPE_NONE)
1418: {
1419: sprintf (str, "%d", (int) newWipeAlgorithm);
1420:
1421: SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE), strlen(str), FALSE);
1422: }
1423: else if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
1424: {
1425: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE));
1426: }
1427:
1428: sprintf (str, "%d", count);
1429:
1430: return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), strlen(str), FALSE);
1431: }
1432: }
1433:
1434:
1435: // Repairs damaged sectors (i.e. those with read errors) by zeroing them.
1436: // Note that this operating fails if there are any write errors.
1437: int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, int sectorSize, uint64 *zeroedSectorCount)
1438: {
1439: int nStatus;
1440: DWORD n;
1441: int64 sectorCount;
1442: LARGE_INTEGER workOffset;
1443: byte *sectorBuffer = NULL;
1444: DWORD dwError;
1445:
1446: workOffset.QuadPart = startOffset.QuadPart;
1447:
1448: sectorBuffer = (byte *) TCalloc (sectorSize);
1449:
1450: if (!sectorBuffer)
1451: return ERR_OUTOFMEMORY;
1452:
1453: if (SetFilePointerEx (dev, startOffset, NULL, FILE_BEGIN) == 0)
1454: {
1455: nStatus = ERR_OS_ERROR;
1456: goto closing_seq;
1457: }
1458:
1459:
1460: for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount)
1461: {
1462: if (ReadFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0)
1463: {
1464: memset (sectorBuffer, 0, sectorSize);
1465:
1466: if (SetFilePointerEx (dev, workOffset, NULL, FILE_BEGIN) == 0)
1467: {
1468: nStatus = ERR_OS_ERROR;
1469: goto closing_seq;
1470: }
1471:
1472: if (WriteFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0)
1473: {
1474: nStatus = ERR_OS_ERROR;
1475: goto closing_seq;
1476: }
1477: ++(*zeroedSectorCount);
1478: }
1479:
1480: workOffset.QuadPart += n;
1481: }
1482:
1483: nStatus = ERR_SUCCESS;
1484:
1485: closing_seq:
1486:
1487: dwError = GetLastError();
1488:
1489: if (sectorBuffer != NULL)
1490: TCfree (sectorBuffer);
1491:
1492: if (nStatus != ERR_SUCCESS)
1493: SetLastError (dwError);
1494:
1495: return nStatus;
1496: }
1497:
1498:
1499: static int OpenBackupHeader (HANDLE dev, const char *devicePath, Password *password, PCRYPTO_INFO *retMasterCryptoInfo, CRYPTO_INFO *headerCryptoInfo, __int64 deviceSize)
1500: {
1501: LARGE_INTEGER offset;
1502: DWORD n;
1503: int nStatus = ERR_SUCCESS;
1504: char *header;
1505: DWORD dwError;
1506:
1507: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1508: if (!header)
1509: return ERR_OUTOFMEMORY;
1510:
1511: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1512:
1513:
1514:
1515: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE;
1516:
1517: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1518: || ReadFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
1519: {
1520: nStatus = ERR_OS_ERROR;
1521: goto closing_seq;
1522: }
1523:
1524:
1525: nStatus = ReadVolumeHeader (FALSE, header, password, retMasterCryptoInfo, headerCryptoInfo);
1526: if (nStatus != ERR_SUCCESS)
1527: goto closing_seq;
1528:
1529:
1530: closing_seq:
1531:
1532: dwError = GetLastError();
1533:
1534: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1535: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1536: TCfree (header);
1537:
1538: dwError = GetLastError();
1539:
1540: if (nStatus != ERR_SUCCESS)
1541: SetLastError (dwError);
1542:
1543: return nStatus;
1544: }
1545:
1546:
1547: static BOOL GetFreeClusterBeforeThreshold (HANDLE volumeHandle, int64 *freeCluster, int64 clusterThreshold)
1548: {
1549: const int bitmapSize = 65536;
1550: byte bitmapBuffer[bitmapSize + sizeof (VOLUME_BITMAP_BUFFER)];
1551: VOLUME_BITMAP_BUFFER *bitmap = (VOLUME_BITMAP_BUFFER *) bitmapBuffer;
1552: STARTING_LCN_INPUT_BUFFER startLcn;
1553: startLcn.StartingLcn.QuadPart = 0;
1554:
1555: DWORD bytesReturned;
1556: while (DeviceIoControl (volumeHandle, FSCTL_GET_VOLUME_BITMAP, &startLcn, sizeof (startLcn), &bitmapBuffer, sizeof (bitmapBuffer), &bytesReturned, NULL)
1557: || GetLastError() == ERROR_MORE_DATA)
1558: {
1559: for (int64 bitmapIndex = 0; bitmapIndex < min (bitmapSize, (bitmap->BitmapSize.QuadPart / 8)); ++bitmapIndex)
1560: {
1561: if (bitmap->StartingLcn.QuadPart + bitmapIndex * 8 >= clusterThreshold)
1562: goto err;
1563:
1564: if (bitmap->Buffer[bitmapIndex] != 0xff)
1565: {
1566: for (int bit = 0; bit < 8; ++bit)
1567: {
1568: if ((bitmap->Buffer[bitmapIndex] & (1 << bit)) == 0)
1569: {
1570: *freeCluster = bitmap->StartingLcn.QuadPart + bitmapIndex * 8 + bit;
1571:
1572: if (*freeCluster >= clusterThreshold)
1573: goto err;
1574:
1575: return TRUE;
1576: }
1577: }
1578: }
1579: }
1580:
1581: startLcn.StartingLcn.QuadPart += min (bitmapSize * 8, bitmap->BitmapSize.QuadPart);
1582: }
1583:
1584: err:
1585: SetLastError (ERROR_DISK_FULL);
1586: return FALSE;
1587: }
1588:
1589:
1590: static BOOL MoveClustersBeforeThresholdInDir (HANDLE volumeHandle, const wstring &directory, int64 clusterThreshold)
1591: {
1592: WIN32_FIND_DATAW findData;
1593:
1594: HANDLE findHandle = FindFirstFileW (((directory.size() <= 3 ? L"" : L"\\\\?\\") + directory + L"\\*").c_str(), &findData);
1595: if (findHandle == INVALID_HANDLE_VALUE)
1596: return TRUE; // Error ignored
1597:
1598: finally_do_arg (HANDLE, findHandle, { FindClose (finally_arg); });
1599:
1600: // Find all files and directories
1601: do
1602: {
1603: if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1604: {
1605: wstring subDir = findData.cFileName;
1606:
1607: if (subDir == L"." || subDir == L"..")
1608: continue;
1609:
1610: if (!MoveClustersBeforeThresholdInDir (volumeHandle, directory + L"\\" + subDir, clusterThreshold))
1611: return FALSE;
1612: }
1613:
1614: DWORD access = FILE_READ_ATTRIBUTES;
1615:
1616: if (findData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
1617: access = FILE_READ_DATA;
1618:
1619: HANDLE fsObject = CreateFileW ((directory + L"\\" + findData.cFileName).c_str(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1620: if (fsObject == INVALID_HANDLE_VALUE)
1621: continue;
1622:
1623: finally_do_arg (HANDLE, fsObject, { CloseHandle (finally_arg); });
1624:
1625: STARTING_VCN_INPUT_BUFFER startVcn;
1626: startVcn.StartingVcn.QuadPart = 0;
1627: RETRIEVAL_POINTERS_BUFFER retPointers;
1628: DWORD bytesReturned;
1629:
1630: // Find clusters allocated beyond the threshold
1631: while (DeviceIoControl (fsObject, FSCTL_GET_RETRIEVAL_POINTERS, &startVcn, sizeof (startVcn), &retPointers, sizeof (retPointers), &bytesReturned, NULL)
1632: || GetLastError() == ERROR_MORE_DATA)
1633: {
1634: if (retPointers.ExtentCount == 0)
1635: break;
1636:
1637: if (retPointers.Extents[0].Lcn.QuadPart != -1)
1638: {
1639: int64 extentStartCluster = retPointers.Extents[0].Lcn.QuadPart;
1640: int64 extentLen = retPointers.Extents[0].NextVcn.QuadPart - retPointers.StartingVcn.QuadPart;
1641: int64 extentEndCluster = extentStartCluster + extentLen - 1;
1642:
1643: if (extentEndCluster >= clusterThreshold)
1644: {
1645: // Move clusters before the threshold
1646: for (int64 movedCluster = max (extentStartCluster, clusterThreshold); movedCluster <= extentEndCluster; ++movedCluster)
1647: {
1648: for (int retry = 0; ; ++retry)
1649: {
1650: MOVE_FILE_DATA moveData;
1651:
1652: if (GetFreeClusterBeforeThreshold (volumeHandle, &moveData.StartingLcn.QuadPart, clusterThreshold))
1653: {
1654: moveData.FileHandle = fsObject;
1655: moveData.StartingVcn.QuadPart = movedCluster - extentStartCluster + retPointers.StartingVcn.QuadPart;
1656: moveData.ClusterCount = 1;
1657:
1658: if (DeviceIoControl (volumeHandle, FSCTL_MOVE_FILE, &moveData, sizeof (moveData), NULL, 0, &bytesReturned, NULL))
1659: break;
1660: }
1661:
1662: if (retry > 200)
1663: return FALSE;
1664:
1665: // There are possible race conditions as we work on a live filesystem
1666: Sleep (100);
1667: }
1668: }
1669: }
1670: }
1671:
1672: startVcn.StartingVcn = retPointers.Extents[0].NextVcn;
1673: }
1674:
1675: } while (FindNextFileW (findHandle, &findData));
1676:
1677: return TRUE;
1678: }
1679:
1680:
1681: BOOL MoveClustersBeforeThreshold (HANDLE volumeHandle, PWSTR volumeDevicePath, int64 clusterThreshold)
1682: {
1683: int drive = GetDiskDeviceDriveLetter (volumeDevicePath);
1684: if (drive == -1)
1685: {
1686: SetLastError (ERROR_INVALID_PARAMETER);
1687: return FALSE;
1688: }
1689:
1690: wstring volumeRoot = L"X:";
1691: volumeRoot[0] = L'A' + drive;
1692:
1693: return MoveClustersBeforeThresholdInDir (volumeHandle, volumeRoot, clusterThreshold);
1694: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.