[iso] add basic El-Torito image parsing to libcdio

* Based on El-Torito specs found at https://pdos.csail.mit.edu/6.828/2014/readings/boot-cdrom.pdf.
* Follows 7-zip's virtual '[BOOT]/#...' naming conventions (though we don't check for the full name).
* Limited to 8 NoEmul images.
This commit is contained in:
Pete Batard 2024-01-16 17:21:32 +00:00
parent 2cebf914fd
commit ae6732c07b
No known key found for this signature in database
GPG Key ID: 38E0CF5E69EDD671
3 changed files with 87 additions and 7 deletions

View File

@ -162,6 +162,7 @@ extern enum iso_vd_enum_s {
extern const char ISO_STANDARD_ID[sizeof("CD001")-1];
#define ISO_STANDARD_ID "CD001"
#define EL_TORITO_ID "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0"
#define CDIO_EXTENT_BLOCKS(size) ((size + (ISO_BLOCKSIZE - 1)) / ISO_BLOCKSIZE)
@ -506,6 +507,37 @@ struct iso9660_svd_s {
typedef struct iso9660_svd_s iso9660_svd_t;
/*!
\brief ISO-9660 Boot Record Volume Descriptor.
*/
struct iso9660_brvd_s {
uint8_t type; /**< ISO_VD_BOOT_RECORD - 0 */
char id[5]; /**< ISO_STANDARD_ID "CD001" */
uint8_t version; /**< value 1 for El Torito */
char system_id[ISO_MAX_SYSTEM_ID]; /**< Boot system ID */
uint8_t unused1[32]; /**< unused - value 0 */
uint32_t boot_catalog_sector; /**< first sector of boot catalog */
uint8_t unused2[1973]; /**< Unused - value 0 */
} GNUC_PACKED;
typedef struct iso9660_brvd_s iso9660_brvd_t;
/*!
\brief ISO-9660 Boot Record Volume Descriptor.
*/
struct iso9660_br_s {
uint8_t boot_id; /**< Boot indicator - 0x88 */
uint8_t media_type; /**< Boot media type - 0 for no emul. */
uint16_t load_seg; /**< Load segment for x86 */
uint8_t system_type; /**< System type - 0 for x86 */
uint8_t unused1;
uint16_t num_sectors; /**< Sector count of the image */
uint32_t image_lsn; /**< Start address of the image */
uint8_t unused2[20];
} GNUC_PACKED;
typedef struct iso9660_br_s iso9660_br_t;
PRAGMA_END_PACKED
/*! \brief A data type for a list of ISO9660
@ -582,7 +614,8 @@ extern enum iso_extension_enum_s {
ISO_EXTENSION_JOLIET_LEVEL2 = 0x02,
ISO_EXTENSION_JOLIET_LEVEL3 = 0x04,
ISO_EXTENSION_ROCK_RIDGE = 0x08,
ISO_EXTENSION_HIGH_SIERRA = 0x10
ISO_EXTENSION_HIGH_SIERRA = 0x10,
ISO_EXTENSION_EL_TORITO = 0x20
} iso_extension_enums;

View File

@ -59,6 +59,8 @@
#include "_cdio_stdio.h"
#include "cdio_private.h"
#define MAX_BOOT_IMAGES 8
/** Implementation of iso9660_t type */
struct _iso9660_s {
cdio_header_t header; /**< Internal header - MUST come first. */
@ -83,6 +85,10 @@ struct _iso9660_s {
be CDIO_CD_FRAMESIZE_RAW (2352) or
M2RAW_SECTOR_SIZE (2336).
*/
struct {
uint32_t lsn; /**< Start LSN of an El-Torito bootable image */
uint32_t num_sectors; /**< Number of sectors of a bootable image */
} boot_img[MAX_BOOT_IMAGES];
int i_fuzzy_offset; /**< Adjustment in bytes to make ISO_STANDARD_ID
("CD001") come out as ISO_PVD_SECTOR
(frame 16). Normally this should be 0
@ -505,7 +511,8 @@ iso9660_ifs_read_superblock (iso9660_t *p_iso,
iso_extension_mask_t iso_extension_mask)
{
iso9660_svd_t p_svd; /* Secondary volume descriptor. */
int i;
iso9660_brvd_t* p_brvd = (iso9660_brvd_t*)&p_svd; /* Boot record volume descriptor. */
int i, j, k;
if (!p_iso || !iso9660_ifs_read_pvd(p_iso, &(p_iso->pvd)))
return false;
@ -516,6 +523,24 @@ iso9660_ifs_read_superblock (iso9660_t *p_iso,
for (i=1; (0 != iso9660_iso_seek_read (p_iso, &p_svd, ISO_PVD_SECTOR+i, 1)); i++) {
if (ISO_VD_END == from_711(p_svd.type) ) /* Last SVD */
break;
if (iso_extension_mask & ISO_EXTENSION_EL_TORITO) {
/* Check for an El-Torito boot volume descriptor */
if (ISO_VD_BOOT_RECORD == from_711(p_svd.type) &&
(memcmp(p_brvd->system_id, EL_TORITO_ID, ISO_MAX_SYSTEM_ID) == 0)) {
/* Perform very 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) {
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;
}
}
}
}
}
if ( ISO_VD_SUPPLEMENTARY == from_711(p_svd.type) ) {
/* We're only interested in Joliet => make sure the SVD isn't overwritten */
if (p_iso->u_joliet_level == 0)
@ -1441,6 +1466,28 @@ iso9660_fs_stat_translate (CdIo_t *p_cdio, const char psz_path[])
iso9660_stat_t *
iso9660_ifs_stat_translate (iso9660_t *p_iso, const char psz_path[])
{
/* Special case for virtual El-Torito boot images ('[BOOT]/#.img') */
if (psz_path && (strncmp(psz_path, "[BOOT]/", 7) == 0)) {
int index = psz_path[7] - '0';
iso9660_stat_t* p_stat;
if (strlen(psz_path) < 8)
return NULL;
if ((psz_path[7] < '0') || (psz_path[7] > '0' + MAX_BOOT_IMAGES - 1))
return NULL;
if (p_iso->boot_img[index].lsn == 0 || p_iso->boot_img[index].num_sectors == 0)
return NULL;
p_stat = calloc(1, sizeof(iso9660_stat_t) + strlen(psz_path));
if (!p_stat) {
cdio_warn("Couldn't calloc(1, %d)", (int)sizeof(iso9660_stat_t));
return NULL;
}
p_stat->lsn = p_iso->boot_img[index].lsn;
p_stat->total_size = p_iso->boot_img[index].num_sectors * ISO_BLOCKSIZE;
p_stat->type = _STAT_FILE;
strcpy(p_stat->filename, psz_path);
return p_stat;
}
return fs_stat_translate(p_iso, (stat_root_t *) _ifs_stat_root,
(stat_traverse_t *) _fs_iso_stat_traverse,
psz_path);

View File

@ -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.2099"
CAPTION "Rufus 4.4.2100"
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,2099,0
PRODUCTVERSION 4,4,2099,0
FILEVERSION 4,4,2100,0
PRODUCTVERSION 4,4,2100,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.2099"
VALUE "FileVersion", "4.4.2100"
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.2099"
VALUE "ProductVersion", "4.4.2100"
END
END
BLOCK "VarFileInfo"