[format] add large FAT32 support

* Based on fat32format from Ridgecrop Consultants Ltd:
  http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
* Initial implementation by Tom Ehlert of DriveSnapshot:
  http://www.drivesnapshot.de/en/index.htm
* Closes #101
This commit is contained in:
Pete Batard 2012-11-03 17:40:33 +00:00
parent 8dc5429d9f
commit 22800bb8a5
6 changed files with 473 additions and 29 deletions

View File

@ -1,6 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Formatting function calls
* Copyright (c) 2007-2009 Tom Thornhill/Ridgecrop
* Copyright (c) 2011-2012 Pete Batard <pete@akeo.ie>
*
* This program is free software: you can redistribute it and/or modify
@ -251,6 +252,349 @@ static void ToValidLabel(WCHAR* name, BOOL bFAT)
wchar_to_utf8_no_alloc(name, iso_report.usb_label, sizeof(iso_report.usb_label));
}
/*
* 28.2 CALCULATING THE VOLUME SERIAL NUMBER
*
* For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
* seconds. DOS takes the date and time just before it writes it to the
* disk.
*
* Low order word is calculated: Volume Serial Number is:
* Month & Day 12/26 0c1ah
* Sec & Hundrenths 41:94 295eh 3578:1d02
* -----
* 3578h
*
* High order word is calculated:
* Hours & Minutes 21:55 1537h
* Year 1995 07cbh
* -----
* 1d02h
*/
static DWORD GetVolumeID(void)
{
SYSTEMTIME s;
DWORD d;
WORD lo,hi,tmp;
GetLocalTime(&s);
lo = s.wDay + (s.wMonth << 8);
tmp = (s.wMilliseconds/10) + (s.wSecond << 8);
lo += tmp;
hi = s.wMinute + (s.wHour << 8);
hi += s.wYear;
d = lo + (hi << 16);
return d;
}
/*
* This is the Microsoft calculation from FATGEN
*
* DWORD RootDirSectors = 0;
* DWORD TmpVal1, TmpVal2, FATSz;
*
* TmpVal1 = DskSize - (ReservedSecCnt + RootDirSectors);
* TmpVal2 = (256 * SecPerClus) + NumFATs;
* TmpVal2 = TmpVal2 / 2;
* FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
*
* return( FatSz );
*/
static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPerClus, DWORD NumFATs, DWORD BytesPerSect)
{
ULONGLONG Numerator, Denominator;
ULONGLONG FatElementSize = 4;
ULONGLONG FatSz;
// This is based on
// http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html
Numerator = FatElementSize * (DskSize - ReservedSecCnt);
Denominator = (SecPerClus * BytesPerSect) + (FatElementSize * NumFATs);
FatSz = Numerator / Denominator;
// round up
FatSz += 1;
return (DWORD)FatSz;
}
/*
* Large FAT32 volume formatting from fat32format by Tom Thornhill
* http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
*/
// TODO: disable slow format for > 32 GB FAT32
static BOOL FormatFAT32(DWORD DriveIndex)
{
BOOL r = FALSE;
char DriveLetter;
DWORD i;
HANDLE hLogicalVolume;
DWORD cbRet;
DISK_GEOMETRY dgDrive;
PARTITION_INFORMATION piDrive;
// Recommended values
DWORD ReservedSectCount = 32;
DWORD NumFATs = 2;
DWORD BackupBootSect = 6;
DWORD VolumeId = 0; // calculated before format
WCHAR wLabel[64], wDriveName[] = L"#:\\";
DWORD BurstSize = 128; // Zero in blocks of 64K typically
// Calculated later
DWORD FatSize = 0;
DWORD BytesPerSect = 0;
DWORD ClusterSize = 0;
DWORD SectorsPerCluster = 0;
DWORD TotalSectors = 0;
DWORD SystemAreaSize = 0;
DWORD UserAreaSize = 0;
ULONGLONG qTotalSectors = 0;
// Structures to be written to the disk
FAT_BOOTSECTOR32 *pFAT32BootSect = NULL;
FAT_FSINFO *pFAT32FsInfo = NULL;
DWORD *pFirstSectOfFat = NULL;
BYTE* pZeroSect = NULL;
char VolId[12] = "NO NAME ";
// Debug temp vars
ULONGLONG FatNeeded, ClusterCount;
PrintStatus(0, TRUE, "Formatting...");
uprintf("Using large FAT32 format method\n");
VolumeId = GetVolumeID();
// Open the drive (volume should already be locked)
hLogicalVolume = GetDriveHandle(DriveIndex, &DriveLetter, TRUE, FALSE);
if (IS_ERROR(FormatStatus)) goto out;
if (hLogicalVolume == INVALID_HANDLE_VALUE)
die("Could not access logical volume\n", ERROR_OPEN_FAILED);
// Make sure we get exclusive access
if (!UnmountDrive(hLogicalVolume))
return r;
// Work out drive params
if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dgDrive,
sizeof(dgDrive), &cbRet, NULL)) {
die("Failed to get device geometry\n", ERROR_NOT_SUPPORTED);
}
if (IS_ERROR(FormatStatus)) goto out;
if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &piDrive,
sizeof(piDrive), &cbRet, NULL)) {
die("Failed to get parition info\n", ERROR_NOT_SUPPORTED);
}
BytesPerSect = dgDrive.BytesPerSector;
// Checks on Disk Size
qTotalSectors = piDrive.PartitionLength.QuadPart/dgDrive.BytesPerSector;
// Low end limit - 65536 sectors
if (qTotalSectors < 65536) {
// Most FAT32 implementations would probably mount this volume just fine,
// but the spec says that we shouldn't do this, so we won't
die("This drive is too small for FAT32 - there must be at least 64K clusters\n", APPERR(ERROR_INVALID_CLUSTER_SIZE));
}
if (qTotalSectors >= 0xffffffff) {
// This is a more fundamental limitation on FAT32 - the total sector count in the root dir
// ís 32bit. With a bit of creativity, FAT32 could be extended to handle at least 2^28 clusters
// There would need to be an extra field in the FSInfo sector, and the old sector count could
// be set to 0xffffffff. This is non standard though, the Windows FAT driver FASTFAT.SYS won't
// understand this. Perhaps a future version of FAT32 and FASTFAT will handle this.
die ("This drive is too big for FAT32 - max 2TB supported\n", APPERR(ERROR_INVALID_VOLUME_SIZE));
}
pFAT32BootSect = (FAT_BOOTSECTOR32*) calloc(BytesPerSect, 1);
pFAT32FsInfo = (FAT_FSINFO*) calloc(BytesPerSect, 1);
pFirstSectOfFat = (DWORD*) calloc(BytesPerSect, 1);
if (!pFAT32BootSect || !pFAT32FsInfo || !pFirstSectOfFat) {
die("Failed to allocate memory\n", ERROR_NOT_ENOUGH_MEMORY);
}
// fill out the boot sector and fs info
pFAT32BootSect->sJmpBoot[0]=0xEB;
pFAT32BootSect->sJmpBoot[1]=0x5A;
pFAT32BootSect->sJmpBoot[2]=0x90;
strncpy((char*)pFAT32BootSect->sOEMName, "MSWIN4.1", 8);
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
ClusterSize = ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize));
SectorsPerCluster = ClusterSize / BytesPerSect;
pFAT32BootSect->bSecPerClus = (BYTE) SectorsPerCluster ;
pFAT32BootSect->wRsvdSecCnt = (WORD) ReservedSectCount;
pFAT32BootSect->bNumFATs = (BYTE) NumFATs;
pFAT32BootSect->wRootEntCnt = 0;
pFAT32BootSect->wTotSec16 = 0;
pFAT32BootSect->bMedia = 0xF8;
pFAT32BootSect->wFATSz16 = 0;
pFAT32BootSect->wSecPerTrk = (WORD) dgDrive.SectorsPerTrack;
pFAT32BootSect->wNumHeads = (WORD) dgDrive.TracksPerCylinder;
pFAT32BootSect->dHiddSec = (DWORD) piDrive.HiddenSectors;
TotalSectors = (DWORD) (piDrive.PartitionLength.QuadPart/dgDrive.BytesPerSector);
pFAT32BootSect->dTotSec32 = TotalSectors;
FatSize = GetFATSizeSectors(pFAT32BootSect->dTotSec32, pFAT32BootSect->wRsvdSecCnt,
pFAT32BootSect->bSecPerClus, pFAT32BootSect->bNumFATs, BytesPerSect);
pFAT32BootSect->dFATSz32 = FatSize;
pFAT32BootSect->wExtFlags = 0;
pFAT32BootSect->wFSVer = 0;
pFAT32BootSect->dRootClus = 2;
pFAT32BootSect->wFSInfo = 1;
pFAT32BootSect->wBkBootSec = (WORD) BackupBootSect;
pFAT32BootSect->bDrvNum = 0x80;
pFAT32BootSect->Reserved1 = 0;
pFAT32BootSect->bBootSig = 0x29;
pFAT32BootSect->dBS_VolID = VolumeId;
memcpy(pFAT32BootSect->sVolLab, VolId, 11);
memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8);
((BYTE*)pFAT32BootSect)[510] = 0x55;
((BYTE*)pFAT32BootSect)[511] = 0xaa;
// FATGEN103.DOC says "NOTE: Many FAT documents mistakenly say that this 0xAA55 signature occupies the "last 2 bytes of
// the boot sector". This statement is correct if - and only if - BPB_BytsPerSec is 512. If BPB_BytsPerSec is greater than
// 512, the offsets of these signature bytes do not change (although it is perfectly OK for the last two bytes at the end
// of the boot sector to also contain this signature)."
//
// Windows seems to only check the bytes at offsets 510 and 511. Other OSs might check the ones at the end of the sector,
// so we'll put them there too.
if (BytesPerSect != 512) {
((BYTE*)pFAT32BootSect)[BytesPerSect-2] = 0x55;
((BYTE*)pFAT32BootSect)[BytesPerSect-1] = 0xaa;
}
// FSInfo sect
pFAT32FsInfo->dLeadSig = 0x41615252;
pFAT32FsInfo->dStrucSig = 0x61417272;
pFAT32FsInfo->dFree_Count = (DWORD) -1;
pFAT32FsInfo->dNxt_Free = (DWORD) -1;
pFAT32FsInfo->dTrailSig = 0xaa550000;
// First FAT Sector
pFirstSectOfFat[0] = 0x0ffffff8; // Reserved cluster 1 media id in low byte
pFirstSectOfFat[1] = 0x0fffffff; // Reserved cluster 2 EOC
pFirstSectOfFat[2] = 0x0fffffff; // end of cluster chain for root dir
// Write boot sector, fats
// Sector 0 Boot Sector
// Sector 1 FSInfo
// Sector 2 More boot code - we write zeros here
// Sector 3 unused
// Sector 4 unused
// Sector 5 unused
// Sector 6 Backup boot sector
// Sector 7 Backup FSInfo sector
// Sector 8 Backup 'more boot code'
// zero'd sectors upto ReservedSectCount
// FAT1 ReservedSectCount to ReservedSectCount + FatSize
// ...
// FATn ReservedSectCount to ReservedSectCount + FatSize
// RootDir - allocated to cluster2
UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
ClusterCount = UserAreaSize / SectorsPerCluster;
// Sanity check for a cluster count of >2^28, since the upper 4 bits of the cluster values in
// the FAT are reserved.
if (ClusterCount > 0x0FFFFFFF) {
die("This drive has more than 2^28 clusters, try to specify a larger cluster size or use the default\n",
ERROR_INVALID_CLUSTER_SIZE);
}
// Sanity check - < 64K clusters means that the volume will be misdetected as FAT16
if (ClusterCount < 65536) {
die("FAT32 must have at least 65536 clusters, try to specify a smaller cluster size or use the default\n",
ERROR_INVALID_CLUSTER_SIZE);
}
// Sanity check, make sure the fat is big enough
// Convert the cluster count into a Fat sector count, and check the fat size value we calculated
// earlier is OK.
FatNeeded = ClusterCount * 4;
FatNeeded += (BytesPerSect-1);
FatNeeded /= BytesPerSect;
if (FatNeeded > FatSize) {
die("This drive is too big for large FAT32 format\n", APPERR(ERROR_INVALID_VOLUME_SIZE));
}
// Now we're commited - print some info first
uprintf("Size : %gGB %u sectors\n", (double) (piDrive.PartitionLength.QuadPart / (1000*1000*1000)), TotalSectors);
uprintf("Cluster size %d bytes, %d Bytes Per Sector\n", SectorsPerCluster*BytesPerSect, BytesPerSect);
uprintf("Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff);
uprintf("%d Reserved Sectors, %d Sectors per FAT, %d FATs\n", ReservedSectCount, FatSize, NumFATs);
uprintf("%d Total clusters\n", ClusterCount);
// Fix up the FSInfo sector
pFAT32FsInfo->dFree_Count = (UserAreaSize/SectorsPerCluster) - 1;
pFAT32FsInfo->dNxt_Free = 3; // clusters 0-1 resered, we used cluster 2 for the root dir
uprintf("%d Free Clusters\n", pFAT32FsInfo->dFree_Count);
// Work out the Cluster count
// First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster
SystemAreaSize = ReservedSectCount + (NumFATs*FatSize) + SectorsPerCluster;
uprintf("Clearing out %d sectors for reserved sectors, FATs and root cluster...\n", SystemAreaSize);
// Not the most effective, but easy on RAM
pZeroSect = (BYTE*)calloc(BytesPerSect, BurstSize);
if (!pZeroSect) {
die("Failed to allocate memory\n", ERROR_NOT_ENOUGH_MEMORY);
}
format_percent = 0.0f;
for (i=0; i<(SystemAreaSize+BurstSize-1); i+=BurstSize) {
format_percent = (100.0f*i)/(1.0f*(SystemAreaSize+BurstSize));
PrintStatus(0, FALSE, "Formatting: %d%% completed.", (int)format_percent);
UpdateProgress(OP_FORMAT, format_percent);
if (IS_ERROR(FormatStatus)) goto out; // For cancellation
if (write_sectors(hLogicalVolume, BytesPerSect, i, BurstSize, pZeroSect) != (BytesPerSect*BurstSize)) {
die("Error clearing reserved sectors\n", ERROR_WRITE_FAULT);
}
}
uprintf ("Initialising reserved sectors and FATs...\n");
// Now we should write the boot sector and fsinfo twice, once at 0 and once at the backup boot sect position
for (i=0; i<2; i++) {
int SectorStart = (i==0) ? 0 : BackupBootSect;
write_sectors(hLogicalVolume, BytesPerSect, SectorStart, 1, pFAT32BootSect);
write_sectors(hLogicalVolume, BytesPerSect, SectorStart+1, 1, pFAT32FsInfo);
}
// Write the first fat sector in the right places
for ( i=0; i<NumFATs; i++ ) {
int SectorStart = ReservedSectCount + (i * FatSize );
uprintf("FAT #%d sector at address: %d\n", i, SectorStart);
write_sectors(hLogicalVolume, BytesPerSect, SectorStart, 1, pFirstSectOfFat);
}
// Set the FAT32 volume label
GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel));
ToValidLabel(wLabel, TRUE);
wDriveName[0] = DriveLetter;
// Handle must be closed for SetVolumeLabel to work
safe_closehandle(hLogicalVolume);
PrintStatus(0, TRUE, "Setting Label (This can take while)...");
if (!SetVolumeLabelW(wDriveName, wLabel)) {
uprintf("Could not set label: %s\n", WindowsErrorString());
}
uprintf("Format completed.\n");
r = TRUE;
out:
safe_closehandle(hLogicalVolume);
safe_free(pFAT32BootSect);
safe_free(pFAT32FsInfo);
safe_free(pFirstSectOfFat);
safe_free(pZeroSect);
return r;
}
/*
* Call on fmifs.dll's FormatEx() to format the drive
*/
@ -398,11 +742,24 @@ static BOOL AnalyzePBR(HANDLE hLogicalVolume)
static BOOL ClearMBR(HANDLE hPhysicalDrive)
{
FILE fake_fd = { 0 };
BOOL r = FALSE;
// Clearing the first 64K seems to help with reluctant access to large drive
size_t SectorSize = 65536;
unsigned char* pBuf = (unsigned char*) calloc(SectorSize, 1);
fake_fd._ptr = (char*)hPhysicalDrive;
fake_fd._bufsiz = SelectedDrive.Geometry.BytesPerSector;
return clear_mbr(&fake_fd);
PrintStatus(0, TRUE, "Clearing MBR...");
if (pBuf == NULL) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
goto out;
}
if ((IS_ERROR(FormatStatus)) || (write_sectors(hPhysicalDrive, SectorSize, 0, 1, pBuf) != SectorSize)) {
goto out;
}
r = TRUE;
out:
safe_free(pBuf);
return r;
}
/*
@ -741,6 +1098,10 @@ static BOOL RemountVolume(char drive_letter)
*/
DWORD WINAPI FormatThread(LPVOID param)
{
int r;
int fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
int dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
BOOL ret;
DWORD num = (DWORD)(uintptr_t)param;
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
HANDLE hLogicalVolume = INVALID_HANDLE_VALUE;
@ -749,7 +1110,6 @@ DWORD WINAPI FormatThread(LPVOID param)
char bb_msg[512];
char logfile[MAX_PATH], *userdir;
FILE* log_fd;
int r, fs, dt;
hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE);
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
@ -839,7 +1199,8 @@ DWORD WINAPI FormatThread(LPVOID param)
// before repartitioning. Else, all kind of bad things happen
if (!ClearMBR(hPhysicalDrive)) {
uprintf("unable to zero MBR\n");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
if (!FormatStatus)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
goto out;
}
UpdateProgress(OP_ZERO_MBR, -1.0f);
@ -853,7 +1214,11 @@ DWORD WINAPI FormatThread(LPVOID param)
// Add a small delay after partitioning to be safe
Sleep(200);
if (!FormatDrive(drive_name[0])) {
// If FAT32 is requested and we have a large drive (>32 GB) use
// large FAT32 format, else use MS's FormatEx.
ret = ((fs == FS_FAT32) && (SelectedDrive.DiskSize > LARGE_FAT32_SIZE))?
FormatFAT32(num):FormatDrive(drive_name[0]);
if (!ret) {
// Error will be set by FormatDrive() in FormatStatus
uprintf("Format error: %s\n", StrError(FormatStatus));
goto out;
@ -867,8 +1232,6 @@ DWORD WINAPI FormatThread(LPVOID param)
}
UpdateProgress(OP_FIX_MBR, -1.0f);
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
if (IsChecked(IDC_DOS)) {
if ((dt == DT_WINME) || (dt == DT_FREEDOS) || ((dt == DT_ISO) && (fs == FS_NTFS))) {
// We still have a lock, which we need to modify the volume boot record

View File

@ -1,6 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Formatting function calls
* Copyright (c) 2007-2009 Tom Thornhill/Ridgecrop
* Copyright (c) 2011-2012 Pete Batard <pete@akeo.ie>
*
* This program is free software: you can redistribute it and/or modify
@ -103,3 +104,53 @@ typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)(
WCHAR* DriveRoot,
ULONG CompressionFlags // FILE_SYSTEM_PROP_FLAG
);
/* Large FAT32 */
#pragma pack(push, 1)
typedef struct tagFAT_BOOTSECTOR32
{
// Common fields.
BYTE sJmpBoot[3];
BYTE sOEMName[8];
WORD wBytsPerSec;
BYTE bSecPerClus;
WORD wRsvdSecCnt;
BYTE bNumFATs;
WORD wRootEntCnt;
WORD wTotSec16; // if zero, use dTotSec32 instead
BYTE bMedia;
WORD wFATSz16;
WORD wSecPerTrk;
WORD wNumHeads;
DWORD dHiddSec;
DWORD dTotSec32;
// Fat 32/16 only
DWORD dFATSz32;
WORD wExtFlags;
WORD wFSVer;
DWORD dRootClus;
WORD wFSInfo;
WORD wBkBootSec;
BYTE Reserved[12];
BYTE bDrvNum;
BYTE Reserved1;
BYTE bBootSig; // == 0x29 if next three fields are ok
DWORD dBS_VolID;
BYTE sVolLab[11];
BYTE sBS_FilSysType[8];
} FAT_BOOTSECTOR32;
typedef struct {
DWORD dLeadSig; // 0x41615252
BYTE sReserved1[480]; // zeros
DWORD dStrucSig; // 0x61417272
DWORD dFree_Count; // 0xFFFFFFFF
DWORD dNxt_Free; // 0xFFFFFFFF
BYTE sReserved2[12]; // zeros
DWORD dTrailSig; // 0xAA550000
} FAT_FSINFO;
#pragma pack(pop)
#define die(msg, err) do { uprintf(msg); \
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|err; \
goto out; } while(0)

View File

@ -42,6 +42,10 @@ const char* additional_copyrights =
"http://e2fsprogs.sourceforge.net\r\n"
"GNU General Public License (GPL) v3 compatible\r\n"
"\r\n"
"Large FAT32 volume formatting from fat32format by Tom Thornhill:\r\n"
"http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm\r\n"
"GNU General Public License (GPL) v2 or later\r\n"
"\r\n"
"fmifs.dll usage based on Formatx by Mark Russinovich:\r\n"
"http://doc.sch130.nsc.ru/www.sysinternals.com/ntw2k/source/fmifs.shtml\r\n"
"http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/fmifs\r\n"

View File

@ -124,7 +124,7 @@ static int64_t last_iso_blocking_status;
*/
static int nb_slots[OP_MAX];
static float slot_end[OP_MAX+1]; // shifted +1 so that we can substract 1 to OP indexes
static float previous_end = 0.0f;
static float previous_end;
/*
* Convert a partition type to its human readable form using
@ -164,7 +164,7 @@ static BOOL DefineClusterSizes(void)
}
/*
* The following is MS's allowed cluster sizes for FAT16 and FAT32:
* The following are MS's allowed cluster sizes for FAT16 and FAT32:
*
* FAT16
* 31M : 512 - 4096
@ -188,8 +188,9 @@ static BOOL DefineClusterSizes(void)
* 4095M: 1024 - 32k
* 7GB : 2048 - 64k
* 15GB : 4096 - 64k
* 31GB : 8192 - 64k
* 32GB+: possible but N/A from Microsoft (see below)
* 31GB : 8192 - 64k This is as far as Microsoft's FormatEx goes...
* 63GB : 16k - 64k ...but we can go higher using fat32format from RidgeCrop.
* 2TB+ : N/A
*/
// FAT 16
@ -206,10 +207,11 @@ static BOOL DefineClusterSizes(void)
}
// FAT 32
// > 32GB FAT32 is not supported by MS (and likely FormatEx) but is feasible
// > 32GB FAT32 is not supported by MS and FormatEx but is achieved using fat32fomat
// See: http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
// < 32 MB FAT32 is not allowed by FormatEx
if ((SelectedDrive.DiskSize >= 32*MB) && (SelectedDrive.DiskSize < 32*GB)) {
// < 32 MB FAT32 is not allowed by FormatEx, so we don't bother
if ((SelectedDrive.DiskSize >= 32*MB) && (SelectedDrive.DiskSize < 2*TB)) {
SelectedDrive.ClusterSize[FS_FAT32].Allowed = 0x000001F8;
for (i=32; i<=(32*1024); i<<=1) { // 32 MB -> 32 GB
if (SelectedDrive.DiskSize < i*MB) {
@ -221,7 +223,7 @@ static BOOL DefineClusterSizes(void)
SelectedDrive.ClusterSize[FS_FAT32].Allowed &= 0x0001FE00;
// Default cluster sizes in the 256MB to 32 GB range do not follow the rule above
if (SelectedDrive.DiskSize >= 256*MB) {
if ((SelectedDrive.DiskSize >= 256*MB) && (SelectedDrive.DiskSize < 32*GB)) {
for (i=8; i<=32; i<<=1) { // 256 MB -> 32 GB
if (SelectedDrive.DiskSize < i*GB) {
SelectedDrive.ClusterSize[FS_FAT32].Default = ((ULONG)i/2)*1024;
@ -229,6 +231,11 @@ static BOOL DefineClusterSizes(void)
}
}
}
// More adjustments for large drives
if (SelectedDrive.DiskSize >= 32*GB) {
SelectedDrive.ClusterSize[FS_FAT32].Allowed &= 0x0001C000;
SelectedDrive.ClusterSize[FS_FAT32].Default = 0x00008000;
}
}
// NTFS
@ -484,12 +491,10 @@ static void SetFSFromISO(void)
void SetMBRProps(void)
{
int fs, dt;
int fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
int dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
BOOL needs_masquerading = (IS_WINPE(iso_report.winpe) && (!iso_report.uses_minint));
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
if ((!mbr_selected_by_user) && ((iso_path == NULL) || (dt != DT_ISO) || (fs != FS_NTFS))) {
CheckDlgButton(hMainDialog, IDC_RUFUS_MBR, BST_UNCHECKED);
IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0));
@ -812,6 +817,10 @@ static void InitProgress(void)
memset(&slot_end, 0, sizeof(slot_end));
previous_end = 0.0f;
memset(nb_slots, 0, sizeof(nb_slots));
memset(slot_end, 0, sizeof(slot_end));
previous_end = 0.0f;
nb_slots[OP_ZERO_MBR] = 1;
if (IsChecked(IDC_BADBLOCKS)) {
nb_slots[OP_BADBLOCKS] = -1;
@ -837,7 +846,8 @@ static void InitProgress(void)
nb_slots[OP_FIX_MBR] = 1;
nb_slots[OP_CREATE_FS] =
nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))];
if (!IsChecked(IDC_QUICKFORMAT)) {
if ( (!IsChecked(IDC_QUICKFORMAT))
|| ((fs == FS_FAT32) && (SelectedDrive.DiskSize >= LARGE_FAT32_SIZE)) ) {
nb_slots[OP_FORMAT] = -1;
}
nb_slots[OP_FINALIZE] = ((dt == DT_ISO) && (fs == FS_NTFS))?2:1;
@ -1512,7 +1522,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
int nDeviceIndex, fs, i, nWidth, nHeight;
static DWORD DeviceNum = 0;
wchar_t wtmp[128], wstr[MAX_PATH];
static UINT uDOSChecked = BST_CHECKED;
static UINT uDOSChecked = BST_CHECKED, uQFChecked;
static BOOL first_log_display = TRUE;
switch (message) {
@ -1625,6 +1635,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
PrintStatus(0, TRUE, "%d device%s found.", ComboBox_GetCount(hDeviceList),
(ComboBox_GetCount(hDeviceList)!=1)?"s":"");
PopulateProperties(ComboBox_GetCurSel(hDeviceList));
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM,
ComboBox_GetCurSel(hFileSystem));
break;
case IDC_NBPASSES:
if (HIWORD(wParam) != CBN_SELCHANGE)
@ -1649,6 +1661,19 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break;
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
SetClusterSizes(fs);
// Disable/restore the quick format control depending on large FAT32
if ((fs == FS_FAT32) && (SelectedDrive.DiskSize > LARGE_FAT32_SIZE)) {
if (IsWindowEnabled(GetDlgItem(hMainDialog, IDC_QUICKFORMAT))) {
uQFChecked = IsDlgButtonChecked(hMainDialog, IDC_QUICKFORMAT);
CheckDlgButton(hMainDialog, IDC_QUICKFORMAT, BST_CHECKED);
EnableWindow(GetDlgItem(hMainDialog, IDC_QUICKFORMAT), FALSE);
}
} else {
if (!IsWindowEnabled(GetDlgItem(hMainDialog, IDC_QUICKFORMAT))) {
CheckDlgButton(hMainDialog, IDC_QUICKFORMAT, uQFChecked);
EnableWindow(GetDlgItem(hMainDialog, IDC_QUICKFORMAT), TRUE);
}
}
if (fs < 0) {
EnableBootOptions(TRUE);
SetMBRProps();

View File

@ -37,6 +37,7 @@
#define MAX_LOG_SIZE 0x7FFFFFFE
#define PROPOSEDLABEL_TOLERANCE 0.10
#define FS_DEFAULT FS_FAT32
#define LARGE_FAT32_SIZE (32*1073741824LL) // Size at which we need to use fat32format
#define WHITE RGB(255,255,255)
#define SEPARATOR_GREY RGB(223,223,223)
#define RUFUS_URL "http://rufus.akeo.ie"

View File

@ -30,7 +30,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 316
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.2.0.185"
CAPTION "Rufus v1.2.0.186"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,278,50,14
@ -77,7 +77,7 @@ BEGIN
DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP
CONTROL "<a href=""http://rufus.akeo.ie"">http://rufus.akeo.ie</a>",IDC_ABOUT_RUFUS_URL,
"SysLink",WS_TABSTOP,46,47,114,9
LTEXT "Version 1.2.0 (Build 185)",IDC_STATIC,46,19,78,8
LTEXT "Version 1.2.0 (Build 186)",IDC_STATIC,46,19,78,8
PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP
EDITTEXT IDC_ABOUT_COPYRIGHTS,46,107,235,63,ES_MULTILINE | ES_READONLY | WS_VSCROLL
LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8
@ -237,8 +237,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,0,185
PRODUCTVERSION 1,2,0,185
FILEVERSION 1,2,0,186
PRODUCTVERSION 1,2,0,186
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -255,13 +255,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.2.0.185"
VALUE "FileVersion", "1.2.0.186"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.2.0.185"
VALUE "ProductVersion", "1.2.0.186"
END
END
BLOCK "VarFileInfo"