mirror of
https://github.com/pbatard/rufus.git
synced 2025-05-23 19:27:03 -04:00
[core] add file System detection from superblock
* Also prevent GitHub Actions from failing on VirusTotal upload
This commit is contained in:
parent
036f6260c5
commit
ebaa7d561a
6 changed files with 140 additions and 7 deletions
1
.github/workflows/codeql.nope
vendored
1
.github/workflows/codeql.nope
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
# Disabled on account of https://github.com/github/codeql-action/issues/850
|
||||||
name: "CodeQL"
|
name: "CodeQL"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
|
1
.github/workflows/mingw.yml
vendored
1
.github/workflows/mingw.yml
vendored
|
@ -80,6 +80,7 @@ jobs:
|
||||||
run: sha256sum ./rufus.exe
|
run: sha256sum ./rufus.exe
|
||||||
|
|
||||||
- name: Upload to VirusTotal
|
- name: Upload to VirusTotal
|
||||||
|
continue-on-error: true
|
||||||
if: ${{ matrix.env == 'i686' && github.event_name == 'push' }}
|
if: ${{ matrix.env == 'i686' && github.event_name == 'push' }}
|
||||||
run: |
|
run: |
|
||||||
curl --request POST --url https://www.virustotal.com/vtapi/v2/file/scan --form apikey=${{ secrets.VIRUSTOTAL_API_KEY }} --form file=@./rufus.exe
|
curl --request POST --url https://www.virustotal.com/vtapi/v2/file/scan --form apikey=${{ secrets.VIRUSTOTAL_API_KEY }} --form file=@./rufus.exe
|
||||||
|
|
1
.github/workflows/vs2022.yml
vendored
1
.github/workflows/vs2022.yml
vendored
|
@ -70,6 +70,7 @@ jobs:
|
||||||
run: sha256sum ./rufus_${{ matrix.TARGET_PLATFORM }}.exe
|
run: sha256sum ./rufus_${{ matrix.TARGET_PLATFORM }}.exe
|
||||||
|
|
||||||
- name: Upload to VirusTotal
|
- name: Upload to VirusTotal
|
||||||
|
continue-on-error: true
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
run: |
|
run: |
|
||||||
curl --request POST --url https://www.virustotal.com/vtapi/v2/file/scan --form apikey=${{ secrets.VIRUSTOTAL_API_KEY }} --form file=@./rufus_${{ matrix.TARGET_PLATFORM }}.exe
|
curl --request POST --url https://www.virustotal.com/vtapi/v2/file/scan --form apikey=${{ secrets.VIRUSTOTAL_API_KEY }} --form file=@./rufus_${{ matrix.TARGET_PLATFORM }}.exe
|
||||||
|
|
131
src/drive.c
131
src/drive.c
|
@ -1638,6 +1638,132 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a crude attempt at detecting file systems through their superblock magic.
|
||||||
|
// Note that we only attempt to detect the file systems that Rufus can actually format.
|
||||||
|
const char* GetFsName(HANDLE hPhysical, LARGE_INTEGER StartingOffset)
|
||||||
|
{
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
const uint8_t magic[8];
|
||||||
|
} win_fs_type;
|
||||||
|
const win_fs_type win_fs_types[] = {
|
||||||
|
{ "exFAT", { 'E', 'X', 'F', 'A', 'T', ' ', ' ', ' ' } },
|
||||||
|
{ "NTFS", { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ' } },
|
||||||
|
{ "ReFS", { 'R', 'e', 'F', 'S', 0, 0, 0, 0 } }
|
||||||
|
};
|
||||||
|
const win_fs_type fat_fs_types[] = {
|
||||||
|
{ "FAT", { 'F', 'A', 'T', ' ', ' ', ' ', ' ', ' ' } },
|
||||||
|
{ "FAT12", { 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' } },
|
||||||
|
{ "FAT16", { 'F', 'A', 'T', '1', '6', ' ', ' ', ' ' } },
|
||||||
|
{ "FAT32", { 'F', 'A', 'T', '3', '2', ' ', ' ', ' ' } },
|
||||||
|
};
|
||||||
|
const uint32_t ext_feature[3][3] = {
|
||||||
|
// feature_compat
|
||||||
|
{ 0x0000017B, 0x00000004, 0x00000E00 },
|
||||||
|
// feature_ro_compat
|
||||||
|
{ 0x00000003, 0x00000000, 0x00008FF8 },
|
||||||
|
// feature_incompat
|
||||||
|
{ 0x00000013, 0x0000004C, 0x0003F780 }
|
||||||
|
};
|
||||||
|
const char* ext_names[] = { "ext", "ext2", "ext3", "ext4" };
|
||||||
|
const char* ret = "(Unrecognized)";
|
||||||
|
DWORD i, j, offset, size, sector_size = 512;
|
||||||
|
uint8_t* buf = calloc(sector_size, 1);
|
||||||
|
if (buf == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
// 1. Try to detect FAT/exFAT/NTFS/ReFS through the 512 bytes superblock at offset 0
|
||||||
|
if (!SetFilePointerEx(hPhysical, StartingOffset, NULL, FILE_BEGIN))
|
||||||
|
goto out;
|
||||||
|
if (!ReadFile(hPhysical, buf, sector_size, &size, NULL) || size != sector_size)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
|
||||||
|
// The beginning of a superblock for FAT/exFAT/NTFS/ReFS is pretty much always the same:
|
||||||
|
// There are 3 bytes potentially used for a jump instruction, and then are 8 bytes of
|
||||||
|
// OEM Name which, even if *not* technically correct, we are going to assume hold an
|
||||||
|
// immutable file system magic for exFAT/NTFS/ReFS (but not for FAT, see below).
|
||||||
|
for (i = 0; i < ARRAYSIZE(win_fs_types); i++)
|
||||||
|
if (memcmp(&buf[0x03], win_fs_types[i].magic, 8) == 0)
|
||||||
|
break;
|
||||||
|
if (i < ARRAYSIZE(win_fs_types)) {
|
||||||
|
ret = win_fs_types[i].name;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For FAT, because the OEM Name may actually be set to something else than what we
|
||||||
|
// expect, we poke the FAT12/16 Extended BIOS Parameter Block:
|
||||||
|
// https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#Extended_BIOS_Parameter_Block
|
||||||
|
// or FAT32 Extended BIOS Parameter Block:
|
||||||
|
// https://en.wikipedia.org/wiki/Design_of_the_FAT_file_system#FAT32_Extended_BIOS_Parameter_Block
|
||||||
|
for (offset = 0x36; offset <= 0x52; offset += 0x1C) {
|
||||||
|
for (i = 0; i < ARRAYSIZE(fat_fs_types); i++)
|
||||||
|
if (memcmp(&buf[offset], fat_fs_types[i].magic, 8) == 0)
|
||||||
|
break;
|
||||||
|
if (i < ARRAYSIZE(fat_fs_types)) {
|
||||||
|
ret = fat_fs_types[i].name;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Try to detect Apple AFS/HFS/HFS+ through the 512 bytes superblock at either offset 0 or 1024
|
||||||
|
// "NXSB" at offset 0x20 => APFS
|
||||||
|
if (strncmp("NXSB", &buf[0x20], 4) == 0) {
|
||||||
|
ret = "APFS";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
// Switch to offset 1024
|
||||||
|
memset(buf, sector_size, 0);
|
||||||
|
StartingOffset.QuadPart += 0x0400ULL;
|
||||||
|
if (!SetFilePointerEx(hPhysical, StartingOffset, NULL, FILE_BEGIN))
|
||||||
|
goto out;
|
||||||
|
if (!ReadFile(hPhysical, buf, sector_size, &size, NULL) || size != sector_size)
|
||||||
|
goto out;
|
||||||
|
// "HX" or "H+" at offset 0x00 => HFS/HFS+
|
||||||
|
if (buf[0] == 'H' && (buf[1] == 'X' || buf[1] == '+')) {
|
||||||
|
ret = "HFS/HFS+";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Try to detect ext2/ext3/ext4 through the 512 bytes superblock at offset 1024
|
||||||
|
// We're already at the right offset
|
||||||
|
if (!SetFilePointerEx(hPhysical, StartingOffset, NULL, FILE_BEGIN))
|
||||||
|
goto out;
|
||||||
|
if (!ReadFile(hPhysical, buf, sector_size, &size, NULL) || size != sector_size)
|
||||||
|
goto out;
|
||||||
|
if (buf[0x38] == 0x53 && buf[0x39] == 0xEF) {
|
||||||
|
uint32_t rev = 0;
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
uint32_t feature = *((uint32_t*)&buf[0x5C + 4 * i]);
|
||||||
|
for (j = 0; j < 3; j++) {
|
||||||
|
if (feature & ext_feature[i][j] && rev <= j)
|
||||||
|
rev = j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(rev < ARRAYSIZE(ext_names));
|
||||||
|
ret = ext_names[rev];
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Try to detect UDF through by looking for a "BEA01\0" string at offset 0xC001
|
||||||
|
// NB: This is not thorough UDF detection but good enough for our purpose.
|
||||||
|
// For the full specs see: http://www.osta.org/specs/pdf/udf260.pdf
|
||||||
|
memset(buf, sector_size, 0);
|
||||||
|
StartingOffset.QuadPart += 0x8000ULL - 0x0400ULL;
|
||||||
|
if (!SetFilePointerEx(hPhysical, StartingOffset, NULL, FILE_BEGIN))
|
||||||
|
goto out;
|
||||||
|
if (!ReadFile(hPhysical, buf, sector_size, &size, NULL) || size != sector_size)
|
||||||
|
goto out;
|
||||||
|
if (strncmp("BEA01", &buf[1], 5) == 0) {
|
||||||
|
ret = "UDF";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(buf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill the drive properties (size, FS, etc)
|
* Fill the drive properties (size, FS, etc)
|
||||||
* Returns TRUE if the drive has a partition that can be mounted in Windows, FALSE otherwise
|
* Returns TRUE if the drive has a partition that can be mounted in Windows, FALSE otherwise
|
||||||
|
@ -1754,9 +1880,11 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
|
||||||
SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
|
SelectedDrive.PartitionOffset[i] = DriveLayout->PartitionEntry[i].StartingOffset.QuadPart;
|
||||||
SelectedDrive.PartitionSize[i] = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
|
SelectedDrive.PartitionSize[i] = DriveLayout->PartitionEntry[i].PartitionLength.QuadPart;
|
||||||
}
|
}
|
||||||
suprintf(" Type: %s (0x%02x)\r\n Size: %s (%lld bytes)\r\n Start Sector: %lld, Boot: %s",
|
suprintf(" Type: %s (0x%02x)\r\n Detected File System: %s\r\n"
|
||||||
|
" Size: %s (%lld bytes)\r\n Start Sector: %lld, Boot: %s",
|
||||||
((part_type == 0x07 || super_floppy_disk) && (FileSystemName[0] != 0)) ?
|
((part_type == 0x07 || super_floppy_disk) && (FileSystemName[0] != 0)) ?
|
||||||
FileSystemName : GetMBRPartitionType(part_type), super_floppy_disk ? 0: part_type,
|
FileSystemName : GetMBRPartitionType(part_type), super_floppy_disk ? 0: part_type,
|
||||||
|
GetFsName(hPhysical, DriveLayout->PartitionEntry[i].StartingOffset),
|
||||||
SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE),
|
SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE),
|
||||||
DriveLayout->PartitionEntry[i].PartitionLength.QuadPart,
|
DriveLayout->PartitionEntry[i].PartitionLength.QuadPart,
|
||||||
DriveLayout->PartitionEntry[i].StartingOffset.QuadPart / SelectedDrive.SectorSize,
|
DriveLayout->PartitionEntry[i].StartingOffset.QuadPart / SelectedDrive.SectorSize,
|
||||||
|
@ -1789,6 +1917,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
|
||||||
GetGPTPartitionType(&DriveLayout->PartitionEntry[i].Gpt.PartitionType));
|
GetGPTPartitionType(&DriveLayout->PartitionEntry[i].Gpt.PartitionType));
|
||||||
if (DriveLayout->PartitionEntry[i].Gpt.Name[0] != 0)
|
if (DriveLayout->PartitionEntry[i].Gpt.Name[0] != 0)
|
||||||
suprintf(" Name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name);
|
suprintf(" Name: '%S'", DriveLayout->PartitionEntry[i].Gpt.Name);
|
||||||
|
suprintf(" Detected File System: %s", GetFsName(hPhysical, DriveLayout->PartitionEntry[i].StartingOffset));
|
||||||
suprintf(" ID: %s\r\n Size: %s (%" PRIi64 " bytes)\r\n Start Sector: %" PRIi64 ", Attributes: 0x%016" PRIX64,
|
suprintf(" ID: %s\r\n Size: %s (%" PRIi64 " bytes)\r\n Start Sector: %" PRIi64 ", Attributes: 0x%016" PRIX64,
|
||||||
GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId),
|
GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId),
|
||||||
SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE),
|
SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE),
|
||||||
|
|
|
@ -406,7 +406,8 @@ static BOOL IsRefsAvailable(MEDIA_TYPE MediaType)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (nWindowsVersion < WINDOWS_8_1 || nWindowsBuildNumber <= 0)
|
if (nWindowsVersion < WINDOWS_8_1 || nWindowsBuildNumber <= 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (nWindowsBuildNumber < 16000)
|
// Per https://gist.github.com/0xbadfca11/da0598e47dd643d933dc
|
||||||
|
if (nWindowsBuildNumber < 16226)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
switch (nWindowsEdition) {
|
switch (nWindowsEdition) {
|
||||||
case 0x0000000A: // Enterprise Server
|
case 0x0000000A: // Enterprise Server
|
||||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
EXSTYLE WS_EX_ACCEPTFILES
|
EXSTYLE WS_EX_ACCEPTFILES
|
||||||
CAPTION "Rufus 3.18.1866"
|
CAPTION "Rufus 3.18.1867"
|
||||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||||
BEGIN
|
BEGIN
|
||||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||||
|
@ -395,8 +395,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 3,18,1866,0
|
FILEVERSION 3,18,1867,0
|
||||||
PRODUCTVERSION 3,18,1866,0
|
PRODUCTVERSION 3,18,1867,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -414,13 +414,13 @@ BEGIN
|
||||||
VALUE "Comments", "https://rufus.ie"
|
VALUE "Comments", "https://rufus.ie"
|
||||||
VALUE "CompanyName", "Akeo Consulting"
|
VALUE "CompanyName", "Akeo Consulting"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "3.18.1866"
|
VALUE "FileVersion", "3.18.1867"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||||
VALUE "OriginalFilename", "rufus-3.18.exe"
|
VALUE "OriginalFilename", "rufus-3.18.exe"
|
||||||
VALUE "ProductName", "Rufus"
|
VALUE "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "3.18.1866"
|
VALUE "ProductVersion", "3.18.1867"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue