mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[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:
parent
8dc5429d9f
commit
22800bb8a5
6 changed files with 473 additions and 29 deletions
381
src/format.c
381
src/format.c
|
@ -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
|
||||
|
|
51
src/format.h
51
src/format.h
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
53
src/rufus.c
53
src/rufus.c
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
12
src/rufus.rc
12
src/rufus.rc
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue