mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[misc] move Large FAT32 and ext formatting to their own source
* Also add randomization to test images
This commit is contained in:
parent
3c9acb0d3c
commit
35af4cbacb
10 changed files with 973 additions and 868 deletions
|
@ -337,6 +337,8 @@
|
|||
<ClCompile Include="..\src\drive.c" />
|
||||
<ClCompile Include="..\src\format.c" />
|
||||
<ClCompile Include="..\src\dos.c" />
|
||||
<ClCompile Include="..\src\format_ext.c" />
|
||||
<ClCompile Include="..\src\format_fat32.c" />
|
||||
<ClCompile Include="..\src\icon.c" />
|
||||
<ClCompile Include="..\src\iso.c" />
|
||||
<ClCompile Include="..\src\localization.c" />
|
||||
|
|
|
@ -81,6 +81,12 @@
|
|||
<ClCompile Include="..\src\ui.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\format_ext.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\format_fat32.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\rufus.h">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
798
src/format.c
798
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 <pete@akeo.ie>
|
||||
*
|
||||
* 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<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;
|
||||
}
|
||||
|
||||
// Error messages for ext2fs
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 };
|
||||
|
|
68
src/format.h
68
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 <pete@akeo.ie>
|
||||
* Copyright © 2011-2020 Pete Batard <pete@akeo.ie>
|
||||
*
|
||||
* 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 <windows.h>
|
||||
#include <winioctl.h> // 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);
|
||||
|
|
491
src/format_ext.c
Normal file
491
src/format_ext.c
Normal file
|
@ -0,0 +1,491 @@
|
|||
/*
|
||||
* Rufus: The Reliable USB Formatting Utility
|
||||
* extfs formatting
|
||||
* Copyright © 2019-2020 Pete Batard <pete@akeo.ie>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
445
src/format_fat32.c
Normal file
445
src/format_fat32.c
Normal file
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* Rufus: The Reliable USB Formatting Utility
|
||||
* Large FAT32 formatting
|
||||
* Copyright © 2007-2009 Tom Thornhill/Ridgecrop
|
||||
* Copyright © 2011-2020 Pete Batard <pete@akeo.ie>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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)
|
||||
|
|
10
src/rufus.rc
10
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"
|
||||
|
|
Loading…
Reference in a new issue