From c2b2624b62c8eb2622d547c735331c47abb21eb4 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 3 Feb 2024 18:38:17 +0000 Subject: [PATCH] [vhd] improve handing of user selected filename on save to VHD/FFU * Use of '*.*' as pattern in file save dialog could lead to assert and crash, so we now try to derive the type of image to be saved from the file extension. We also did not properly handle user cancellation in the file save dialog. * Also update iso9660/iso9660_fs.c to latest proposal of El Torito image handling. * Also add a couple asserts in the hash table functions so that, if these ever get triggered we will pick them from Windows Store reports, and clean up code. --- src/libcdio/iso9660/iso9660_fs.c | 34 ++++++++++++++++++++++++++++---- src/rufus.rc | 10 +++++----- src/stdfn.c | 16 ++++++++------- src/vhd.c | 27 +++++++++++++++---------- 4 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/libcdio/iso9660/iso9660_fs.c b/src/libcdio/iso9660/iso9660_fs.c index d0244279..b6e66a99 100644 --- a/src/libcdio/iso9660/iso9660_fs.c +++ b/src/libcdio/iso9660/iso9660_fs.c @@ -60,7 +60,7 @@ #include "_cdio_stdio.h" #include "cdio_private.h" -/* Maximum number of El-Torito boot images we keep an index for */ +/* Maximum number of El-Torito boot images we keep an index for */ #define MAX_BOOT_IMAGES 8 /** Implementation of iso9660_t type */ @@ -532,13 +532,39 @@ iso9660_ifs_read_superblock (iso9660_t *p_iso, (memcmp(p_brvd->system_id, EL_TORITO_ID, ISO_MAX_SYSTEM_ID) == 0)) { /* Perform basic parsing of boot entries to fill an image table */ iso9660_br_t br[ISO_BLOCKSIZE / sizeof(iso9660_br_t)]; - if (iso9660_iso_seek_read(p_iso, &br, p_brvd->boot_catalog_sector, 1) == ISO_BLOCKSIZE) { + if (iso9660_iso_seek_read(p_iso, &br, p_brvd->boot_catalog_sector, 1) == + ISO_BLOCKSIZE) { for (j = 0, k = 0; j < (ISO_BLOCKSIZE / sizeof(iso9660_br_t)) && k < MAX_BOOT_IMAGES; j++) { if (br[j].boot_id == 0x88 && br[j].media_type == 0) { - p_iso->boot_img[k].lsn = br[j].image_lsn; - p_iso->boot_img[k++].num_sectors = br[j].num_sectors; + p_iso->boot_img[k].lsn = uint32_from_le(br[j].image_lsn); + p_iso->boot_img[k++].num_sectors = uint16_from_le(br[j].num_sectors); + } + } + /* Special case for non specs-compliant images that do follow the UEFI */ + /* specs and that use size 0 or 1 for images larger than 0xffff virtual */ + /* sectors, in which case the image runs to the end of the volume (per */ + /* UEFI specs) or to the next LSN (as seen with some software). */ + cdio_assert(ISO_BLOCKSIZE / VIRTUAL_SECTORSIZE == 4); + for (j = 0; j < MAX_BOOT_IMAGES; j++) { + uint32_t next_lsn = from_733(p_iso->pvd.volume_space_size); + if (p_iso->boot_img[j].lsn == 0) + continue; + /* Find the closest LSN after the one from this image */ + cdio_assert(p_iso->boot_img[j].lsn < next_lsn); + for (k = 0; k < MAX_BOOT_IMAGES; k++) { + if (p_iso->boot_img[k].lsn > p_iso->boot_img[j].lsn && + p_iso->boot_img[k].lsn < next_lsn) + next_lsn = p_iso->boot_img[k].lsn; + } + /* If the image has a sector size of 0 or 1 and theres' more than */ + /* 0xffff sectors to the next LSN, assume it needs expansion. */ + if (p_iso->boot_img[j].num_sectors <= 1 && + (next_lsn - p_iso->boot_img[j].lsn) >= 0x4000) { + p_iso->boot_img[j].num_sectors = + (next_lsn - p_iso->boot_img[j].lsn) * 4; + cdio_warn("Auto-expanding the size of %d-Boot-NoEmul.img", j); } } } diff --git a/src/rufus.rc b/src/rufus.rc index f9872d92..22e2b668 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 4.4.2105" +CAPTION "Rufus 4.4.2106" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -392,8 +392,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,4,2105,0 - PRODUCTVERSION 4,4,2105,0 + FILEVERSION 4,4,2106,0 + PRODUCTVERSION 4,4,2106,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -411,13 +411,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.4.2105" + VALUE "FileVersion", "4.4.2106" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2024 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.4.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.4.2105" + VALUE "ProductVersion", "4.4.2106" END END BLOCK "VarFileInfo" diff --git a/src/stdfn.c b/src/stdfn.c index f23019c0..dd9d4547 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -80,8 +80,9 @@ BOOL htab_create(uint32_t nel, htab_table* htab) if (htab == NULL) { return FALSE; } + assert(htab->table == NULL); if (htab->table != NULL) { - uprintf("warning: htab_create() was called with a non empty table"); + uprintf("Warning: htab_create() was called with a non empty table"); return FALSE; } @@ -96,7 +97,7 @@ BOOL htab_create(uint32_t nel, htab_table* htab) // allocate memory and zero out. htab->table = (htab_entry*)calloc(htab->size + 1, sizeof(htab_entry)); if (htab->table == NULL) { - uprintf("could not allocate space for hash table\n"); + uprintf("Could not allocate space for hash table"); return FALSE; } @@ -166,7 +167,7 @@ uint32_t htab_hash(char* str, htab_table* htab) // existing hash return idx; } - // uprintf("hash collision ('%s' vs '%s')\n", str, htab->table[idx].str); + // uprintf("Hash collision ('%s' vs '%s')", str, htab->table[idx].str); // Second hash function, as suggested in [Knuth] hval2 = 1 + hval % (htab->size - 2); @@ -196,19 +197,20 @@ uint32_t htab_hash(char* str, htab_table* htab) // Not found => New entry // If the table is full return an error + assert(htab->filled < htab->size); if (htab->filled >= htab->size) { - uprintf("hash table is full (%d entries)", htab->size); + uprintf("Hash table is full (%d entries)", htab->size); return 0; } safe_free(htab->table[idx].str); htab->table[idx].used = hval; - htab->table[idx].str = (char*) malloc(safe_strlen(str)+1); + htab->table[idx].str = (char*) malloc(safe_strlen(str) + 1); if (htab->table[idx].str == NULL) { - uprintf("could not duplicate string for hash table\n"); + uprintf("Could not duplicate string for hash table"); return 0; } - memcpy(htab->table[idx].str, str, safe_strlen(str)+1); + memcpy(htab->table[idx].str, str, safe_strlen(str) + 1); ++htab->filled; return idx; diff --git a/src/vhd.c b/src/vhd.c index 60508262..9340079b 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Virtual Disk Handling functions - * Copyright © 2013-2023 Pete Batard + * Copyright © 2013-2024 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -1111,6 +1111,7 @@ void VhdSaveImage(void) char filename[128]; char path[MAX_PATH]; int DriveIndex = ComboBox_GetCurSel(hDeviceList); + enum { image_type_vhd = 1, image_type_vhdx = 2, image_type_ffu = 3 }; static EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhd", "*.vhdx", "*.ffu"), __VA_GROUP__(lmprintf(MSG_343), lmprintf(MSG_342), lmprintf(MSG_344))); ULARGE_INTEGER free_space; @@ -1123,20 +1124,26 @@ void VhdSaveImage(void) img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex); img_save.DevicePath = GetPhysicalName(img_save.DeviceNum); // FFU support requires GPT - if (!has_ffu_support || SelectedDrive.PartitionStyle != PARTITION_STYLE_GPT) - img_ext.count = 2; - for (i = 1; i <= (UINT)img_ext.count && (safe_strcmp(&_img_ext_x[i - 1][2], save_image_type) != 0); i++); + img_ext.count = (!has_ffu_support || SelectedDrive.PartitionStyle != PARTITION_STYLE_GPT) ? 2 : 3; + for (i = 1; i <= (UINT)img_ext.count && (safe_strcmp(save_image_type , &_img_ext_x[i - 1][2]) != 0); i++); if (i > (UINT)img_ext.count) - i = 2; + i = image_type_vhdx; img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, &i); - assert(i > 0 && i <= (UINT)img_ext.count); - save_image_type = (char*) &_img_ext_x[i - 1][2]; - WriteSettingStr(SETTING_PREFERRED_SAVE_IMAGE_TYPE, save_image_type); + if (img_save.ImagePath == NULL) + goto out; + for (i = 1; i <= (UINT)img_ext.count && (strstr(img_save.ImagePath, &_img_ext_x[i - 1][1]) == NULL); i++); + if (i > (UINT)img_ext.count) { + uprintf("Warning: Can not determine image type from extension - Saving to uncompressed VHD."); + i = image_type_vhd; + } else { + save_image_type = (char*)&_img_ext_x[i - 1][2]; + WriteSettingStr(SETTING_PREFERRED_SAVE_IMAGE_TYPE, save_image_type); + } switch (i) { - case 1: + case image_type_vhd: img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHD; break; - case 3: + case image_type_ffu: img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_FFU; break; default: