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…
	
	Add table
		Add a link
		
	
		Reference in a new issue