|
|
1.1 root 1: /*
1.1.1.2 root 2: Copyright (c) 2008-2009 TrueCrypt Foundation. All rights reserved.
1.1 root 3:
1.1.1.3 ! root 4: Governed by the TrueCrypt License 2.7 the full text of which is contained
1.1 root 5: in the file License.txt included in TrueCrypt binary and source code
6: distribution packages.
7: */
8:
9:
1.1.1.2 root 10: /* In this file, _WIN32_WINNT is defined as 0x0600 to make filesystem shrink available (Vista
1.1 root 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
1.1.1.2 root 120: && sscanf (devicePath, "\\Device\\Harddisk%d\\Partition%d", &driveNumber, &partitionNumber) != 2)
1.1 root 121: {
122: if (!silent)
123: Error ("INPLACE_ENC_INVALID_PATH");
124:
125: return FALSE;
126: }
127:
1.1.1.2 root 128: if (partitionNumber == 0)
1.1 root 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
1.1.1.2 root 502: for (int wipePass = 0; wipePass < (wipeAlgorithm == TC_WIPE_NONE ? 1 : PRAND_DISK_WIPE_PASSES); wipePass++)
503: {
504: nStatus = CreateVolumeHeaderInMemory (FALSE,
505: header,
506: volParams->ea,
507: FIRST_MODE_OF_OPERATION_ID,
508: volParams->password,
509: volParams->pkcs5,
510: wipePass == 0 ? NULL : (char *) cryptoInfo->master_keydata,
511: &cryptoInfo,
512: dataAreaSize,
513: 0,
514: TC_VOLUME_DATA_OFFSET + dataAreaSize, // Start of the encrypted area = the first byte of the backup heeader (encrypting from the end)
515: 0, // No data is encrypted yet
516: 0,
517: volParams->headerFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC,
518: wipeAlgorithm == TC_WIPE_NONE ? FALSE : (wipePass < PRAND_DISK_WIPE_PASSES - 1));
1.1 root 519:
1.1.1.2 root 520: if (nStatus != 0)
521: goto closing_seq;
1.1 root 522:
1.1.1.2 root 523: offset.QuadPart = TC_VOLUME_DATA_OFFSET + dataAreaSize;
1.1 root 524:
1.1.1.2 root 525: if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
526: {
527: nStatus = ERR_OS_ERROR;
528: goto closing_seq;
529: }
1.1 root 530:
1.1.1.2 root 531: // Write the backup header to the partition
532: if (_lwrite ((HFILE) dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE) == HFILE_ERROR)
533: {
534: nStatus = ERR_OS_ERROR;
535: goto closing_seq;
536: }
1.1 root 537:
1.1.1.2 root 538: // Fill the reserved sectors of the backup header area with random data
539: nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, dataAreaSize, FALSE, TRUE);
1.1 root 540:
1.1.1.2 root 541: if (nStatus != ERR_SUCCESS)
542: goto closing_seq;
543: }
1.1 root 544:
545:
546: /* Now we will try to decrypt the backup header to verify it has been correctly written. */
547:
548: nStatus = OpenBackupHeader (dev, volParams->volumePath, volParams->password, &cryptoInfo2, NULL, deviceSize);
549:
550: if (nStatus != ERR_SUCCESS
551: || cryptoInfo->EncryptedAreaStart.Value != cryptoInfo2->EncryptedAreaStart.Value
552: || cryptoInfo2->EncryptedAreaStart.Value == 0)
553: {
554: if (nStatus == ERR_SUCCESS)
555: nStatus = ERR_PARAMETER_INCORRECT;
556:
557: goto closing_seq;
558: }
559:
560: // The backup header is valid so we know we should be able to safely resume in-place encryption
561: // of this partition even if the system/app crashes.
562:
563:
564:
565: /* Conceal the NTFS filesystem (by performing an easy-to-undo modification). This will prevent Windows
566: and apps from interfering with the volume until it has been fully encrypted. */
567:
568: nStatus = ConcealNTFS (dev);
569:
570: if (nStatus != ERR_SUCCESS)
571: goto closing_seq;
572:
573:
574:
575: // /* If a drive letter is assigned to the device, remove it (so that users do not try to open it, which
576: //would cause Windows to ask them if they want to format the volume and other dangerous things). */
577:
578: //if (driveLetter >= 0)
579: //{
580: // char rootPath[] = { driveLetter + 'A', ':', '\\', 0 };
581:
582: // // Try to remove the assigned drive letter
583: // if (DeleteVolumeMountPoint (rootPath))
584: // driveLetter = -1;
585: //}
586:
587:
588:
589: /* Update config files and app data */
590:
591: // In the config file, increase the number of partitions where in-place encryption is in progress
592:
593: SaveNonSysInPlaceEncSettings (1, wipeAlgorithm);
594:
595:
596: // Add the wizard to the system startup sequence if appropriate
597:
598: if (!IsNonInstallMode ())
599: ManageStartupSeqWiz (FALSE, "/prinplace");
600:
601:
602: nStatus = ERR_SUCCESS;
603:
604:
605: closing_seq:
606:
607: dwError = GetLastError();
608:
609: if (cryptoInfo != NULL)
610: {
611: crypto_close (cryptoInfo);
612: cryptoInfo = NULL;
613: }
614:
615: if (cryptoInfo2 != NULL)
616: {
617: crypto_close (cryptoInfo2);
618: cryptoInfo2 = NULL;
619: }
620:
621: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
622: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
623: TCfree (header);
624:
625: if (dosDev[0])
626: RemoveFakeDosName (volParams->volumePath, dosDev);
627:
628: *outHandle = dev;
629:
630: if (nStatus != ERR_SUCCESS)
631: SetLastError (dwError);
632:
633: return nStatus;
634: }
635:
636:
637: int EncryptPartitionInPlaceResume (HANDLE dev,
638: volatile FORMAT_VOL_PARAMETERS *volParams,
639: WipeAlgorithmId wipeAlgorithm,
640: volatile BOOL *bTryToCorrectReadErrors)
641: {
642: PCRYPTO_INFO masterCryptoInfo = NULL, headerCryptoInfo = NULL, tmpCryptoInfo = NULL;
643: UINT64_STRUCT unitNo;
644: char *buf = NULL, *header = NULL;
645: byte *wipeBuffer = NULL;
646: byte wipeRandChars [TC_WIPE_RAND_CHAR_COUNT];
647: byte wipeRandCharsUpdate [TC_WIPE_RAND_CHAR_COUNT];
648: char dosDev[TC_MAX_PATH] = {0};
649: char devName[MAX_PATH] = {0};
650: WCHAR deviceName[MAX_PATH];
651: int nStatus = ERR_SUCCESS;
652: __int64 deviceSize;
653: uint64 remainingBytes, lastHeaderUpdateDistance = 0, zeroedSectorCount = 0;
654: uint32 workChunkSize;
655: DWORD dwError, dwResult;
656: BOOL bPause = FALSE, bEncryptedAreaSizeChanged = FALSE;
657: LARGE_INTEGER offset;
658: int sectorSize;
659: int i;
660: DWORD n;
661: char *devicePath = volParams->volumePath;
662: Password *password = volParams->password;
663: DISK_GEOMETRY driveGeometry;
664:
665:
666: bInPlaceEncNonSysResumed = TRUE;
667:
668: buf = (char *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE);
669: if (!buf)
670: {
671: nStatus = ERR_OUTOFMEMORY;
672: goto closing_seq;
673: }
674:
675: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
676: if (!header)
677: {
678: nStatus = ERR_OUTOFMEMORY;
679: goto closing_seq;
680: }
681:
682: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
683:
684: if (wipeAlgorithm != TC_WIPE_NONE)
685: {
686: wipeBuffer = (byte *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE);
687: if (!wipeBuffer)
688: {
689: nStatus = ERR_OUTOFMEMORY;
690: goto closing_seq;
691: }
692: }
693:
694: headerCryptoInfo = crypto_open();
695:
696: if (headerCryptoInfo == NULL)
697: {
698: nStatus = ERR_OUTOFMEMORY;
699: goto closing_seq;
700: }
701:
702: deviceSize = GetDeviceSize (devicePath);
703: if (deviceSize < 0)
704: {
705: // Cannot determine the size of the partition
706: nStatus = ERR_OS_ERROR;
707: goto closing_seq;
708: }
709:
710: if (dev == INVALID_HANDLE_VALUE)
711: {
712: strcpy ((char *)deviceName, devicePath);
713: ToUNICODE ((char *)deviceName);
714:
715: if (FakeDosNameForDevice (devicePath, dosDev, devName, FALSE) != 0)
716: {
717: nStatus = ERR_OS_ERROR;
718: goto closing_seq;
719: }
720:
721: dev = OpenPartitionVolume (devName,
722: FALSE, // Do not require exclusive access
723: FALSE, // Do not require shared access
724: TRUE, // Ask the user to confirm shared access (if exclusive fails)
725: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages)
726: FALSE); // Non-silent mode
727:
728: if (dev == INVALID_HANDLE_VALUE)
729: {
730: nStatus = ERR_DONT_REPORT;
731: goto closing_seq;
732: }
733: }
734:
735: // This should never be needed, but is still performed for extra safety (without checking the result)
736: DeviceIoControl (dev,
737: FSCTL_ALLOW_EXTENDED_DASD_IO,
738: NULL,
739: 0,
740: NULL,
741: 0,
742: &dwResult,
743: NULL);
744:
745:
746: if (!DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveGeometry, sizeof (driveGeometry), &dwResult, NULL))
747: {
748: nStatus = ERR_OS_ERROR;
749: goto closing_seq;
750: }
751:
752: sectorSize = driveGeometry.BytesPerSector;
753:
754:
755: nStatus = OpenBackupHeader (dev, devicePath, password, &masterCryptoInfo, headerCryptoInfo, deviceSize);
756:
757: if (nStatus != ERR_SUCCESS)
758: goto closing_seq;
759:
760:
761:
762: remainingBytes = masterCryptoInfo->VolumeSize.Value - masterCryptoInfo->EncryptedAreaLength.Value;
763:
764: lastHeaderUpdateDistance = 0;
765:
766:
767: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value / SECTOR_SIZE);
768:
769: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_ENCRYPTING);
770:
771: bFirstNonSysInPlaceEncResumeDone = TRUE;
772:
773:
774: /* The in-place encryption core */
775:
776: while (remainingBytes > 0)
777: {
778: workChunkSize = (uint32) min (remainingBytes, TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE);
779:
780: if (workChunkSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
781: {
782: nStatus = ERR_PARAMETER_INCORRECT;
783: goto closing_seq;
784: }
785:
786: unitNo.Value = (remainingBytes - workChunkSize + TC_VOLUME_DATA_OFFSET) / ENCRYPTION_DATA_UNIT_SIZE;
787:
788:
789: // Read the plaintext into RAM
790:
791: inplace_enc_read:
792:
793: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET;
794:
795: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
796: {
797: nStatus = ERR_OS_ERROR;
798: goto closing_seq;
799: }
800:
801: if (ReadFile (dev, buf, workChunkSize, &n, NULL) == 0)
802: {
803: // Read error
804:
805: DWORD dwTmpErr = GetLastError ();
806:
1.1.1.2 root 807: if (IsDiskReadError (dwTmpErr) && !bVolTransformThreadCancel)
1.1 root 808: {
809: // Physical defect or data corruption
810:
811: if (!*bTryToCorrectReadErrors)
812: {
813: *bTryToCorrectReadErrors = (AskWarnYesNo ("ENABLE_BAD_SECTOR_ZEROING") == IDYES);
814: }
815:
816: if (*bTryToCorrectReadErrors)
817: {
818: // Try to correct the read errors physically
819:
820: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET;
821:
822: nStatus = ZeroUnreadableSectors (dev, offset, workChunkSize, sectorSize, &zeroedSectorCount);
823:
824: if (nStatus != ERR_SUCCESS)
825: {
826: // Due to write errors, we can't correct the read errors
827: nStatus = ERR_OS_ERROR;
828: goto closing_seq;
829: }
830:
831: goto inplace_enc_read;
832: }
833: }
834:
835: SetLastError (dwTmpErr); // Preserve the original error code
836:
837: nStatus = ERR_OS_ERROR;
838: goto closing_seq;
839: }
840:
841: if (remainingBytes - workChunkSize < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE)
842: {
843: // We reached the inital portion of the filesystem, which we had concealed (in order to prevent
844: // Windows from interfering with the volume). Now we need to undo that modification.
845:
846: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE - (remainingBytes - workChunkSize); i++)
847: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
848: }
849:
850:
851: // Encrypt the plaintext in RAM
852:
853: EncryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
854:
855:
856: // If enabled, wipe the area to which we will write the ciphertext
857:
858: if (wipeAlgorithm != TC_WIPE_NONE)
859: {
860: byte wipePass;
861:
862: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize;
863:
864: for (wipePass = 1; wipePass <= GetWipePassCount (wipeAlgorithm); ++wipePass)
865: {
866: if (!WipeBuffer (wipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, workChunkSize))
867: {
868: ULONG i;
869: for (i = 0; i < workChunkSize; ++i)
870: {
871: wipeBuffer[i] = buf[i] + wipePass;
872: }
873:
874: EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
875: memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate));
876: }
877:
878: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
879: || WriteFile (dev, wipeBuffer, workChunkSize, &n, NULL) == 0)
880: {
881: // Write error
882: dwError = GetLastError();
883:
884: // Undo failed write operation
885: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
886: {
887: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
888: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL);
889: }
890:
891: SetLastError (dwError);
892: nStatus = ERR_OS_ERROR;
893: goto closing_seq;
894: }
895: }
896:
897: memcpy (wipeRandChars, wipeRandCharsUpdate, sizeof (wipeRandCharsUpdate));
898: }
899:
900:
901: // Write the ciphertext
902:
903: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize;
904:
905: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
906: {
907: nStatus = ERR_OS_ERROR;
908: goto closing_seq;
909: }
910:
911: if (WriteFile (dev, buf, workChunkSize, &n, NULL) == 0)
912: {
913: // Write error
914: dwError = GetLastError();
915:
916: // Undo failed write operation
917: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
918: {
919: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo);
920: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL);
921: }
922:
923: SetLastError (dwError);
924: nStatus = ERR_OS_ERROR;
925: goto closing_seq;
926: }
927:
928:
929: masterCryptoInfo->EncryptedAreaStart.Value -= workChunkSize;
930: masterCryptoInfo->EncryptedAreaLength.Value += workChunkSize;
931:
932: remainingBytes -= workChunkSize;
933: lastHeaderUpdateDistance += workChunkSize;
934:
935: bEncryptedAreaSizeChanged = TRUE;
936:
937: if (lastHeaderUpdateDistance >= TC_NONSYS_INPLACE_ENC_HEADER_UPDATE_INTERVAL)
938: {
939: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize);
940:
941: if (nStatus != ERR_SUCCESS)
942: goto closing_seq;
943:
944: lastHeaderUpdateDistance = 0;
945: }
946:
947: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value / SECTOR_SIZE);
948:
949: if (bVolTransformThreadCancel)
950: {
951: bPause = TRUE;
952: break;
953: }
954: }
955:
956: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize);
957:
958:
959: if (nStatus != ERR_SUCCESS)
960: goto closing_seq;
961:
962:
963: if (!bPause)
964: {
965: /* The data area has been fully encrypted; create and write the primary volume header */
966:
967: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINALIZING);
968:
1.1.1.2 root 969: for (int wipePass = 0; wipePass < (wipeAlgorithm == TC_WIPE_NONE ? 1 : PRAND_DISK_WIPE_PASSES); wipePass++)
970: {
971: nStatus = CreateVolumeHeaderInMemory (FALSE,
972: header,
973: headerCryptoInfo->ea,
974: headerCryptoInfo->mode,
975: password,
976: masterCryptoInfo->pkcs5,
977: (char *) masterCryptoInfo->master_keydata,
978: &tmpCryptoInfo,
979: masterCryptoInfo->VolumeSize.Value,
980: 0,
981: masterCryptoInfo->EncryptedAreaStart.Value,
982: masterCryptoInfo->EncryptedAreaLength.Value,
983: masterCryptoInfo->RequiredProgramVersion,
984: masterCryptoInfo->HeaderFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC,
985: wipeAlgorithm == TC_WIPE_NONE ? FALSE : (wipePass < PRAND_DISK_WIPE_PASSES - 1));
1.1 root 986:
1.1.1.2 root 987: if (nStatus != ERR_SUCCESS)
988: goto closing_seq;
1.1 root 989:
990:
1.1.1.2 root 991: offset.QuadPart = TC_VOLUME_HEADER_OFFSET;
1.1 root 992:
1.1.1.2 root 993: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
994: || WriteFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
995: {
996: nStatus = ERR_OS_ERROR;
997: goto closing_seq;
998: }
1.1 root 999:
1.1.1.2 root 1000: // Fill the reserved sectors of the header area with random data
1001: nStatus = WriteRandomDataToReservedHeaderAreas (dev, headerCryptoInfo, masterCryptoInfo->VolumeSize.Value, TRUE, FALSE);
1.1 root 1002:
1.1.1.2 root 1003: if (nStatus != ERR_SUCCESS)
1004: goto closing_seq;
1005: }
1.1 root 1006:
1007: // Update the configuration files
1008:
1009: SaveNonSysInPlaceEncSettings (-1, wipeAlgorithm);
1010:
1011:
1012:
1013: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINISHED);
1014:
1015: nStatus = ERR_SUCCESS;
1016: }
1017: else
1018: {
1019: // The process has been paused by the user or aborted by the wizard (e.g. on app exit)
1020:
1021: nStatus = ERR_USER_ABORT;
1022:
1023: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PAUSED);
1024: }
1025:
1026:
1027: closing_seq:
1028:
1029: dwError = GetLastError();
1030:
1031: if (bEncryptedAreaSizeChanged
1032: && dev != INVALID_HANDLE_VALUE
1033: && masterCryptoInfo != NULL
1034: && headerCryptoInfo != NULL
1035: && deviceSize > 0)
1036: {
1037: // Execution of the core loop may have been interrupted due to an error or user action without updating the header
1038: FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize);
1039: }
1040:
1041: if (masterCryptoInfo != NULL)
1042: {
1043: crypto_close (masterCryptoInfo);
1044: masterCryptoInfo = NULL;
1045: }
1046:
1047: if (headerCryptoInfo != NULL)
1048: {
1049: crypto_close (headerCryptoInfo);
1050: headerCryptoInfo = NULL;
1051: }
1052:
1053: if (tmpCryptoInfo != NULL)
1054: {
1055: crypto_close (tmpCryptoInfo);
1056: tmpCryptoInfo = NULL;
1057: }
1058:
1059: if (dosDev[0])
1060: RemoveFakeDosName (devicePath, dosDev);
1061:
1062: if (dev != INVALID_HANDLE_VALUE)
1063: {
1064: CloseHandle (dev);
1065: dev = INVALID_HANDLE_VALUE;
1066: }
1067:
1068: if (buf != NULL)
1069: TCfree (buf);
1070:
1071: if (header != NULL)
1072: {
1073: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1074: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1075: TCfree (header);
1076: }
1077:
1078: if (wipeBuffer != NULL)
1079: TCfree (wipeBuffer);
1080:
1081: if (zeroedSectorCount > 0)
1082: {
1083: wchar_t msg[30000] = {0};
1084: wchar_t sizeStr[500] = {0};
1085:
1086: GetSizeString (zeroedSectorCount * sectorSize, sizeStr);
1087:
1088: wsprintfW (msg,
1089: GetString ("ZEROED_BAD_SECTOR_COUNT"),
1090: zeroedSectorCount,
1091: sizeStr);
1092:
1093: WarningDirect (msg);
1094: }
1095:
1096: if (nStatus != ERR_SUCCESS && nStatus != ERR_USER_ABORT)
1097: SetLastError (dwError);
1098:
1099: return nStatus;
1100: }
1101:
1102:
1103: int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_INFO *masterCryptoInfo, __int64 deviceSize)
1104: {
1105: LARGE_INTEGER offset;
1106: DWORD n;
1107: int nStatus = ERR_SUCCESS;
1108: byte *header;
1109: DWORD dwError;
1110: uint32 headerCrc32;
1111: byte *fieldPos;
1112:
1113: header = (byte *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1114:
1115: if (!header)
1116: return ERR_OUTOFMEMORY;
1117:
1118: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1119:
1120:
1121: fieldPos = (byte *) header + TC_HEADER_OFFSET_ENCRYPTED_AREA_START;
1122:
1123: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE;
1124:
1125: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1126: || ReadFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
1127: {
1128: nStatus = ERR_OS_ERROR;
1129: goto closing_seq;
1130: }
1131:
1132:
1133: DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1134:
1135: if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545)
1136: {
1137: nStatus = ERR_PARAMETER_INCORRECT;
1138: goto closing_seq;
1139: }
1140:
1141: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaStart.Value));
1142: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaLength.Value));
1143:
1144:
1145: headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
1146: fieldPos = (byte *) header + TC_HEADER_OFFSET_HEADER_CRC;
1147: mputLong (fieldPos, headerCrc32);
1148:
1149: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1150:
1151:
1152: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1153: || WriteFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
1154: {
1155: nStatus = ERR_OS_ERROR;
1156: goto closing_seq;
1157: }
1158:
1159:
1160: closing_seq:
1161:
1162: dwError = GetLastError();
1163:
1164: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1165: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1166: TCfree (header);
1167:
1168: if (nStatus != ERR_SUCCESS)
1169: SetLastError (dwError);
1170:
1171: return nStatus;
1172: }
1173:
1174:
1175: static HANDLE OpenPartitionVolume (const char *devName,
1176: BOOL bExclusiveRequired,
1177: BOOL bSharedRequired,
1178: BOOL bSharedRequiresConfirmation,
1179: BOOL bShowAlternativeSteps,
1180: BOOL bSilent)
1181: {
1182: HANDLE dev = INVALID_HANDLE_VALUE;
1183: int retryCount = 0;
1184:
1185: if (bExclusiveRequired)
1186: bSharedRequired = FALSE;
1187:
1188: if (bExclusiveRequired || !bSharedRequired)
1189: {
1190: // Exclusive access
1191: // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries).
1192: while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES)
1193: {
1194: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
1195:
1196: if (retryCount > 1)
1197: Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY);
1198: }
1199: }
1200:
1201: if (dev == INVALID_HANDLE_VALUE)
1202: {
1203: if (bExclusiveRequired)
1204: {
1205: if (!bSilent)
1206: {
1207: handleWin32Error (MainDlg);
1208:
1209: if (bShowAlternativeSteps)
1210: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
1211: else
1212: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
1213: }
1214: return INVALID_HANDLE_VALUE;
1215: }
1216:
1217: // Shared mode
1218: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL);
1219: if (dev != INVALID_HANDLE_VALUE)
1220: {
1221: if (bSharedRequiresConfirmation
1222: && !bSilent
1223: && AskWarnNoYes ("DEVICE_IN_USE_INPLACE_ENC") == IDNO)
1224: {
1225: CloseHandle (dev);
1226: return INVALID_HANDLE_VALUE;
1227: }
1228: }
1229: else
1230: {
1231: if (!bSilent)
1232: {
1233: handleWin32Error (MainDlg);
1234:
1235: if (bShowAlternativeSteps)
1236: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE);
1237: else
1238: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL");
1239: }
1240: return INVALID_HANDLE_VALUE;
1241: }
1242: }
1243:
1244: return dev;
1245: }
1246:
1247:
1248: static int DismountFileSystem (HANDLE dev,
1249: int driveLetter,
1250: BOOL bForcedAllowed,
1251: BOOL bForcedRequiresConfirmation,
1252: BOOL bSilent)
1253: {
1254: int attempt;
1255: BOOL bResult;
1256: DWORD dwResult;
1257:
1258: CloseVolumeExplorerWindows (MainDlg, driveLetter);
1259:
1260: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10;
1261:
1262: while (!(bResult = DeviceIoControl (dev, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
1263: && attempt > 0)
1264: {
1265: Sleep (UNMOUNT_AUTO_RETRY_DELAY);
1266: attempt--;
1267: }
1268:
1269: if (!bResult)
1270: {
1271: if (!bForcedAllowed)
1272: {
1273: if (!bSilent)
1274: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE);
1275:
1276: return ERR_DONT_REPORT;
1277: }
1278:
1279: if (bForcedRequiresConfirmation
1280: && !bSilent
1281: && AskWarnYesNo ("VOL_LOCK_FAILED_OFFER_FORCED_DISMOUNT") == IDNO)
1282: {
1283: return ERR_DONT_REPORT;
1284: }
1285: }
1286:
1287: // Dismount the volume
1288:
1289: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10;
1290:
1291: while (!(bResult = DeviceIoControl (dev, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
1292: && attempt > 0)
1293: {
1294: Sleep (UNMOUNT_AUTO_RETRY_DELAY);
1295: attempt--;
1296: }
1297:
1298: if (!bResult)
1299: {
1300: if (!bSilent)
1301: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE);
1302:
1303: return ERR_DONT_REPORT;
1304: }
1305:
1306: return ERR_SUCCESS;
1307: }
1308:
1309:
1310: // Easy-to-undo modification applied to conceal the NTFS filesystem (to prevent Windows and apps from
1311: // interfering with it until the volume has been fully encrypted). Note that this function will precisely
1312: // undo any modifications it made to the filesystem automatically if an error occurs when writing (including
1313: // physical drive defects).
1314: static int ConcealNTFS (HANDLE dev)
1315: {
1316: char buf [TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE];
1317: DWORD nbrBytesProcessed, nbrBytesProcessed2;
1318: int i;
1319: LARGE_INTEGER offset;
1320: DWORD dwError;
1321:
1322: offset.QuadPart = 0;
1323:
1324: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
1325: return ERR_OS_ERROR;
1326:
1327: if (ReadFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
1328: return ERR_OS_ERROR;
1329:
1330: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++)
1331: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
1332:
1333: offset.QuadPart = 0;
1334:
1335: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0)
1336: return ERR_OS_ERROR;
1337:
1338: if (WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0)
1339: {
1340: // One or more of the sectors is/are probably damaged and cause write errors.
1341: // We must undo the modifications we made.
1342:
1343: dwError = GetLastError();
1344:
1345: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++)
1346: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT;
1347:
1348: offset.QuadPart = 0;
1349:
1350: do
1351: {
1352: Sleep (1);
1353: }
1354: while (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1355: || WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed2, NULL) == 0);
1356:
1357: SetLastError (dwError);
1358:
1359: return ERR_OS_ERROR;
1360: }
1361:
1362: return ERR_SUCCESS;
1363: }
1364:
1365:
1366: void ShowInPlaceEncErrMsgWAltSteps (char *iniStrId, BOOL bErr)
1367: {
1368: wchar_t msg[30000];
1369:
1370: wcscpy (msg, GetString (iniStrId));
1371:
1372: wcscat (msg, L"\n\n\n");
1373: wcscat (msg, GetString ("INPLACE_ENC_ALTERNATIVE_STEPS"));
1374:
1375: if (bErr)
1376: ErrorDirect (msg);
1377: else
1378: WarningDirect (msg);
1379: }
1380:
1381:
1382: static void ExportProgressStats (__int64 bytesDone, __int64 totalSectors)
1383: {
1384: NonSysInplaceEncBytesDone = bytesDone;
1385: NonSysInplaceEncTotalSectors = totalSectors;
1386: }
1387:
1388:
1389: void SetNonSysInplaceEncUIStatus (int nonSysInplaceEncStatus)
1390: {
1391: NonSysInplaceEncStatus = nonSysInplaceEncStatus;
1392: }
1393:
1394:
1395: BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm)
1396: {
1397: int count;
1398: char str[32];
1399: WipeAlgorithmId savedWipeAlgorithm = TC_WIPE_NONE;
1400:
1401: if (delta == 0)
1402: return TRUE;
1403:
1404: count = LoadNonSysInPlaceEncSettings (&savedWipeAlgorithm) + delta;
1405:
1406: if (count < 1)
1407: {
1.1.1.2 root 1408: RemoveNonSysInPlaceEncNotifications();
1.1 root 1409: return TRUE;
1410: }
1411: else
1412: {
1413: if (newWipeAlgorithm != TC_WIPE_NONE)
1414: {
1415: sprintf (str, "%d", (int) newWipeAlgorithm);
1416:
1417: SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE), strlen(str), FALSE);
1418: }
1419: else if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
1420: {
1421: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE));
1422: }
1423:
1424: sprintf (str, "%d", count);
1425:
1426: return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), strlen(str), FALSE);
1427: }
1428: }
1429:
1430:
1431: // Repairs damaged sectors (i.e. those with read errors) by zeroing them.
1432: // Note that this operating fails if there are any write errors.
1433: int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, int sectorSize, uint64 *zeroedSectorCount)
1434: {
1435: int nStatus;
1436: DWORD n;
1437: int64 sectorCount;
1438: LARGE_INTEGER workOffset;
1439: byte *sectorBuffer = NULL;
1440: DWORD dwError;
1441:
1442: workOffset.QuadPart = startOffset.QuadPart;
1443:
1444: sectorBuffer = (byte *) TCalloc (sectorSize);
1445:
1446: if (!sectorBuffer)
1447: return ERR_OUTOFMEMORY;
1448:
1449: if (SetFilePointerEx (dev, startOffset, NULL, FILE_BEGIN) == 0)
1450: {
1451: nStatus = ERR_OS_ERROR;
1452: goto closing_seq;
1453: }
1454:
1455:
1456: for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount)
1457: {
1458: if (ReadFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0)
1459: {
1460: memset (sectorBuffer, 0, sectorSize);
1461:
1462: if (SetFilePointerEx (dev, workOffset, NULL, FILE_BEGIN) == 0)
1463: {
1464: nStatus = ERR_OS_ERROR;
1465: goto closing_seq;
1466: }
1467:
1468: if (WriteFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0)
1469: {
1470: nStatus = ERR_OS_ERROR;
1471: goto closing_seq;
1472: }
1473: ++(*zeroedSectorCount);
1474: }
1475:
1476: workOffset.QuadPart += n;
1477: }
1478:
1479: nStatus = ERR_SUCCESS;
1480:
1481: closing_seq:
1482:
1483: dwError = GetLastError();
1484:
1485: if (sectorBuffer != NULL)
1486: TCfree (sectorBuffer);
1487:
1488: if (nStatus != ERR_SUCCESS)
1489: SetLastError (dwError);
1490:
1491: return nStatus;
1492: }
1493:
1494:
1495: static int OpenBackupHeader (HANDLE dev, const char *devicePath, Password *password, PCRYPTO_INFO *retMasterCryptoInfo, CRYPTO_INFO *headerCryptoInfo, __int64 deviceSize)
1496: {
1497: LARGE_INTEGER offset;
1498: DWORD n;
1499: int nStatus = ERR_SUCCESS;
1500: char *header;
1501: DWORD dwError;
1502:
1503: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1504: if (!header)
1505: return ERR_OUTOFMEMORY;
1506:
1507: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1508:
1509:
1510:
1511: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE;
1512:
1513: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0
1514: || ReadFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0)
1515: {
1516: nStatus = ERR_OS_ERROR;
1517: goto closing_seq;
1518: }
1519:
1520:
1521: nStatus = ReadVolumeHeader (FALSE, header, password, retMasterCryptoInfo, headerCryptoInfo);
1522: if (nStatus != ERR_SUCCESS)
1523: goto closing_seq;
1524:
1525:
1526: closing_seq:
1527:
1528: dwError = GetLastError();
1529:
1530: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1531: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
1532: TCfree (header);
1533:
1534: dwError = GetLastError();
1535:
1536: if (nStatus != ERR_SUCCESS)
1537: SetLastError (dwError);
1538:
1539: return nStatus;
1540: }
1541:
1542:
1543: static BOOL GetFreeClusterBeforeThreshold (HANDLE volumeHandle, int64 *freeCluster, int64 clusterThreshold)
1544: {
1545: const int bitmapSize = 65536;
1546: byte bitmapBuffer[bitmapSize + sizeof (VOLUME_BITMAP_BUFFER)];
1547: VOLUME_BITMAP_BUFFER *bitmap = (VOLUME_BITMAP_BUFFER *) bitmapBuffer;
1548: STARTING_LCN_INPUT_BUFFER startLcn;
1549: startLcn.StartingLcn.QuadPart = 0;
1550:
1551: DWORD bytesReturned;
1552: while (DeviceIoControl (volumeHandle, FSCTL_GET_VOLUME_BITMAP, &startLcn, sizeof (startLcn), &bitmapBuffer, sizeof (bitmapBuffer), &bytesReturned, NULL)
1553: || GetLastError() == ERROR_MORE_DATA)
1554: {
1555: for (int64 bitmapIndex = 0; bitmapIndex < min (bitmapSize, (bitmap->BitmapSize.QuadPart / 8)); ++bitmapIndex)
1556: {
1557: if (bitmap->StartingLcn.QuadPart + bitmapIndex * 8 >= clusterThreshold)
1558: goto err;
1559:
1560: if (bitmap->Buffer[bitmapIndex] != 0xff)
1561: {
1562: for (int bit = 0; bit < 8; ++bit)
1563: {
1564: if ((bitmap->Buffer[bitmapIndex] & (1 << bit)) == 0)
1565: {
1566: *freeCluster = bitmap->StartingLcn.QuadPart + bitmapIndex * 8 + bit;
1567:
1568: if (*freeCluster >= clusterThreshold)
1569: goto err;
1570:
1571: return TRUE;
1572: }
1573: }
1574: }
1575: }
1576:
1577: startLcn.StartingLcn.QuadPart += min (bitmapSize * 8, bitmap->BitmapSize.QuadPart);
1578: }
1579:
1580: err:
1581: SetLastError (ERROR_DISK_FULL);
1582: return FALSE;
1583: }
1584:
1585:
1586: static BOOL MoveClustersBeforeThresholdInDir (HANDLE volumeHandle, const wstring &directory, int64 clusterThreshold)
1587: {
1588: WIN32_FIND_DATAW findData;
1589:
1590: HANDLE findHandle = FindFirstFileW (((directory.size() <= 3 ? L"" : L"\\\\?\\") + directory + L"\\*").c_str(), &findData);
1591: if (findHandle == INVALID_HANDLE_VALUE)
1592: return TRUE; // Error ignored
1593:
1594: finally_do_arg (HANDLE, findHandle, { FindClose (finally_arg); });
1595:
1596: // Find all files and directories
1597: do
1598: {
1599: if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1600: {
1601: wstring subDir = findData.cFileName;
1602:
1603: if (subDir == L"." || subDir == L"..")
1604: continue;
1605:
1606: if (!MoveClustersBeforeThresholdInDir (volumeHandle, directory + L"\\" + subDir, clusterThreshold))
1607: return FALSE;
1608: }
1609:
1610: DWORD access = FILE_READ_ATTRIBUTES;
1611:
1612: if (findData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
1613: access = FILE_READ_DATA;
1614:
1615: 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);
1616: if (fsObject == INVALID_HANDLE_VALUE)
1617: continue;
1618:
1619: finally_do_arg (HANDLE, fsObject, { CloseHandle (finally_arg); });
1620:
1621: STARTING_VCN_INPUT_BUFFER startVcn;
1622: startVcn.StartingVcn.QuadPart = 0;
1623: RETRIEVAL_POINTERS_BUFFER retPointers;
1624: DWORD bytesReturned;
1625:
1626: // Find clusters allocated beyond the threshold
1627: while (DeviceIoControl (fsObject, FSCTL_GET_RETRIEVAL_POINTERS, &startVcn, sizeof (startVcn), &retPointers, sizeof (retPointers), &bytesReturned, NULL)
1628: || GetLastError() == ERROR_MORE_DATA)
1629: {
1630: if (retPointers.ExtentCount == 0)
1631: break;
1632:
1633: if (retPointers.Extents[0].Lcn.QuadPart != -1)
1634: {
1635: int64 extentStartCluster = retPointers.Extents[0].Lcn.QuadPart;
1636: int64 extentLen = retPointers.Extents[0].NextVcn.QuadPart - retPointers.StartingVcn.QuadPart;
1637: int64 extentEndCluster = extentStartCluster + extentLen - 1;
1638:
1639: if (extentEndCluster >= clusterThreshold)
1640: {
1641: // Move clusters before the threshold
1642: for (int64 movedCluster = max (extentStartCluster, clusterThreshold); movedCluster <= extentEndCluster; ++movedCluster)
1643: {
1644: for (int retry = 0; ; ++retry)
1645: {
1646: MOVE_FILE_DATA moveData;
1647:
1648: if (GetFreeClusterBeforeThreshold (volumeHandle, &moveData.StartingLcn.QuadPart, clusterThreshold))
1649: {
1650: moveData.FileHandle = fsObject;
1651: moveData.StartingVcn.QuadPart = movedCluster - extentStartCluster + retPointers.StartingVcn.QuadPart;
1652: moveData.ClusterCount = 1;
1653:
1654: if (DeviceIoControl (volumeHandle, FSCTL_MOVE_FILE, &moveData, sizeof (moveData), NULL, 0, &bytesReturned, NULL))
1655: break;
1656: }
1657:
1.1.1.2 root 1658: if (retry > 600)
1.1 root 1659: return FALSE;
1660:
1661: // There are possible race conditions as we work on a live filesystem
1662: Sleep (100);
1663: }
1664: }
1665: }
1666: }
1667:
1668: startVcn.StartingVcn = retPointers.Extents[0].NextVcn;
1669: }
1670:
1671: } while (FindNextFileW (findHandle, &findData));
1672:
1673: return TRUE;
1674: }
1675:
1676:
1677: BOOL MoveClustersBeforeThreshold (HANDLE volumeHandle, PWSTR volumeDevicePath, int64 clusterThreshold)
1678: {
1679: int drive = GetDiskDeviceDriveLetter (volumeDevicePath);
1680: if (drive == -1)
1681: {
1682: SetLastError (ERROR_INVALID_PARAMETER);
1683: return FALSE;
1684: }
1685:
1686: wstring volumeRoot = L"X:";
1687: volumeRoot[0] = L'A' + drive;
1688:
1689: return MoveClustersBeforeThresholdInDir (volumeHandle, volumeRoot, clusterThreshold);
1690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.