From 579ce2fd31f01b0befba947ed863ed1d5e4be3f0 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Wed, 28 Jun 2023 00:47:58 +0200 Subject: Windows: Better handling of quick format for file container We write a zeroed sector every 128 MiB, leaving other sectors untouched This helps users visualize the progress of actual file creation while forcing Windows to allocate the disk space of each 128 MiB chunk immediately, otherwise, Windows would delay the allocation until we write the backup header at the end of the volume which would make the user think that the format process has stalled after progress bar reaches 100%. --- src/Common/Fat.c | 63 +++++++++++++++++++++++++++++++++++++++++++---------- src/Common/Fat.h | 2 +- src/Common/Format.c | 56 ++++++++++++++++++++++++++++++++++++++++------- src/Common/Format.h | 5 +++-- 4 files changed, 104 insertions(+), 22 deletions(-) (limited to 'src/Common') diff --git a/src/Common/Fat.c b/src/Common/Fat.c index cd2c124f..19720b17 100644 --- a/src/Common/Fat.c +++ b/src/Common/Fat.c @@ -255,11 +255,14 @@ static void PutFSInfo (unsigned char *sector, fatparams *ft) int -FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat) +FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat, BOOL bDevice) { int write_buf_cnt = 0; char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf; unsigned __int64 nSecNo = startSector; + unsigned __int64 nSkipSectors = 128 * (unsigned __int64) BYTES_PER_MB / ft->sector_size; + unsigned __int64 num_sectors; + DWORD bytesWritten; int x, n; int retVal; CRYPTOPP_ALIGN_DATA(16) char temporaryKey[MASTER_KEYDATA_SIZE]; @@ -288,7 +291,7 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void goto fail; PutBoot (ft, (unsigned char *) sector); - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; @@ -297,7 +300,7 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void { /* fsinfo */ PutFSInfo((unsigned char *) sector, ft); - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; @@ -307,7 +310,7 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void memset (sector, 0, ft->sector_size); sector[508+3]=0xaa; /* TrailSig */ sector[508+2]=0x55; - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; } @@ -315,12 +318,12 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void /* bootsector backup */ memset (sector, 0, ft->sector_size); PutBoot (ft, (unsigned char *) sector); - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; PutFSInfo((unsigned char *) sector, ft); - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; } @@ -329,7 +332,7 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void while (nSecNo - startSector < (unsigned int)ft->reserved) { memset (sector, 0, ft->sector_size); - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; } @@ -373,7 +376,7 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void } } - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; } @@ -384,7 +387,7 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void for (x = 0; x < ft->size_root_dir / ft->sector_size; x++) { memset (sector, 0, ft->sector_size); - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; @@ -450,11 +453,11 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void x = ft->num_sectors - ft->reserved - ft->size_root_dir / ft->sector_size - ft->fat_length * 2; while (x--) { - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; } - UpdateProgressBar (nSecNo * ft->sector_size); + UpdateProgressBar ((nSecNo - startSector) * ft->sector_size); if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo)) { @@ -466,6 +469,44 @@ FormatFat (void* hwndDlgPtr, unsigned __int64 startSector, fatparams * ft, void burn (&tmpCI, sizeof (tmpCI)); VirtualUnlock (&tmpCI, sizeof (tmpCI)); } + else if (!bDevice) + { + if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo)) + goto fail; + + // Quick format: write a zeroed sector every 128 MiB, leaving other sectors untouched + // This helps users visualize the progress of actual file creation while forcing Windows + // to allocate the disk space of each 128 MiB chunk immediately, otherwise, Windows + // would delay the allocation until we write the backup header at the end of the volume which + // would make the user think that the format process has stalled after progress bar reaches 100%. + num_sectors = ft->num_sectors - ft->reserved - ft->size_root_dir / ft->sector_size - ft->fat_length * 2; + while (num_sectors >= nSkipSectors) + { + // seek to next sector to be written + nSecNo += (nSkipSectors - 1); + startOffset.QuadPart = nSecNo * ft->sector_size; + if (!MoveFilePointer ((HANDLE) dev, startOffset)) + { + goto fail; + } + + // sector array has been zeroed above + if (!WriteFile ((HANDLE) dev, sector, ft->sector_size, &bytesWritten, NULL) + || bytesWritten != ft->sector_size) + { + goto fail; + } + + nSecNo++; + num_sectors -= nSkipSectors; + + if (UpdateProgressBar ((nSecNo - startSector)* ft->sector_size)) + goto fail; + } + + nSecNo += num_sectors; + UpdateProgressBar ((nSecNo - startSector)* ft->sector_size); + } else { UpdateProgressBar ((uint64) ft->num_sectors * ft->sector_size); diff --git a/src/Common/Fat.h b/src/Common/Fat.h index 375b9dc2..b2457be2 100644 --- a/src/Common/Fat.h +++ b/src/Common/Fat.h @@ -66,4 +66,4 @@ struct msdos_boot_sector void GetFatParams ( fatparams *ft ); void PutBoot ( fatparams *ft , unsigned char *boot ); -int FormatFat (void* hwndDlg, unsigned __int64 startSector, fatparams * ft, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat); +int FormatFat (void* hwndDlg, unsigned __int64 startSector, fatparams * ft, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat, BOOL bDevice); diff --git a/src/Common/Format.c b/src/Common/Format.c index f34ee39b..15ca9518 100644 --- a/src/Common/Format.c +++ b/src/Common/Format.c @@ -538,7 +538,7 @@ begin_format: goto error; } - nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat); + nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat, volParams->bDevice); if (volParams->bDevice) StopFormatWriteThread(); @@ -571,7 +571,7 @@ begin_format: goto error; } - nStatus = FormatFat (hwndDlg, startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat); + nStatus = FormatFat (hwndDlg, startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat, volParams->bDevice); if (volParams->bDevice) StopFormatWriteThread(); @@ -847,11 +847,13 @@ fv_end: } -int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat) +int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, unsigned __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat, BOOL bDevice) { int write_buf_cnt = 0; char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf; unsigned __int64 nSecNo = startSector; + unsigned __int64 nSkipSectors = 128 * (unsigned __int64) BYTES_PER_MB / FormatSectorSize; + DWORD bytesWritten; int retVal = 0; DWORD err; CRYPTOPP_ALIGN_DATA(16) char temporaryKey[MASTER_KEYDATA_SIZE]; @@ -927,18 +929,56 @@ int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, while (num_sectors--) { - if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, startSector, cryptoInfo) == FALSE) goto fail; } + if (UpdateProgressBar ((nSecNo - startSector) * FormatSectorSize)) + return FALSE; + if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo)) goto fail; } + else if (!bDevice) + { + // Quick format: write a zeroed sector every 128 MiB, leaving other sectors untouched + // This helps users visualize the progress of actual file creation while forcing Windows + // to allocate the disk space of each 128 MiB chunk immediately, otherwise, Windows + // would delay the allocation until we write the backup header at the end of the volume which + // would make the user think that the format process has stalled after progress bar reaches 100%. + while (num_sectors >= nSkipSectors) + { + // seek to next sector to be written + nSecNo += (nSkipSectors - 1); + startOffset.QuadPart = nSecNo * FormatSectorSize; + if (!MoveFilePointer ((HANDLE) dev, startOffset)) + { + goto fail; + } + + // sector array has been zeroed above + if (!WriteFile ((HANDLE) dev, sector, FormatSectorSize, &bytesWritten, NULL) + || bytesWritten != FormatSectorSize) + { + goto fail; + } + + nSecNo++; + num_sectors -= nSkipSectors; + + if (UpdateProgressBar ((nSecNo - startSector)* FormatSectorSize)) + goto fail; + } + + nSecNo += num_sectors; + } else - nSecNo = num_sectors; + { + nSecNo += num_sectors; + } - UpdateProgressBar (nSecNo * FormatSectorSize); + UpdateProgressBar ((nSecNo - startSector) * FormatSectorSize); // Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2)); @@ -1269,7 +1309,7 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType) BOOL WriteSector (void *dev, char *sector, char *write_buf, int *write_buf_cnt, - __int64 *nSecNo, PCRYPTO_INFO cryptoInfo) + unsigned __int64 *nSecNo, unsigned __int64 startSector, PCRYPTO_INFO cryptoInfo) { static __int32 updateTime = 0; @@ -1283,7 +1323,7 @@ BOOL WriteSector (void *dev, char *sector, if (GetTickCount () - updateTime > 25) { - if (UpdateProgressBar (*nSecNo * FormatSectorSize)) + if (UpdateProgressBar ((*nSecNo - startSector) * FormatSectorSize)) return FALSE; updateTime = GetTickCount (); diff --git a/src/Common/Format.h b/src/Common/Format.h index 139607e5..f5d65f14 100644 --- a/src/Common/Format.h +++ b/src/Common/Format.h @@ -78,11 +78,12 @@ BOOL FormatNtfs (int driveNo, int clusterSize); BOOL FormatFs (int driveNo, int clusterSize, int fsType); BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType); uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize); -int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void *dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat); -BOOL WriteSector ( void *dev , char *sector , char *write_buf , int *write_buf_cnt , __int64 *nSecNo , PCRYPTO_INFO cryptoInfo ); +int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, unsigned __int64 num_sectors, void *dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat, BOOL bDevice); +BOOL WriteSector ( void *dev , char *sector , char *write_buf , int *write_buf_cnt , unsigned __int64 *nSecNo , unsigned __int64 startSector, PCRYPTO_INFO cryptoInfo ); BOOL FlushFormatWriteBuffer (void *dev, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo); static BOOL StartFormatWriteThread (); static void StopFormatWriteThread (); +BOOL MoveFilePointer (HANDLE dev, LARGE_INTEGER offset); #define FILESYS_NONE 0 #define FILESYS_FAT 1 -- cgit v1.2.3