diff --git a/.vs/rufus.vcxproj b/.vs/rufus.vcxproj
index 6a4fcc47..9aef5e72 100644
--- a/.vs/rufus.vcxproj
+++ b/.vs/rufus.vcxproj
@@ -337,6 +337,8 @@
+
+
diff --git a/.vs/rufus.vcxproj.filters b/.vs/rufus.vcxproj.filters
index 97df1b3a..1e5e232d 100644
--- a/.vs/rufus.vcxproj.filters
+++ b/.vs/rufus.vcxproj.filters
@@ -81,6 +81,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 38dba118..5d9fcfc1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,7 +10,7 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V))
%_rc.o: %.rc ../res/loc/embedded.loc
$(AM_V_WINDRES) $(AM_RCFLAGS) -i $< -o $@
-rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \
+rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c format_ext.c format_fat32.c icon.c iso.c localization.c \
net.c parser.c pki.c process.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c ui.c vhd.c
rufus_CFLAGS = -I$(srcdir)/ms-sys/inc -I$(srcdir)/syslinux/libfat -I$(srcdir)/syslinux/libinstaller -I$(srcdir)/syslinux/win -I$(srcdir)/libcdio $(AM_CFLAGS) \
-DEXT2_FLAT_INCLUDES=0
diff --git a/src/Makefile.in b/src/Makefile.in
index 1db35975..bf95bce1 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -90,7 +90,8 @@ PROGRAMS = $(noinst_PROGRAMS)
am_rufus_OBJECTS = rufus-badblocks.$(OBJEXT) rufus-checksum.$(OBJEXT) \
rufus-dev.$(OBJEXT) rufus-dos.$(OBJEXT) \
rufus-dos_locale.$(OBJEXT) rufus-drive.$(OBJEXT) \
- rufus-format.$(OBJEXT) rufus-icon.$(OBJEXT) \
+ rufus-format.$(OBJEXT) rufus-format_ext.$(OBJEXT) \
+ rufus-format_fat32.$(OBJEXT) rufus-icon.$(OBJEXT) \
rufus-iso.$(OBJEXT) rufus-localization.$(OBJEXT) \
rufus-net.$(OBJEXT) rufus-parser.$(OBJEXT) rufus-pki.$(OBJEXT) \
rufus-process.$(OBJEXT) rufus-rufus.$(OBJEXT) \
@@ -272,7 +273,7 @@ AM_V_WINDRES_0 = @echo " RC $@";$(WINDRES)
AM_V_WINDRES_1 = $(WINDRES)
AM_V_WINDRES_ = $(AM_V_WINDRES_$(AM_DEFAULT_VERBOSITY))
AM_V_WINDRES = $(AM_V_WINDRES_$(V))
-rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \
+rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c format_ext.c format_fat32.c icon.c iso.c localization.c \
net.c parser.c pki.c process.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c ui.c vhd.c
rufus_CFLAGS = -I$(srcdir)/ms-sys/inc -I$(srcdir)/syslinux/libfat -I$(srcdir)/syslinux/libinstaller -I$(srcdir)/syslinux/win -I$(srcdir)/libcdio $(AM_CFLAGS) \
@@ -378,6 +379,18 @@ rufus-format.o: format.c
rufus-format.obj: format.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-format.obj `if test -f 'format.c'; then $(CYGPATH_W) 'format.c'; else $(CYGPATH_W) '$(srcdir)/format.c'; fi`
+rufus-format_ext.o: format_ext.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-format_ext.o `test -f 'format_ext.c' || echo '$(srcdir)/'`format_ext.c
+
+rufus-format_ext.obj: format_ext.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-format_ext.obj `if test -f 'format_ext.c'; then $(CYGPATH_W) 'format_ext.c'; else $(CYGPATH_W) '$(srcdir)/format_ext.c'; fi`
+
+rufus-format_fat32.o: format_fat32.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-format_fat32.o `test -f 'format_fat32.c' || echo '$(srcdir)/'`format_fat32.c
+
+rufus-format_fat32.obj: format_fat32.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-format_fat32.obj `if test -f 'format_fat32.c'; then $(CYGPATH_W) 'format_fat32.c'; else $(CYGPATH_W) '$(srcdir)/format_fat32.c'; fi`
+
rufus-icon.o: icon.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-icon.o `test -f 'icon.c' || echo '$(srcdir)/'`icon.c
diff --git a/src/format.c b/src/format.c
index 950ba564..78ce2577 100644
--- a/src/format.c
+++ b/src/format.c
@@ -1,7 +1,6 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Formatting function calls
- * Copyright © 2007-2009 Tom Thornhill/Ridgecrop
* Copyright © 2011-2020 Pete Batard
*
* This program is free software: you can redistribute it and/or modify
@@ -70,7 +69,6 @@ extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive,
extern BOOL use_vds;
uint8_t *grub2_buf = NULL, *sec_buf = NULL;
long grub2_len;
-static BOOL WritePBR(HANDLE hLogicalDrive);
/*
* Convert the fmifs outputs messages (that use an OEM code page) to UTF-8
@@ -313,799 +311,6 @@ static void ToValidLabel(char* Label, BOOL bFAT)
free(wLabel);
}
-/*
- * 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 & Hundredths 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;
-}
-
-/*
- * Proper computation of FAT size
- * See: http://www.syslinux.org/archives/2016-February/024850.html
- * and subsequent replies.
- */
-static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPerClus, DWORD NumFATs, DWORD BytesPerSect)
-{
- ULONGLONG Numerator, Denominator;
- ULONGLONG FatElementSize = 4;
- ULONGLONG ReservedClusCnt = 2;
- ULONGLONG FatSz;
-
- Numerator = DskSize - ReservedSecCnt + ReservedClusCnt * SecPerClus;
- Denominator = SecPerClus * BytesPerSect / FatElementSize + NumFATs;
- FatSz = Numerator / Denominator + 1; // +1 to ensure we are rounded up
-
- return (DWORD)FatSz;
-}
-
-/*
- * Large FAT32 volume formatting from fat32format by Tom Thornhill
- * http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
- */
-static BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags)
-{
- BOOL r = FALSE;
- DWORD i;
- HANDLE hLogicalVolume = NULL;
- DWORD cbRet;
- DISK_GEOMETRY dgDrive;
- BYTE geometry_ex[256]; // DISK_GEOMETRY_EX is variable size
- PDISK_GEOMETRY_EX xdgDrive = (PDISK_GEOMETRY_EX)(void*)geometry_ex;
- PARTITION_INFORMATION piDrive;
- PARTITION_INFORMATION_EX xpiDrive;
- // Recommended values
- DWORD ReservedSectCount = 32;
- DWORD NumFATs = 2;
- DWORD BackupBootSect = 6;
- DWORD VolumeId = 0; // calculated before format
- char* VolumeName = NULL;
- DWORD BurstSize = 128; // Zero in blocks of 64K typically
-
- // Calculated later
- DWORD FatSize = 0;
- DWORD BytesPerSect = 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;
-
- if (safe_strncmp(FSName, "FAT", 3) != 0) {
- FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_INVALID_PARAMETER;
- goto out;
- }
- PrintInfoDebug(0, MSG_222, "Large FAT32");
- UpdateProgressWithInfoInit(NULL, TRUE);
- VolumeId = GetVolumeID();
-
- // Open the drive and lock it
- hLogicalVolume = GetLogicalHandle(DriveIndex, PartitionOffset, TRUE, TRUE, FALSE);
- if (IS_ERROR(FormatStatus))
- goto out;
- if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL))
- die("Invalid logical volume handle", ERROR_INVALID_HANDLE);
-
- // Try to disappear the volume while we're formatting it
- UnmountVolume(hLogicalVolume);
-
- // Work out drive params
- if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dgDrive,
- sizeof(dgDrive), &cbRet, NULL)) {
- if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, xdgDrive,
- sizeof(geometry_ex), &cbRet, NULL)) {
- uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY error: %s", WindowsErrorString());
- die("Failed to get device geometry (both regular and _ex)", ERROR_NOT_SUPPORTED);
- }
- memcpy(&dgDrive, &xdgDrive->Geometry, sizeof(dgDrive));
- }
- if (dgDrive.BytesPerSector < 512)
- dgDrive.BytesPerSector = 512;
- if (IS_ERROR(FormatStatus)) goto out;
- if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &piDrive,
- sizeof(piDrive), &cbRet, NULL)) {
- if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &xpiDrive,
- sizeof(xpiDrive), &cbRet, NULL)) {
- uprintf("IOCTL_DISK_GET_PARTITION_INFO error: %s", WindowsErrorString());
- die("Failed to get partition info (both regular and _ex)", ERROR_NOT_SUPPORTED);
- }
-
- memset(&piDrive, 0, sizeof(piDrive));
- piDrive.StartingOffset.QuadPart = xpiDrive.StartingOffset.QuadPart;
- piDrive.PartitionLength.QuadPart = xpiDrive.PartitionLength.QuadPart;
- piDrive.HiddenSectors = (DWORD) (xpiDrive.StartingOffset.QuadPart / dgDrive.BytesPerSector);
- }
- if (IS_ERROR(FormatStatus)) goto out;
-
- 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", APPERR(ERROR_INVALID_CLUSTER_SIZE));
- }
-
- if (qTotalSectors >= 0xffffffff) {
- // This is a more fundamental limitation on FAT32 - the total sector count in the root dir
- // is 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", APPERR(ERROR_INVALID_VOLUME_SIZE));
- }
-
- // coverity[tainted_data]
- 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", ERROR_NOT_ENOUGH_MEMORY);
- }
-
- // fill out the boot sector and fs info
- pFAT32BootSect->sJmpBoot[0]=0xEB;
- pFAT32BootSect->sJmpBoot[1]=0x58; // jmp.s $+0x5a is 0xeb 0x58, not 0xeb 0x5a. Thanks Marco!
- pFAT32BootSect->sJmpBoot[2]=0x90;
- memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8);
- pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
- 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'
- // zeroed 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",
- 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",
- 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", APPERR(ERROR_INVALID_VOLUME_SIZE));
- }
-
- // Now we're committed - print some info first
- uprintf("Size : %s %u sectors", SizeToHumanReadable(piDrive.PartitionLength.QuadPart, TRUE, FALSE), TotalSectors);
- uprintf("Cluster size %d bytes, %d Bytes Per Sector", SectorsPerCluster*BytesPerSect, BytesPerSect);
- uprintf("Volume ID is %x:%x", VolumeId>>16, VolumeId&0xffff);
- uprintf("%d Reserved Sectors, %d Sectors per FAT, %d FATs", ReservedSectCount, FatSize, NumFATs);
- uprintf("%d Total clusters", ClusterCount);
-
- // Fix up the FSInfo sector
- pFAT32FsInfo->dFree_Count = (UserAreaSize/SectorsPerCluster) - 1;
- pFAT32FsInfo->dNxt_Free = 3; // clusters 0-1 reserved, we used cluster 2 for the root dir
-
- uprintf("%d Free Clusters", 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...", SystemAreaSize);
-
- // Not the most effective, but easy on RAM
- pZeroSect = (BYTE*)calloc(BytesPerSect, BurstSize);
- if (!pZeroSect) {
- die("Failed to allocate memory", ERROR_NOT_ENOUGH_MEMORY);
- }
-
- for (i=0; i<(SystemAreaSize+BurstSize-1); i+=BurstSize) {
- UpdateProgressWithInfo(OP_FORMAT, MSG_217, (uint64_t)i, (uint64_t)(SystemAreaSize + BurstSize));
- CHECK_FOR_USER_CANCEL;
- if (write_sectors(hLogicalVolume, BytesPerSect, i, BurstSize, pZeroSect) != (BytesPerSect*BurstSize)) {
- die("Error clearing reserved sectors", ERROR_WRITE_FAULT);
- }
- }
-
- uprintf ("Initializing reserved sectors and FATs...");
- // 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 EXT2_ET_BASE) && error_code < (EXT2_ET_BASE + 1000)) {
- static_sprintf(error_string, "Unknown ext2fs error %ld (EXT2_ET_BASE + %ld)", error_code, error_code - EXT2_ET_BASE);
- } else {
- SetLastError((FormatStatus == 0) ? (ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | (error_code & 0xFFFF)) : FormatStatus);
- static_sprintf(error_string, WindowsErrorString());
- }
- return error_string;
- }
-}
-
-static float ext2_percent_start = 0.0f, ext2_percent_share = 0.5f;
-const float ext2_max_marker = 80.0f;
-errcode_t ext2fs_print_progress(int64_t cur_value, int64_t max_value)
-{
- static int64_t last_value = -1;
- if (max_value == 0)
- return 0;
- UpdateProgressWithInfo(OP_FORMAT, MSG_217, (uint64_t)((ext2_percent_start * max_value) + (ext2_percent_share * cur_value)), max_value);
- cur_value = (int64_t)(((float)cur_value / (float)max_value) * min(ext2_max_marker, (float)max_value));
- if ((cur_value < last_value) || (cur_value > last_value)) {
- last_value = cur_value;
- uprintfs("+");
- }
- return IS_ERROR(FormatStatus) ? EXT2_ET_CANCEL_REQUESTED : 0;
-}
-
-const char* GetExtFsLabel(DWORD DriveIndex, uint64_t PartitionOffset)
-{
- static char label[EXT2_LABEL_LEN + 1];
- errcode_t r;
- ext2_filsys ext2fs = NULL;
- io_manager manager = nt_io_manager();
- char* volume_name = AltGetLogicalName(DriveIndex, PartitionOffset, FALSE, TRUE);
-
- if (volume_name == NULL)
- return NULL;
- r = ext2fs_open(volume_name, EXT2_FLAG_SKIP_MMP, 0, 0, manager, &ext2fs);
- free(volume_name);
- if (r == 0) {
- strncpy(label, ext2fs->super->s_volume_name, EXT2_LABEL_LEN);
- label[EXT2_LABEL_LEN] = 0;
- }
- if (ext2fs != NULL)
- ext2fs_close(ext2fs);
- return (r == 0) ? label : NULL;
-}
-
-BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags)
-{
- // Mostly taken from mke2fs.conf
- const float reserve_ratio = 0.05f;
- const ext2fs_default_t ext2fs_default[5] = {
- { 3*MB, 1024, 128, 3}, // "floppy"
- { 512*MB, 1024, 128, 2}, // "small"
- { 4*GB, 4096, 256, 2}, // "default"
- { 16*GB, 4096, 256, 3}, // "big"
- { 1024*TB, 4096, 256, 4} // "huge"
- };
-
- BOOL ret = FALSE;
- char *volume_name = NULL;
- int i, count;
- struct ext2_super_block features = { 0 };
- io_manager manager = nt_io_manager();
- blk_t journal_size;
- blk64_t size = 0, cur;
- ext2_filsys ext2fs = NULL;
- errcode_t r;
- uint8_t* buf = NULL;
-
-#if defined(RUFUS_TEST)
- // Create a 32 MB disk image file to test
- uint8_t zb[1024];
- HANDLE h;
- DWORD dwSize;
- volume_name = strdup("\\??\\C:\\tmp\\disk.img");
- memset(zb, 0xFF, sizeof(zb)); // Set to nonzero so we can detect init issues
- h = CreateFileU(volume_name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- for (i = 0; i < 32 * 1024; i++) {
- if (!WriteFile(h, zb, sizeof(zb), &dwSize, NULL) || (dwSize != sizeof(zb))) {
- uprintf("Write error: %s", WindowsErrorString());
- break;
- }
- }
- CloseHandle(h);
-#else
- volume_name = AltGetLogicalName(DriveIndex, PartitionOffset, FALSE, TRUE);
-#endif
- if ((volume_name == NULL) | (strlen(FSName) != 4) || (strncmp(FSName, "ext", 3) != 0)) {
- FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_INVALID_PARAMETER;
- goto out;
- }
- if (strchr(volume_name, ' ') != NULL)
- uprintf("Notice: Using physical device to access partition data");
-
- if ((strcmp(FSName, FileSystemLabel[FS_EXT2]) != 0) && (strcmp(FSName, FileSystemLabel[FS_EXT3]) != 0)) {
- if (strcmp(FSName, FileSystemLabel[FS_EXT4]) == 0)
- uprintf("ext4 file system is not supported, defaulting to ext3");
- else
- uprintf("Invalid ext file system version requested, defaulting to ext3");
- }
-
- if ((strcmp(FSName, FileSystemLabel[FS_EXT2]) != 0) && (strcmp(FSName, FileSystemLabel[FS_EXT3]) != 0))
- FSName = FileSystemLabel[FS_EXT3];
-
- PrintInfoDebug(0, MSG_222, FSName);
- UpdateProgressWithInfoInit(NULL, TRUE);
-
- // Figure out the volume size and block size
- r = ext2fs_get_device_size2(volume_name, KB, &size);
- if ((r != 0) || (size == 0)) {
- FormatStatus = ext2_last_winerror(ERROR_READ_FAULT);
- uprintf("Could not read device size: %s", error_message(r));
- goto out;
- }
- size *= KB;
- for (i = 0; i < ARRAYSIZE(ext2fs_default); i++) {
- if (size < ext2fs_default[i].max_size)
- break;
- }
- assert(i < ARRAYSIZE(ext2fs_default));
- // NB: We validated that BlockSize is a power of two in FormatPartition()
- if (BlockSize == 0)
- BlockSize = ext2fs_default[i].block_size;
- size /= BlockSize;
- for (features.s_log_block_size = 0; EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE; features.s_log_block_size++) {
- if (EXT2_BLOCK_SIZE(&features) == BlockSize)
- break;
- }
- assert(EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE);
-
- // Set the blocks, reserved blocks and inodes
- ext2fs_blocks_count_set(&features, size);
- ext2fs_r_blocks_count_set(&features, (blk64_t)(reserve_ratio * size));
- features.s_rev_level = 1;
- features.s_inode_size = ext2fs_default[i].inode_size;
- features.s_inodes_count = ((ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio) > UINT32_MAX) ?
- UINT32_MAX : (uint32_t)(ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio);
- uprintf("%d possible inodes out of %lld blocks (block size = %d)", features.s_inodes_count, size, EXT2_BLOCK_SIZE(&features));
- uprintf("%lld blocks (%0.1f%%) reserved for the super user", ext2fs_r_blocks_count(&features), reserve_ratio * 100.0f);
-
- // Set features
- ext2fs_set_feature_xattr(&features);
- ext2fs_set_feature_resize_inode(&features);
- ext2fs_set_feature_dir_index(&features);
- ext2fs_set_feature_filetype(&features);
- ext2fs_set_feature_sparse_super(&features);
- ext2fs_set_feature_large_file(&features);
- if (FSName[3] != '2')
- ext2fs_set_feature_journal(&features);
- features.s_backup_bgs[0] = ~0;
- features.s_default_mount_opts = EXT2_DEFM_XATTR_USER | EXT2_DEFM_ACL;
-
- // Now that we have set our base features, initialize a virtual superblock
- r = ext2fs_initialize(volume_name, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_INVALID_DATA);
- uprintf("Could not initialize %s features: %s", FSName, error_message(r));
- goto out;
- }
-
- // Zero 16 blocks of data from the start of our volume
- buf = calloc(16, ext2fs->io->block_size);
- assert(buf != NULL);
- r = io_channel_write_blk64(ext2fs->io, 0, 16, buf);
- safe_free(buf);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
- uprintf("Could not zero %s superblock area: %s", FSName, error_message(r));
- goto out;
- }
-
- // Finish setting up the file system
- IGNORE_RETVAL(CoCreateGuid((GUID*)ext2fs->super->s_uuid));
- ext2fs_init_csum_seed(ext2fs);
- ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4;
- IGNORE_RETVAL(CoCreateGuid((GUID*)ext2fs->super->s_hash_seed));
- ext2fs->super->s_max_mnt_count = -1;
- ext2fs->super->s_creator_os = EXT2_OS_WINDOWS;
- ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE;
- if (Label != NULL)
- static_strcpy(ext2fs->super->s_volume_name, Label);
-
- r = ext2fs_allocate_tables(ext2fs);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_INVALID_DATA);
- uprintf("Could not allocate %s tables: %s", FSName, error_message(r));
- goto out;
- }
- r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map);
- if (r != 0) {
- uprintf("Could not set %s cluster bitmap: %s", FSName, error_message(r));
- goto out;
- }
-
- ext2_percent_start = 0.0f;
- ext2_percent_share = (FSName[3] == '2') ? 1.0f : 0.5f;
- uprintf("Creating %d inode sets: [1 marker = %0.1f set(s)]", ext2fs->group_desc_count,
- max((float)ext2fs->group_desc_count / ext2_max_marker, 1.0f));
- for (i = 0; i < (int)ext2fs->group_desc_count; i++) {
- if (ext2fs_print_progress((int64_t)i, (int64_t)ext2fs->group_desc_count))
- goto out;
- cur = ext2fs_inode_table_loc(ext2fs, i);
- count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(ext2fs, i))
- * EXT2_BLOCK_SIZE(ext2fs->super), EXT2_BLOCK_SIZE(ext2fs->super));
- r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
- uprintf("\r\nCould not zero inode set at position %llu (%d blocks): %s", cur, count, error_message(r));
- goto out;
- }
- }
- uprintfs("\r\n");
-
- // Create root and lost+found dirs
- r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_DIR_NOT_ROOT);
- uprintf("Failed to create %s root dir: %s", FSName, error_message(r));
- goto out;
- }
- ext2fs->umask = 077;
- r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found");
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_DIR_NOT_ROOT);
- uprintf("Failed to create %s 'lost+found' dir: %s", FSName, error_message(r));
- goto out;
- }
-
- // Create bitmaps
- for (i = EXT2_ROOT_INO + 1; i < (int)EXT2_FIRST_INODE(ext2fs->super); i++)
- ext2fs_inode_alloc_stats(ext2fs, i, 1);
- ext2fs_mark_ib_dirty(ext2fs);
-
- r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
- uprintf("Could not set inode bitmaps: %s", error_message(r));
- goto out;
- }
- ext2fs_inode_alloc_stats(ext2fs, EXT2_BAD_INO, 1);
- r = ext2fs_update_bb_inode(ext2fs, NULL);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
- uprintf("Could not set inode stats: %s", error_message(r));
- goto out;
- }
-
- if (FSName[3] != '2') {
- // Create the journal
- ext2_percent_start = 0.5f;
- journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(ext2fs->super));
- journal_size /= 2; // That journal init is really killing us!
- uprintf("Creating %d journal blocks: [1 marker = %0.1f block(s)]", journal_size,
- max((float)journal_size / ext2_max_marker, 1.0f));
- // Even with EXT2_MKJOURNAL_LAZYINIT, this call is absolutely dreadful in terms of speed...
- r = ext2fs_add_journal_inode(ext2fs, journal_size, EXT2_MKJOURNAL_NO_MNT_CHECK | ((Flags & FP_QUICK) ? EXT2_MKJOURNAL_LAZYINIT : 0));
- uprintfs("\r\n");
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
- uprintf("Could not create %s journal: %s", FSName, error_message(r));
- goto out;
- }
- }
-
- // Create a 'persistence.conf' file if required
- if (Flags & FP_CREATE_PERSISTENCE_CONF) {
- // You *do* want the LF at the end of the "/ union" line, else Debian Live bails out...
- const char *name = "persistence.conf", data[] = "/ union\n";
- int written = 0, fsize = sizeof(data) - 1;
- ext2_file_t ext2fd;
- ext2_ino_t inode_id;
- uint32_t ctime = (uint32_t)time(0);
- struct ext2_inode inode = { 0 };
- inode.i_mode = 0100644;
- inode.i_links_count = 1;
- inode.i_atime = ctime;
- inode.i_ctime = ctime;
- inode.i_mtime = ctime;
- inode.i_size = fsize;
-
- ext2fs_namei(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, &inode_id);
- ext2fs_new_inode(ext2fs, EXT2_ROOT_INO, 010755, 0, &inode_id);
- ext2fs_link(ext2fs, EXT2_ROOT_INO, name, inode_id, EXT2_FT_REG_FILE);
- ext2fs_inode_alloc_stats(ext2fs, inode_id, 1);
- ext2fs_write_new_inode(ext2fs, inode_id, &inode);
- ext2fs_file_open(ext2fs, inode_id, EXT2_FILE_WRITE, &ext2fd);
- if ((ext2fs_file_write(ext2fd, data, fsize, &written) != 0) || (written != fsize))
- uprintf("Error: Could not create '%s' file", name);
- else
- uprintf("Created '%s' file", name);
- ext2fs_file_close(ext2fd);
- }
-
- // Finally we can call close() to get the file system gets created
- r = ext2fs_close(ext2fs);
- if (r != 0) {
- FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
- uprintf("Could not create %s volume: %s", FSName, error_message(r));
- goto out;
- }
- UpdateProgressWithInfo(OP_FORMAT, MSG_217, 100, 100);
- uprintf("Done");
- ret = TRUE;
-
-out:
- free(volume_name);
- ext2fs_free(ext2fs);
- free(buf);
- return ret;
-}
-
/*
* Call on VDS to format a partition
*/
@@ -1772,7 +977,8 @@ static __inline const char* bt_to_name(void) {
return ((boot_type == BT_IMAGE) && HAS_KOLIBRIOS(img_report)) ? "KolibriOS" : "Standard";
}
}
-static BOOL WritePBR(HANDLE hLogicalVolume)
+
+BOOL WritePBR(HANDLE hLogicalVolume)
{
int i;
FAKE_FD fake_fd = { 0 };
diff --git a/src/format.h b/src/format.h
index d150d498..48aeb081 100644
--- a/src/format.h
+++ b/src/format.h
@@ -1,8 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Formatting function calls
- * Copyright © 2007-2009 Tom Thornhill/Ridgecrop
- * Copyright © 2011-2019 Pete Batard
+ * Copyright © 2011-2020 Pete Batard
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,8 +19,6 @@
#include
#include // for MEDIA_TYPE
-#include "ext2fs/ext2fs.h"
-
#pragma once
/* Callback command types (some errorcode were filled from HPUSBFW V2.2.3 and their
@@ -107,63 +104,6 @@ typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)(
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)
-
-// For ext2/ext3/ext4 formatting
-typedef struct {
- uint64_t max_size;
- uint32_t block_size;
- uint32_t inode_size;
- uint32_t inode_ratio; // inode to data ration (bitshift)
-} ext2fs_default_t;
-
-extern io_manager nt_io_manager(void);
-extern DWORD ext2_last_winerror(DWORD default_error);
+BOOL WritePBR(HANDLE hLogicalDrive);
+BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags);
+BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags);
diff --git a/src/format_ext.c b/src/format_ext.c
new file mode 100644
index 00000000..4085f89c
--- /dev/null
+++ b/src/format_ext.c
@@ -0,0 +1,491 @@
+/*
+ * Rufus: The Reliable USB Formatting Utility
+ * extfs formatting
+ * Copyright © 2019-2020 Pete Batard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifdef _CRTDBG_MAP_ALLOC
+#include
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+#include "rufus.h"
+#include "file.h"
+#include "drive.h"
+#include "format.h"
+#include "missing.h"
+#include "resource.h"
+#include "msapi_utf8.h"
+#include "localization.h"
+#include "ext2fs/ext2fs.h"
+
+extern const char* FileSystemLabel[FS_MAX];
+extern io_manager nt_io_manager(void);
+extern DWORD ext2_last_winerror(DWORD default_error);
+static float ext2_percent_start = 0.0f, ext2_percent_share = 0.5f;
+const float ext2_max_marker = 80.0f;
+
+typedef struct {
+ uint64_t max_size;
+ uint32_t block_size;
+ uint32_t inode_size;
+ uint32_t inode_ratio;
+} ext2fs_default_t;
+
+const char* error_message(errcode_t error_code)
+{
+ static char error_string[256];
+
+ switch (error_code) {
+ case EXT2_ET_MAGIC_EXT2FS_FILSYS:
+ case EXT2_ET_MAGIC_BADBLOCKS_LIST:
+ case EXT2_ET_MAGIC_BADBLOCKS_ITERATE:
+ case EXT2_ET_MAGIC_INODE_SCAN:
+ case EXT2_ET_MAGIC_IO_CHANNEL:
+ case EXT2_ET_MAGIC_IO_MANAGER:
+ case EXT2_ET_MAGIC_BLOCK_BITMAP:
+ case EXT2_ET_MAGIC_INODE_BITMAP:
+ case EXT2_ET_MAGIC_GENERIC_BITMAP:
+ case EXT2_ET_MAGIC_ICOUNT:
+ case EXT2_ET_MAGIC_EXTENT_HANDLE:
+ case EXT2_ET_BAD_MAGIC:
+ return "Bad magic";
+ case EXT2_ET_RO_FILSYS:
+ return "Read-only file system";
+ case EXT2_ET_GDESC_BAD_BLOCK_MAP:
+ case EXT2_ET_GDESC_BAD_INODE_MAP:
+ case EXT2_ET_GDESC_BAD_INODE_TABLE:
+ return "Bad map or table";
+ case EXT2_ET_UNEXPECTED_BLOCK_SIZE:
+ return "Unexpected block size";
+ case EXT2_ET_DIR_CORRUPTED:
+ return "Corrupted entry";
+ case EXT2_ET_GDESC_READ:
+ case EXT2_ET_GDESC_WRITE:
+ case EXT2_ET_INODE_BITMAP_WRITE:
+ case EXT2_ET_INODE_BITMAP_READ:
+ case EXT2_ET_BLOCK_BITMAP_WRITE:
+ case EXT2_ET_BLOCK_BITMAP_READ:
+ case EXT2_ET_INODE_TABLE_WRITE:
+ case EXT2_ET_INODE_TABLE_READ:
+ case EXT2_ET_NEXT_INODE_READ:
+ case EXT2_ET_SHORT_READ:
+ case EXT2_ET_SHORT_WRITE:
+ return "read/write error";
+ case EXT2_ET_DIR_NO_SPACE:
+ return "no space left";
+ case EXT2_ET_TOOSMALL:
+ return "Too small";
+ case EXT2_ET_BAD_DEVICE_NAME:
+ return "Bad device name";
+ case EXT2_ET_MISSING_INODE_TABLE:
+ return "Missing inode table";
+ case EXT2_ET_CORRUPT_SUPERBLOCK:
+ return "Superblock is corrupted";
+ case EXT2_ET_CALLBACK_NOTHANDLED:
+ return "Unhandled callback";
+ case EXT2_ET_BAD_BLOCK_IN_INODE_TABLE:
+ return "Bad block in inode table";
+ case EXT2_ET_UNSUPP_FEATURE:
+ case EXT2_ET_RO_UNSUPP_FEATURE:
+ case EXT2_ET_UNIMPLEMENTED:
+ return "Unsupported feature";
+ case EXT2_ET_LLSEEK_FAILED:
+ return "Seek failed";
+ case EXT2_ET_NO_MEMORY:
+ case EXT2_ET_BLOCK_ALLOC_FAIL:
+ case EXT2_ET_INODE_ALLOC_FAIL:
+ return "Out of memory";
+ case EXT2_ET_INVALID_ARGUMENT:
+ return "Invalid argument";
+ case EXT2_ET_NO_DIRECTORY:
+ return "No directory";
+ case EXT2_ET_FILE_NOT_FOUND:
+ return "File not found";
+ case EXT2_ET_FILE_RO:
+ return "File is read-only";
+ case EXT2_ET_DIR_EXISTS:
+ return "Directory already exists";
+ case EXT2_ET_CANCEL_REQUESTED:
+ return "Cancel requested";
+ case EXT2_ET_FILE_TOO_BIG:
+ return "File too big";
+ case EXT2_ET_JOURNAL_NOT_BLOCK:
+ case EXT2_ET_NO_JOURNAL_SB:
+ return "No journal superblock";
+ case EXT2_ET_JOURNAL_TOO_SMALL:
+ return "Journal too small";
+ case EXT2_ET_NO_JOURNAL:
+ return "No journal";
+ case EXT2_ET_TOO_MANY_INODES:
+ return "Too many inodes";
+ case EXT2_ET_NO_CURRENT_NODE:
+ return "No current node";
+ case EXT2_ET_OP_NOT_SUPPORTED:
+ return "Operation not supported";
+ case EXT2_ET_IO_CHANNEL_NO_SUPPORT_64:
+ return "I/O Channel does not support 64-bit operation";
+ case EXT2_ET_BAD_DESC_SIZE:
+ return "Bad descriptor size";
+ case EXT2_ET_INODE_CSUM_INVALID:
+ case EXT2_ET_INODE_BITMAP_CSUM_INVALID:
+ case EXT2_ET_EXTENT_CSUM_INVALID:
+ case EXT2_ET_DIR_CSUM_INVALID:
+ case EXT2_ET_EXT_ATTR_CSUM_INVALID:
+ case EXT2_ET_SB_CSUM_INVALID:
+ case EXT2_ET_BLOCK_BITMAP_CSUM_INVALID:
+ case EXT2_ET_MMP_CSUM_INVALID:
+ return "Invalid checksum";
+ case EXT2_ET_UNKNOWN_CSUM:
+ return "Unknown checksum";
+ case EXT2_ET_FILE_EXISTS:
+ return "File exists";
+ case EXT2_ET_INODE_IS_GARBAGE:
+ return "Inode is garbage";
+ case EXT2_ET_JOURNAL_FLAGS_WRONG:
+ return "Wrong journal flags";
+ case EXT2_ET_FILESYSTEM_CORRUPTED:
+ return "File system is corrupted";
+ case EXT2_ET_BAD_CRC:
+ return "Bad CRC";
+ case EXT2_ET_CORRUPT_JOURNAL_SB:
+ return "Journal Superblock is corrupted";
+ case EXT2_ET_INODE_CORRUPTED:
+ case EXT2_ET_EA_INODE_CORRUPTED:
+ return "Inode is corrupted";
+ default:
+ if ((error_code > EXT2_ET_BASE) && error_code < (EXT2_ET_BASE + 1000)) {
+ static_sprintf(error_string, "Unknown ext2fs error %ld (EXT2_ET_BASE + %ld)", error_code, error_code - EXT2_ET_BASE);
+ } else {
+ SetLastError((FormatStatus == 0) ? (ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | (error_code & 0xFFFF)) : FormatStatus);
+ static_sprintf(error_string, WindowsErrorString());
+ }
+ return error_string;
+ }
+}
+
+errcode_t ext2fs_print_progress(int64_t cur_value, int64_t max_value)
+{
+ static int64_t last_value = -1;
+ if (max_value == 0)
+ return 0;
+ UpdateProgressWithInfo(OP_FORMAT, MSG_217, (uint64_t)((ext2_percent_start * max_value) + (ext2_percent_share * cur_value)), max_value);
+ cur_value = (int64_t)(((float)cur_value / (float)max_value) * min(ext2_max_marker, (float)max_value));
+ if ((cur_value < last_value) || (cur_value > last_value)) {
+ last_value = cur_value;
+ uprintfs("+");
+ }
+ return IS_ERROR(FormatStatus) ? EXT2_ET_CANCEL_REQUESTED : 0;
+}
+
+const char* GetExtFsLabel(DWORD DriveIndex, uint64_t PartitionOffset)
+{
+ static char label[EXT2_LABEL_LEN + 1];
+ errcode_t r;
+ ext2_filsys ext2fs = NULL;
+ io_manager manager = nt_io_manager();
+ char* volume_name = AltGetLogicalName(DriveIndex, PartitionOffset, FALSE, TRUE);
+
+ if (volume_name == NULL)
+ return NULL;
+ r = ext2fs_open(volume_name, EXT2_FLAG_SKIP_MMP, 0, 0, manager, &ext2fs);
+ free(volume_name);
+ if (r == 0) {
+ strncpy(label, ext2fs->super->s_volume_name, EXT2_LABEL_LEN);
+ label[EXT2_LABEL_LEN] = 0;
+ }
+ if (ext2fs != NULL)
+ ext2fs_close(ext2fs);
+ return (r == 0) ? label : NULL;
+}
+
+BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags)
+{
+ // Mostly taken from mke2fs.conf
+ const float reserve_ratio = 0.05f;
+ const ext2fs_default_t ext2fs_default[5] = {
+ { 3 * MB, 1024, 128, 3}, // "floppy"
+ { 512 * MB, 1024, 128, 2}, // "small"
+ { 4 * GB, 4096, 256, 2}, // "default"
+ { 16 * GB, 4096, 256, 3}, // "big"
+ { 1024 * TB, 4096, 256, 4} // "huge"
+ };
+
+ BOOL ret = FALSE;
+ char* volume_name = NULL;
+ int i, count;
+ struct ext2_super_block features = { 0 };
+ io_manager manager = nt_io_manager();
+ blk_t journal_size;
+ blk64_t size = 0, cur;
+ ext2_filsys ext2fs = NULL;
+ errcode_t r;
+ uint8_t* buf = NULL;
+
+#if defined(RUFUS_TEST)
+ // Create a disk image file to test
+ uint8_t zb[1024];
+ HANDLE h;
+ DWORD dwSize;
+ HCRYPTPROV hCryptProv = 0;
+ volume_name = strdup(TEST_IMG_PATH);
+ uprintf("Creating '%s'...", volume_name);
+ if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) || !CryptGenRandom(hCryptProv, sizeof(zb), zb)) {
+ uprintf("Failed to randomize buffer - filling with constant value");
+ memset(zb, rand(), sizeof(zb));
+ }
+ CryptReleaseContext(hCryptProv, 0);
+ h = CreateFileU(volume_name, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ for (i = 0; i < TEST_IMG_SIZE * sizeof(zb); i++) {
+ if (!WriteFile(h, zb, sizeof(zb), &dwSize, NULL) || (dwSize != sizeof(zb))) {
+ uprintf("Write error: %s", WindowsErrorString());
+ break;
+ }
+ }
+ CloseHandle(h);
+#else
+ volume_name = AltGetLogicalName(DriveIndex, PartitionOffset, FALSE, TRUE);
+#endif
+ if ((volume_name == NULL) | (strlen(FSName) != 4) || (strncmp(FSName, "ext", 3) != 0)) {
+ FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_INVALID_PARAMETER;
+ goto out;
+ }
+ if (strchr(volume_name, ' ') != NULL)
+ uprintf("Notice: Using physical device to access partition data");
+
+ if ((strcmp(FSName, FileSystemLabel[FS_EXT2]) != 0) && (strcmp(FSName, FileSystemLabel[FS_EXT3]) != 0)) {
+ if (strcmp(FSName, FileSystemLabel[FS_EXT4]) == 0)
+ uprintf("ext4 file system is not supported, defaulting to ext3");
+ else
+ uprintf("Invalid ext file system version requested, defaulting to ext3");
+ }
+
+ if ((strcmp(FSName, FileSystemLabel[FS_EXT2]) != 0) && (strcmp(FSName, FileSystemLabel[FS_EXT3]) != 0))
+ FSName = FileSystemLabel[FS_EXT3];
+
+ PrintInfoDebug(0, MSG_222, FSName);
+ UpdateProgressWithInfoInit(NULL, TRUE);
+
+ // Figure out the volume size and block size
+ r = ext2fs_get_device_size2(volume_name, KB, &size);
+ if ((r != 0) || (size == 0)) {
+ FormatStatus = ext2_last_winerror(ERROR_READ_FAULT);
+ uprintf("Could not read device size: %s", error_message(r));
+ goto out;
+ }
+ size *= KB;
+ for (i = 0; i < ARRAYSIZE(ext2fs_default); i++) {
+ if (size < ext2fs_default[i].max_size)
+ break;
+ }
+ assert(i < ARRAYSIZE(ext2fs_default));
+ // NB: We validated that BlockSize is a power of two in FormatPartition()
+ if (BlockSize == 0)
+ BlockSize = ext2fs_default[i].block_size;
+ size /= BlockSize;
+ for (features.s_log_block_size = 0; EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE; features.s_log_block_size++) {
+ if (EXT2_BLOCK_SIZE(&features) == BlockSize)
+ break;
+ }
+ assert(EXT2_BLOCK_SIZE_BITS(&features) <= EXT2_MAX_BLOCK_LOG_SIZE);
+
+ // Set the blocks, reserved blocks and inodes
+ ext2fs_blocks_count_set(&features, size);
+ ext2fs_r_blocks_count_set(&features, (blk64_t)(reserve_ratio * size));
+ features.s_rev_level = 1;
+ features.s_inode_size = ext2fs_default[i].inode_size;
+ features.s_inodes_count = ((ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio) > UINT32_MAX) ?
+ UINT32_MAX : (uint32_t)(ext2fs_blocks_count(&features) >> ext2fs_default[i].inode_ratio);
+ uprintf("%d possible inodes out of %lld blocks (block size = %d)", features.s_inodes_count, size, EXT2_BLOCK_SIZE(&features));
+ uprintf("%lld blocks (%0.1f%%) reserved for the super user", ext2fs_r_blocks_count(&features), reserve_ratio * 100.0f);
+
+ // Set features
+ ext2fs_set_feature_xattr(&features);
+ // ext2fs_set_feature_resize_inode(&features);
+ ext2fs_set_feature_dir_index(&features);
+ ext2fs_set_feature_filetype(&features);
+ ext2fs_set_feature_sparse_super(&features);
+ ext2fs_set_feature_large_file(&features);
+ if (FSName[3] != '2')
+ ext2fs_set_feature_journal(&features);
+ features.s_backup_bgs[0] = ~0;
+ features.s_default_mount_opts = EXT2_DEFM_XATTR_USER | EXT2_DEFM_ACL;
+
+ // Now that we have set our base features, initialize a virtual superblock
+ r = ext2fs_initialize(volume_name, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_INVALID_DATA);
+ uprintf("Could not initialize %s features: %s", FSName, error_message(r));
+ goto out;
+ }
+
+ // Zero 16 blocks of data from the start of our volume
+ buf = calloc(16, ext2fs->io->block_size);
+ assert(buf != NULL);
+ r = io_channel_write_blk64(ext2fs->io, 0, 16, buf);
+ safe_free(buf);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
+ uprintf("Could not zero %s superblock area: %s", FSName, error_message(r));
+ goto out;
+ }
+
+ // Finish setting up the file system
+ IGNORE_RETVAL(CoCreateGuid((GUID*)ext2fs->super->s_uuid));
+ ext2fs_init_csum_seed(ext2fs);
+ ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4;
+ IGNORE_RETVAL(CoCreateGuid((GUID*)ext2fs->super->s_hash_seed));
+ ext2fs->super->s_max_mnt_count = -1;
+ ext2fs->super->s_creator_os = EXT2_OS_WINDOWS;
+ ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE;
+ if (Label != NULL)
+ static_strcpy(ext2fs->super->s_volume_name, Label);
+
+ r = ext2fs_allocate_tables(ext2fs);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_INVALID_DATA);
+ uprintf("Could not allocate %s tables: %s", FSName, error_message(r));
+ goto out;
+ }
+ r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map);
+ if (r != 0) {
+ uprintf("Could not set %s cluster bitmap: %s", FSName, error_message(r));
+ goto out;
+ }
+
+ ext2_percent_start = 0.0f;
+ ext2_percent_share = (FSName[3] == '2') ? 1.0f : 0.5f;
+ uprintf("Creating %d inode sets: [1 marker = %0.1f set(s)]", ext2fs->group_desc_count,
+ max((float)ext2fs->group_desc_count / ext2_max_marker, 1.0f));
+ for (i = 0; i < (int)ext2fs->group_desc_count; i++) {
+ if (ext2fs_print_progress((int64_t)i, (int64_t)ext2fs->group_desc_count))
+ goto out;
+ cur = ext2fs_inode_table_loc(ext2fs, i);
+ count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(ext2fs, i))
+ * EXT2_BLOCK_SIZE(ext2fs->super), EXT2_BLOCK_SIZE(ext2fs->super));
+ r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
+ uprintf("\r\nCould not zero inode set at position %llu (%d blocks): %s", cur, count, error_message(r));
+ goto out;
+ }
+ }
+ uprintfs("\r\n");
+
+ // Create root and lost+found dirs
+ r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_DIR_NOT_ROOT);
+ uprintf("Failed to create %s root dir: %s", FSName, error_message(r));
+ goto out;
+ }
+ ext2fs->umask = 077;
+ r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found");
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_DIR_NOT_ROOT);
+ uprintf("Failed to create %s 'lost+found' dir: %s", FSName, error_message(r));
+ goto out;
+ }
+
+ // Create bitmaps
+ for (i = EXT2_ROOT_INO + 1; i < (int)EXT2_FIRST_INODE(ext2fs->super); i++)
+ ext2fs_inode_alloc_stats(ext2fs, i, 1);
+ ext2fs_mark_ib_dirty(ext2fs);
+
+ r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
+ uprintf("Could not set inode bitmaps: %s", error_message(r));
+ goto out;
+ }
+ ext2fs_inode_alloc_stats(ext2fs, EXT2_BAD_INO, 1);
+ r = ext2fs_update_bb_inode(ext2fs, NULL);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
+ uprintf("Could not set inode stats: %s", error_message(r));
+ goto out;
+ }
+
+ if (FSName[3] != '2') {
+ // Create the journal
+ ext2_percent_start = 0.5f;
+ journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(ext2fs->super));
+ journal_size /= 2; // That journal init is really killing us!
+ uprintf("Creating %d journal blocks: [1 marker = %0.1f block(s)]", journal_size,
+ max((float)journal_size / ext2_max_marker, 1.0f));
+ // Even with EXT2_MKJOURNAL_LAZYINIT, this call is absolutely dreadful in terms of speed...
+ r = ext2fs_add_journal_inode(ext2fs, journal_size, EXT2_MKJOURNAL_NO_MNT_CHECK | ((Flags & FP_QUICK) ? EXT2_MKJOURNAL_LAZYINIT : 0));
+ uprintfs("\r\n");
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
+ uprintf("Could not create %s journal: %s", FSName, error_message(r));
+ goto out;
+ }
+ }
+
+ // Create a 'persistence.conf' file if required
+ if (Flags & FP_CREATE_PERSISTENCE_CONF) {
+ // You *do* want the LF at the end of the "/ union" line, else Debian Live bails out...
+ const char* name = "persistence.conf", data[] = "/ union\n";
+ int written = 0, fsize = sizeof(data) - 1;
+ ext2_file_t ext2fd;
+ ext2_ino_t inode_id;
+ uint32_t ctime = (uint32_t)time(0);
+ struct ext2_inode inode = { 0 };
+ inode.i_mode = 0100644;
+ inode.i_links_count = 1;
+ inode.i_atime = ctime;
+ inode.i_ctime = ctime;
+ inode.i_mtime = ctime;
+ inode.i_size = fsize;
+
+ ext2fs_namei(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, &inode_id);
+ ext2fs_new_inode(ext2fs, EXT2_ROOT_INO, 010755, 0, &inode_id);
+ ext2fs_link(ext2fs, EXT2_ROOT_INO, name, inode_id, EXT2_FT_REG_FILE);
+ ext2fs_inode_alloc_stats(ext2fs, inode_id, 1);
+ ext2fs_write_new_inode(ext2fs, inode_id, &inode);
+ ext2fs_file_open(ext2fs, inode_id, EXT2_FILE_WRITE, &ext2fd);
+ if ((ext2fs_file_write(ext2fd, data, fsize, &written) != 0) || (written != fsize))
+ uprintf("Error: Could not create '%s' file", name);
+ else
+ uprintf("Created '%s' file", name);
+ ext2fs_file_close(ext2fd);
+ }
+
+ // Finally we can call close() to get the file system gets created
+ r = ext2fs_close(ext2fs);
+ if (r != 0) {
+ FormatStatus = ext2_last_winerror(ERROR_WRITE_FAULT);
+ uprintf("Could not create %s volume: %s", FSName, error_message(r));
+ goto out;
+ }
+ UpdateProgressWithInfo(OP_FORMAT, MSG_217, 100, 100);
+ uprintf("Done");
+ ret = TRUE;
+
+out:
+ free(volume_name);
+ ext2fs_free(ext2fs);
+ free(buf);
+ return ret;
+}
+
diff --git a/src/format_fat32.c b/src/format_fat32.c
new file mode 100644
index 00000000..5bd289f8
--- /dev/null
+++ b/src/format_fat32.c
@@ -0,0 +1,445 @@
+/*
+ * Rufus: The Reliable USB Formatting Utility
+ * Large FAT32 formatting
+ * Copyright © 2007-2009 Tom Thornhill/Ridgecrop
+ * Copyright © 2011-2020 Pete Batard
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifdef _CRTDBG_MAP_ALLOC
+#include
+#include
+#endif
+
+#include
+#include
+#include
+#include
+
+#include "rufus.h"
+#include "file.h"
+#include "drive.h"
+#include "format.h"
+#include "resource.h"
+#include "msapi_utf8.h"
+#include "localization.h"
+
+#define die(msg, err) do { uprintf(msg); \
+ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|err; \
+ goto out; } while(0)
+
+/* 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)
+
+/*
+ * 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 & Hundredths 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;
+}
+
+/*
+ * Proper computation of FAT size
+ * See: http://www.syslinux.org/archives/2016-February/024850.html
+ * and subsequent replies.
+ */
+static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPerClus, DWORD NumFATs, DWORD BytesPerSect)
+{
+ ULONGLONG Numerator, Denominator;
+ ULONGLONG FatElementSize = 4;
+ ULONGLONG ReservedClusCnt = 2;
+ ULONGLONG FatSz;
+
+ Numerator = DskSize - ReservedSecCnt + ReservedClusCnt * SecPerClus;
+ Denominator = SecPerClus * BytesPerSect / FatElementSize + NumFATs;
+ FatSz = Numerator / Denominator + 1; // +1 to ensure we are rounded up
+
+ return (DWORD)FatSz;
+}
+
+/*
+ * Large FAT32 volume formatting from fat32format by Tom Thornhill
+ * http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
+ */
+BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags)
+{
+ BOOL r = FALSE;
+ DWORD i;
+ HANDLE hLogicalVolume = NULL;
+ DWORD cbRet;
+ DISK_GEOMETRY dgDrive;
+ BYTE geometry_ex[256]; // DISK_GEOMETRY_EX is variable size
+ PDISK_GEOMETRY_EX xdgDrive = (PDISK_GEOMETRY_EX)(void*)geometry_ex;
+ PARTITION_INFORMATION piDrive;
+ PARTITION_INFORMATION_EX xpiDrive;
+ // Recommended values
+ DWORD ReservedSectCount = 32;
+ DWORD NumFATs = 2;
+ DWORD BackupBootSect = 6;
+ DWORD VolumeId = 0; // calculated before format
+ char* VolumeName = NULL;
+ DWORD BurstSize = 128; // Zero in blocks of 64K typically
+
+ // Calculated later
+ DWORD FatSize = 0;
+ DWORD BytesPerSect = 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;
+
+ if (safe_strncmp(FSName, "FAT", 3) != 0) {
+ FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_INVALID_PARAMETER;
+ goto out;
+ }
+ PrintInfoDebug(0, MSG_222, "Large FAT32");
+ UpdateProgressWithInfoInit(NULL, TRUE);
+ VolumeId = GetVolumeID();
+
+ // Open the drive and lock it
+ hLogicalVolume = GetLogicalHandle(DriveIndex, PartitionOffset, TRUE, TRUE, FALSE);
+ if (IS_ERROR(FormatStatus))
+ goto out;
+ if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL))
+ die("Invalid logical volume handle", ERROR_INVALID_HANDLE);
+
+ // Try to disappear the volume while we're formatting it
+ UnmountVolume(hLogicalVolume);
+
+ // Work out drive params
+ if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dgDrive,
+ sizeof(dgDrive), &cbRet, NULL)) {
+ if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, xdgDrive,
+ sizeof(geometry_ex), &cbRet, NULL)) {
+ uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY error: %s", WindowsErrorString());
+ die("Failed to get device geometry (both regular and _ex)", ERROR_NOT_SUPPORTED);
+ }
+ memcpy(&dgDrive, &xdgDrive->Geometry, sizeof(dgDrive));
+ }
+ if (dgDrive.BytesPerSector < 512)
+ dgDrive.BytesPerSector = 512;
+ if (IS_ERROR(FormatStatus)) goto out;
+ if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &piDrive,
+ sizeof(piDrive), &cbRet, NULL)) {
+ if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &xpiDrive,
+ sizeof(xpiDrive), &cbRet, NULL)) {
+ uprintf("IOCTL_DISK_GET_PARTITION_INFO error: %s", WindowsErrorString());
+ die("Failed to get partition info (both regular and _ex)", ERROR_NOT_SUPPORTED);
+ }
+
+ memset(&piDrive, 0, sizeof(piDrive));
+ piDrive.StartingOffset.QuadPart = xpiDrive.StartingOffset.QuadPart;
+ piDrive.PartitionLength.QuadPart = xpiDrive.PartitionLength.QuadPart;
+ piDrive.HiddenSectors = (DWORD)(xpiDrive.StartingOffset.QuadPart / dgDrive.BytesPerSector);
+ }
+ if (IS_ERROR(FormatStatus)) goto out;
+
+ 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", APPERR(ERROR_INVALID_CLUSTER_SIZE));
+ }
+
+ if (qTotalSectors >= 0xffffffff) {
+ // This is a more fundamental limitation on FAT32 - the total sector count in the root dir
+ // is 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", APPERR(ERROR_INVALID_VOLUME_SIZE));
+ }
+
+ // coverity[tainted_data]
+ 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", ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ // fill out the boot sector and fs info
+ pFAT32BootSect->sJmpBoot[0] = 0xEB;
+ pFAT32BootSect->sJmpBoot[1] = 0x58; // jmp.s $+0x5a is 0xeb 0x58, not 0xeb 0x5a. Thanks Marco!
+ pFAT32BootSect->sJmpBoot[2] = 0x90;
+ memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8);
+ pFAT32BootSect->wBytsPerSec = (WORD)BytesPerSect;
+ 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'
+ // zeroed 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",
+ 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",
+ 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", APPERR(ERROR_INVALID_VOLUME_SIZE));
+ }
+
+ // Now we're committed - print some info first
+ uprintf("Size : %s %u sectors", SizeToHumanReadable(piDrive.PartitionLength.QuadPart, TRUE, FALSE), TotalSectors);
+ uprintf("Cluster size %d bytes, %d Bytes Per Sector", SectorsPerCluster * BytesPerSect, BytesPerSect);
+ uprintf("Volume ID is %x:%x", VolumeId >> 16, VolumeId & 0xffff);
+ uprintf("%d Reserved Sectors, %d Sectors per FAT, %d FATs", ReservedSectCount, FatSize, NumFATs);
+ uprintf("%d Total clusters", ClusterCount);
+
+ // Fix up the FSInfo sector
+ pFAT32FsInfo->dFree_Count = (UserAreaSize / SectorsPerCluster) - 1;
+ pFAT32FsInfo->dNxt_Free = 3; // clusters 0-1 reserved, we used cluster 2 for the root dir
+
+ uprintf("%d Free Clusters", 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...", SystemAreaSize);
+
+ // Not the most effective, but easy on RAM
+ pZeroSect = (BYTE*)calloc(BytesPerSect, BurstSize);
+ if (!pZeroSect) {
+ die("Failed to allocate memory", ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ for (i = 0; i < (SystemAreaSize + BurstSize - 1); i += BurstSize) {
+ UpdateProgressWithInfo(OP_FORMAT, MSG_217, (uint64_t)i, (uint64_t)(SystemAreaSize + BurstSize));
+ CHECK_FOR_USER_CANCEL;
+ if (write_sectors(hLogicalVolume, BytesPerSect, i, BurstSize, pZeroSect) != (BytesPerSect * BurstSize)) {
+ die("Error clearing reserved sectors", ERROR_WRITE_FAULT);
+ }
+ }
+
+ uprintf ("Initializing reserved sectors and FATs...");
+ // 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", i, SectorStart);
+ write_sectors(hLogicalVolume, BytesPerSect, SectorStart, 1, pFirstSectOfFat);
+ }
+
+ if (!(Flags & FP_NO_BOOT)) {
+ // Must do it here, as have issues when trying to write the PBR after a remount
+ PrintInfoDebug(0, MSG_229);
+ if (!WritePBR(hLogicalVolume)) {
+ // Non fatal error, but the drive probably won't boot
+ uprintf("Could not write partition boot record - drive may not boot...");
+ }
+ }
+
+ // Set the FAT32 volume label
+ PrintInfoDebug(0, MSG_221);
+ // Handle must be closed for SetVolumeLabel to work
+ safe_closehandle(hLogicalVolume);
+ VolumeName = GetLogicalName(DriveIndex, PartitionOffset, TRUE, TRUE);
+ if ((VolumeName == NULL) || (!SetVolumeLabelA(VolumeName, Label))) {
+ uprintf("Could not set label: %s", WindowsErrorString());
+ // Non fatal error
+ }
+
+ uprintf("Format completed.");
+ r = TRUE;
+
+out:
+ safe_free(VolumeName);
+ safe_closehandle(hLogicalVolume);
+ safe_free(pFAT32BootSect);
+ safe_free(pFAT32FsInfo);
+ safe_free(pFirstSectOfFat);
+ safe_free(pZeroSect);
+ return r;
+}
diff --git a/src/rufus.h b/src/rufus.h
index 767c0d8e..5571c423 100644
--- a/src/rufus.h
+++ b/src/rufus.h
@@ -124,6 +124,8 @@
// Bit masks used for the display of additional image options in the UI
#define IMOP_WINTOGO 0x01
#define IMOP_PERSISTENCE 0x02
+#define TEST_IMG_PATH "\\??\\C:\\tmp\\disk.img"
+#define TEST_IMG_SIZE 4500 // Size in MB
#define safe_free(p) do {free((void*)p); p = NULL;} while(0)
#define safe_mm_free(p) do {_mm_free((void*)p); p = NULL;} while(0)
diff --git a/src/rufus.rc b/src/rufus.rc
index cb3f3606..e925d017 100644
--- a/src/rufus.rc
+++ b/src/rufus.rc
@@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
-CAPTION "Rufus 3.9.1603"
+CAPTION "Rufus 3.9.1604"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@@ -394,8 +394,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 3,9,1603,0
- PRODUCTVERSION 3,9,1603,0
+ FILEVERSION 3,9,1604,0
+ PRODUCTVERSION 3,9,1604,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -413,13 +413,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
- VALUE "FileVersion", "3.9.1603"
+ VALUE "FileVersion", "3.9.1604"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2020 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-3.9.exe"
VALUE "ProductName", "Rufus"
- VALUE "ProductVersion", "3.9.1603"
+ VALUE "ProductVersion", "3.9.1604"
END
END
BLOCK "VarFileInfo"